diff --git a/busybox-1_37_0/.gitignore b/busybox-1_37_0/.gitignore new file mode 100644 index 000000000..becd9bf6d --- /dev/null +++ b/busybox-1_37_0/.gitignore @@ -0,0 +1,63 @@ +# +# Kbuild ignores +# +.* +*.o +*.o.* +*.a +*.s +Kbuild +Config.in + +# +# Never ignore these +# +!.gitignore + +# +# Normal output +# +/busybox +/busybox_old +/busybox_unstripped* + +# +# Backups / patches +# +*~ +*.orig +*.rej +/*.patch + +# +# debugging stuff +# +core +.gdb_history +.gdbinit + +# +# testing output +# +/busybox.links +/runtest-tempdir-links +/testsuite/echo-ne + +# +# cscope output +# +cscope.files +cscope.in.out +cscope.out +cscope.po.out + +# +# ctags output +# +tags +TAGS + +# +# user-supplied scripts +# +/embed diff --git a/busybox-1_37_0/AUTHORS b/busybox-1_37_0/AUTHORS new file mode 100644 index 000000000..9ec0e2ee4 --- /dev/null +++ b/busybox-1_37_0/AUTHORS @@ -0,0 +1,186 @@ +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 +incorrect, _please_ let me know. + + -Erik + +----------- + +Peter Willis + eject + +Emanuele Aina + run-parts + +Erik Andersen + Tons of new stuff, major rewrite of most of the + core apps, tons of new apps as noted in header files. + Lots of tedious effort writing these boring docs that + nobody is going to actually read. + +Laurence Anderson + rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm + +Jeff Angielski + ftpput, ftpget + +Enrik Berkhan + setconsole + +Jim Bauer + modprobe shell dependency + +Edward Betts + expr, hostid, logname, whoami + +John Beppu + du, nslookup, sort + +David Brownell + zcip + +Brian Candler + tiny-ls(ls) + +Randolph Chung + fbset, ping, hostname + +Dave Cinege + more(v2), makedevs, dutmp, modularization, auto links file, + various fixes, Linux Router Project maintenance + +Jordan Crouse + ipcalc + +Magnus Damm + tftp client + insmod powerpc support + +Larry Doolittle + pristine source directory compilation, lots of patches and fixes. + +Glenn Engel + httpd + +Gennady Feldman + Sysklogd (single threaded syslogd, IPC Circular buffer support, + logread), various fixes. + +Robert Griebl + modprobe, hwclock, suid/sgid handling, tinylogin integration + many bugfixes and enhancements + +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 + +Rob Landley + Became busybox maintainer in 2006. + + sed (major rewrite in 2003, and I now maintain the thing) + bunzip2 (complete from-scratch rewrite, then mjn3 optimized the result) + sort (more or less from scratch rewrite in 2004, I now maintain it) + mount (rewrite in 2005, I maintain the new one) + +Stephan Linz + ipcalc, Red Hat equivalence + +John Lombardo + tr + +Glenn McGrath + Common unarchiving code and unarchiving applets, ifupdown, ftpgetput, + nameif, sed, patch, fold, install, uudecode. + Various bugfixes, review and apply numerous patches. + +Manuel Novoa III + cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes, + mesg, vconfig, nice, renice, + make_directory, parse_mode, dirname, mode_string, + get_last_path_component, simplify_path, and a number trivial libbb routines + + also bug fixes, partial rewrites, and size optimizations in + ash, basename, cal, cmp, cp, df, du, echo, env, ln, logname, md5sum, mkdir, + mv, realpath, rm, sort, tail, touch, uname, watch, arith, human_readable, + interface, dutmp, ifconfig, route + +Vladimir Oleynik + cmdedit; bb_mkdep, xargs(current), httpd(current); + ports: ash, crond, fdisk (initial, unmaintained now), inetd, stty, traceroute, + top; + locale, various fixes + and irreconcilable critic of everything not perfect. + +Bruce Perens + Original author of BusyBox in 1995, 1996. Some of his code can + still be found hiding here and there... + +Rodney Radford + ipcs, ipcrm + +Tim Riker + bug fixes, member of fan club + +Kent Robotti + reset, tons and tons of bug reports and patches. + +Chip Rosenthal , + wget - Contributed by permission of Covad Communications + +Pavel Roskin + Lots of bugs fixes and patches. + +Gyepi Sam + Remote logging feature for syslogd + +Rob Sullivan + comm + +Linus Torvalds + mkswap, fsck.minix, mkfs.minix + +Linus Walleij + fbset and fbsplash config RGBA parsing + rewrite of mdev helper to create devices from /sys/dev + +Mark Whitley + grep, sed, cut, xargs(previous), + 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 + +Tito Ragusa + devfsd and size optimizations in strings, openvt, chvt, deallocvt, hdparm, + fdformat, lsattr, chattr, id and eject. + +Paul Fox + vi editing mode for ash, various other patches/fixes + +Roberto A. Foglietta + port: dnsd + +Bernhard Reutner-Fischer + misc + +Mike Frysinger + initial e2fsprogs, printenv, setarch, sum, misc + +Jie Zhang + fixed two bugs in msh and hush (exitcode of killed processes) + +Maxime Coste + paste implementation + +Roger Knecht + tree diff --git a/busybox-1_37_0/INSTALL b/busybox-1_37_0/INSTALL new file mode 100644 index 000000000..750cfc45b --- /dev/null +++ b/busybox-1_37_0/INSTALL @@ -0,0 +1,142 @@ +Building: +========= + +The BusyBox build process is similar to the Linux kernel build: + + make menuconfig # This creates a file called ".config" + make # This creates the "busybox" executable + make install # or make CONFIG_PREFIX=/path/from/root install + +The full list of configuration and install options is available by typing: + + make help + +Quick Start: +============ + +The easy way to try out BusyBox for the first time, without having to install +it, is to enable all features and then use "standalone shell" mode with a +blank command $PATH. + +To enable all features, use "make defconfig", which produces the largest +general-purpose configuration. It's allyesconfig minus debugging options, +optional packaging choices, and a few special-purpose features requiring +extra configuration to use. Then enable "standalone shell" feature: + + make defconfig + make menuconfig + # select Busybox Settings + # then General Configuration + # then exec prefers applets + # exit back to top level menu + # select Shells + # then Standalone shell + # exit back to top level menu + # exit and save new configuration + # OR + # use these commands to modify .config directly: + sed -e 's/.*FEATURE_PREFER_APPLETS.*/CONFIG_FEATURE_PREFER_APPLETS=y/' -i .config + sed -e 's/.*FEATURE_SH_STANDALONE.*/CONFIG_FEATURE_SH_STANDALONE=y/' -i .config + make + PATH= ./busybox ash + +Standalone shell mode causes busybox's built-in command shell to run +any built-in busybox applets directly, without looking for external +programs by that name. Supplying an empty command path (as above) means +the only commands busybox can find are the built-in ones. + +Note that the standalone shell requires CONFIG_BUSYBOX_EXEC_PATH +to be set appropriately, depending on whether or not /proc/self/exe is +available. If you do not have /proc, then point that config option +to the location of your busybox binary, usually /bin/busybox. +Another solution is to patch the kernel (see +examples/linux-*_proc_self_exe.patch) to make exec("/proc/self/exe") +always work. + +Configuring Busybox: +==================== + +Busybox is optimized for size, but enabling the full set of functionality +still results in a fairly large executable -- more than 1 megabyte when +statically linked. To save space, busybox can be configured with only the +set of applets needed for each environment. The minimal configuration, with +all applets disabled, produces a 4k executable. (It's useless, but very small.) + +The manual configurator "make menuconfig" modifies the existing configuration. +(For systems without ncurses, try "make config" instead.) The two most +interesting starting configurations are "make allnoconfig" (to start with +everything disabled and add just what you need), and "make defconfig" (to +start with everything enabled and remove what you don't need). If menuconfig +is run without an existing configuration, make defconfig will run first to +create a known starting point. + +Other starting configurations (mostly used for testing purposes) include +"make allbareconfig" (enables all applets but disables all optional features), +"make allyesconfig" (enables absolutely everything including debug features), +and "make randconfig" (produce a random configuration). The configs/ directory +contains a number of additional configuration files ending in _defconfig which +are useful in specific cases. "make help" will list them. + +Configuring BusyBox produces a file ".config", which can be saved for future +use. Run "make oldconfig" to bring a .config file from an older version of +busybox up to date. + +Installing Busybox: +=================== + +Busybox is a single executable that can behave like many different commands, +and BusyBox uses the name it was invoked under to determine the desired +behavior. (Try "mv busybox ls" and then "./ls -l".) + +Installing busybox consists of creating symlinks (or hardlinks) to the busybox +binary for each applet enabled in busybox, and making sure these symlinks are +in the shell's command $PATH. Running "make install" creates these symlinks, +or "make install-hardlinks" creates hardlinks instead (useful on systems with +a limited number of inodes). This install process uses the file +"busybox.links" (created by make), which contains the list of enabled applets +and the path at which to install them. + +Installing links to busybox is not always necessary. The special applet name +"busybox" (or with any optional suffix, such as "busybox-static") uses the +first argument to determine which applet to behave as, for example +"./busybox cat LICENSE". (Running the busybox applet with no arguments gives +a list of all enabled applets.) The standalone shell can also call busybox +applets without links to busybox under other names in the filesystem. You can +also configure a standalone install capability into the busybox base applet, +and then install such links at runtime with one of "busybox --install" (for +hardlinks) or "busybox --install -s" (for symlinks). + +If you enabled the busybox shared library feature (libbusybox.so) and want +to run tests without installing, set your LD_LIBRARY_PATH accordingly when +running the executable: + + LD_LIBRARY_PATH=`pwd` ./busybox + +Building out-of-tree: +===================== + +By default, the BusyBox build puts its temporary files in the source tree. +Building from a read-only source tree, or building multiple configurations from +the same source directory, requires the ability to put the temporary files +somewhere else. + +To build out of tree, cd to an empty directory and configure busybox from there: + + make KBUILD_SRC=/path/to/source -f /path/to/source/Makefile defconfig + make + make install + +Alternately, use the O=$BUILDPATH option (with an absolute path) during the +configuration step, as in: + + make O=/some/empty/directory allyesconfig + cd /some/empty/directory + make + make CONFIG_PREFIX=. install + +More Information: +================= + +Se also the busybox FAQ, under the questions "How can I get started using +BusyBox" and "How do I build a BusyBox-based system?" The BusyBox FAQ is +available from http://www.busybox.net/FAQ.html diff --git a/busybox-1_37_0/LICENSE b/busybox-1_37_0/LICENSE new file mode 100644 index 000000000..6f50a7164 --- /dev/null +++ b/busybox-1_37_0/LICENSE @@ -0,0 +1,348 @@ +--- A note on GPL versions + +BusyBox is distributed under version 2 of the General Public License (included +in its entirety, below). Version 2 is the only version of this license which +this version of BusyBox (or modified versions derived from this one) may be +distributed under. + +------------------------------------------------------------------------ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 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-1_37_0/Makefile b/busybox-1_37_0/Makefile new file mode 100644 index 000000000..1ec8ac3fd --- /dev/null +++ b/busybox-1_37_0/Makefile @@ -0,0 +1,1329 @@ +VERSION = 1 +PATCHLEVEL = 37 +SUBLEVEL = 0 +EXTRAVERSION = +NAME = Unnamed + +# *DOCUMENTATION* +# To see a list of typical targets execute "make help" +# More info can be located in ./README +# Comments in this file are targeted only to the developer, do not +# expect to learn how to build the kernel reading this file. + +# Do not print "Entering directory ..." +MAKEFLAGS += --no-print-directory + +# We are using a recursive build, so we need to do a little thinking +# to get the ordering right. +# +# Most importantly: sub-Makefiles should only ever modify files in +# their own directory. If in some directory we have a dependency on +# a file in another dir (which doesn't happen often, but it's often +# unavoidable when linking the built-in.o targets which finally +# turn into busybox), we will call a sub make in that other dir, and +# after that we are sure that everything which is in that other dir +# is now up to date. +# +# The only cases where we need to modify files which have global +# effects are thus separated out and done before the recursive +# descending is started. They are now explicitly listed as the +# prepare rule. + +# To put more focus on warnings, be less verbose as default +# Use 'make V=1' to see the full commands + +ifdef V + ifeq ("$(origin V)", "command line") + KBUILD_VERBOSE = $(V) + endif +endif +ifndef KBUILD_VERBOSE + KBUILD_VERBOSE = 0 +endif + +# Call sparse as part of compilation of C files +# Use 'make C=1' to enable sparse checking + +ifdef C + ifeq ("$(origin C)", "command line") + KBUILD_CHECKSRC = $(C) + endif +endif +ifndef KBUILD_CHECKSRC + KBUILD_CHECKSRC = 0 +endif + +# Use make M=dir to specify directory of external module to build +# Old syntax make ... SUBDIRS=$PWD is still supported +# Setting the environment variable KBUILD_EXTMOD take precedence +ifdef SUBDIRS + KBUILD_EXTMOD ?= $(SUBDIRS) +endif +ifdef M + ifeq ("$(origin M)", "command line") + KBUILD_EXTMOD := $(M) + endif +endif + + +# kbuild supports saving output files in a separate directory. +# To locate output files in a separate directory two syntaxes are supported. +# In both cases the working directory must be the root of the kernel src. +# 1) O= +# Use "make O=dir/to/store/output/files/" +# +# 2) Set KBUILD_OUTPUT +# Set the environment variable KBUILD_OUTPUT to point to the directory +# where the output files shall be placed. +# export KBUILD_OUTPUT=dir/to/store/output/files/ +# make +# +# The O= assignment takes precedence over the KBUILD_OUTPUT environment +# variable. + + +# KBUILD_SRC is set on invocation of make in OBJ directory +# KBUILD_SRC is not intended to be used by the regular user (for now) +ifeq ($(KBUILD_SRC),) + +# OK, Make called in directory where kernel src resides +# Do we want to locate output files in a separate directory? +ifdef O + ifeq ("$(origin O)", "command line") + KBUILD_OUTPUT := $(O) + endif +endif + +# That's our default target when none is given on the command line +PHONY := _all +_all: + +ifneq ($(KBUILD_OUTPUT),) +# Invoke a second make in the output directory, passing relevant variables +# check that the output directory actually exists +saved-output := $(KBUILD_OUTPUT) +KBUILD_OUTPUT := $(shell cd $(KBUILD_OUTPUT) && /bin/pwd) +$(if $(KBUILD_OUTPUT),, \ + $(error output directory "$(saved-output)" does not exist)) + +PHONY += $(MAKECMDGOALS) + +$(filter-out _all,$(MAKECMDGOALS)) _all: + $(if $(KBUILD_VERBOSE:1=),@)$(MAKE) -C $(KBUILD_OUTPUT) \ + KBUILD_SRC=$(CURDIR) \ + KBUILD_EXTMOD="$(KBUILD_EXTMOD)" -f $(CURDIR)/Makefile $@ + +# Leave processing to above invocation of make +skip-makefile := 1 +endif # ifneq ($(KBUILD_OUTPUT),) +endif # ifeq ($(KBUILD_SRC),) + +# We process the rest of the Makefile if this is the final invocation of make +ifeq ($(skip-makefile),) + +# If building an external module we do not care about the all: rule +# but instead _all depend on modules +PHONY += all +ifeq ($(KBUILD_EXTMOD),) +_all: all +else +_all: modules +endif + +srctree := $(if $(KBUILD_SRC),$(KBUILD_SRC),$(CURDIR)) +TOPDIR := $(srctree) +# FIXME - TOPDIR is obsolete, use srctree/objtree +objtree := $(CURDIR) +src := $(srctree) +obj := $(objtree) + +VPATH := $(srctree)$(if $(KBUILD_EXTMOD),:$(KBUILD_EXTMOD)) + +export srctree objtree VPATH TOPDIR + + +# Cross compiling and selecting different set of gcc/bin-utils +# --------------------------------------------------------------------------- +# +# When performing cross compilation for other architectures ARCH shall be set +# to the target architecture. (See arch/* for the possibilities). +# ARCH can be set during invocation of make: +# make ARCH=ia64 +# Another way is to have ARCH set in the environment. +# The default ARCH is the host where make is executed. + +# CROSS_COMPILE specify the prefix used for all executables used +# during compilation. Only gcc and related bin-utils executables +# are prefixed with $(CROSS_COMPILE). +# CROSS_COMPILE can be set on the command line +# make CROSS_COMPILE=ia64-linux- +# Alternatively CROSS_COMPILE can be set in the environment. +# Default value for CROSS_COMPILE is not to prefix executables +# Note: Some architectures assign CROSS_COMPILE in their arch/*/Makefile + +CROSS_COMPILE ?= +# bbox: we may have CONFIG_CROSS_COMPILER_PREFIX in .config, +# and it has not been included yet... thus using an awkward syntax. +ifeq ($(CROSS_COMPILE),) +CROSS_COMPILE := $(shell grep ^CONFIG_CROSS_COMPILER_PREFIX .config 2>/dev/null) +CROSS_COMPILE := $(subst CONFIG_CROSS_COMPILER_PREFIX=,,$(CROSS_COMPILE)) +CROSS_COMPILE := $(subst ",,$(CROSS_COMPILE)) +#") +endif + +# SUBARCH tells the usermode build what the underlying arch is. That is set +# first, and if a usermode build is happening, the "ARCH=um" on the command +# line overrides the setting of ARCH below. If a native build is happening, +# then ARCH is assigned, getting whatever value it gets normally, and +# SUBARCH is subsequently ignored. + +ifneq ($(CROSS_COMPILE),) +SUBARCH := $(shell echo $(CROSS_COMPILE) | cut -d- -f1 | sed 's:^.*/::g') +else +SUBARCH := $(shell uname -m) +endif +SUBARCH := $(shell echo $(SUBARCH) | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ \ + -e s/arm.*/arm/ -e s/sa110/arm/ \ + -e s/s390x/s390/ -e s/parisc64/parisc/ \ + -e s/ppc.*/powerpc/ -e s/mips.*/mips/ ) + +ARCH ?= $(SUBARCH) + +# Architecture as present in compile.h +UTS_MACHINE := $(ARCH) + +# SHELL used by kbuild +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) + +# Decide whether to build built-in, modular, or both. +# Normally, just do built-in. + +KBUILD_MODULES := +KBUILD_BUILTIN := 1 + +# If we have only "make modules", don't compile built-in objects. +# When we're building modules with modversions, we need to consider +# the built-in objects during the descend as well, in order to +# make sure the checksums are uptodate before we record them. + +ifeq ($(MAKECMDGOALS),modules) + KBUILD_BUILTIN := $(if $(CONFIG_MODVERSIONS),1) +endif + +# If we have "make modules", compile modules +# in addition to whatever we do anyway. +# Just "make" or "make all" shall build modules as well + +ifneq ($(filter all _all modules,$(MAKECMDGOALS)),) + KBUILD_MODULES := 1 +endif + +ifeq ($(MAKECMDGOALS),) + KBUILD_MODULES := 1 +endif + +export KBUILD_MODULES KBUILD_BUILTIN +export KBUILD_CHECKSRC KBUILD_SRC KBUILD_EXTMOD + +# Beautify output +# --------------------------------------------------------------------------- +# +# Normally, we echo the whole command before executing it. By making +# that echo $($(quiet)$(cmd)), we now have the possibility to set +# $(quiet) to choose other forms of output instead, e.g. +# +# quiet_cmd_cc_o_c = Compiling $(RELDIR)/$@ +# cmd_cc_o_c = $(CC) $(c_flags) -c -o $@ $< +# +# If $(quiet) is empty, the whole command will be printed. +# If it is set to "quiet_", only the short version will be printed. +# If it is set to "silent_", nothing wil be printed at all, since +# the variable $(silent_cmd_cc_o_c) doesn't exist. +# +# A simple variant is to prefix commands with $(Q) - that's useful +# for commands that shall be hidden in non-verbose mode. +# +# $(Q)ln $@ :< +# +# If KBUILD_VERBOSE equals 0 then the above command will be hidden. +# If KBUILD_VERBOSE equals 1 then the above command is displayed. + +ifeq ($(KBUILD_VERBOSE),1) + quiet = + Q = +else + quiet=quiet_ + Q = @ +endif + +# If the user is running make -s (silent mode), suppress echoing of +# commands + +ifneq ($(findstring s,$(MAKEFLAGS)),) + quiet=silent_ +endif + +export quiet Q KBUILD_VERBOSE + + +# Look for make include files relative to root of kernel src +MAKEFLAGS += --include-dir=$(srctree) + +HOSTCC = gcc +HOSTCXX = g++ +HOSTCFLAGS := +HOSTCXXFLAGS := +# We need some generic definitions +include $(srctree)/scripts/Kbuild.include + +HOSTCFLAGS += $(call hostcc-option,-Wall -Wstrict-prototypes -O2 -fomit-frame-pointer,) +HOSTCXXFLAGS += -O2 + +# For maximum performance (+ possibly random breakage, uncomment +# the following) + +MAKEFLAGS += -rR + +# Make variables (CC, etc...) + +AS = $(CROSS_COMPILE)as +CC = $(CROSS_COMPILE)gcc +LD = $(CC) -nostdlib +CPP = $(CC) -E +AR = $(CROSS_COMPILE)ar +NM = $(CROSS_COMPILE)nm +STRIP = $(CROSS_COMPILE)strip +OBJCOPY = $(CROSS_COMPILE)objcopy +OBJDUMP = $(CROSS_COMPILE)objdump +PKG_CONFIG ?= $(CROSS_COMPILE)pkg-config +AWK = awk +GENKSYMS = scripts/genksyms/genksyms +DEPMOD = /sbin/depmod +KALLSYMS = scripts/kallsyms +PERL = perl +CHECK = sparse + +CHECKFLAGS := -D__linux__ -Dlinux -D__STDC__ -Dunix -D__unix__ -Wbitwise $(CF) +MODFLAGS = -DMODULE +CFLAGS_MODULE = $(MODFLAGS) +AFLAGS_MODULE = $(MODFLAGS) +LDFLAGS_MODULE = -r +CFLAGS_KERNEL = +AFLAGS_KERNEL = + + +# Use LINUXINCLUDE when you must reference the include/ directory. +# Needed to be compatible with the O= option +CFLAGS := $(CFLAGS) +# Added only to final link stage of busybox binary +CFLAGS_busybox := $(CFLAGS_busybox) +CPPFLAGS := $(CPPFLAGS) +AFLAGS := $(AFLAGS) +LDFLAGS := $(LDFLAGS) +LDLIBS := + +# Read KERNELRELEASE from .kernelrelease (if it exists) +KERNELRELEASE = $(shell cat .kernelrelease 2> /dev/null) +KERNELVERSION = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +export VERSION PATCHLEVEL SUBLEVEL KERNELRELEASE KERNELVERSION \ + ARCH CONFIG_SHELL HOSTCC HOSTCFLAGS CROSS_COMPILE AS LD CC \ + CPP AR NM STRIP OBJCOPY OBJDUMP MAKE AWK GENKSYMS PERL UTS_MACHINE \ + HOSTCXX HOSTCXXFLAGS LDFLAGS_MODULE CHECK CHECKFLAGS + +export CPPFLAGS NOSTDINC_FLAGS LINUXINCLUDE OBJCOPYFLAGS LDFLAGS +export CFLAGS CFLAGS_KERNEL CFLAGS_MODULE +export AFLAGS AFLAGS_KERNEL AFLAGS_MODULE +export FLTFLAGS + +# When compiling out-of-tree modules, put MODVERDIR in the module +# tree rather than in the kernel tree. The kernel tree might +# even be read-only. +export MODVERDIR := $(if $(KBUILD_EXTMOD),$(firstword $(KBUILD_EXTMOD))/).tmp_versions + +# Files to ignore in find ... statements + +RCS_FIND_IGNORE := \( -name SCCS -o -name BitKeeper -o -name .svn -o -name CVS -o -name .pc -o -name .hg -o -name .git \) -prune -o +export RCS_TAR_IGNORE := --exclude SCCS --exclude BitKeeper --exclude .svn --exclude CVS --exclude .pc --exclude .hg --exclude .git + +# =========================================================================== +# Rules shared between *config targets and build targets + +# Basic helpers built in scripts/ +PHONY += scripts_basic +scripts_basic: + $(Q)$(MAKE) $(build)=scripts/basic + +# To avoid any implicit rule to kick in, define an empty command. +scripts/basic/%: scripts_basic ; + +# This target generates Kbuild's and Config.in's from *.c files +PHONY += gen_build_files +gen_build_files: $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) $(wildcard $(srctree)/embed/*) + $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) + +# bbox: we have helpers in applets/ +# we depend on scripts_basic, since scripts/basic/fixdep +# must be built before any other host prog +PHONY += applets_dir +applets_dir: scripts_basic gen_build_files include/config/MARKER + $(Q)$(MAKE) $(build)=applets + +applets/%: applets_dir ; + +PHONY += outputmakefile +# outputmakefile generates a Makefile in the output directory, if using a +# separate output directory. This allows convenient use of make in the +# output directory. +outputmakefile: +ifneq ($(KBUILD_SRC),) + $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \ + $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL) +endif + +# To make sure we do not include .config for any of the *config targets +# catch them early, and hand them over to scripts/kconfig/Makefile +# It is allowed to specify more targets when calling make, including +# mixing *config targets and build targets. +# For example 'make oldconfig all'. +# Detect when mixed targets is specified, and make a second invocation +# of make so .config is not included in this case either (for *config). + +no-dot-config-targets := clean mrproper distclean \ + cscope TAGS tags help %docs +#bbox# check% is removed from above + +config-targets := 0 +mixed-targets := 0 +dot-config := 1 + +ifneq ($(filter $(no-dot-config-targets), $(MAKECMDGOALS)),) + ifeq ($(filter-out $(no-dot-config-targets), $(MAKECMDGOALS)),) + dot-config := 0 + endif +endif + +ifeq ($(KBUILD_EXTMOD),) + ifneq ($(filter config %config,$(MAKECMDGOALS)),) + config-targets := 1 + ifneq ($(filter-out config %config,$(MAKECMDGOALS)),) + mixed-targets := 1 + endif + endif +endif + +ifeq ($(mixed-targets),1) +# =========================================================================== +# We're called with mixed targets (*config and build targets). +# Handle them one by one. + +%:: FORCE + $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= $@ + +else +ifeq ($(config-targets),1) +# =========================================================================== +# *config targets only - make sure prerequisites are updated, and descend +# in scripts/kconfig to make the *config target + +# Read arch specific Makefile to set KBUILD_DEFCONFIG as needed. +# KBUILD_DEFCONFIG may point out an alternative default configuration +# used for 'make defconfig' +-include $(srctree)/arch/$(ARCH)/Makefile +export KBUILD_DEFCONFIG + +config: scripts_basic outputmakefile gen_build_files FORCE + $(Q)mkdir -p include + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease + +%config: scripts_basic outputmakefile gen_build_files FORCE + $(Q)mkdir -p include + $(Q)$(MAKE) $(build)=scripts/kconfig $@ + $(Q)$(MAKE) -C $(srctree) KBUILD_SRC= .kernelrelease + +else +# =========================================================================== +# Build targets only - this includes busybox, arch specific targets, clean +# targets and others. In general all targets except *config targets. + +ifeq ($(KBUILD_EXTMOD),) +# Additional helpers built in scripts/ +# Carefully list dependencies so we do not try to build scripts twice +# in parallel +PHONY += scripts +scripts: gen_build_files scripts_basic include/config/MARKER + $(Q)$(MAKE) $(build)=$(@) + +scripts_basic: include/autoconf.h + +# Objects we will link into busybox / subdirs we need to visit +core-y := \ + applets/ \ + +libs-y := \ + archival/ \ + archival/libarchive/ \ + console-tools/ \ + coreutils/ \ + coreutils/libcoreutils/ \ + debianutils/ \ + klibc-utils/ \ + e2fsprogs/ \ + editors/ \ + findutils/ \ + init/ \ + libbb/ \ + libpwdgrp/ \ + loginutils/ \ + mailutils/ \ + miscutils/ \ + modutils/ \ + networking/ \ + networking/libiproute/ \ + networking/udhcp/ \ + printutils/ \ + procps/ \ + runit/ \ + selinux/ \ + shell/ \ + sysklogd/ \ + util-linux/ \ + util-linux/volume_id/ \ + +endif # KBUILD_EXTMOD + +ifeq ($(dot-config),1) +# In this section, we need .config + +# Read in dependencies to all Kconfig* files, make sure to run +# oldconfig if changes are detected. +-include .kconfig.d + +-include .config + +# If .config needs to be updated, it will be done via the dependency +# that autoconf has on .config. +# To avoid any implicit rule to kick in, define an empty command +.config .kconfig.d: ; + +-include $(srctree)/arch/$(ARCH)/Makefile + +# Now we can define CFLAGS etc according to .config +include $(srctree)/Makefile.flags + +# If .config is newer than include/autoconf.h, someone tinkered +# with it and forgot to run make oldconfig. +# If kconfig.d is missing then we are probarly in a cleaned tree so +# we execute the config step to be sure to catch updated Kconfig files +include/autoconf.h: .kconfig.d .config $(wildcard $(srctree)/*/*.c) $(wildcard $(srctree)/*/*/*.c) | gen_build_files + $(Q)$(MAKE) -f $(srctree)/Makefile silentoldconfig + +include/usage.h: gen_build_files + +else +# Dummy target needed, because used as prerequisite +include/autoconf.h: ; +endif + +# The all: target is the default when no target is given on the +# command line. +# This allow a user to issue only 'make' to build a kernel including modules +# Defaults busybox but it is usually overridden in the arch makefile +all: busybox doc + +# arch Makefile may override CC so keep this after arch Makefile is included +#bbox# NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) +CHECKFLAGS += $(NOSTDINC_FLAGS) + +# Default kernel image to build when no specific target is given. +# KBUILD_IMAGE may be overruled on the commandline or +# set in the environment +# Also any assignments in arch/$(ARCH)/Makefile take precedence over +# this default value +export KBUILD_IMAGE ?= busybox + +# +# INSTALL_PATH specifies where to place the updated kernel and system map +# images. Default is /boot, but you can set it to other values +export INSTALL_PATH ?= /boot + +# +# INSTALL_MOD_PATH specifies a prefix to MODLIB for module directory +# relocations required by build roots. This is not defined in the +# makefile but the argument can be passed to make if needed. +# + +MODLIB = $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) +export MODLIB + + +ifeq ($(KBUILD_EXTMOD),) +busybox-dirs := $(patsubst %/,%,$(filter %/, $(core-y) $(core-m) $(libs-y) $(libs-m))) + +busybox-alldirs := $(sort $(busybox-dirs) $(patsubst %/,%,$(filter %/, \ + $(core-n) $(core-) $(libs-n) $(libs-) \ + ))) + +core-y := $(patsubst %/, %/built-in.o, $(core-y)) +libs-y1 := $(patsubst %/, %/lib.a, $(libs-y)) +libs-y2 := $(patsubst %/, %/built-in.o, $(libs-y)) +libs-y := $(libs-y1) $(libs-y2) + +# Build busybox +# --------------------------------------------------------------------------- +# busybox is build from the objects selected by $(busybox-init) and +# $(busybox-main). Most are built-in.o files from top-level directories +# in the kernel tree, others are specified in arch/$(ARCH)Makefile. +# Ordering when linking is important, and $(busybox-init) must be first. +# +# busybox +# ^ +# | +# +-< $(busybox-init) +# | +--< init/version.o + more +# | +# +--< $(busybox-main) +# | +--< driver/built-in.o mm/built-in.o + more +# | +# +-< kallsyms.o (see description in CONFIG_KALLSYMS section) +# +# busybox version (uname -v) cannot be updated during normal +# descending-into-subdirs phase since we do not yet know if we need to +# update busybox. +# Therefore this step is delayed until just before final link of busybox - +# except in the kallsyms case where it is done just before adding the +# symbols to the kernel. +# +# System.map is generated to document addresses of all kernel symbols + +busybox-all := $(core-y) $(libs-y) + +# Rule to link busybox - also used during CONFIG_KALLSYMS +# May be overridden by arch/$(ARCH)/Makefile +quiet_cmd_busybox__ ?= LINK $@ + cmd_busybox__ ?= $(srctree)/scripts/trylink \ + "$@" \ + "$(CC)" \ + "$(CFLAGS) $(CFLAGS_busybox)" \ + "$(LDFLAGS) $(EXTRA_LDFLAGS)" \ + "$(core-y)" \ + "$(libs-y)" \ + "$(LDLIBS)" \ + "$(CONFIG_EXTRA_LDLIBS)" \ + && $(srctree)/scripts/generate_BUFSIZ.sh --post include/common_bufsiz.h + +# Generate System.map +quiet_cmd_sysmap = SYSMAP + cmd_sysmap = $(CONFIG_SHELL) $(srctree)/scripts/mksysmap + +# Link of busybox +# If CONFIG_KALLSYMS is set .version is already updated +# Generate System.map and verify that the content is consistent +# Use + in front of the busybox_version rule to silent warning with make -j2 +# First command is ':' to allow us to use + in front of the rule +define rule_busybox__ + : + $(call cmd,busybox__) + $(Q)echo 'cmd_$@ := $(cmd_busybox__)' > $(@D)/.$(@F).cmd +endef + + +ifdef CONFIG_KALLSYMS +# Generate section listing all symbols and add it into busybox $(kallsyms.o) +# It's a three stage process: +# o .tmp_busybox1 has all symbols and sections, but __kallsyms is +# empty +# Running kallsyms on that gives us .tmp_kallsyms1.o with +# the right size - busybox version (uname -v) is updated during this step +# o .tmp_busybox2 now has a __kallsyms section of the right size, +# but due to the added section, some addresses have shifted. +# From here, we generate a correct .tmp_kallsyms2.o +# o The correct .tmp_kallsyms2.o is linked into the final busybox. +# o Verify that the System.map from busybox matches the map from +# .tmp_busybox2, just in case we did not generate kallsyms correctly. +# o If CONFIG_KALLSYMS_EXTRA_PASS is set, do an extra pass using +# .tmp_busybox3 and .tmp_kallsyms3.o. This is only meant as a +# temporary bypass to allow the kernel to be built while the +# maintainers work out what went wrong with kallsyms. + +ifdef CONFIG_KALLSYMS_EXTRA_PASS +last_kallsyms := 3 +else +last_kallsyms := 2 +endif + +kallsyms.o := .tmp_kallsyms$(last_kallsyms).o + +define verify_kallsyms + $(Q)$(if $($(quiet)cmd_sysmap), \ + echo ' $($(quiet)cmd_sysmap) .tmp_System.map' &&) \ + $(cmd_sysmap) .tmp_busybox$(last_kallsyms) .tmp_System.map + $(Q)cmp -s System.map .tmp_System.map || \ + (echo Inconsistent kallsyms data; \ + echo Try setting CONFIG_KALLSYMS_EXTRA_PASS; \ + rm .tmp_kallsyms* ; /bin/false ) +endef + +# Update busybox version before link +# Use + in front of this rule to silent warning about make -j1 +# First command is ':' to allow us to use + in front of this rule +cmd_ksym_ld = $(cmd_busybox__) +define rule_ksym_ld + : + +$(call cmd,busybox_version) + $(call cmd,busybox__) + $(Q)echo 'cmd_$@ := $(cmd_busybox__)' > $(@D)/.$(@F).cmd +endef + +# Generate .S file with all kernel symbols +quiet_cmd_kallsyms = KSYM $@ + cmd_kallsyms = $(NM) -n $< | $(KALLSYMS) \ + $(if $(CONFIG_KALLSYMS_ALL),--all-symbols) > $@ + +.tmp_kallsyms1.o .tmp_kallsyms2.o .tmp_kallsyms3.o: %.o: %.S scripts FORCE + $(call if_changed_dep,as_o_S) + +.tmp_kallsyms%.S: .tmp_busybox% $(KALLSYMS) + $(call cmd,kallsyms) + +# .tmp_busybox1 must be complete except kallsyms, so update busybox version +.tmp_busybox1: $(busybox-lds) $(busybox-all) FORCE + $(call if_changed_rule,ksym_ld) + +.tmp_busybox2: $(busybox-lds) $(busybox-all) .tmp_kallsyms1.o FORCE + $(call if_changed,busybox__) + +.tmp_busybox3: $(busybox-lds) $(busybox-all) .tmp_kallsyms2.o FORCE + $(call if_changed,busybox__) + +# Needs to visit scripts/ before $(KALLSYMS) can be used. +$(KALLSYMS): scripts ; + +# Generate some data for debugging strange kallsyms problems +debug_kallsyms: .tmp_map$(last_kallsyms) + +.tmp_map%: .tmp_busybox% FORCE + ($(OBJDUMP) -h $< | $(AWK) '/^ +[0-9]/{print $$4 " 0 " $$2}'; $(NM) $<) | sort > $@ + +.tmp_map3: .tmp_map2 + +.tmp_map2: .tmp_map1 + +endif # ifdef CONFIG_KALLSYMS + +# busybox image - including updated kernel symbols +busybox_unstripped: $(busybox-all) FORCE + $(call if_changed_rule,busybox__) + $(Q)rm -f .old_version + +busybox: busybox_unstripped +ifeq ($(SKIP_STRIP),y) + $(Q)cp $< $@ +else + $(Q)$(STRIP) -s --remove-section=.note --remove-section=.comment \ + busybox_unstripped -o $@ +# strip is confused by PIE executable and does not set exec bits + $(Q)chmod a+x $@ +endif + +# The actual objects are generated when descending, +# make sure no implicit rule kicks in +$(sort $(busybox-all)): $(busybox-dirs) ; + +# Handle descending into subdirectories listed in $(busybox-dirs) +# Preset locale variables to speed up the build process. Limit locale +# tweaks to this spot to avoid wrong language settings when running +# make menuconfig etc. +# Error messages still appears in the original language + +PHONY += $(busybox-dirs) +$(busybox-dirs): prepare scripts + $(Q)$(MAKE) $(build)=$@ + +# Build the kernel release string +# The KERNELRELEASE is stored in a file named .kernelrelease +# to be used when executing for example make install or make modules_install +# +# Take the contents of any files called localversion* and the config +# variable CONFIG_LOCALVERSION and append them to KERNELRELEASE. +# LOCALVERSION from the command line override all of this + +nullstring := +space := $(nullstring) # end of line + +___localver = $(objtree)/localversion* $(srctree)/localversion* +__localver = $(sort $(wildcard $(___localver))) +# skip backup files (containing '~') +_localver = $(foreach f, $(__localver), $(if $(findstring ~, $(f)),,$(f))) + +localver = $(subst $(space),, \ + $(shell cat /dev/null $(_localver)) \ + $(patsubst "%",%,$(CONFIG_LOCALVERSION))) + +# If CONFIG_LOCALVERSION_AUTO is set scripts/setlocalversion is called +# and if the SCM is know a tag from the SCM is appended. +# The appended tag is determinded by the SCM used. +# +# Currently, only git is supported. +# Other SCMs can edit scripts/setlocalversion and add the appropriate +# checks as needed. +ifdef _BB_DISABLED_CONFIG_LOCALVERSION_AUTO + _localver-auto = $(shell $(CONFIG_SHELL) \ + $(srctree)/scripts/setlocalversion $(srctree)) + localver-auto = $(LOCALVERSION)$(_localver-auto) +endif + +localver-full = $(localver)$(localver-auto) + +# Store (new) KERNELRELASE string in .kernelrelease +kernelrelease = $(KERNELVERSION)$(localver-full) +.kernelrelease: FORCE + $(Q)rm -f $@ + $(Q)echo $(kernelrelease) > $@ + + +# Things we need to do before we recursively start building the kernel +# or the modules are listed in "prepare". +# A multi level approach is used. prepareN is processed before prepareN-1. +# archprepare is used in arch Makefiles and when processed asm symlink, +# version.h and scripts_basic is processed / created. + +# Listed in dependency order +PHONY += prepare archprepare prepare0 prepare1 prepare2 prepare3 + +# prepare-all is deprecated, use prepare as valid replacement +PHONY += prepare-all + +# prepare3 is used to check if we are building in a separate output directory, +# and if so do: +# 1) Check that make has not been executed in the kernel src $(srctree) +# 2) Create the include2 directory, used for the second asm symlink +prepare3: .kernelrelease +ifneq ($(KBUILD_SRC),) + @echo ' Using $(srctree) as source for busybox' + $(Q)if [ -f $(srctree)/.config ]; then \ + echo " $(srctree) is not clean, please run 'make mrproper'";\ + echo " in the '$(srctree)' directory.";\ + /bin/false; \ + fi; + $(Q)if [ ! -d include2 ]; then mkdir -p include2; fi; + $(Q)ln -fsn $(srctree)/include/asm-$(ARCH) include2/asm +endif + +# prepare2 creates a makefile if using a separate output directory +prepare2: prepare3 outputmakefile + +prepare1: prepare2 include/config/MARKER +ifneq ($(KBUILD_MODULES),) + $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* +endif + +archprepare: prepare1 scripts_basic applets_dir + +prepare0: archprepare FORCE + $(Q)$(MAKE) $(build)=. + +# All the preparing.. +prepare prepare-all: prepare0 + +# Leave this as default for preprocessing busybox.lds.S, which is now +# done in arch/$(ARCH)/kernel/Makefile + +export CPPFLAGS_busybox.lds += -P -C -U$(ARCH) + +# FIXME: The asm symlink changes when $(ARCH) changes. That's +# hard to detect, but I suppose "make mrproper" is a good idea +# before switching between archs anyway. + +#bbox# include/asm: +#bbox# @echo ' SYMLINK $@ -> include/asm-$(ARCH)' +#bbox# $(Q)if [ ! -d include ]; then mkdir -p include; fi; +#bbox# @ln -fsn asm-$(ARCH) $@ + +# Split autoconf.h into include/linux/config/* +quiet_cmd_gen_bbconfigopts = GEN include/bbconfigopts.h + cmd_gen_bbconfigopts = $(srctree)/scripts/mkconfigs include/bbconfigopts.h include/bbconfigopts_bz2.h +quiet_cmd_gen_common_bufsiz = GEN include/common_bufsiz.h + cmd_gen_common_bufsiz = $(srctree)/scripts/generate_BUFSIZ.sh include/common_bufsiz.h +quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/* + cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config +quiet_cmd_gen_embedded_scripts = GEN include/embedded_scripts.h + cmd_gen_embedded_scripts = $(srctree)/scripts/embedded_scripts include/embedded_scripts.h $(srctree)/embed $(srctree)/applets_sh +#bbox# piggybacked generation of few .h files +include/config/MARKER: scripts/basic/split-include include/autoconf.h $(wildcard $(srctree)/embed/*) $(wildcard $(srctree)/applets_sh/*) $(srctree)/scripts/embedded_scripts + $(call cmd,split_autoconf) + $(call cmd,gen_bbconfigopts) + $(call cmd,gen_common_bufsiz) + $(call cmd,gen_embedded_scripts) + @touch $@ + +# Generate some files +# --------------------------------------------------------------------------- + +# KERNELRELEASE can change from a few different places, meaning version.h +# needs to be updated, so this check is forced on all builds + +uts_len := 64 + +define filechk_version.h + if [ `echo -n "$(KERNELRELEASE)" | wc -c ` -gt $(uts_len) ]; then \ + echo '"$(KERNELRELEASE)" exceeds $(uts_len) characters' >&2; \ + exit 1; \ + fi; \ + (echo \#define UTS_RELEASE \"$(KERNELRELEASE)\"; \ + echo \#define LINUX_VERSION_CODE `expr $(VERSION) \\* 65536 + $(PATCHLEVEL) \\* 256 + $(SUBLEVEL)`; \ + echo '#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c))'; \ + ) +endef + +# --------------------------------------------------------------------------- + +PHONY += depend dep +depend dep: + @echo '*** Warning: make $@ is unnecessary now.' + +# --------------------------------------------------------------------------- +# Modules + +ifdef _BB_DISABLED_CONFIG_MODULES + +# By default, build modules as well + +all: modules + +# Build modules + +PHONY += modules +modules: $(busybox-dirs) $(if $(KBUILD_BUILTIN),busybox) + @echo ' Building modules, stage 2.'; + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost + + +# Target to prepare building external modules +PHONY += modules_prepare +modules_prepare: prepare scripts + +# Target to install modules +PHONY += modules_install +modules_install: _modinst_ _modinst_post + +PHONY += _modinst_ +_modinst_: + @if [ -z "`$(DEPMOD) -V 2>/dev/null | grep module-init-tools`" ]; then \ + echo "Warning: you may need to install module-init-tools"; \ + echo "See http://www.codemonkey.org.uk/docs/post-halloween-2.6.txt";\ + sleep 1; \ + fi + @rm -rf $(MODLIB)/kernel + @rm -f $(MODLIB)/source + @mkdir -p $(MODLIB)/kernel + @ln -s $(srctree) $(MODLIB)/source + @if [ ! $(objtree) -ef $(MODLIB)/build ]; then \ + rm -f $(MODLIB)/build ; \ + ln -s $(objtree) $(MODLIB)/build ; \ + fi + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst + +# If System.map exists, run depmod. This deliberately does not have a +# dependency on System.map since that would run the dependency tree on +# busybox. This depmod is only for convenience to give the initial +# boot a modules.dep even before / is mounted read-write. However the +# boot script depmod is the master version. +ifeq "$(strip $(INSTALL_MOD_PATH))" "" +depmod_opts := +else +depmod_opts := -b $(INSTALL_MOD_PATH) -r +endif +PHONY += _modinst_post +_modinst_post: _modinst_ + if [ -r System.map -a -x $(DEPMOD) ]; then $(DEPMOD) -ae -F System.map $(depmod_opts) $(KERNELRELEASE); fi + +else # CONFIG_MODULES + +# Modules not configured +# --------------------------------------------------------------------------- + +modules modules_install: FORCE + @echo + @echo "The present busybox configuration has modules disabled." + @echo "Type 'make config' and enable loadable module support." + @echo "Then build a kernel with module support enabled." + @echo + @exit 1 + +endif # CONFIG_MODULES + +### +# Cleaning is done on three levels. +# make clean Delete most generated files +# Leave enough to build external modules +# make mrproper Delete the current configuration, and all generated files +# make distclean Remove editor backup files, patch leftover files and the like + +# Directories & files removed with 'make clean' +CLEAN_DIRS += $(MODVERDIR) _install 0_lib +CLEAN_FILES += busybox busybox_unstripped* busybox.links \ + busybox*.suid busybox*.nosuid \ + System.map .kernelrelease \ + .tmp_kallsyms* .tmp_version .tmp_busybox* .tmp_System.map + +# Directories & files removed with 'make mrproper' +MRPROPER_DIRS += include/config include2 +MRPROPER_FILES += .config .config.old include/asm .version .old_version \ + include/NUM_APPLETS.h \ + include/common_bufsiz.h \ + include/autoconf.h \ + include/bbconfigopts.h \ + include/bbconfigopts_bz2.h \ + include/embedded_scripts.h \ + include/usage_compressed.h \ + include/applet_tables.h \ + include/applets.h \ + include/usage.h \ + applets/usage \ + .kernelrelease Module.symvers tags TAGS cscope* \ + busybox_old + +# clean - Delete most, but leave enough to build external modules +# +clean: rm-dirs := $(CLEAN_DIRS) +clean: rm-files := $(CLEAN_FILES) +clean-dirs := $(addprefix _clean_,$(srctree) $(busybox-alldirs)) + +PHONY += $(clean-dirs) clean archclean +$(clean-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) + +clean: archclean $(clean-dirs) + $(call cmd,rmdirs) + $(call cmd,rmfiles) + @find . $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ + -type f -print | xargs rm -f + +PHONY += doc-clean +doc-clean: rm-files := docs/busybox.pod \ + docs/BusyBox.html docs/busybox.1 docs/BusyBox.txt +doc-clean: + $(call cmd,rmfiles) + +# mrproper - Delete all generated files, including .config +# +mrproper: rm-dirs := $(wildcard $(MRPROPER_DIRS)) +mrproper: rm-files := $(wildcard $(MRPROPER_FILES)) +mrproper-dirs := $(addprefix _mrproper_,scripts) + +PHONY += $(mrproper-dirs) mrproper archmrproper +$(mrproper-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _mrproper_%,%,$@) + +mrproper: clean archmrproper $(mrproper-dirs) + $(call cmd,rmdirs) + $(call cmd,rmfiles) + @find . -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f + @find . -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f + +# distclean +# +PHONY += distclean + +distclean: mrproper + @find $(srctree) $(RCS_FIND_IGNORE) \ + \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ + -o -name '*.bak' -o -name '#*#' -o -name '.*.orig' \ + -o -name '.*.rej' -o -name '*.tmp' -o -size 0 \ + -o -name '*%' -o -name '.*.cmd' -o -name 'core' \) \ + -type f -print | xargs rm -f + + +# Packaging of the kernel to various formats +# --------------------------------------------------------------------------- +# rpm target kept for backward compatibility +package-dir := $(srctree)/scripts/package + +%pkg: FORCE + $(Q)$(MAKE) $(build)=$(package-dir) $@ +rpm: FORCE + $(Q)$(MAKE) $(build)=$(package-dir) $@ + + +# Brief documentation of the typical targets used +# --------------------------------------------------------------------------- + +boards := $(wildcard $(srctree)/configs/*_defconfig) +boards := $(notdir $(boards)) + +-include $(srctree)/Makefile.help + +# Documentation targets +# --------------------------------------------------------------------------- +%docs: scripts_basic FORCE + $(Q)$(MAKE) $(build)=Documentation/DocBook $@ + +else # KBUILD_EXTMOD + +### +# External module support. +# When building external modules the kernel used as basis is considered +# read-only, and no consistency checks are made and the make +# system is not used on the basis kernel. If updates are required +# in the basis kernel ordinary make commands (without M=...) must +# be used. +# +# The following are the only valid targets when building external +# modules. +# make M=dir clean Delete all automatically generated files +# make M=dir modules Make all modules in specified dir +# make M=dir Same as 'make M=dir modules' +# make M=dir modules_install +# Install the modules build in the module directory +# Assumes install directory is already created + +# We are always building modules +KBUILD_MODULES := 1 +PHONY += crmodverdir +crmodverdir: + $(Q)mkdir -p $(MODVERDIR) + $(Q)rm -f $(MODVERDIR)/* + +PHONY += $(objtree)/Module.symvers +$(objtree)/Module.symvers: + @test -e $(objtree)/Module.symvers || ( \ + echo; \ + echo " WARNING: Symbol version dump $(objtree)/Module.symvers"; \ + echo " is missing; modules will have no dependencies and modversions."; \ + echo ) + +module-dirs := $(addprefix _module_,$(KBUILD_EXTMOD)) +PHONY += $(module-dirs) modules +$(module-dirs): crmodverdir $(objtree)/Module.symvers + $(Q)$(MAKE) $(build)=$(patsubst _module_%,%,$@) + +modules: $(module-dirs) + @echo ' Building modules, stage 2.'; + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost + +PHONY += modules_install +modules_install: _emodinst_ _emodinst_post + +install-dir := $(if $(INSTALL_MOD_DIR),$(INSTALL_MOD_DIR),extra) +PHONY += _emodinst_ +_emodinst_: + $(Q)mkdir -p $(MODLIB)/$(install-dir) + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modinst + +# Run depmod only is we have System.map and depmod is executable +quiet_cmd_depmod = DEPMOD $(KERNELRELEASE) + cmd_depmod = if [ -r System.map -a -x $(DEPMOD) ]; then \ + $(DEPMOD) -ae -F System.map \ + $(if $(strip $(INSTALL_MOD_PATH)), \ + -b $(INSTALL_MOD_PATH) -r) \ + $(KERNELRELEASE); \ + fi + +PHONY += _emodinst_post +_emodinst_post: _emodinst_ + $(call cmd,depmod) + +clean-dirs := $(addprefix _clean_,$(KBUILD_EXTMOD)) + +PHONY += $(clean-dirs) clean +$(clean-dirs): + $(Q)$(MAKE) $(clean)=$(patsubst _clean_%,%,$@) + +clean: rm-dirs := $(MODVERDIR) +clean: $(clean-dirs) + $(call cmd,rmdirs) + @find $(KBUILD_EXTMOD) $(RCS_FIND_IGNORE) \ + \( -name '*.[oas]' -o -name '*.ko' -o -name '.*.cmd' \ + -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ + -type f -print | xargs rm -f + +# Dummies... +PHONY += prepare scripts +prepare: ; +scripts: ; +endif # KBUILD_EXTMOD + +# Generate tags for editors +# --------------------------------------------------------------------------- + +#We want __srctree to totally vanish out when KBUILD_OUTPUT is not set +#(which is the most common case IMHO) to avoid unneeded clutter in the big tags file. +#Adding $(srctree) adds about 20M on i386 to the size of the output file! + +ifeq ($(src),$(obj)) +__srctree = +else +__srctree = $(srctree)/ +endif + +ifeq ($(ALLSOURCE_ARCHS),) +ifeq ($(ARCH),um) +ALLINCLUDE_ARCHS := $(ARCH) $(SUBARCH) +else +ALLINCLUDE_ARCHS := $(ARCH) +endif +else +#Allow user to specify only ALLSOURCE_PATHS on the command line, keeping existing behaviour. +ALLINCLUDE_ARCHS := $(ALLSOURCE_ARCHS) +endif + +ALLSOURCE_ARCHS := $(ARCH) + +define all-sources + ( find -regex '.*\.[ch]$$' ) +endef + +quiet_cmd_cscope-file = FILELST cscope.files + cmd_cscope-file = (echo \-k; echo \-q; $(all-sources)) > cscope.files + +quiet_cmd_cscope = MAKE cscope.out + cmd_cscope = cscope -b + +cscope: FORCE + $(call cmd,cscope-file) + $(call cmd,cscope) + +quiet_cmd_TAGS = MAKE $@ +define cmd_TAGS + rm -f $@; \ + ETAGSF=`etags --version | grep -i exuberant >/dev/null && \ + echo "-I __initdata,__exitdata,__acquires,__releases \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + --extra=+f --c-kinds=+px"`; \ + $(all-sources) | xargs etags $$ETAGSF -a +endef + +TAGS: FORCE + $(call cmd,TAGS) + + +quiet_cmd_tags = MAKE $@ +define cmd_tags + rm -f $@; \ + CTAGSF=`ctags --version | grep -i exuberant >/dev/null && \ + echo "-I __initdata,__exitdata,__acquires,__releases \ + -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL \ + --extra=+f --c-kinds=+px"`; \ + $(all-sources) | xargs ctags $$CTAGSF -a +endef + +tags: FORCE + $(call cmd,tags) + + +# Scripts to check various things for consistency +# --------------------------------------------------------------------------- + +includecheck: + find * $(RCS_FIND_IGNORE) \ + -name '*.[hcS]' -type f -print | sort \ + | xargs $(PERL) -w scripts/checkincludes.pl + +versioncheck: + find * $(RCS_FIND_IGNORE) \ + -name '*.[hcS]' -type f -print | sort \ + | xargs $(PERL) -w scripts/checkversion.pl + +namespacecheck: + $(PERL) $(srctree)/scripts/namespace.pl + +endif #ifeq ($(config-targets),1) +endif #ifeq ($(mixed-targets),1) + +PHONY += checkstack +checkstack: + $(OBJDUMP) -d busybox $$(find . -name '*.ko') | \ + $(PERL) $(src)/scripts/checkstack.pl $(ARCH) + +kernelrelease: + $(if $(wildcard .kernelrelease), $(Q)echo $(KERNELRELEASE), \ + $(error kernelrelease not valid - run 'make *config' to update it)) +kernelversion: + @echo $(KERNELVERSION) + +# Single targets +# --------------------------------------------------------------------------- +# Single targets are compatible with: +# - build whith mixed source and output +# - build with separate output dir 'make O=...' +# - external modules +# +# target-dir => where to store outputfile +# build-dir => directory in kernel source tree to use + +ifeq ($(KBUILD_EXTMOD),) + build-dir = $(patsubst %/,%,$(dir $@)) + target-dir = $(dir $@) +else + zap-slash=$(filter-out .,$(patsubst %/,%,$(dir $@))) + build-dir = $(KBUILD_EXTMOD)$(if $(zap-slash),/$(zap-slash)) + target-dir = $(if $(KBUILD_EXTMOD),$(dir $<),$(dir $@)) +endif + +%.s: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.i: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.lst: %.c prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.s: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) +%.o: %.S prepare scripts FORCE + $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) + +# Modules +%/: prepare scripts FORCE + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) +/: prepare scripts FORCE + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) + +%.ko: prepare scripts FORCE + $(Q)$(MAKE) KBUILD_MODULES=$(if $(CONFIG_MODULES),1) \ + $(build)=$(build-dir) $(@:.ko=.o) + $(Q)$(MAKE) -rR -f $(srctree)/scripts/Makefile.modpost + +# FIXME Should go into a make.lib or something +# =========================================================================== + +quiet_cmd_rmdirs = $(if $(wildcard $(rm-dirs)),CLEAN $(wildcard $(rm-dirs))) + cmd_rmdirs = rm -rf $(rm-dirs) + +quiet_cmd_rmfiles = $(if $(wildcard $(rm-files)),CLEAN $(wildcard $(rm-files))) + cmd_rmfiles = rm -f $(rm-files) + +# read all saved command lines + +targets := $(wildcard $(sort $(targets))) +cmd_files := $(wildcard .*.cmd $(foreach f,$(targets),$(dir $(f)).$(notdir $(f)).cmd)) + +ifneq ($(cmd_files),) + $(cmd_files): ; # Do not try to update included dependency files + include $(cmd_files) +endif + +# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.clean obj=dir +# Usage: +# $(Q)$(MAKE) $(clean)=dir +clean := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.clean obj + +endif # skip-makefile + +PHONY += FORCE +FORCE: + +-include $(srctree)/Makefile.custom + +# Declare the contents of the .PHONY variable as phony. We keep that +# information in a variable se we can use it in if_changed and friends. +.PHONY: $(PHONY) diff --git a/busybox-1_37_0/Makefile.custom b/busybox-1_37_0/Makefile.custom new file mode 100644 index 000000000..6f679c4e1 --- /dev/null +++ b/busybox-1_37_0/Makefile.custom @@ -0,0 +1,201 @@ +# ========================================================================== +# Build system +# ========================================================================== + +busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h include/applets.h + $(Q)-$(SHELL) $^ > $@ + +busybox.cfg.suid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h + $(Q)-SUID="yes" $(SHELL) $^ > $@ +busybox.cfg.nosuid: $(srctree)/applets/busybox.mksuid $(objtree)/include/autoconf.h include/applets.h + $(Q)-SUID="DROP" $(SHELL) $^ > $@ + +.PHONY: install +ifeq ($(CONFIG_INSTALL_APPLET_DONT),y) +INSTALL_OPTS:= --none +endif +ifeq ($(CONFIG_INSTALL_APPLET_SYMLINKS),y) +INSTALL_OPTS:= --symlinks +endif +ifeq ($(CONFIG_INSTALL_APPLET_HARDLINKS),y) +INSTALL_OPTS:= --hardlinks +endif +ifeq ($(CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS),y) +ifeq ($(CONFIG_INSTALL_SH_APPLET_SYMLINK),y) +INSTALL_OPTS:= --sw-sh-sym +endif +ifeq ($(CONFIG_INSTALL_SH_APPLET_HARDLINK),y) +INSTALL_OPTS:= --sw-sh-hard +endif +ifeq ($(CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER),y) +INSTALL_OPTS:= --scriptwrapper +endif +endif +ifeq ($(CONFIG_FEATURE_INDIVIDUAL),y) +INSTALL_OPTS:= --binaries +LIBBUSYBOX_SONAME:= 0_lib/libbusybox.so.$(BB_VER) +endif +install: $(srctree)/applets/install.sh busybox busybox.links + $(Q)DO_INSTALL_LIBS="$(strip $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS))" \ + $(SHELL) $< $(CONFIG_PREFIX) $(INSTALL_OPTS) +ifeq ($(strip $(CONFIG_FEATURE_SUID)),y) + @echo + @echo + @echo -------------------------------------------------- + @echo You will probably need to make your busybox binary + @echo setuid root to ensure all configured applets will + @echo work properly. + @echo -------------------------------------------------- + @echo +endif + +install-noclobber: INSTALL_OPTS+=--noclobber +install-noclobber: install + +uninstall: busybox.links + rm -f $(CONFIG_PREFIX)/bin/busybox + for i in `cat busybox.links` ; do rm -f $(CONFIG_PREFIX)$$i; done +ifneq ($(strip $(DO_INSTALL_LIBS)),n) + for i in $(LIBBUSYBOX_SONAME) $(DO_INSTALL_LIBS); do \ + rm -f $(CONFIG_PREFIX)$$i; \ + done +endif + +# Not very elegant: copies testsuite to objdir... +# (cp -pPR is POSIX-compliant (cp -dpR or cp -a would not be)) +.PHONY: check +.PHONY: test +ifeq ($(CONFIG_UNIT_TEST),y) +UNIT_CMD = ./busybox unit +endif +check test: busybox busybox.links + $(UNIT_CMD) + test -d $(objtree)/testsuite || cp -pPR $(srctree)/testsuite $(objtree) + bindir=$(objtree) srcdir=$(srctree)/testsuite \ + $(SHELL) -c "cd $(objtree)/testsuite && $(srctree)/testsuite/runtest $(if $(KBUILD_VERBOSE:0=),-v)" + +.PHONY: release +release: distclean + cd ..; \ + rm -r -f busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION); \ + cp -pPR busybox busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) && { \ + find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type d \ + -name .svn \ + -print \ + -exec rm -r -f {} \; ; \ + find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type d \ + -name .git \ + -print \ + -exec rm -r -f {} \; ; \ + find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \ + -name .gitignore \ + -print \ + -exec rm -f {} \; ; \ + find busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ -type f \ + -name .\#* \ + -print \ + -exec rm -f {} \; ; \ + tar -czf busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION).tar.gz \ + busybox-$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)/ ; } + +.PHONY: checkhelp +checkhelp: + $(Q)$(srctree)/scripts/checkhelp.awk \ + $(patsubst %,$(srctree)/%,$(wildcard $(patsubst %,%/Config.in,$(busybox-dirs) ./))) + +.PHONY: sizes +sizes: busybox_unstripped + $(NM) --size-sort $(<) + +.PHONY: bloatcheck +bloatcheck: busybox_old busybox_unstripped + @$(srctree)/scripts/bloat-o-meter busybox_old busybox_unstripped + @$(CROSS_COMPILE)size busybox_old busybox_unstripped + +.PHONY: baseline +baseline: busybox_unstripped + @mv busybox_unstripped busybox_old + +.PHONY: objsizes +objsizes: busybox_unstripped + $(srctree)/scripts/objsizes + +.PHONY: stksizes +stksizes: busybox_unstripped + $(CROSS_COMPILE)objdump -d busybox_unstripped | $(srctree)/scripts/checkstack.pl $(ARCH) | uniq + +.PHONY: bigdata +bigdata: busybox_unstripped + $(CROSS_COMPILE)nm --size-sort busybox_unstripped | grep -vi ' [trw] ' + +# Documentation Targets +.PHONY: doc +doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html + +# FIXME: Doesn't belong here + cmd_doc = + quiet_cmd_doc = $(Q)echo " DOC $(@F)" +silent_cmd_doc = +disp_doc = $($(quiet)cmd_doc) + +# sed adds newlines after "Options:" etc, +# this is needed in order to get good BusyBox.{1,txt,html} +docs/busybox.pod: $(srctree)/docs/busybox_header.pod \ + include/usage.h \ + $(srctree)/docs/busybox_footer.pod \ + applets/usage_pod + $(disp_doc) + $(Q)-mkdir -p docs + $(Q)-( \ + cat $(srctree)/docs/busybox_header.pod; \ + echo; \ + applets/usage_pod | sed 's/^[A-Za-z][A-Za-z ]*[a-z]:$$/&\n/'; \ + cat $(srctree)/docs/busybox_footer.pod; \ + ) > docs/busybox.pod + +docs/BusyBox.txt: docs/busybox.pod + $(disp_doc) + $(Q)-mkdir -p docs + $(Q)-pod2text $< > $@ + +docs/busybox.1: docs/busybox.pod + $(disp_doc) + $(Q)-mkdir -p docs + $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ + +docs/BusyBox.html: docs/busybox.net/BusyBox.html + $(disp_doc) + $(Q)-mkdir -p docs + $(Q)-rm -f docs/BusyBox.html + $(Q)-cp docs/busybox.net/BusyBox.html docs/BusyBox.html + +docs/busybox.net/BusyBox.html: docs/busybox.pod + $(Q)-mkdir -p docs/busybox.net + $(Q)-pod2html --noindex $< > $@ + $(Q)-rm -f pod2htm* + +# documentation, cross-reference +# Modern distributions already ship synopsis packages (e.g. debian) +# If you have an old distribution go to http://synopsis.fresco.org/ +syn_tgt = $(wildcard $(patsubst %,%/*.c,$(busybox-alldirs))) +syn = $(patsubst %.c, %.syn, $(syn_tgt)) + +comma:= , +brace_open:= ( +brace_close:= ) + +SYN_CPPFLAGS := $(strip $(CPPFLAGS) $(EXTRA_CPPFLAGS)) +SYN_CPPFLAGS := $(subst $(brace_open),\$(brace_open),$(SYN_CPPFLAGS)) +SYN_CPPFLAGS := $(subst $(brace_close),\$(brace_close),$(SYN_CPPFLAGS)) +#SYN_CPPFLAGS := $(subst ",\",$(SYN_CPPFLAGS)) +#") +#SYN_CPPFLAGS := [$(patsubst %,'%'$(comma),$(SYN_CPPFLAGS))''] + +%.syn: %.c + synopsis -p C -l Comments.SSDFilter,Comments.Previous -Wp,preprocess=True,cppflags="'$(SYN_CPPFLAGS)'" -o $@ $< + +.PHONY: html +html: $(syn) + synopsis -f HTML -Wf,title="'BusyBox Documentation'" -o $@ $^ + +-include $(srctree)/Makefile.local diff --git a/busybox-1_37_0/Makefile.flags b/busybox-1_37_0/Makefile.flags new file mode 100644 index 000000000..97cb4dca2 --- /dev/null +++ b/busybox-1_37_0/Makefile.flags @@ -0,0 +1,223 @@ +# ========================================================================== +# Build system +# ========================================================================== + +BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) +export BB_VER +SKIP_STRIP ?= n + +# -std=gnu99 needed for [U]LLONG_MAX on some systems +CPPFLAGS += $(call cc-option,-std=gnu99,) + +CPPFLAGS += \ + -Iinclude -Ilibbb \ + $(if $(KBUILD_SRC),-Iinclude2 -I$(srctree)/include -I$(srctree)/libbb) \ + -include include/autoconf.h \ + -D_GNU_SOURCE -DNDEBUG \ + $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ + $(if $(CONFIG_TIME64),-D_TIME_BITS=64) \ + -DBB_VER=$(squote)$(quote)$(BB_VER)$(quote)$(squote) + +CFLAGS += $(call cc-option,-Wall,) +CFLAGS += $(call cc-option,-Wshadow,) +CFLAGS += $(call cc-option,-Wwrite-strings,) +CFLAGS += $(call cc-option,-Wundef,) +CFLAGS += $(call cc-option,-Wstrict-prototypes,) +CFLAGS += $(call cc-option,-Wunused -Wunused-parameter,) +CFLAGS += $(call cc-option,-Wunused-function -Wunused-value,) +CFLAGS += $(call cc-option,-Wmissing-prototypes -Wmissing-declarations,) +CFLAGS += $(call cc-option,-Wno-format-security,) +# warn about C99 declaration after statement +CFLAGS += $(call cc-option,-Wdeclaration-after-statement,) +# If you want to add more -Wsomething above, make sure that it is +# still possible to build bbox without warnings. + +ifeq ($(CONFIG_WERROR),y) +CFLAGS += $(call cc-option,-Werror,) +## TODO: +## gcc version 4.4.0 20090506 (Red Hat 4.4.0-4) (GCC) is a PITA: +## const char *ptr; ... off_t v = *(off_t*)ptr; -> BOOM +## and no easy way to convince it to shut the hell up. +## We have a lot of such things all over the place. +## Classic *(off_t*)(void*)ptr does not work, +## and I am unwilling to do crazy gcc specific ({ void *ppp = ...; }) +## stuff in macros. This would obfuscate the code too much. +## Maybe try __attribute__((__may_alias__))? +#CFLAGS += $(call cc-ifversion, -eq, 0404, -fno-strict-aliasing) +endif +# gcc 3.x emits bogus "old style proto" warning on find.c:alloc_action() +CFLAGS += $(call cc-ifversion, -ge, 0400, -Wold-style-definition) + +ifneq ($(lastword $(subst -, ,$(CC))),clang) +# "clang-9: warning: optimization flag '-finline-limit=0' is not supported +CFLAGS += $(call cc-option,-finline-limit=0,) +endif + +CFLAGS += $(call cc-option,-fno-builtin-strlen -fomit-frame-pointer -ffunction-sections -fdata-sections,) +# -fno-guess-branch-probability: prohibit pseudo-random guessing +# of branch probabilities (hopefully makes bloatcheck more stable): +CFLAGS += $(call cc-option,-fno-guess-branch-probability,) +CFLAGS += $(call cc-option,-funsigned-char,) + +ifeq ($(CONFIG_STATIC_LIBGCC),y) +# Disable it, for example, if you get +# "clang-9: warning: argument unused during compilation: '-static-libgcc'" +CFLAGS += $(call cc-option,-static-libgcc,) +endif + +CFLAGS += $(call cc-option,-falign-functions=1,) +ifneq ($(lastword $(subst -, ,$(CC))),clang) +# "clang-9: warning: optimization flag '-falign-jumps=1' is not supported" (and same for other two) +CFLAGS += $(call cc-option,-falign-jumps=1 -falign-labels=1 -falign-loops=1,) +endif + +# Defeat .eh_frame bloat (gcc 4.6.3 x86-32 defconfig: 20% smaller busybox binary): +CFLAGS += $(call cc-option,-fno-unwind-tables,) +CFLAGS += $(call cc-option,-fno-asynchronous-unwind-tables,) +# No automatic printf->puts,putchar conversions +# (try disabling this and comparing assembly, it's instructive) +CFLAGS += $(call cc-option,-fno-builtin-printf,) + +# clang-9 does not like "str" + N and "if (CONFIG_ITEM && cond)" constructs +ifeq ($(lastword $(subst -, ,$(CC))),clang) +CFLAGS += $(call cc-option,-Wno-string-plus-int -Wno-constant-logical-operand) +endif + +# FIXME: These warnings are at least partially to be concerned about and should +# be fixed.. +#CFLAGS += $(call cc-option,-Wconversion,) + +ifneq ($(CONFIG_DEBUG),y) +CFLAGS += $(call cc-option,-Oz,$(call cc-option,-Os,$(call cc-option,-O2,))) +else +CFLAGS += $(call cc-option,-g,) +#CFLAGS += "-D_FORTIFY_SOURCE=2" +ifeq ($(CONFIG_DEBUG_PESSIMIZE),y) +CFLAGS += $(call cc-option,-O0,) +else +CFLAGS += $(call cc-option,-Oz,$(call cc-option,-Os,$(call cc-option,-O2,))) +endif +endif +ifeq ($(CONFIG_DEBUG_SANITIZE),y) +CFLAGS += $(call cc-option,-fsanitize=address,) +CFLAGS += $(call cc-option,-fsanitize=leak,) +CFLAGS += $(call cc-option,-fsanitize=undefined,) +endif + +# If arch/$(ARCH)/Makefile did not override it (with, say, -fPIC)... +ARCH_FPIC ?= -fpic +ARCH_FPIE ?= -fpie +ARCH_PIE ?= -pie + +# Usage: $(eval $(call pkg_check_modules,VARIABLE-PREFIX,MODULES)) +define pkg_check_modules +$(1)_CFLAGS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --cflags $(2)) +$(1)_LIBS := $(shell $(PKG_CONFIG) $(PKG_CONFIG_FLAGS) --libs $(2)) +endef + +ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y) +# on i386: 14% smaller libbusybox.so +# (code itself is 9% bigger, we save on relocs/PLT/GOT) +CFLAGS += $(ARCH_FPIC) +# and another 4% reduction of libbusybox.so: +# (external entry points must be marked EXTERNALLY_VISIBLE) +CFLAGS += $(call cc-option,-fvisibility=hidden) +endif + +ifeq ($(CONFIG_STATIC),y) +CFLAGS_busybox += -static +PKG_CONFIG_FLAGS += --static +endif + +ifeq ($(CONFIG_PIE),y) +CFLAGS_busybox += $(ARCH_PIE) +CFLAGS += $(ARCH_FPIE) +endif + +ifneq ($(CONFIG_EXTRA_CFLAGS),) +CFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_CFLAGS))) +#")) +endif + +# Note: both "" (string consisting of two quote chars) and empty string +# are possible, and should be skipped below. +ifneq ($(subst "",,$(CONFIG_SYSROOT)),) +CFLAGS += --sysroot=$(CONFIG_SYSROOT) +export SYSROOT=$(CONFIG_SYSROOT) +endif + +# libm may be needed for dc, awk, ntpd +LDLIBS += m +# Android has no separate crypt library +# gcc-4.2.1 fails if we try to feed C source on stdin: +# echo 'int main(void){return 0;}' | $(CC) $(CFLAGS) -lcrypt -o /dev/null -xc - +# fall back to using a temp file: +CRYPT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) $(CFLAGS_busybox) -lcrypt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c) +RT_AVAILABLE := $(shell echo 'int main(void){return 0;}' >bb_libtest.c; $(CC) $(CFLAGS) $(CFLAGS_busybox) -lrt -o /dev/null bb_libtest.c >/dev/null 2>&1 && echo "y"; rm bb_libtest.c) +ifeq ($(CRYPT_AVAILABLE),y) +LDLIBS += crypt +endif +# librt may be needed for clock_gettime() +ifeq ($(RT_AVAILABLE),y) +LDLIBS += rt +endif + +# libpam may use libpthread, libdl and/or libaudit. +# On some platforms that requires an explicit -lpthread, -ldl, -laudit. +# However, on *other platforms* it fails when some of those flags +# given needlessly. On some systems, crypt needs pthread. +# +# I even had a system where a runtime test for pthread +# (similar to CRYPT_AVAILABLE test above) was not reliable. +# +# Do not propagate this mess by adding libraries to CONFIG_PAM/CRYPT_AVAILABLE blocks. +# Add libraries you need to CONFIG_EXTRA_LDLIBS instead. + +ifeq ($(CONFIG_PAM),y) +LDLIBS += pam pam_misc +endif + +ifeq ($(CONFIG_SELINUX),y) +SELINUX_PC_MODULES = libselinux libsepol +$(eval $(call pkg_check_modules,SELINUX,$(SELINUX_PC_MODULES))) +CPPFLAGS += $(SELINUX_CFLAGS) +LDLIBS += $(if $(SELINUX_LIBS),$(SELINUX_LIBS:-l%=%),$(SELINUX_PC_MODULES:lib%=%)) +endif + +ifeq ($(CONFIG_FEATURE_NSLOOKUP_BIG),y) +ifneq (,$(findstring linux,$(shell $(CC) $(CFLAGS) -dumpmachine))) +LDLIBS += resolv +endif +ifneq (,$(findstring gnu,$(shell $(CC) $(CFLAGS) -dumpmachine))) +LDLIBS += resolv +endif +endif + +ifeq ($(CONFIG_EFENCE),y) +LDLIBS += efence +endif + +ifeq ($(CONFIG_DMALLOC),y) +LDLIBS += dmalloc +endif + +# If a flat binary should be built, CFLAGS_busybox="-elf2flt" +# env var should be set for make invocation. +# Here we check whether CFLAGS_busybox indeed contains that flag. +# (For historical reasons, we also check LDFLAGS, which doesn't +# seem to be entirely correct variable to put "-elf2flt" into). +W_ELF2FLT = -elf2flt +ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) +SKIP_STRIP = y +endif + +ifneq ($(CONFIG_EXTRA_LDFLAGS),) +LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) +#")) +endif + +# Busybox is a stack-fatty so make sure we increase default size +# TODO: use "make stksizes" to find & fix big stack users +# (we stole scripts/checkstack.pl from the kernel... thanks guys!) +# Reduced from 20k to 16k in 1.9.0. +FLTFLAGS += -s 16000 diff --git a/busybox-1_37_0/Makefile.help b/busybox-1_37_0/Makefile.help new file mode 100644 index 000000000..6a23e2a80 --- /dev/null +++ b/busybox-1_37_0/Makefile.help @@ -0,0 +1,44 @@ +# ========================================================================== +# Build system +# ========================================================================== + +help: + @echo 'Cleaning:' + @echo ' clean - delete temporary files created by build' + @echo ' distclean - delete all non-source files (including .config)' + @echo ' doc-clean - delete all generated documentation' + @echo + @echo 'Build:' + @echo ' all - Executable and documentation' + @echo ' busybox - the swiss-army executable' + @echo ' doc - docs/BusyBox.{txt,html,1}' + @echo ' html - create html-based cross-reference' + @echo + @echo 'Configuration:' + @echo ' allnoconfig - disable all symbols in .config' + @echo ' allyesconfig - enable all symbols in .config (see defconfig)' + @echo ' config - text based configurator (of last resort)' + @echo ' defconfig - set .config to largest generic configuration' + @echo ' menuconfig - interactive curses-based configurator' + @echo ' oldconfig - resolve any unresolved symbols in .config' + @$(if $(boards), \ + $(foreach b, $(boards), \ + printf " %-21s - Build for %s\\n" $(b) $(subst _defconfig,,$(b));) \ + echo '') + @echo + @echo 'Installation:' + @echo ' install - install busybox into CONFIG_PREFIX' + @echo ' uninstall' + @echo + @echo 'Development:' + @echo ' baseline - create busybox_old for bloatcheck.' + @echo ' bloatcheck - show size difference between old and new versions' + @echo ' check - run the test suite for all applets' + @echo ' checkhelp - check for missing help-entries in Config.in' + @echo ' randconfig - generate a random configuration' + @echo ' release - create a distribution tarball' + @echo ' sizes - show size of all enabled busybox symbols' + @echo ' objsizes - show size of each .o object built' + @echo ' bigdata - show data objects, biggest first' + @echo ' stksizes - show stack users, biggest first' + @echo diff --git a/busybox-1_37_0/NOFORK_NOEXEC.lst b/busybox-1_37_0/NOFORK_NOEXEC.lst new file mode 100644 index 000000000..055f9fb24 --- /dev/null +++ b/busybox-1_37_0/NOFORK_NOEXEC.lst @@ -0,0 +1,437 @@ +Why an applet can't be NOFORK or NOEXEC? + +Why can't be NOFORK: +interactive: may wait for user input, ^C has to work +spawner: "tool PROG ARGS" which changes program state and execs - must fork +changes state: e.g. environment, signal handlers +leaks: does not free allocated memory or opened fds + alloc+xfunc: xmalloc, then xfunc - leaks memory if xfunc dies + open+xfunc: opens fd, then calls xfunc - fd is leaked if xfunc dies +talks to network/serial/etc: it's not known how long the delay can be, + it's reasonable to expect it might be many seconds + (even if usually it is not), so ^C has to work +runner: sometimes may run for long(ish) time, and/or works with network: + ^C has to work (cat BIGFILE, chmod -R, ftpget, nc) + +"runners" can become eligible after shell is taught ^C to interrupt NOFORKs, +need to be inspected that they do not fall into alloc+xfunc, open+xfunc, +leak categories. + +Why can't be NOEXEC: +suid: runs under different uid - must fork+exec +if it's important that /proc/PID/cmdline and comm are correct. + ("pkill sh" killing itself before it kills real "sh" is no fun) + +Why shouldn't be NOFORK/NOEXEC: +rare: not started often enough to bother optimizing (example: poweroff) +daemon: runs indefinitely; these are also always fit "rare" category +longterm: often runs for a long time (many seconds), execing makes + memory footprint smaller +complex: no immediately obvious reason why NOFORK wouldn't work, + but does some non-obvoius operations (example: fuser, lsof, losetup); + detailed audit often turns out that it's a leaker +hardware: performs unusual hardware ops which may take long, + or even hang due to hardware or firmware bugs + +Interesting example of "interactive" applet which is nevertheless can be +(and is) NOEXEC is "rm". Yes, "rm -i" is interactive - but it's not that typical +for users to keep it waiting for many minutes, whereas running "rm" in shell +is very typical, and speeding up this common use via NOEXEC is useful. +IOW: rm is "interactive", but not "longterm". + +Interesting example of an applet which can be NOFORK but if not, +then should not be NOEXEC, is "usleep". As NOFORK, it amount to simply +nanosleep()ing in the calling program (usually shell). No memory wasted. +But if ran as NOEXEC, it would create a potentially long-term process, +which would be taking more memory because it did not exec +and did not free much of the copied memory of the parent +(COW helps with this only as long as parent doesn't modify its memory). + + +[ - NOFORK +[[ - NOFORK +acpid - daemon +add-shell - noexec. leaks: open+xfunc +addgroup - noexec. leaks +adduser - noexec. leaks +adjtimex - NOFORK +ar - runner +arch - NOFORK +arp - talks to network: arp -n queries DNS +arping - longterm +ash - interactive, longterm +awk - noexec. runner +base64 - runner +basename - NOFORK +beep - longterm: beep -r 999999999 +blkdiscard - noexec. leaks: open+xioctl +blkid - noexec +blockdev - noexec. leaks fd +bootchartd - daemon +brctl - noexec +bunzip2 - runner +bzcat - runner +bzip2 - runner +cal - noexec. can be runner: cal -n9999 +cat - runner: cat HUGEFILE +chat - longterm (when used as intended - talking to modem over stdin/out) +chattr - noexec. runner +chgrp - noexec. runner +chmod - noexec. runner +chown - noexec. runner +chpasswd - longterm? (list of "user:password"s from stdin) +chpst - noexec. spawner +chroot - noexec. spawner +chrt - noexec. spawner +chvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds +cksum - noexec. runner +clear - NOFORK +cmp - runner +comm - runner +conspy - interactive, longterm +cp - noexec. sometimes runner +cpio - runner +crond - daemon +crontab - longterm (runs $EDITOR), leaks: open+xasprintf +cryptpw - noexec. changes state: with --password-fd=N, moves N to stdin +cttyhack - noexec. spawner +cut - noexec. runner +date - noexec. nofork candidate(needs to stop messing up env, free xasprintf result, not use xfuncs after xasprintf) +dc - longterm (eats stdin if no params) +dd - noexec. runner +deallocvt - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds +delgroup - noexec. leaks +deluser - noexec. leaks +depmod - longterm(ish) +devmem - hardware (access to device memory may hang) +df - noexec. leaks: nested allocs +dhcprelay - daemon +diff - runner +dirname - NOFORK +dmesg - runner +dnsd - daemon +dnsdomainname - noexec. talks to network (may query DNS) +dos2unix - noexec. runner +dpkg - runner +du - runner +dumpkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds +dumpleases - noexec. leaks: open+xread +echo - NOFORK +ed - interactive, longterm +egrep - longterm runner ("CMD | egrep ..." may run indefinitely, better to exec to conserve memory) +eject - hardware, leaks: open+ioctl_or_perror_and_die, changes state (moves fds) +env - noexec. spawner, changes state (env) +envdir - noexec. spawner +envuidgid - noexec. spawner +expand - runner +expr - noexec. leaks: nested allocs +factor - longterm (eats stdin if no params) +fakeidentd - daemon +false - NOFORK +fatattr - noexec. leaks: open+xioctl, complex +fbset - hardware, leaks: open+xfunc +fbsplash - runner, longterm +fdflush - hardware, leaks: open+ioctl_or_perror_and_die +fdformat - hardware, longterm +fdisk - interactive, longterm +fgconsole - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds +fgrep - longterm runner ("CMD | fgrep ..." may run indefinitely, better to exec to conserve memory) +find - noexec. runner +findfs - suid +flash_eraseall - hardware +flash_lock - hardware +flash_unlock - hardware +flashcp - hardware +flock - spawner, changes state (file locks), let's play safe and not be noexec +fold - noexec. runner +free - NOFORK +freeramdisk - noexec. leaks: open+ioctl_or_perror_and_die +fsck - interactive, longterm +fsck.minix - needs ^C +fsfreeze - noexec. leaks: open+xioctl +fstrim - noexec. leaks: open+xioctl, find_block_device -> readdir+xstrdup +fsync - NOFORK +ftpd - daemon +ftpget - runner +ftpput - runner +fuser - complex +getopt - noexec. leaks: many allocs +getty - interactive, longterm +grep - longterm runner ("CMD | grep ..." may run indefinitely, better to exec to conserve memory) +groups - noexec +gunzip - runner +gzip - runner +halt - rare +hd - noexec. runner +hdparm - hardware +head - noexec. runner +hexdump - noexec. runner +hexedit - interactive, longterm +hostid - NOFORK +hostname - noexec. talks to network (hostname -d may query DNS) +httpd - daemon +hush - interactive, longterm +hwclock - hardware (xioctl(RTC_RD_TIME)) +i2cdetect - hardware +i2cdump - hardware +i2cget - hardware +i2cset - hardware +id - noexec +ifconfig - hardware? (mem_start NN io_addr NN irq NN), leaks: xsocket+ioctl_or_perror_and_die +ifenslave - noexec. leaks: xsocket+bb_perror_msg_and_die +ifplugd - daemon +inetd - daemon +init - daemon +inotifyd - daemon +insmod - noexec +install - runner +ionice - noexec. spawner +iostat - longterm: "iostat 1" runs indefinitely +ip - noexec +ipaddr - noexec +ipcalc - noexec. ipcalc -h talks to network +ipcrm - noexec +ipcs - noexec +iplink - noexec +ipneigh - noexec +iproute - noexec +iprule - noexec +iptunnel - noexec +kbd_mode - noexec. leaks: xopen_nonblocking+xioctl +kill - NOFORK +killall - NOFORK +killall5 - NOFORK +klogd - daemon +last - runner (I've got 1300 lines of output when tried it) +less - interactive, longterm +link - NOFORK +linux32 - noexec. spawner +linux64 - noexec. spawner +linuxrc - daemon +ln - noexec +loadfont - noexec. leaks: config_open+bb_error_msg_and_die("map format") +loadkmap - noexec. leaks: get_console_fd_or_die() may open a new fd, or return one of stdio fds +logger - runner +login - suid, interactive, longterm +logname - NOFORK +losetup - noexec. complex +lpd - daemon +lpq - runner +lpr - runner +ls - noexec. runner +lsattr - noexec. runner +lsmod - noexec +lsof - complex +lspci - noexec. too rare to bother for nofork +lsscsi - noexec. too rare to bother for nofork +lsusb - noexec. too rare to bother for nofork +lzcat - runner +lzma - runner +lzop - runner +lzopcat - runner +makedevs - noexec +makemime - runner +man - spawner, interactive, longterm +md5sum - noexec. runner +mdev - daemon +mesg - NOFORK +microcom - interactive, longterm +minips - noexec +mkdir - NOFORK +mkdosfs - needs ^C +mke2fs - needs ^C +mkfifo - noexec +mkfs.ext2 - needs ^C +mkfs.minix - needs ^C +mkfs.vfat - needs ^C +mknod - noexec +mkpasswd - noexec. changes state: with --password-fd=N, moves N to stdin +mkswap - needs ^C +mktemp - noexec. leaks: xstrdup+concat_path_file +modinfo - noexec +modprobe - noexec +more - interactive, longterm +mount - suid +mountpoint - noexec. leaks: option -n "print dev name": find_block_device -> readdir+xstrdup +mpstat - longterm: "mpstat 1" runs indefinitely +mt - hardware +mv - noexec. sometimes runner +nameif - noexec. openlog(), leaks: config_open2+ioctl_or_perror_and_die +nbd-client - noexec +nc - runner +netstat - longterm with -c (continuous listing) +nice - noexec. spawner +nl - runner +nmeter - longterm +nohup - noexec. spawner +nproc - NOFORK +ntpd - daemon +nuke - noexec +od - runner +openvt - longterm: spawns a child and waits for it +partprobe - noexec. leaks: open+ioctl_or_perror_and_die(BLKRRPART) +passwd - suid +paste - noexec. runner +patch - needs ^C +pgrep - must fork+exec to get correct /proc/PID/cmdline and comm field +pidof - must fork+exec to get correct /proc/PID/cmdline and comm field +ping - suid, longterm +ping6 - suid, longterm +pipe_progress - longterm +pivot_root - NOFORK +pkill - must fork+exec to get correct /proc/PID/cmdline and comm field +pmap - noexec candidate, leaks: open+xstrdup +popmaildir - runner +poweroff - rare +powertop - interactive, longterm +printenv - NOFORK +printf - NOFORK +ps - noexec +pscan - talks to network +pstree - noexec +pwd - NOFORK +pwdx - NOFORK +raidautorun - noexec. very simple. leaks: open+xioctl +rdate - talks to network +rdev - noexec. leaks: find_block_device -> readdir+xstrdup +readlink - NOFORK +readprofile - reads /boot/System.map and /proc/profile, better to free more memory by execing? +realpath - NOFORK +reboot - rare +reformime - runner +remove-shell - noexec. leaks: open+xfunc +renice - noexec. nofork candidate(uses getpwnam, is that ok?) +reset - noexec. spawner (execs "stty") +resize - noexec. changes state (signal handlers) +resume - noexec +rev - runner +rm - noexec. rm -i interactive +rmdir - NOFORK +rmmod - noexec +route - talks to network (may query DNS to convert IPs to names) +rpm - runner +rpm2cpio - runner +rtcwake - longterm: puts system to sleep, optimizing this for speed is pointless +run-init - spawner, rare, changes state (oh yes), execing may be important to free binary's inode +run-parts - longterm +runlevel - noexec. can be nofork if "endutxent()" is called unconditionally, but too rare to bother? +runsv - daemon +runsvdir - daemon +rx - runner +script - longterm: pumps script output from slave pty +scriptreplay - longterm: plays back "script" saved output, sleeping as necessary. +sed - runner +sendmail - runner +seq - noexec. runner +setarch - noexec. spawner +setconsole - noexec +setfattr - noexec +setfont - noexec. leaks a lot of stuff +setkeycodes - noexec +setlogcons - noexec +setpriv - spawner, changes state, let's play safe and not be noexec +setserial - noexec +setsid - spawner, uses fork_or_rexec() [not audited to work in noexec], let's play safe and not be noexec +setuidgid - noexec. spawner +sha1sum - noexec. runner +sha256sum - noexec. runner +sha3sum - noexec. runner +sha512sum - noexec. runner +showkey - interactive, longterm +shred - runner +shuf - noexec. runner +slattach - longterm (may sleep forever), uses bb_common_bufsiz1 +sleep - longterm. Could be nofork, if not the problem of "killall sleep" not killing it. +smemcap - runner +softlimit - noexec. spawner +sort - noexec. runner +split - runner +ssl_client - longterm +start-stop-daemon - not noexec: uses bb_common_bufsiz1 +stat - noexec. nofork candidate(needs fewer allocs) +strings - runner +stty - noexec. nofork candidate: has no allocs or opens except xmove_fd(xopen("-F DEVICE"),STDIN). tcsetattr(STDIN) is not a problem: it would work the same across processes sharing this fd +su - suid, spawner +sulogin - noexec. spawner +sum - runner +sv - noexec. needs ^C (uses usleep(420000)) +svc - noexec. needs ^C (uses usleep(420000)) +svlogd - daemon +swapoff - longterm: may cause memory pressure, execing is beneficial +swapon - rare +switch_root - spawner, rare, changes state (oh yes), execing may be important to free binary's inode +sync - NOFORK +sysctl - noexec. leaks: xstrdup+xmalloc_read +syslogd - daemon +tac - noexec. runner +tail - runner +tar - runner +taskset - noexec. spawner +tcpsvd - daemon +tee - runner +telnet - interactive, longterm +telnetd - daemon +test - NOFORK +tftp - runner +tftpd - daemon +time - spawner, longterm, changes state (signals) +timeout - spawner, longterm, changes state (signals) +top - interactive, longterm +touch - NOFORK +tr - runner +traceroute - suid, longterm +traceroute6 - suid, longterm +true - NOFORK +truncate - NOFORK +tty - NOFORK +ttysize - NOFORK +tunctl - noexec +tune2fs - noexec. leaks: open+xfunc +ubiattach - hardware +ubidetach - hardware +ubimkvol - hardware +ubirename - hardware +ubirmvol - hardware +ubirsvol - hardware +ubiupdatevol - hardware +udhcpc - daemon +udhcpd - daemon +udpsvd - daemon +uevent - daemon +umount - noexec. leaks: nested xmalloc +uname - NOFORK +uncompress - runner +unexpand - runner +uniq - runner +unix2dos - noexec. runner +unlink - NOFORK +unlzma - runner +unlzop - runner +unxz - runner +unzip - runner +uptime - noexec. nofork candidate(is getutxent ok?) +users - noexec. nofork candidate(is getutxent ok?) +usleep - NOFORK. But what about "killall usleep"? +uudecode - runner +uuencode - runner +vconfig - noexec. leaks: xsocket+ioctl_or_perror_and_die +vi - interactive, longterm +vlock - suid +volname - hardware (reads CDROM, this can take long-ish if need to spin up) +w - noexec. nofork candidate(is getutxent ok?) +wall - suid +watch - longterm +watchdog - daemon +wc - runner +wget - longterm +which - NOFORK +who - noexec. nofork candidate(is getutxent ok?) +whoami - NOFORK +whois - talks to network +xargs - noexec. spawner +xxd - noexec. runner +xz - runner +xzcat - runner +yes - noexec. runner +zcat - runner +zcip - daemon diff --git a/busybox-1_37_0/NOFORK_NOEXEC.sh b/busybox-1_37_0/NOFORK_NOEXEC.sh new file mode 100755 index 000000000..f4eeeef87 --- /dev/null +++ b/busybox-1_37_0/NOFORK_NOEXEC.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +exec >NOFORK_NOEXEC.lst1 + +false && grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \ +| grep -v 'noexec.' | grep -v 'noexec$' \ +| grep -v ' suid' \ +| grep -v ' daemon' \ +| grep -v ' longterm' \ +| grep rare + +echo === nofork candidate +grep -F 'nofork candidate' NOFORK_NOEXEC.lst \ + +echo === noexec candidate +grep -F 'noexec candidate' NOFORK_NOEXEC.lst \ + +echo === ^C +grep -F '^C' NOFORK_NOEXEC.lst \ +| grep -F ' - ' \ + +echo === talks +grep -F 'talks' NOFORK_NOEXEC.lst \ +| grep -F ' - ' \ + +echo === +grep -Fv 'NOFORK' NOFORK_NOEXEC.lst \ +| grep '^[^ ][^ ]* - ' \ +| grep -v 'noexec.' | grep -v ' - noexec$' \ +| grep -v ' suid' \ +| grep -v ' daemon' \ +| grep -v 'longterm' \ +| grep -v 'interactive' \ +| grep -v 'hardware' \ diff --git a/busybox-1_37_0/README b/busybox-1_37_0/README new file mode 100644 index 000000000..ada5935b9 --- /dev/null +++ b/busybox-1_37_0/README @@ -0,0 +1,204 @@ +Please see the LICENSE file for details on copying and usage. +Please refer to the INSTALL file for instructions on how to build. + +What is busybox: + + 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 bzip2, coreutils, dhcp, diffutils, e2fsprogs, + file, findutils, gawk, grep, inetutils, less, modutils, net-tools, procps, + sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The utilities + in BusyBox often have fewer options than their full-featured cousins; + however, the options that are included provide the expected functionality + and behave very much like their larger counterparts. + + BusyBox has been written with size-optimization and limited resources in + mind, both to produce small binaries and to reduce run-time memory usage. + Busybox is also extremely modular so you can easily include or exclude + commands (or features) at compile time. This makes it easy to customize + embedded systems; to create a working system, just add /dev, /etc, and a + Linux kernel. Busybox (usually together with uClibc) has also been used as + a component of "thin client" desktop systems, live-CD distributions, rescue + disks, installers, and so on. + + BusyBox provides a fairly complete POSIX environment for any small system, + both embedded environments and more full featured systems concerned about + space. Busybox is slowly working towards implementing the full Single Unix + Specification V3 (http://www.opengroup.org/onlinepubs/009695399/), but isn't + there yet (and for size reasons will probably support at most UTF-8 for + internationalization). We are also interested in passing the Linux Test + Project (http://ltp.sourceforge.net). + +---------------- + +Using busybox: + + BusyBox is extremely configurable. This allows you to include only the + components and options you need, thereby reducing binary size. Run 'make + config' or 'make menuconfig' to select the functionality that you wish to + enable. (See 'make help' for more commands.) + + The behavior of busybox is determined by the name it's called under: as + "cp" it behaves like cp, as "sed" it behaves like sed, and so on. Called + as "busybox" it takes the second argument as the name of the applet to + run (I.E. "./busybox ls -l /proc"). + + The "standalone shell" mode is an easy way to try out busybox; this is a + command shell that calls the built-in applets without needing them to be + installed in the path. (Note that this requires /proc to be mounted, if + testing from a boot floppy or in a chroot environment.) + + The build automatically generates a file "busybox.links", which is used by + 'make install' to create symlinks to the BusyBox binary for all compiled in + commands. This uses the CONFIG_PREFIX environment variable to specify + where to install, and installs hardlinks or symlinks depending + on the configuration preferences. (You can also manually run + the install script at "applets/install.sh"). + +---------------- + +Downloading the current source code: + + Source for the latest released version, as well as daily snapshots, can always + be downloaded from + + http://busybox.net/downloads/ + + You can browse the up to the minute source code and change history online. + + http://git.busybox.net/busybox/ + + Anonymous GIT access is available. For instructions, check out: + + http://www.busybox.net/source.html + + For those that are actively contributing and would like to check files in, + see: + + http://busybox.net/developer.html + + The developers also have a bug and patch tracking system + (https://bugs.busybox.net) although posting a bug/patch to the mailing list + is generally a faster way of getting it fixed, and the complete archive of + what happened is the git changelog. + + Note: if you want to compile busybox in a busybox environment you must + select CONFIG_DESKTOP. + +---------------- + +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 detailed bug report to the busybox mailing + list at busybox@busybox.net. 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: + + to: busybox@busybox.net + from: diligent@testing.linux.org + subject: /bin/date doesn't work + + package: busybox + version: 1.00 + + when i execute busybox 'date' it produces unexpected results. + with gnu date i get the following output: + + $ date + fri oct 8 14:19:41 mdt 2004 + + but when i use busybox date i get this instead: + + $ date + illegal instruction + + i am using debian unstable, kernel version 2.4.25-vrs2 on a netwinder, + and the latest uclibc from cvs. + + -diligent + + note the careful description and use of examples showing not only what + busybox does, but also a counter example showing what an equivalent app + does (or pointing to the text of a relevant standard). Bug reports lacking + such detail may never be fixed... Thanks for understanding. + +---------------- + +Portability: + + Busybox is developed and tested on Linux 2.4 and 2.6 kernels, compiled + with gcc (the unit-at-a-time optimizations in version 3.4 and later are + worth upgrading to get, but older versions should work), and linked against + uClibc (0.9.27 or greater) or glibc (2.2 or greater). In such an + environment, the full set of busybox features should work, and if + anything doesn't we want to know about it so we can fix it. + + There are many other environments out there, in which busybox may build + and run just fine. We just don't test them. Since busybox consists of a + large number of more or less independent applets, portability is a question + of which features work where. Some busybox applets (such as cat and rm) are + highly portable and likely to work just about anywhere, while others (such as + insmod and losetup) require recent Linux kernels with recent C libraries. + + Earlier versions of Linux and glibc may or may not work, for any given + configuration. Linux 2.2 or earlier should mostly work (there's still + some support code in things like mount.c) but this is no longer regularly + tested, and inherently won't support certain features (such as long files + and --bind mounts). The same is true for glibc 2.0 and 2.1: expect a higher + testing and debugging burden using such old infrastructure. (The busybox + developers are not very interested in supporting these older versions, but + will probably accept small self-contained patches to fix simple problems.) + + Some environments are not recommended. Early versions of uClibc were buggy + and missing many features: upgrade. Linking against libc5 or dietlibc is + not supported and not interesting to the busybox developers. (The first is + obsolete and has no known size or feature advantages over uClibc, the second + has known bugs that its developers have actively refused to fix.) Ancient + Linux kernels (2.0.x and earlier) are similarly uninteresting. + + In theory it's possible to use Busybox under other operating systems (such as + MacOS X, Solaris, Cygwin, or the BSD Fork Du Jour). This generally involves + a different kernel and a different C library at the same time. While it + should be possible to port the majority of the code to work in one of + these environments, don't be surprised if it doesn't work out of the box. If + you're into that sort of thing, start small (selecting just a few applets) + and work your way up. + + In 2005 Shaun Jackman has ported busybox to a combination of newlib + and libgloss, and some of his patches have been integrated. + +Supported hardware: + + BusyBox in general will build on any architecture supported by gcc. We + support both 32 and 64 bit platforms, and both big and little endian + systems. + + Under 2.4 Linux kernels, kernel module loading was implemented in a + platform-specific manner. Busybox's insmod utility has been reported to + work under ARM, CRIS, H8/300, x86, ia64, x86_64, m68k, MIPS, PowerPC, S390, + SH3/4/5, Sparc, and v850e. Anything else probably won't work. + + The module loading mechanism for the 2.6 kernel is much more generic, and + we believe 2.6.x kernel module loading support should work on all + architectures supported by the kernel. + +---------------- + +Please feed suggestions, bug reports, insults, and bribes back to the busybox +mailing list: + + busybox@busybox.net + +and/or maintainer: + + Denys Vlasenko + diff --git a/busybox-1_37_0/TODO b/busybox-1_37_0/TODO new file mode 100644 index 000000000..6c7415a81 --- /dev/null +++ b/busybox-1_37_0/TODO @@ -0,0 +1,256 @@ +Busybox TODO + +Harvest patches from +http://git.openembedded.org/cgit.cgi/openembedded/tree/recipes/busybox/ +https://dev.openwrt.org/browser/trunk/package/busybox/patches/ + + +Stuff that needs to be done. This is organized by who plans to get around to +doing it eventually, but that doesn't mean they "own" the item. If you want to +do one of these bounce an email off the person it's listed under to see if they +have any suggestions how they plan to go about it, and to minimize conflicts +between your work and theirs. But otherwise, all of these are fair game. + +Rob Landley suggested this: + Implement bb_realpath() that can handle NULL on non-glibc. + + sh + The command shell situation is a mess. We have two different + shells that don't really share any code, and the "standalone shell" doesn't + work all that well (especially not in a chroot environment), due to apps not + being reentrant. + + Do a SUSv3 audit + Look at the full Single Unix Specification version 3 (available online at + "http://www.opengroup.org/onlinepubs/009695399/nfindex.html") and + figure out which of our apps are compliant, and what we're missing that + we might actually care about. + + Even better would be some kind of automated compliance test harness that + exercises each command line option and the various corner cases. + + Internationalization + How much internationalization should we do? + + The low hanging fruit is UTF-8 character set support. We should do this. + See TODO_unicode file. + + We also have lots of hardwired english text messages. Consolidating this + into some kind of message table not only makes translation easier, but + also allows us to consolidate redundant (or close) strings. + + We probably don't want to be bloated with locale support. (Not unless we + can cleanly export it from our underlying C library without having to + concern ourselves with it directly. Perhaps a few specific things like a + config option for "date" are low hanging fruit here?) + + What level should things happen at? How much do we care about + internationalizing the text console when X11 and xterms are so much better + at it? (There's some infrastructure here we don't implement: The + "unicode_start" and "unicode_stop" shell scripts need "vt-is-UTF8" and a + --unicode option to loadkeys. That implies a real loadkeys/dumpkeys + implementation to replace loadkmap/dumpkmap. Plus messing with console font + loading. Is it worth it, or do we just say "use X"?) + + Individual compilation of applets. + It would be nice if busybox had the option to compile to individual applets, + for people who want an alternate implementation less bloated than the gnu + utils (or simply with less political baggage), but without it being one big + executable. + + Turning libbb into a real dll is another possibility, especially if libbb + could export some of the other library interfaces we've already more or less + got the code for (like zlib). + + buildroot - Make a "dogfood" option + Busybox 1.1 will be capable of replacing most gnu packages for real world + use, such as developing software or in a live CD. It needs wider testing. + + Busybox should now be able to replace bzip2, coreutils, e2fsprogs, file, + findutils, gawk, grep, inetutils, less, modutils, net-tools, patch, procps, + sed, shadow, sysklogd, sysvinit, tar, util-linux, and vim. The resulting + system should be self-hosting (I.E. able to rebuild itself from source + code). This means it would need (at least) binutils, gcc, and make, or + equivalents. + + It would be a good "eating our own dogfood" test if buildroot had the option + of using a "make allyesconfig" busybox instead of the all of the above + packages. Anything that's wrong with the resulting system, we can fix. (It + would be nice to be able to upgrade busybox to be able to replace bash and + diffutils as well, but we're not there yet.) + + One example of an existing system that does this already is Firmware Linux: + http://www.landley.net/code/firmware + + initramfs + Busybox should have a sample initramfs build script. This depends on + shell, mdev, and switch_root. + + mkdep + Write a mkdep that doesn't segfault if there's a directory it doesn't + have permission to read, isn't based on manually editing the output of + lexx and yacc, doesn't make such a mess under include/config, etc. + + Group globals into unions of structures. + Go through and turn all the global and static variables into structures, + and have all those structures be in a big union shared between processes, + so busybox uses less bss. (This is a big win on nommu machines.) See + sed.c and mdev.c for examples. + + Go through bugs.busybox.net and close out all of that somehow. + This one's open to everybody, but I'll wind up doing it... + +Bernhard Reutner-Fischer suggests to look at these: + New debug options: + -Wlarger-than-127 + Cleanup any big users + Collate BUFSIZ IOBUF_SIZE MY_BUF_SIZE PIPE_PROGRESS_SIZE BUFSIZE PIPESIZE + make bb_common_bufsiz1 configurable, size wise. + make pipesize configurable, size wise. + Use bb_common_bufsiz1 throughout applets! + +As yet unclaimed: + +---- +diff + Make sure we handle empty files properly: + From the patch man page: + + you can remove a file by sending out a context diff that compares + the file to be deleted with an empty file dated the Epoch. The + file will be removed unless patch is conforming to POSIX and the + -E or --remove-empty-files option is not given. +--- +patch + Should have simple fuzz factor support to apply patches at an offset which + shouldn't take up too much space. + + And while we're at it, a new patch filename quoting format is apparently + coming soon: http://marc.theaimsgroup.com/?l=git&m=112927316408690&w=2 + +Architectural issues: + +bb_close() with fsync() + We should have a bb_close() in place of normal close, with a CONFIG_ option + to not just check the return value of close() for an error, but fsync(). + Close can't reliably report anything useful because if write() accepted the + data then it either went out to the network or it's in cache or a pipe + buffer. Either way, there's no guarantee it'll make it to its final + destination before close() gets called, so there's no guarantee that any + error will be reported. + + You need to call fsync() if you care about errors that occur after write(), + but that can have a big performance impact. So make it a config option. +--- +Unify archivers + Lots of archivers have the same general infrastructure. The directory + traversal code should be factored out, and the guts of each archiver could + be some setup code and a series of callbacks for "add this file", + "add this directory", "add this symlink" and so on. + + This could clean up tar and zip, and make it cheaper to add cpio and ar + write support, and possibly even cheaply add things like mkisofs or + mksquashfs someday, if they become relevant. +--- +Text buffer support. + Several existing applets (sort, vi, less...) read + a whole file into memory and act on it. Use open_read_close(). +--- +Memory Allocation + We have a CONFIG_BUFFER mechanism that lets us select whether to do memory + allocation on the stack or the heap. Unfortunately, we're not using it much. + We need to audit our memory allocations and turn a lot of malloc/free calls + into RESERVE_CONFIG_BUFFER/RELEASE_CONFIG_BUFFER. + For a start, see e.g. make EXTRA_CFLAGS=-Wlarger-than-64 + + And while we're at it, many of the CONFIG_FEATURE_CLEAN_UP #ifdefs will be + optimized out by the compiler in the stack allocation case (since there's no + free for an alloca()), and this means that various cleanup loops that just + call free might also be optimized out by the compiler if written right, so + we can yank those #ifdefs too, and generally clean up the code. +--- +FEATURE_CLEAN_UP + This is more an unresolved issue than a to-do item. More thought is needed. + + Normally we rely on exit() to free memory, close files and unmap segments + for us. This makes most calls to free(), close(), and unmap() optional in + busybox applets that don't intend to run for very long, and optional stuff + can be omitted to save size. + + The idea was raised that we could simulate fork/exit with setjmp/longjmp + for _really_ brainless embedded systems, or speed up the standalone shell + by not forking. Doing so would require a reliable FEATURE_CLEAN_UP. + Unfortunately, this isn't as easy as it sounds. + + The problem is, lots of things exit(), sometimes unexpectedly (xmalloc()) + and sometimes reliably (bb_perror_msg_and_die() or show_usage()). This + jumps out of the normal flow control and bypasses any cleanup code we + put at the end of our applets. + + It's possible to add hooks to libbb functions like xmalloc() and xopen() + to add their entries to a linked list, which could be traversed and + freed/closed automatically. (This would need to be able to free just the + entries after a checkpoint to be usable for a forkless standalone shell. + You don't want to free the shell's own resources.) + + Right now, FEATURE_CLEAN_UP is more or less a debugging aid, to make things + like valgrind happy. It's also documentation of _what_ we're trusting + exit() to clean up for us. But new infrastructure to auto-free stuff would + render the existing FEATURE_CLEAN_UP code redundant. + + For right now, exit() handles it just fine. + + +Minor stuff: + watchdog.c could autodetect the timer duration via: + if(!ioctl (fd, WDIOC_GETTIMEOUT, &tmo)) timer_duration = 1 + (tmo / 2); + Unfortunately, that needs linux/watchdog.h and that contains unfiltered + kernel types on some distros, which breaks the build. +--- + use bb_error_msg where appropriate: See + egrep "(printf.*\([[:space:]]*(stderr|2)|[^_]write.*\([[:space:]]*(stderr|2))" +--- + use bb_perror_msg where appropriate: See + egrep "[^_]perror" +--- + possible code duplication ingroup() and is_a_group_member() +--- + Move __get_hz() to a better place and (re)use it in route.c, ash.c +--- + See grep -r strtod + Alot of duplication that wants cleanup. +--- + unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. +--- + +(TODO list after discussion 11.05.2009) + +* shrink tc/brctl/ip + tc/brctl seem like fairly large things to try and tackle in your timeframe, + and i think people have posted attempts in the past. Adding additional + options to ip though seems reasonable. + +* add tests for some applets + +* implement POSIX utilities and audit them for POSIX conformance. then + audit them for GNU conformance. then document all your findings in a new + doc/conformance.txt file while perhaps implementing some of the missing + features. + you can find the latest POSIX documentation (1003.1-2008) here: + http://www.opengroup.org/onlinepubs/9699919799/ + and the complete list of all utilities that POSIX covers: + http://www.opengroup.org/onlinepubs/9699919799/idx/utilities.html + The first step would to generate a file/matrix what is already archived + (also IPV6) + +* implement 'at' + +* rpcbind (former portmap) or equivalent + so that we don't have to use -o nolock on nfs mounts + +* check IPV6 compliance + +* generate a mini example using kernel+busybox only (+libc) for example + +* more support for advanced linux 2.6.x features, see: iotop + most likely there is more diff --git a/busybox-1_37_0/TODO_unicode b/busybox-1_37_0/TODO_unicode new file mode 100644 index 000000000..b310e8d4d --- /dev/null +++ b/busybox-1_37_0/TODO_unicode @@ -0,0 +1,45 @@ +Already fixed applets: +cal +lsmod +df +dumpleases + +Applets which may need unicode handling (more extensive than sanitizing +of filenames in error messages): + +ls - work in progress +expand, unexpand - uses unicode_strlen, not scrlen +ash, hush through lineedit - uses unicode_strlen, not scrlen +top - need to sanitize process args +ps - need to sanitize process args +less +more +vi +ed +cut +awk +sed +tr +grep egrep fgrep +fold +sort +head, tail +catv - "display nonprinting chars" - what this could mean for unicode? +wc +chat +dumpkmap +last - just line up columns +man +microcom +strings +watch + +Unsure, may need fixing: + +hostname - do we really want to protect against bad chars in it? +patch +addgroup, adduser, delgroup, deluser +telnet +telnetd +od +printf diff --git a/busybox-1_37_0/applets/.gitignore b/busybox-1_37_0/applets/.gitignore new file mode 100644 index 000000000..459938d67 --- /dev/null +++ b/busybox-1_37_0/applets/.gitignore @@ -0,0 +1,3 @@ +/applet_tables +/usage +/usage_pod diff --git a/busybox-1_37_0/applets/Kbuild.src b/busybox-1_37_0/applets/Kbuild.src new file mode 100644 index 000000000..3aedbbffe --- /dev/null +++ b/busybox-1_37_0/applets/Kbuild.src @@ -0,0 +1,57 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +obj-y := +obj-y += applets.o + +hostprogs-y:= +hostprogs-y += usage usage_pod applet_tables + +always:= $(hostprogs-y) + +# Generated files need additional love + +# This trick decreases amount of rebuilds +# if tree is merely renamed/copied +ifeq ($(srctree),$(objtree)) +srctree_slash = +else +srctree_slash = $(srctree)/ +endif + +HOSTCFLAGS_usage.o = -I$(srctree_slash)include -Iinclude +HOSTCFLAGS_usage_pod.o = -I$(srctree_slash)include -Iinclude + +applets/applets.o: include/usage_compressed.h include/applet_tables.h + +applets/applet_tables: .config include/applets.h +applets/usage: .config include/applets.h +applets/usage_pod: .config include/applets.h include/applet_tables.h + +quiet_cmd_gen_usage_compressed = GEN include/usage_compressed.h + cmd_gen_usage_compressed = $(srctree_slash)applets/usage_compressed include/usage_compressed.h applets + +include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compressed + $(call cmd,gen_usage_compressed) + +quiet_cmd_gen_applet_tables = GEN include/applet_tables.h include/NUM_APPLETS.h + cmd_gen_applet_tables = applets/applet_tables include/applet_tables.h include/NUM_APPLETS.h + +include/NUM_APPLETS.h: applets/applet_tables + $(call cmd,gen_applet_tables) + +# In fact, include/applet_tables.h depends only on applets/applet_tables, +# and is generated by it. But specifying only it can run +# applets/applet_tables twice, possibly in parallel. +# We say that it also needs NUM_APPLETS.h +# +# Unfortunately, we need to list the same command, +# and it can be executed twice (sequentially). +# The alternative is to not list any command, +# and then if include/applet_tables.h is deleted, it won't be rebuilt. +# +include/applet_tables.h: include/NUM_APPLETS.h applets/applet_tables + $(call cmd,gen_applet_tables) diff --git a/busybox-1_37_0/applets/applet_tables.c b/busybox-1_37_0/applets/applet_tables.c new file mode 100644 index 000000000..66ef7e4ac --- /dev/null +++ b/busybox-1_37_0/applets/applet_tables.c @@ -0,0 +1,244 @@ +/* vi: set sw=4 ts=4: */ +/* + * Applet table generator. + * Runs on host and produces include/applet_tables.h + * + * Copyright (C) 2007 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#undef ARRAY_SIZE +#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) + +#ifndef PATH_MAX +#define PATH_MAX 1024 +#endif + +#include "../include/autoconf.h" +#include "../include/applet_metadata.h" + +struct bb_applet { + const char *name; + const char *main; + enum bb_install_loc_t install_loc; + enum bb_suid_t need_suid; + /* true if instead of fork(); exec("applet"); waitpid(); + * one can do fork(); exit(applet_main(argc,argv)); waitpid(); */ + unsigned char noexec; + /* Even nicer */ + /* true if instead of fork(); exec("applet"); waitpid(); + * one can simply call applet_main(argc,argv); */ + unsigned char nofork; +}; + +/* Define struct bb_applet applets[] */ +#include "../include/applets.h" + +enum { NUM_APPLETS = ARRAY_SIZE(applets) }; + +static int cmp_name(const void *a, const void *b) +{ + const struct bb_applet *aa = a; + const struct bb_applet *bb = b; + return strcmp(aa->name, bb->name); +} + +static int str_isalnum_(const char *s) +{ + while (*s) { + if (!isalnum((unsigned char)*s) && *s != '_') + return 0; + s++; + } + return 1; +} + +int main(int argc, char **argv) +{ + int i, j; + char tmp1[PATH_MAX], tmp2[PATH_MAX]; + + // In find_applet_by_name(), before linear search, narrow it down + // by looking at N "equidistant" names. With ~350 applets: + // KNOWN_APPNAME_OFFSETS cycles + // 0 9057 + // 2 4604 + ~100 bytes of code + // 4 2407 + 4 bytes + // 8 1342 + 8 bytes + // 16 908 + 16 bytes + // 32 884 + 32 bytes + // With 8, int16_t applet_nameofs[] table has 7 elements. + int KNOWN_APPNAME_OFFSETS = 8; + // With 128 applets we do two linear searches, with 1..7 strcmp's in the first one + // and 1..16 strcmp's in the second. With 256 apps, second search does 1..32 strcmp's. + if (NUM_APPLETS < 128) + KNOWN_APPNAME_OFFSETS = 4; + if (NUM_APPLETS < 32) + KNOWN_APPNAME_OFFSETS = 0; + + qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); + + for (i = j = 0; i < NUM_APPLETS-1; ++i) { + if (cmp_name(applets+i, applets+i+1) == 0) { + fprintf(stderr, "%s: duplicate applet name '%s'\n", argv[0], + applets[i].name); + j = 1; + } + } + + if (j != 0 || !argv[1]) + return 1; + snprintf(tmp1, PATH_MAX, "%s.%u.new", argv[1], (int) getpid()); + i = open(tmp1, O_WRONLY | O_TRUNC | O_CREAT, 0666); + if (i < 0) + return 1; + dup2(i, 1); + + /* Keep in sync with include/busybox.h! */ + + printf("/* This is a generated file, don't edit */\n\n"); + + printf("#define NUM_APPLETS %u\n", NUM_APPLETS); + if (NUM_APPLETS == 1) { + printf("#define SINGLE_APPLET_STR \"%s\"\n", applets[0].name); + printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main); + } + + printf("#define KNOWN_APPNAME_OFFSETS %u\n\n", KNOWN_APPNAME_OFFSETS); + if (KNOWN_APPNAME_OFFSETS > 0) { + int ofs, offset[KNOWN_APPNAME_OFFSETS], index[KNOWN_APPNAME_OFFSETS]; + for (i = 0; i < KNOWN_APPNAME_OFFSETS; i++) + index[i] = i * NUM_APPLETS / KNOWN_APPNAME_OFFSETS; + ofs = 0; + for (i = 0; i < NUM_APPLETS; i++) { + for (j = 0; j < KNOWN_APPNAME_OFFSETS; j++) + if (i == index[j]) + offset[j] = ofs; + ofs += strlen(applets[i].name) + 1; + } + /* If the list of names is too long refuse to proceed */ + if (ofs > 0xffff) + return 1; + printf("const uint16_t applet_nameofs[] ALIGN2 = {\n"); + for (i = 1; i < KNOWN_APPNAME_OFFSETS; i++) + printf("%d,\n", offset[i]); + printf("};\n\n"); + } + + //printf("#ifndef SKIP_definitions\n"); + printf("const char applet_names[] ALIGN1 = \"\"\n"); + for (i = 0; i < NUM_APPLETS; i++) { + printf("\"%s\" \"\\0\"\n", applets[i].name); +// if (MAX_APPLET_NAME_LEN < strlen(applets[i].name)) +// MAX_APPLET_NAME_LEN = strlen(applets[i].name); + } + printf(";\n\n"); + + for (i = 0; i < NUM_APPLETS; i++) { + if (str_isalnum_(applets[i].name)) + printf("#define APPLET_NO_%s %d\n", applets[i].name, i); + } + printf("\n"); + + printf("#ifndef SKIP_applet_main\n"); + printf("int (*const applet_main[])(int argc, char **argv) = {\n"); + for (i = 0; i < NUM_APPLETS; i++) { + printf("%s_main,\n", applets[i].main); + } + printf("};\n"); + printf("#endif\n\n"); + +#if ENABLE_FEATURE_PREFER_APPLETS \ + || ENABLE_FEATURE_SH_STANDALONE \ + || ENABLE_FEATURE_SH_NOFORK + printf("const uint8_t applet_flags[] ALIGN1 = {\n"); + i = 0; + while (i < NUM_APPLETS) { + int v = applets[i].nofork + (applets[i].noexec << 1); + if (++i < NUM_APPLETS) + v |= (applets[i].nofork + (applets[i].noexec << 1)) << 2; + if (++i < NUM_APPLETS) + v |= (applets[i].nofork + (applets[i].noexec << 1)) << 4; + if (++i < NUM_APPLETS) + v |= (applets[i].nofork + (applets[i].noexec << 1)) << 6; + printf("0x%02x,\n", v); + i++; + } + printf("};\n\n"); +#endif + +#if ENABLE_FEATURE_SUID + printf("const uint8_t applet_suid[] ALIGN1 = {\n"); + i = 0; + while (i < NUM_APPLETS) { + int v = applets[i].need_suid; /* 2 bits */ + if (++i < NUM_APPLETS) + v |= applets[i].need_suid << 2; + if (++i < NUM_APPLETS) + v |= applets[i].need_suid << 4; + if (++i < NUM_APPLETS) + v |= applets[i].need_suid << 6; + printf("0x%02x,\n", v); + i++; + } + printf("};\n\n"); +#endif + +#if ENABLE_FEATURE_INSTALLER + printf("const uint8_t applet_install_loc[] ALIGN1 = {\n"); + i = 0; + while (i < NUM_APPLETS) { + int v = applets[i].install_loc; /* 3 bits */ + if (++i < NUM_APPLETS) + v |= applets[i].install_loc << 4; /* 3 bits */ + printf("0x%02x,\n", v); + i++; + } + printf("};\n"); +#endif + //printf("#endif /* SKIP_definitions */\n"); + +// printf("\n"); +// printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); + + if (argv[2]) { + FILE *fp; + char line_new[80]; +// char line_old[80]; + + sprintf(line_new, "#define NUM_APPLETS %u\n", NUM_APPLETS); +// line_old[0] = 0; +// fp = fopen(argv[2], "r"); +// if (fp) { +// fgets(line_old, sizeof(line_old), fp); +// fclose(fp); +// } +// if (strcmp(line_old, line_new) != 0) { + snprintf(tmp2, PATH_MAX, "%s.%u.new", argv[2], (int) getpid()); + fp = fopen(tmp2, "w"); + if (!fp) + return 1; + fputs(line_new, fp); + if (fclose(fp)) + return 1; +// } + } + + if (fclose(stdout)) + return 1; + if (rename(tmp1, argv[1])) + return 1; + if (rename(tmp2, argv[2])) + return 1; + return 0; +} diff --git a/busybox-1_37_0/applets/applets.c b/busybox-1_37_0/applets/applets.c new file mode 100644 index 000000000..98c2b44f5 --- /dev/null +++ b/busybox-1_37_0/applets/applets.c @@ -0,0 +1,16 @@ +/* vi: set sw=4 ts=4: */ +/* + * Stub for linking busybox binary against libbusybox. + * + * Copyright (C) 2007 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "busybox.h" + +#if ENABLE_BUILD_LIBBUSYBOX +int main(int argc UNUSED_PARAM, char **argv) +{ + return lbb_main(argv); +} +#endif diff --git a/busybox-1_37_0/applets/busybox.mkll b/busybox-1_37_0/applets/busybox.mkll new file mode 100755 index 000000000..68dbf2162 --- /dev/null +++ b/busybox-1_37_0/applets/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:-include/autoconf.h} +APPLETS_H=${2:-include/applets.h} +$HOSTCC -E -DMAKE_LINKS -include $CONFIG_H $APPLETS_H | + awk '/^[ \t]*LINK/{ + dir=substr($2,7) + gsub("_","/",dir) + if(dir=="/ROOT") dir="" + file=$3 + gsub("\"","",file) + if (file=="busybox") next + print tolower(dir) "/" file + }' diff --git a/busybox-1_37_0/applets/busybox.mkscripts b/busybox-1_37_0/applets/busybox.mkscripts new file mode 100755 index 000000000..935685cba --- /dev/null +++ b/busybox-1_37_0/applets/busybox.mkscripts @@ -0,0 +1,16 @@ +#!/bin/sh +# Make busybox scripted applet 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 + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +CONFIG_H=${1:-include/autoconf.h} +APPLETS_H=${2:-include/applets.h} +$HOSTCC -E -DMAKE_SCRIPTS -include $CONFIG_H $APPLETS_H | + awk '/^[ \t]*SCRIPT/{ + print $2 + }' diff --git a/busybox-1_37_0/applets/busybox.mksuid b/busybox-1_37_0/applets/busybox.mksuid new file mode 100755 index 000000000..6492c079a --- /dev/null +++ b/busybox-1_37_0/applets/busybox.mksuid @@ -0,0 +1,54 @@ +#!/bin/sh +# Make list of configuration variables regarding suid handling + +# input $1: full path to autoconf.h +# input $2: full path to applets.h +# input $3: full path to .config +# output (stdout): list of CONFIG_ that do or may require suid + +# If the environment variable SUID is not set or set to DROP, +# lists all config options that do not require suid permissions. +# Otherwise, lists all config options for applets that DO or MAY require +# suid permissions. + +# Maintainer: Bernhard Reutner-Fischer + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +CONFIG_H=${1:-include/autoconf.h} +APPLETS_H=${2:-include/applets.h} +DOT_CONFIG=${3:-.config} + +case ${SUID:-DROP} in +[dD][rR][oO][pP]) USE="DROP" ;; +*) USE="suid" ;; +esac + +$HOSTCC -E -DMAKE_SUID -include $CONFIG_H $APPLETS_H | + awk -v USE=${USE} ' + /^SUID[ \t]/{ + if (USE == "DROP") { + if ($2 != "BB_SUID_DROP") next + } else { + if ($2 == "BB_SUID_DROP") next + } + cfg = $NF + gsub("\"", "", cfg) + cfg = substr(cfg, 8) + s[i++] = "CONFIG_" cfg + s[i++] = "CONFIG_FEATURE_" cfg "_.*" + } + END{ + while (getline < ARGV[2]) { + for (j in s) { + if ($0 ~ "^" s[j] "=y$") { + sub(/=.*/, "") + print + if (s[j] !~ /\*$/) delete s[j] # can drop this applet now + } + } + } + } +' - $DOT_CONFIG + diff --git a/busybox-1_37_0/applets/individual.c b/busybox-1_37_0/applets/individual.c new file mode 100644 index 000000000..2f743d906 --- /dev/null +++ b/busybox-1_37_0/applets/individual.c @@ -0,0 +1,24 @@ +/* Minimal wrapper to build an individual busybox applet. + * + * Copyright 2005 Rob Landley +#include +#include "usage.h" + +int main(int argc, char **argv) +{ + applet_name = argv[0]; + return APPLET_main(argc, argv); +} + +void bb_show_usage(void) +{ + fputs_stdout(APPLET_full_usage "\n"); + exit_FAILURE(); +} diff --git a/busybox-1_37_0/applets/install.sh b/busybox-1_37_0/applets/install.sh new file mode 100755 index 000000000..415896893 --- /dev/null +++ b/busybox-1_37_0/applets/install.sh @@ -0,0 +1,137 @@ +#!/bin/sh + +export LC_ALL=POSIX +export LC_CTYPE=POSIX + +prefix=$1 +if [ -z "$prefix" ]; then + echo "usage: applets/install.sh DESTINATION TYPE [OPTS ...]" + echo " TYPE is one of: --symlinks --hardlinks --binaries --scriptwrapper --none" + echo " OPTS is one or more of: --cleanup --noclobber" + exit 1 +fi +shift # Keep only remaining options + +# Source the configuration +. ./.config + +h=`sort busybox.links | uniq` + +sharedlib_dir="0_lib" + +linkopts="" +scriptwrapper="n" +binaries="n" +cleanup="0" +noclobber="0" +while [ ${#} -gt 0 ]; do + case "$1" in + --hardlinks) linkopts="-f";; + --symlinks) linkopts="-fs";; + --binaries) binaries="y";; + --scriptwrapper) scriptwrapper="y"; swrapall="y";; + --sw-sh-hard) scriptwrapper="y"; linkopts="-f";; + --sw-sh-sym) scriptwrapper="y"; linkopts="-fs";; + --cleanup) cleanup="1";; + --noclobber) noclobber="1";; + --none) h="";; + *) echo "Unknown install option: $1"; exit 1;; + esac + shift +done + +if [ -n "$DO_INSTALL_LIBS" ] && [ x"$DO_INSTALL_LIBS" != x"n" ]; then + # get the target dir for the libs + # assume it starts with lib + libdir=$($CC -print-file-name=libc.so | \ + sed -n 's%^.*\(/lib[^\/]*\)/libc.so%\1%p') + if test -z "$libdir"; then + libdir=/lib + fi + + mkdir -p "$prefix/$libdir" || exit 1 + for i in $DO_INSTALL_LIBS; do + rm -f "$prefix/$libdir/$i" || exit 1 + if [ -f "$i" ]; then + echo " Installing $i to the target at $prefix/$libdir/" + cp -pPR "$i" "$prefix/$libdir/" || exit 1 + chmod 0644 "$prefix/$libdir/`basename $i`" || exit 1 + fi + done +fi + +if [ x"$cleanup" = x"1" ] && [ -e "$prefix/bin/busybox" ]; then + inode=`ls -i "$prefix/bin/busybox" | awk '{print $1}'` + sub_shell_it=` + cd "$prefix" + for d in usr/sbin usr/bin sbin bin; do + pd=$PWD + if [ -d "$d" ]; then + cd "$d" + ls -iL . | grep "^ *$inode" | awk '{print $2}' | env -i xargs rm -f + fi + cd "$pd" + done + ` + exit 0 +fi + +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"` + app=`basename "$i"` + if [ x"$noclobber" = x"1" ] && ([ -e "$prefix/$i" ] || [ -h "$prefix/$i" ]); then + echo " $prefix/$i already exists" + continue + fi + mkdir -p "$prefix/$appdir" || exit 1 + if [ x"$scriptwrapper" = x"y" ]; then + if [ x"$swrapall" != x"y" ] && [ x"$i" = x"/bin/sh" ]; then + ln $linkopts busybox "$prefix/$i" || exit 1 + else + rm -f "$prefix/$i" + echo "#!/bin/busybox" >"$prefix/$i" + chmod +x "$prefix/$i" + fi + echo " $prefix/$i" + elif [ x"$binaries" = x"y" ]; then + # Copy the binary over rather + if [ -e "$sharedlib_dir/$app" ]; then + echo " Copying $sharedlib_dir/$app to $prefix/$i" + cp -pPR "$sharedlib_dir/$app" "$prefix/$i" || exit 1 + else + echo "Error: Could not find $sharedlib_dir/$app" + exit 1 + fi + else + if [ x"$linkopts" = x"-f" ]; 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 + fi +done + +exit 0 diff --git a/busybox-1_37_0/applets/usage.c b/busybox-1_37_0/applets/usage.c new file mode 100644 index 000000000..94520ff66 --- /dev/null +++ b/busybox-1_37_0/applets/usage.c @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2008 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include +#include +#include + +#include "autoconf.h" + +/* Since we can't use platform.h, have to do this again by hand: */ +#if ENABLE_NOMMU +# define BB_MMU 0 +# define USE_FOR_NOMMU(...) __VA_ARGS__ +# define USE_FOR_MMU(...) +#else +# define BB_MMU 1 +# define USE_FOR_NOMMU(...) +# define USE_FOR_MMU(...) __VA_ARGS__ +#endif + +#include "usage.h" +#define MAKE_USAGE(aname, usage) { aname, usage }, +static struct usage_data { + const char *aname; + const char *usage; +} usage_array[] = { +#include "applets.h" +}; + +static int compare_func(const void *a, const void *b) +{ + const struct usage_data *ua = a; + const struct usage_data *ub = b; + return strcmp(ua->aname, ub->aname); +} + +int main(void) +{ + int i; + int num_messages = sizeof(usage_array) / sizeof(usage_array[0]); + + if (num_messages == 0) + return 0; + + qsort(usage_array, + num_messages, sizeof(usage_array[0]), + compare_func); + for (i = 0; i < num_messages; i++) + write(STDOUT_FILENO, usage_array[i].usage, strlen(usage_array[i].usage) + 1); + + return 0; +} diff --git a/busybox-1_37_0/applets/usage_compressed b/busybox-1_37_0/applets/usage_compressed new file mode 100755 index 000000000..36fc2a007 --- /dev/null +++ b/busybox-1_37_0/applets/usage_compressed @@ -0,0 +1,62 @@ +#!/bin/sh + +target="$1" +loc="$2" + +test "$target" || exit 1 +test "$loc" || loc=. +test -x "$loc/usage" || exit 1 +test "$SED" || SED=sed +test "$DD" || DD=dd + +# Some people were bitten by their system lacking a (proper) od +od -v -b /dev/null +if test $? != 0; then + echo 'od tool is not installed or cannot accept "-v -b" options' + exit 1 +fi + +exec >"$target.$$" + +echo '#define UNPACKED_USAGE "" \' +"$loc/usage" | od -v -b \ +| grep -v '^ ' \ +| $SED -e 's/^[^ ]*//' \ + -e 's/ //g' \ + -e '/^$/d' \ + -e 's/\(...\)/\\\1/g' \ + -e 's/^/"/' \ + -e 's/$/" \\/' +echo '' +# "grep -v '^ '" is for toybox's od bug: od -b prints some extra lines: +#0000000 010 000 010 000 133 055 144 146 135 040 133 055 143 040 103 117 +# 000010 000010 026533 063144 020135 026533 020143 047503 +#0000020 116 106 104 111 122 135 040 133 055 154 040 114 117 107 106 111 +# 043116 044504 056522 055440 066055 046040 043517 044506 +#0000040 114 105 135 040 133 055 141 040 101 103 124 111 117 116 106 111 +# 042514 020135 026533 020141 041501 044524 047117 044506 + +echo "#define UNPACKED_USAGE_LENGTH `$loc/usage | wc -c`" +echo + +echo '#define PACKED_USAGE \' +## Breaks on big-endian systems! +## # Extra effort to avoid using "od -t x1": -t is not available +## # in non-CONFIG_DESKTOPed busybox od +## +## "$loc/usage" | bzip2 -1 | od -v -x \ +## | $SED -e 's/^[^ ]*//' \ +## -e 's/ //g' \ +## -e '/^$/d' \ +## -e 's/\(..\)\(..\)/0x\2,0x\1,/g' +## -e 's/$/ \\/' +"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \ +| grep -v '^ ' \ +| $SED -e 's/^[^ ]*//' \ + -e 's/ //g' \ + -e '/^$/d' \ + -e 's/\(...\)/0\1,/g' \ + -e 's/$/ \\/' +echo '' + +mv -- "$target.$$" "$target" diff --git a/busybox-1_37_0/applets/usage_pod.c b/busybox-1_37_0/applets/usage_pod.c new file mode 100644 index 000000000..9e6d3f0ee --- /dev/null +++ b/busybox-1_37_0/applets/usage_pod.c @@ -0,0 +1,113 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2009 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include +#include +#include +#include +#include + +#include "autoconf.h" + +#define SKIP_applet_main +#define ALIGN1 /* nothing, just to placate applet_tables.h */ +#define ALIGN2 /* nothing, just to placate applet_tables.h */ +#include "applet_tables.h" + +/* Since we can't use platform.h, have to do this again by hand: */ +#if ENABLE_NOMMU +# define BB_MMU 0 +# define USE_FOR_NOMMU(...) __VA_ARGS__ +# define USE_FOR_MMU(...) +#else +# define BB_MMU 1 +# define USE_FOR_NOMMU(...) +# define USE_FOR_MMU(...) __VA_ARGS__ +#endif + +#include "usage.h" +#define MAKE_USAGE(aname, usage) { aname, usage }, +static struct usage_data { + const char *aname; + const char *usage; +} usage_array[] = { +#include "applets.h" +}; + +static int compare_func(const void *a, const void *b) +{ + const struct usage_data *ua = a; + const struct usage_data *ub = b; + return strcmp(ua->aname, ub->aname); +} + +int main(void) +{ + int col, len2; + + int i; + int num_messages = sizeof(usage_array) / sizeof(usage_array[0]); + + if (num_messages == 0) + return 0; + + qsort(usage_array, + num_messages, sizeof(usage_array[0]), + compare_func); + + col = 0; + for (i = 0; i < num_messages; i++) { + len2 = strlen(usage_array[i].aname) + 2; + if (col >= 76 - len2) { + printf(",\n"); + col = 0; + } + if (col == 0) { + col = 6; + printf("\t"); + } else { + printf(", "); + } + printf("%s", usage_array[i].aname); + col += len2; + } + printf("\n\n"); + + printf("=head1 COMMAND DESCRIPTIONS\n\n"); + printf("=over 4\n\n"); + + for (i = 0; i < num_messages; i++) { + if (usage_array[i].aname[0] >= 'a' && usage_array[i].aname[0] <= 'z' + && usage_array[i].usage[0] != NOUSAGE_STR[0] + ) { + printf("=item B<%s>\n\n", usage_array[i].aname); + if (usage_array[i].usage[0]) + printf("%s %s\n\n", usage_array[i].aname, usage_array[i].usage); + else + printf("%s\n\n", usage_array[i].aname); + } + } + printf("=back\n\n"); + + return 0; +} + +/* TODO: we used to make options bold with B<> and output an example too: + +=item B + +cat [B<-u>] [FILE]... + +Concatenate FILE(s) and print them to stdout + +Options: + -u Use unbuffered i/o (ignored) + +Example: + $ cat /proc/uptime + 110716.72 17.67 + +*/ diff --git a/busybox-1_37_0/applets_sh/mim b/busybox-1_37_0/applets_sh/mim new file mode 100755 index 000000000..2a65c35bb --- /dev/null +++ b/busybox-1_37_0/applets_sh/mim @@ -0,0 +1,39 @@ +#!/bin/sh +MIMFILE="Mimfile" +if [ $# -ge 2 ] && [ "$1" = "-f" ] +then + MIMFILE="$2" + shift 2 +fi +exec <"$MIMFILE" || exit 1 +{ + INCASE=false + while read -r REPLY + do + case $REPLY in + *:) + if ! $INCASE + then + printf '[ $# -eq 0 ] && set -- "%s" +TARGET="$1" +shift +case "$TARGET" in +' "${REPLY%:}" + else + printf ';;\n' + fi + printf '%s)\n' "${REPLY%:}" + INCASE=true + ;; + "") ;; + *) printf '%s\n' "${REPLY##[ ]}";; + esac + done + $INCASE && printf ';;\n' + printf '*) +echo "Unknown command $TARGET" +exit 1 +;; +esac +' +} | sh -s "$@" diff --git a/busybox-1_37_0/applets_sh/nologin b/busybox-1_37_0/applets_sh/nologin new file mode 100755 index 000000000..4ed5f6ca3 --- /dev/null +++ b/busybox-1_37_0/applets_sh/nologin @@ -0,0 +1,3 @@ +cat /etc/nologin.txt 2>/dev/null || echo This account is not available +sleep 5 +exit 1 diff --git a/busybox-1_37_0/arch/i386/Makefile b/busybox-1_37_0/arch/i386/Makefile new file mode 100644 index 000000000..2fa008fa7 --- /dev/null +++ b/busybox-1_37_0/arch/i386/Makefile @@ -0,0 +1,21 @@ +# ========================================================================== +# Build system +# ========================================================================== + +# Allow i486 insns (basically, bswap insn) +# Do not try to tune for 486+ (might add padding) +CFLAGS += $(call cc-option,-march=i486 -mtune=i386,) + +ifeq ($(CONFIG_STACK_OPTIMIZATION_386),y) +# -mpreferred-stack-boundary=2 is essential in preventing gcc 4.2.x +# from aligning stack to 16 bytes. (Which is gcc's way of supporting SSE). +CFLAGS += $(call cc-option,-mpreferred-stack-boundary=2,) +endif + +# "Control how GCC aligns variables. +# Supported values for type are compat uses increased alignment value +# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI, +# and cacheline uses increased alignment value to match the cache line size. +# compat is the default." +# "abi" seems to be somewhat successful in preventing oversealous data alignment. +CFLAGS += $(call cc-option,-malign-data=abi,) diff --git a/busybox-1_37_0/arch/sparc/Makefile b/busybox-1_37_0/arch/sparc/Makefile new file mode 100644 index 000000000..0b1c56cb5 --- /dev/null +++ b/busybox-1_37_0/arch/sparc/Makefile @@ -0,0 +1,11 @@ +# When building a library, even intra-library references, +# such as from find_applet_by_name() to applet_names[], +# don't work with -fpic on sparc, needs -fPIC. +# Don't know why it fails in this case but works when +# a binary is being built. +# +# (if is superfluous, ARCH_FPIC is only used by library build, but it +# demonstrates the point: non-pic binary does not need it) +ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y) +ARCH_FPIC = -fPIC +endif diff --git a/busybox-1_37_0/arch/sparc64/Makefile b/busybox-1_37_0/arch/sparc64/Makefile new file mode 100644 index 000000000..0b1c56cb5 --- /dev/null +++ b/busybox-1_37_0/arch/sparc64/Makefile @@ -0,0 +1,11 @@ +# When building a library, even intra-library references, +# such as from find_applet_by_name() to applet_names[], +# don't work with -fpic on sparc, needs -fPIC. +# Don't know why it fails in this case but works when +# a binary is being built. +# +# (if is superfluous, ARCH_FPIC is only used by library build, but it +# demonstrates the point: non-pic binary does not need it) +ifeq ($(CONFIG_BUILD_LIBBUSYBOX),y) +ARCH_FPIC = -fPIC +endif diff --git a/busybox-1_37_0/arch/x86_64/Makefile b/busybox-1_37_0/arch/x86_64/Makefile new file mode 100644 index 000000000..16576fb81 --- /dev/null +++ b/busybox-1_37_0/arch/x86_64/Makefile @@ -0,0 +1,11 @@ +# ========================================================================== +# Build system +# ========================================================================== + +# "Control how GCC aligns variables. +# Supported values for type are compat uses increased alignment value +# compatible uses GCC 4.8 and earlier, abi uses alignment value as specified by the psABI, +# and cacheline uses increased alignment value to match the cache line size. +# compat is the default." +# "abi" seems to be somewhat successful in preventing oversealous data alignment. +CFLAGS += $(call cc-option,-malign-data=abi,) diff --git a/busybox-1_37_0/archival/Config.src b/busybox-1_37_0/archival/Config.src new file mode 100644 index 000000000..6f4f30c43 --- /dev/null +++ b/busybox-1_37_0/archival/Config.src @@ -0,0 +1,38 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Archival Utilities" + +config FEATURE_SEAMLESS_XZ + bool "Make tar, rpm, modprobe etc understand .xz data" + default y + +config FEATURE_SEAMLESS_LZMA + bool "Make tar, rpm, modprobe etc understand .lzma data" + default y + +config FEATURE_SEAMLESS_BZ2 + bool "Make tar, rpm, modprobe etc understand .bz2 data" + default y + +config FEATURE_SEAMLESS_GZ + bool "Make tar, rpm, modprobe etc understand .gz data" + default y + +config FEATURE_SEAMLESS_Z + bool "Make tar, rpm, modprobe etc understand .Z data" + default n # it is ancient + +INSERT + +config FEATURE_LZMA_FAST + bool "Optimize lzma for speed" + default n + depends on UNLZMA || LZCAT || LZMA || FEATURE_SEAMLESS_LZMA + help + This option reduces decompression time by about 25% at the cost of + a 1K bigger binary. + +endmenu diff --git a/busybox-1_37_0/archival/Kbuild.src b/busybox-1_37_0/archival/Kbuild.src new file mode 100644 index 000000000..b3a7d538f --- /dev/null +++ b/busybox-1_37_0/archival/Kbuild.src @@ -0,0 +1,11 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +libs-y += libarchive/ + +lib-y:= + +INSERT diff --git a/busybox-1_37_0/archival/ar.c b/busybox-1_37_0/archival/ar.c new file mode 100644 index 000000000..320cbae72 --- /dev/null +++ b/busybox-1_37_0/archival/ar.c @@ -0,0 +1,301 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini ar implementation for busybox + * + * Copyright (C) 2000 by Glenn McGrath + * + * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Archive creation support: + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Written by Alexander Shishkin. + * + * There is no single standard to adhere to so ar may not portable + * between different systems + * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html + */ +//config:config AR +//config: bool "ar (9.5 kb)" +//config: default n # needs to be improved to be able to replace binutils ar +//config: help +//config: ar is an archival utility program used to create, modify, and +//config: extract contents from archives. In practice, it is used exclusively +//config: for object module archives used by compilers. +//config: +//config: Unless you have a specific application which requires ar, you should +//config: probably say N here: most compilers come with their own ar utility. +//config: +//config:config FEATURE_AR_LONG_FILENAMES +//config: bool "Support long filenames (not needed for debs)" +//config: default y +//config: depends on AR +//config: help +//config: By default the ar format can only store the first 15 characters +//config: of the filename, this option removes that limitation. +//config: It supports the GNU ar long filename method which moves multiple long +//config: filenames into a the data section of a new ar entry. +//config: +//config:config FEATURE_AR_CREATE +//config: bool "Support archive creation" +//config: default y +//config: depends on AR +//config: help +//config: This enables archive creation (-c and -r) with busybox ar. + +//applet:IF_AR(APPLET(ar, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_AR) += ar.o + +#include "libbb.h" +#include "bb_archive.h" +#include "ar_.h" + +#if ENABLE_FEATURE_AR_CREATE +/* filter out entries with same names as specified on the command line */ +static char FAST_FUNC filter_replaceable(archive_handle_t *handle) +{ + if (find_list_entry(handle->accept, handle->file_header->name)) + return EXIT_FAILURE; + + return EXIT_SUCCESS; +} + +static void output_ar_header(archive_handle_t *handle) +{ + /* GNU ar 2.19.51.0.14 creates malformed archives + * if input files are >10G. It also truncates files >4GB + * (uses "size mod 4G"). We abort in this case: + * We could add support for up to 10G files, but this is unlikely to be useful. + * Note that unpacking side limits all fields to "unsigned int" data type, + * and treats "all ones" as an error indicator. Thus max we allow here is UINT_MAX-1. + */ + enum { + /* for 2nd field: mtime */ + MAX11CHARS = UINT_MAX > 0xffffffff ? (unsigned)99999999999 : UINT_MAX-1, + /* for last field: filesize */ + MAX10CHARS = UINT_MAX > 0xffffffff ? (unsigned)9999999999 : UINT_MAX-1, + }; + + struct file_header_t *fh = handle->file_header; + + if (handle->offset & 1) { + xwrite(handle->src_fd, "\n", 1); + handle->offset++; + } + + /* Careful! The widths should be exact. Fields must be separated */ + if (sizeof(off_t) > 4 && fh->size > (off_t)MAX10CHARS) { + bb_error_msg_and_die("'%s' is bigger than ar can handle", fh->name); + } + fdprintf(handle->src_fd, "%-16.16s%-12lu%-6u%-6u%-8o%-10"OFF_FMT"u`\n", + fh->name, + (sizeof(time_t) > 4 && fh->mtime > MAX11CHARS) ? (long)0 : (long)fh->mtime, + fh->uid > 99999 ? 0 : (int)fh->uid, + fh->gid > 99999 ? 0 : (int)fh->gid, + (int)fh->mode & 07777777, + fh->size + ); + + handle->offset += AR_HEADER_LEN; +} + +/* + * when replacing files in an existing archive, copy from the + * original archive those files that are to be left intact + */ +static void FAST_FUNC copy_data(archive_handle_t *handle) +{ + archive_handle_t *out_handle = handle->ar__out; + struct file_header_t *fh = handle->file_header; + + out_handle->file_header = fh; + output_ar_header(out_handle); + + bb_copyfd_exact_size(handle->src_fd, out_handle->src_fd, fh->size); + out_handle->offset += fh->size; +} + +static int write_ar_header(archive_handle_t *handle) +{ + char *fn; + char fn_h[17]; /* 15 + "/" + NUL */ + struct stat st; + int fd; + + fn = llist_pop(&handle->accept); + if (!fn) + return -1; + + xstat(fn, &st); + + handle->file_header->mtime = st.st_mtime; + handle->file_header->uid = st.st_uid; + handle->file_header->gid = st.st_gid; + handle->file_header->mode = st.st_mode; + handle->file_header->size = st.st_size; + handle->file_header->name = fn_h; +//TODO: if ENABLE_FEATURE_AR_LONG_FILENAMES... + sprintf(fn_h, "%.15s/", bb_basename(fn)); + + output_ar_header(handle); + + fd = xopen(fn, O_RDONLY); + bb_copyfd_exact_size(fd, handle->src_fd, st.st_size); + close(fd); + handle->offset += st.st_size; + + return 0; +} + +static int write_ar_archive(archive_handle_t *handle) +{ + struct stat st; + archive_handle_t *out_handle; + + xfstat(handle->src_fd, &st, handle->ar__name); + + /* if archive exists, create a new handle for output. + * we create it in place of the old one. + */ + if (st.st_size != 0) { + out_handle = init_handle(); + xunlink(handle->ar__name); + out_handle->src_fd = xopen(handle->ar__name, O_WRONLY | O_CREAT | O_TRUNC); + out_handle->accept = handle->accept; + } else { + out_handle = handle; + } + + handle->ar__out = out_handle; + + xwrite(out_handle->src_fd, AR_MAGIC "\n", AR_MAGIC_LEN + 1); + out_handle->offset += AR_MAGIC_LEN + 1; + + /* skip to the end of the archive if we have to append stuff */ + if (st.st_size != 0) { + handle->filter = filter_replaceable; + handle->action_data = copy_data; + unpack_ar_archive(handle); + } + + while (write_ar_header(out_handle) == 0) + continue; + + /* optional, since we exit right after we return */ + if (ENABLE_FEATURE_CLEAN_UP) { + close(handle->src_fd); + if (out_handle->src_fd != handle->src_fd) + close(out_handle->src_fd); + } + + return EXIT_SUCCESS; +} +#endif /* FEATURE_AR_CREATE */ + +static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header) +{ + char mode[12]; + char *mtime; + + bb_mode_string(mode, file_header->mode); + mtime = ctime(&file_header->mtime); + mtime[16] = ' '; + memmove(&mtime[17], &mtime[20], 4); + mtime[21] = '\0'; + printf("%s %u/%u%7"OFF_FMT"u %s %s\n", &mode[1], + (int)file_header->uid, (int)file_header->gid, + file_header->size, + &mtime[4], file_header->name + ); +} + +//usage:#define ar_trivial_usage +//usage: "x|p|t"IF_FEATURE_AR_CREATE("|r")" [-ov] ARCHIVE [FILE]..." +//usage:#define ar_full_usage "\n\n" +//usage: "Extract or list FILEs from an ar archive"IF_FEATURE_AR_CREATE(", or create it")"\n" +//usage: "\n x Extract" +//usage: "\n p Extract to stdout" +//usage: "\n t List" +//usage: IF_FEATURE_AR_CREATE( +//usage: "\n r Create" +//usage: ) +//usage: "\n -o Restore mtime" +//usage: "\n -v Verbose" + +int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ar_main(int argc UNUSED_PARAM, char **argv) +{ + archive_handle_t *archive_handle; + unsigned opt, t; + enum { + OPT_VERBOSE = (1 << 0), + OPT_PRESERVE_DATE = (1 << 1), + /* "ar r" implies create, but warns about it. c suppresses warning. + * bbox accepts but ignores it: */ + OPT_CREATE = (1 << 2), + CMD_PRINT = (1 << 3), + FIRST_CMD = CMD_PRINT, + CMD_LIST = (1 << 4), + CMD_EXTRACT = (1 << 5), + CMD_INSERT = ((1 << 6) * ENABLE_FEATURE_AR_CREATE), + }; + + archive_handle = init_handle(); + + /* prepend '-' to the first argument if required */ + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') + argv[1] = xasprintf("-%s", argv[1]); + opt = getopt32(argv, "^" + "voc""ptx"IF_FEATURE_AR_CREATE("r") + "\0" + /* -1: at least one arg is reqd */ + /* one of p,t,x[,r] is required */ + "-1:p:t:x"IF_FEATURE_AR_CREATE(":r") + ); + argv += optind; + + t = opt / FIRST_CMD; + if (t & (t-1)) /* more than one of p,t,x[,r] are specified */ + bb_show_usage(); + + if (opt & CMD_PRINT) { + archive_handle->action_data = data_extract_to_stdout; + } + if (opt & CMD_LIST) { + archive_handle->action_header = header_list; + } + if (opt & CMD_EXTRACT) { + archive_handle->action_data = data_extract_all; + } + if (opt & OPT_PRESERVE_DATE) { + archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; + } + if (opt & OPT_VERBOSE) { + archive_handle->action_header = header_verbose_list_ar; + } +#if ENABLE_FEATURE_AR_CREATE + archive_handle->ar__name = *argv; +#endif + archive_handle->src_fd = xopen(*argv++, + (opt & CMD_INSERT) + ? O_RDWR | O_CREAT + : O_RDONLY + ); + + if (*argv) + archive_handle->filter = filter_accept_list; + while (*argv) { + llist_add_to_end(&archive_handle->accept, *argv++); + } + +#if ENABLE_FEATURE_AR_CREATE + if (opt & CMD_INSERT) + return write_ar_archive(archive_handle); +#endif + + unpack_ar_archive(archive_handle); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/bbunzip.c b/busybox-1_37_0/archival/bbunzip.c new file mode 100644 index 000000000..b7944a62a --- /dev/null +++ b/busybox-1_37_0/archival/bbunzip.c @@ -0,0 +1,603 @@ +/* vi: set sw=4 ts=4: */ +/* + * Common code for gunzip-like applets + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//kbuild:lib-$(CONFIG_ZCAT) += bbunzip.o +//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o +//kbuild:lib-$(CONFIG_BZCAT) += bbunzip.o +//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o + +/* lzop_main() uses bbunpack(), need this: */ +//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o +//kbuild:lib-$(CONFIG_LZOPCAT) += bbunzip.o +//kbuild:lib-$(CONFIG_UNLZOP) += bbunzip.o +/* bzip2_main() too: */ +//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o +/* gzip_main() too: */ +//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o + +#include "libbb.h" +#include "bb_archive.h" + +static +int open_to_or_warn(int to_fd, const char *filename, int flags, int mode) +{ + int fd = open3_or_warn(filename, flags, mode); + if (fd < 0) { + return 1; + } + xmove_fd(fd, to_fd); + return 0; +} + +char* FAST_FUNC append_ext(char *filename, const char *expected_ext) +{ + return xasprintf("%s.%s", filename, expected_ext); +} + +int FAST_FUNC bbunpack(char **argv, + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_state_t *xstate), + char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), + const char *expected_ext +) +{ + struct stat stat_buf; + IF_DESKTOP(long long) int status = 0; + char *filename, *new_name; + smallint exitcode = 0; + transformer_state_t xstate; + + do { + /* NB: new_name is *maybe* malloc'ed! */ + new_name = NULL; + filename = *argv; /* can be NULL - 'streaming' bunzip2 */ + + if (filename && LONE_DASH(filename)) + filename = NULL; + + /* Open src */ + if (filename) { + if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) { + if (stat(filename, &stat_buf) != 0) { + err_name: + bb_simple_perror_msg(filename); + err: + exitcode = 1; + goto free_name; + } + if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) + goto err; + } else { + /* "clever zcat" with FILE */ + /* fail_if_not_compressed because zcat refuses uncompressed input */ + int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1); + if (fd < 0) + goto err_name; + xmove_fd(fd, STDIN_FILENO); + } + } else + if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { + /* "clever zcat" on stdin */ + if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) + goto err; + } + + /* Special cases: test, stdout */ + if (option_mask32 & (BBUNPK_OPT_STDOUT|BBUNPK_OPT_TEST)) { + if (option_mask32 & BBUNPK_OPT_TEST) + if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) + xfunc_die(); + filename = NULL; + } + + /* Open dst if we are going to unpack to file */ + if (filename) { + new_name = make_new_name(filename, expected_ext); + if (!new_name) { + bb_error_msg("%s: unknown suffix - ignored", filename); + goto err; + } + + /* -f: overwrite existing output files */ + if (option_mask32 & BBUNPK_OPT_FORCE) { + unlink(new_name); + } + + /* O_EXCL: "real" bunzip2 doesn't overwrite files */ + /* GNU gunzip does not bail out, but goes to next file */ + if (open_to_or_warn(STDOUT_FILENO, new_name, O_WRONLY | O_CREAT | O_EXCL, + stat_buf.st_mode)) + goto err; + } + + /* Check that the input is sane */ + if (!(option_mask32 & BBUNPK_OPT_FORCE) && isatty(STDIN_FILENO)) { + bb_simple_error_msg_and_die("compressed data not read from terminal, " + "use -f to force it"); + } + + if (!(option_mask32 & BBUNPK_SEAMLESS_MAGIC)) { + init_transformer_state(&xstate); + /*xstate.signature_skipped = 0; - already is */ + /*xstate.src_fd = STDIN_FILENO; - already is */ + xstate.dst_fd = STDOUT_FILENO; + status = unpacker(&xstate); + if (status < 0) + exitcode = 1; + } else { + if (bb_copyfd_eof(STDIN_FILENO, STDOUT_FILENO) < 0) + /* Disk full, tty closed, etc. No point in continuing */ + xfunc_die(); + } + + if (!(option_mask32 & BBUNPK_OPT_STDOUT)) + xclose(STDOUT_FILENO); /* with error check! */ + + if (filename) { + char *del = new_name; + + if (status >= 0) { + unsigned new_name_len; + + /* TODO: restore other things? */ + if (xstate.mtime != 0) { + struct timeval times[2]; + + times[1].tv_sec = times[0].tv_sec = xstate.mtime; + times[1].tv_usec = times[0].tv_usec = 0; + /* Note: we closed it first. + * On some systems calling utimes + * then closing resets the mtime + * back to current time. */ + utimes(new_name, times); /* ignoring errors */ + } + + if (ENABLE_DESKTOP) + new_name_len = strlen(new_name); + /* Restore source filename (unless tgz -> tar case) */ + if (new_name == filename) { + new_name_len = strlen(filename); + filename[new_name_len] = '.'; + } + /* Extreme bloat for gunzip compat */ + /* Some users do want this info... */ + if (ENABLE_DESKTOP && (option_mask32 & BBUNPK_OPT_VERBOSE)) { + unsigned percent = status + ? ((uoff_t)stat_buf.st_size * 100u / (unsigned long long)status) + : 0; + fprintf(stderr, "%s: %u%% - replaced with %.*s\n", + filename, + 100u - percent, + new_name_len, new_name + ); + } + /* Delete _source_ file */ + del = filename; + if (option_mask32 & BBUNPK_OPT_KEEP) /* ... unless -k */ + del = NULL; + } + if (del) + xunlink(del); + free_name: + if (new_name != filename) + free(new_name); + } + } while (*argv && *++argv); + + if (option_mask32 & BBUNPK_OPT_STDOUT) + xclose(STDOUT_FILENO); /* with error check! */ + + return exitcode; +} + +#if ENABLE_UNCOMPRESS \ + || ENABLE_FEATURE_BZIP2_DECOMPRESS \ + || ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA \ + || ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ +static +char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) +{ + char *extension = strrchr(filename, '.'); + if (!extension || strcmp(extension + 1, expected_ext) != 0) { + /* Mimic GNU gunzip - "real" bunzip2 tries to */ + /* unpack file anyway, to file.out */ + return NULL; + } + *extension = '\0'; + return filename; +} +#endif + + +/* + * Uncompress applet for busybox (c) 2002 Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//usage:#define uncompress_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define uncompress_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Overwrite" + +//config:config UNCOMPRESS +//config: bool "uncompress (7.1 kb)" +//config: default n # ancient +//config: help +//config: uncompress is used to decompress archives created by compress. +//config: Not much used anymore, replaced by gzip/gunzip. + +//applet:IF_UNCOMPRESS(APPLET(uncompress, BB_DIR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_UNCOMPRESS) += bbunzip.o +#if ENABLE_UNCOMPRESS +int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uncompress_main(int argc UNUSED_PARAM, char **argv) +{ +// (N)compress 4.2.4.4: +// -d If given, decompression is done instead +// -c Write output on stdout, don't remove original +// -b Parameter limits the max number of bits/code +// -f Forces output file to be generated +// -v Write compression statistics +// -V Output vesion and compile options +// -r Recursive. If a filename is a directory, descend into it and compress everything + getopt32(argv, "cf"); + + argv += optind; + + return bbunpack(argv, unpack_Z_stream, make_new_name_generic, "Z"); +} +#endif + + +/* + * 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 + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * 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. + */ +//usage:#define gunzip_trivial_usage +//usage: "[-cfkt] [FILE]..." +//usage:#define gunzip_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define gunzip_example_usage +//usage: "$ ls -la /tmp/BusyBox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" +//usage: "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" +//usage: "$ ls -la /tmp/BusyBox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" +//usage: +//usage:#define zcat_trivial_usage +//usage: "[FILE]..." +//usage:#define zcat_full_usage "\n\n" +//usage: "Decompress to stdout" + +//config:config GUNZIP +//config: bool "gunzip (11 kb)" +//config: default y +//config: select FEATURE_GZIP_DECOMPRESS +//config: help +//config: gunzip is used to decompress archives created by gzip. +//config: You can use the '-t' option to test the integrity of +//config: an archive, without decompressing it. +//config: +//config:config ZCAT +//config: bool "zcat (24 kb)" +//config: default y +//config: select FEATURE_GZIP_DECOMPRESS +//config: help +//config: Alias to "gunzip -c". +//config: +//config:config FEATURE_GUNZIP_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on (GUNZIP || ZCAT) && LONG_OPTS + +//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_ZCAT(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat)) +#if ENABLE_FEATURE_GZIP_DECOMPRESS +static +char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) +{ + char *extension = strrchr(filename, '.'); + + if (!extension) + return NULL; + + extension++; + if (strcmp(extension, "tgz" + 1) == 0 +#if ENABLE_FEATURE_SEAMLESS_Z + || (extension[0] == 'Z' && extension[1] == '\0') +#endif + ) { + extension[-1] = '\0'; + } else if (strcmp(extension, "tgz") == 0) { + filename = xstrdup(filename); + extension = strrchr(filename, '.'); + extension[2] = 'a'; + extension[3] = 'r'; + } else { + return NULL; + } + return filename; +} + +#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS +static const char gunzip_longopts[] ALIGN1 = + "stdout\0" No_argument "c" + "to-stdout\0" No_argument "c" + "force\0" No_argument "f" + "test\0" No_argument "t" + "no-name\0" No_argument "n" + ; +#endif + +/* + * Linux kernel build uses gzip -d -n. We accept and ignore it. + * Man page says: + * -n --no-name + * gzip: do not save the original file name and time stamp. + * (The original name is always saved if the name had to be truncated.) + * gunzip: do not restore the original file name/time even if present + * (remove only the gzip suffix from the compressed file name). + * This option is the default when decompressing. + * -N --name + * gzip: always save the original file name and time stamp (this is the default) + * gunzip: restore the original file name and time stamp if present. + */ +int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int gunzip_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_FEATURE_GUNZIP_LONG_OPTIONS + getopt32long(argv, BBUNPK_OPTSTR "dtn", gunzip_longopts); +#else + getopt32(argv, BBUNPK_OPTSTR "dtn"); +#endif + argv += optind; + + /* If called as zcat... + * Normally, "zcat" is just "gunzip -c". + * But if seamless magic is enabled, then we are much more clever. + */ + if (ENABLE_ZCAT && applet_name[1] == 'c') + option_mask32 |= BBUNPK_OPT_STDOUT | BBUNPK_SEAMLESS_MAGIC; + + return bbunpack(argv, unpack_gz_stream, make_new_name_gunzip, /*unused:*/ NULL); +} +#endif /* FEATURE_GZIP_DECOMPRESS */ + + +/* + * Modified for busybox by Glenn McGrath + * Added support output to stdout by Thomas Lundquist + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//usage:#define bunzip2_trivial_usage +//usage: "[-cfk] [FILE]..." +//usage:#define bunzip2_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define bzcat_trivial_usage +//usage: "[FILE]..." +//usage:#define bzcat_full_usage "\n\n" +//usage: "Decompress to stdout" + +//config:config BUNZIP2 +//config: bool "bunzip2 (9.1 kb)" +//config: default y +//config: select FEATURE_BZIP2_DECOMPRESS +//config: help +//config: bunzip2 is a compression utility using the Burrows-Wheeler block +//config: sorting text compression algorithm, and Huffman coding. Compression +//config: is generally considerably better than that achieved by more +//config: conventional LZ77/LZ78-based compressors, and approaches the +//config: performance of the PPM family of statistical compressors. +//config: +//config: Unless you have a specific application which requires bunzip2, you +//config: should probably say N here. +//config: +//config:config BZCAT +//config: bool "bzcat (9 kb)" +//config: default y +//config: select FEATURE_BZIP2_DECOMPRESS +//config: help +//config: Alias to "bunzip2 -c". + +//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_BZCAT(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) +#if ENABLE_FEATURE_BZIP2_DECOMPRESS || ENABLE_BUNZIP2 || ENABLE_BZCAT +int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int bunzip2_main(int argc UNUSED_PARAM, char **argv) +{ + getopt32(argv, BBUNPK_OPTSTR "dt"); + argv += optind; + if (ENABLE_BZCAT && (!ENABLE_BUNZIP2 || applet_name[2] == 'c')) /* bzcat */ + option_mask32 |= BBUNPK_OPT_STDOUT; + + return bbunpack(argv, unpack_bz2_stream, make_new_name_generic, "bz2"); +} +#endif + + +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs + * + * Based on bunzip.c from busybox + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//usage:#define unlzma_trivial_usage +//usage: "[-cfk] [FILE]..." +//usage:#define unlzma_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define lzma_trivial_usage +//usage: "-d [-cfk] [FILE]..." +//usage:#define lzma_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define lzcat_trivial_usage +//usage: "[FILE]..." +//usage:#define lzcat_full_usage "\n\n" +//usage: "Decompress to stdout" + +//config:config UNLZMA +//config: bool "unlzma (7.8 kb)" +//config: default y +//config: help +//config: unlzma is a compression utility using the Lempel-Ziv-Markov chain +//config: compression algorithm, and range coding. Compression +//config: is generally considerably better than that achieved by the bzip2 +//config: compressors. +//config: +//config:config LZCAT +//config: bool "lzcat (7.8 kb)" +//config: default y +//config: help +//config: Alias to "unlzma -c". +//config: +//config:config LZMA +//config: bool "lzma -d" +//config: default y +//config: help +//config: Enable this option if you want commands like "lzma -d" to work. +//config: IOW: you'll get lzma applet, but it will always require -d option. + +//applet:IF_UNLZMA(APPLET(unlzma, BB_DIR_USR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_LZCAT(APPLET_ODDNAME(lzcat, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzcat)) +//applet:IF_LZMA( APPLET_ODDNAME(lzma, unlzma, BB_DIR_USR_BIN, BB_SUID_DROP, lzma)) +//kbuild:lib-$(CONFIG_UNLZMA) += bbunzip.o +//kbuild:lib-$(CONFIG_LZCAT) += bbunzip.o +//kbuild:lib-$(CONFIG_LZMA) += bbunzip.o +#if ENABLE_UNLZMA || ENABLE_LZCAT || ENABLE_LZMA +int unlzma_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unlzma_main(int argc UNUSED_PARAM, char **argv) +{ + IF_LZMA(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt"); +# if ENABLE_LZMA + /* lzma without -d or -t? */ + if (applet_name[2] == 'm' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST))) + bb_show_usage(); +# endif + /* lzcat? */ + if (ENABLE_LZCAT && applet_name[2] == 'c') + option_mask32 |= BBUNPK_OPT_STDOUT; + + argv += optind; + return bbunpack(argv, unpack_lzma_stream, make_new_name_generic, "lzma"); +} +#endif + + +//usage:#define unxz_trivial_usage +//usage: "[-cfk] [FILE]..." +//usage:#define unxz_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define xz_trivial_usage +//usage: "-d [-cfk] [FILE]..." +//usage:#define xz_full_usage "\n\n" +//usage: "Decompress FILEs (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: "\n -t Test integrity" +//usage: +//usage:#define xzcat_trivial_usage +//usage: "[FILE]..." +//usage:#define xzcat_full_usage "\n\n" +//usage: "Decompress to stdout" + +//config:config UNXZ +//config: bool "unxz (13 kb)" +//config: default y +//config: help +//config: unxz is a unlzma successor. +//config: +//config:config XZCAT +//config: bool "xzcat (13 kb)" +//config: default y +//config: help +//config: Alias to "unxz -c". +//config: +//config:config XZ +//config: bool "xz -d" +//config: default y +//config: help +//config: Enable this option if you want commands like "xz -d" to work. +//config: IOW: you'll get xz applet, but it will always require -d option. + +//applet:IF_UNXZ(APPLET(unxz, BB_DIR_USR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_XZCAT(APPLET_ODDNAME(xzcat, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xzcat)) +//applet:IF_XZ( APPLET_ODDNAME(xz, unxz, BB_DIR_USR_BIN, BB_SUID_DROP, xz)) +//kbuild:lib-$(CONFIG_UNXZ) += bbunzip.o +//kbuild:lib-$(CONFIG_XZCAT) += bbunzip.o +//kbuild:lib-$(CONFIG_XZ) += bbunzip.o +#if ENABLE_UNXZ || ENABLE_XZCAT || ENABLE_XZ +int unxz_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unxz_main(int argc UNUSED_PARAM, char **argv) +{ + IF_XZ(int opts =) getopt32(argv, BBUNPK_OPTSTR "dt"); +# if ENABLE_XZ + /* xz without -d or -t? */ + if (applet_name[2] == '\0' && !(opts & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST))) + bb_show_usage(); +# endif + /* xzcat? */ + if (ENABLE_XZCAT && applet_name[2] == 'c') + option_mask32 |= BBUNPK_OPT_STDOUT; + + argv += optind; + return bbunpack(argv, unpack_xz_stream, make_new_name_generic, "xz"); +} +#endif diff --git a/busybox-1_37_0/archival/bbunzip_test.sh b/busybox-1_37_0/archival/bbunzip_test.sh new file mode 100644 index 000000000..b8e31bf97 --- /dev/null +++ b/busybox-1_37_0/archival/bbunzip_test.sh @@ -0,0 +1,61 @@ +#!/bin/sh +# Test that concatenated gz files are unpacking correctly. +# It also tests that unpacking in general is working right. +# Since zip code has many corner cases, run it for a few hours +# to get a decent coverage (200000 tests or more). + +gzip="gzip" +gunzip="../busybox gunzip" +# Or the other way around: +#gzip="../busybox gzip" +#gunzip="gunzip" + +c=0 +i=$PID +while true; do + c=$((c+1)) + + # RANDOM is not very random on some shells. Spice it up. + # 100003 is prime + len1=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 )) + i=$((i * 1664525 + 1013904223)) + len2=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 )) + + # Just using urandom will make gzip use method 0 (store) - + # not good for test coverage! + cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \ + | dd bs=$len1 count=1 >z1 2>/dev/null + cat /dev/urandom | while true; do read junk; echo "junk $c $i $junk"; done \ + | dd bs=$len2 count=1 >z2 2>/dev/null + + $gzip zz.gz + $gzip >zz.gz + $gunzip -c zz.gz >z9 || { + echo "Exitcode $?" + exit + } + sum=`cat z1 z2 | md5sum` + sum9=`md5sum /dev/null + $gzip z1 + $gzip z2 + cat z1.gz z2.gz z1.gz z2.gz >zz.gz + $gunzip -c zz.gz >z9 || { + echo "Exitcode $? (2)" + exit + } + sum9=`md5sum /dev/null diff --git a/busybox-1_37_0/archival/bbunzip_test3.sh b/busybox-1_37_0/archival/bbunzip_test3.sh new file mode 100644 index 000000000..2dc4afda1 --- /dev/null +++ b/busybox-1_37_0/archival/bbunzip_test3.sh @@ -0,0 +1,23 @@ +#!/bin/sh +# Leak test for gunzip. Watch top for growing process size. +# In this case we look for leaks in "concatenated .gz" code - +# we feed gunzip with a stream of .gz files. + +i=$PID +c=0 +while true; do + c=$((c + 1)) + echo "Block# $c" >&2 + # RANDOM is not very random on some shells. Spice it up. + i=$((i * 1664525 + 1013904223)) + # 100003 is prime + len=$(( (((RANDOM*RANDOM)^i) & 0x7ffffff) % 100003 )) + + # Just using urandom will make gzip use method 0 (store) - + # not good for test coverage! + cat /dev/urandom \ + | while true; do read junk; echo "junk $c $i $junk"; done \ + | dd bs=$len count=1 2>/dev/null \ + | gzip >xxx.gz + cat xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz xxx.gz +done | ../busybox gunzip -c >/dev/null diff --git a/busybox-1_37_0/archival/bzip2.c b/busybox-1_37_0/archival/bzip2.c new file mode 100644 index 000000000..bce13cf93 --- /dev/null +++ b/busybox-1_37_0/archival/bzip2.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2007 Denys Vlasenko + * + * This file uses bzip2 library code which is written + * by Julian Seward . + * See README and LICENSE files in bz/ directory for more information + * about bzip2 library code. + */ +//config:config BZIP2 +//config: bool "bzip2 (16 kb)" +//config: default y +//config: help +//config: bzip2 is a compression utility using the Burrows-Wheeler block +//config: sorting text compression algorithm, and Huffman coding. Compression +//config: is generally considerably better than that achieved by more +//config: conventional LZ77/LZ78-based compressors, and approaches the +//config: performance of the PPM family of statistical compressors. +//config: +//config: Unless you have a specific application which requires bzip2, you +//config: should probably say N here. +//config: +//config:config BZIP2_SMALL +//config: int "Trade bytes for speed (0:fast, 9:small)" +//config: default 8 # all "fast or small" options default to small +//config: range 0 9 +//config: depends on BZIP2 +//config: help +//config: Trade code size versus speed. +//config: Approximate values with gcc-6.3.0 "bzip -9" compressing +//config: linux-4.15.tar were: +//config: value time (sec) code size (386) +//config: 9 (smallest) 70.11 7687 +//config: 8 67.93 8091 +//config: 7 67.88 8405 +//config: 6 67.78 8624 +//config: 5 67.05 9427 +//config: 4-0 (fastest) 64.14 12083 +//config: +//config:config FEATURE_BZIP2_DECOMPRESS +//config: bool "Enable decompression" +//config: default y +//config: depends on BZIP2 || BUNZIP2 || BZCAT +//config: help +//config: Enable -d (--decompress) and -t (--test) options for bzip2. +//config: This will be automatically selected if bunzip2 or bzcat is +//config: enabled. + +//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o + +//usage:#define bzip2_trivial_usage +//usage: "[-cfk" IF_FEATURE_BZIP2_DECOMPRESS("dt") "123456789] [FILE]..." +//usage:#define bzip2_full_usage "\n\n" +//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n" +//usage: "\n -1..9 Compression level" +//usage: IF_FEATURE_BZIP2_DECOMPRESS( +//usage: "\n -d Decompress" +//usage: ) +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: IF_FEATURE_BZIP2_DECOMPRESS( +//usage: "\n -t Test integrity" +//usage: ) + +#include "libbb.h" +#include "bb_archive.h" + +#if CONFIG_BZIP2_SMALL >= 4 +#define BZIP2_SPEED (9 - CONFIG_BZIP2_SMALL) +#else +#define BZIP2_SPEED 5 +#endif + +/* Speed test: + * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache). + * Stock bzip2 is 26.4% slower than bbox bzip2 at SPEED 1 + * (time to compress gcc-4.2.1.tar is 126.4% compared to bbox). + * At SPEED 5 difference is 32.7%. + * + * Test run of all BZIP2_SPEED values on a 11Mb text file: + * Size Time (3 runs) + * 0: 10828 4.145 4.146 4.148 + * 1: 11097 3.845 3.860 3.861 + * 2: 11392 3.763 3.767 3.768 + * 3: 11892 3.722 3.724 3.727 + * 4: 12740 3.637 3.640 3.644 + * 5: 17273 3.497 3.509 3.509 + */ + + +#define BZ_DEBUG 0 +/* Takes ~300 bytes, detects corruption caused by bad RAM etc */ +#define BZ_LIGHT_DEBUG 0 + +#include "libarchive/bz/bzlib.h" + +#include "libarchive/bz/bzlib_private.h" + +#include "libarchive/bz/blocksort.c" +#include "libarchive/bz/bzlib.c" +#include "libarchive/bz/compress.c" +#include "libarchive/bz/huffman.c" + +/* No point in being shy and having very small buffer here. + * bzip2 internal buffers are much bigger anyway, hundreds of kbytes. + * If iobuf is several pages long, malloc() may use mmap, + * making iobuf page aligned and thus (maybe) have one memcpy less + * if kernel is clever enough. + */ +enum { + IOBUF_SIZE = 8 * 1024 +}; + +/* NB: compressStream() has to return -1 on errors, not die. + * bbunpack() will correctly clean up in this case + * (delete incomplete .bz2 file) + */ + +/* Returns: + * -1 on errors + * total written bytes so far otherwise + */ +static +IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf) +{ + int n, n2, ret; + + strm->avail_in = rlen; + strm->next_in = rbuf; + while (1) { + strm->avail_out = IOBUF_SIZE; + strm->next_out = wbuf; + + ret = BZ2_bzCompress(strm, rlen ? BZ_RUN : BZ_FINISH); + if (ret != BZ_RUN_OK /* BZ_RUNning */ + && ret != BZ_FINISH_OK /* BZ_FINISHing, but not done yet */ + && ret != BZ_STREAM_END /* BZ_FINISHed */ + ) { + bb_error_msg_and_die("internal error %d", ret); + } + + n = IOBUF_SIZE - strm->avail_out; + if (n) { + n2 = full_write(STDOUT_FILENO, wbuf, n); + if (n2 != n) { + if (n2 >= 0) + errno = 0; /* prevent bogus error message */ + bb_simple_perror_msg(n2 >= 0 ? "short write" : bb_msg_write_error); + return -1; + } + } + + if (ret == BZ_STREAM_END) + break; + if (rlen && strm->avail_in == 0) + break; + } + return 0 IF_DESKTOP( + strm->total_out ); +} + +static +IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_state_t *xstate UNUSED_PARAM) +{ + IF_DESKTOP(long long) int total; + unsigned opt, level; + ssize_t count; + bz_stream bzs; /* it's small */ +#define strm (&bzs) + char *iobuf; +#define rbuf iobuf +#define wbuf (iobuf + IOBUF_SIZE) + + iobuf = xmalloc(2 * IOBUF_SIZE); + + opt = option_mask32 >> (BBUNPK_OPTSTRLEN IF_FEATURE_BZIP2_DECOMPRESS(+ 2) + 2); + /* skipped BBUNPK_OPTSTR, "dt" and "zs" bits */ + opt |= 0x100; /* if nothing else, assume -9 */ + level = 0; + for (;;) { + level++; + if (opt & 1) break; + opt >>= 1; + } + + BZ2_bzCompressInit(strm, level); + + while (1) { + count = full_read(STDIN_FILENO, rbuf, IOBUF_SIZE); + if (count < 0) { + bb_simple_perror_msg(bb_msg_read_error); + total = -1; + break; + } + /* if count == 0, bz_write finalizes compression */ + total = bz_write(strm, rbuf, count, wbuf); + if (count == 0 || total < 0) + break; + } + + /* Can't be conditional on ENABLE_FEATURE_CLEAN_UP - + * we are called repeatedly + */ + BZ2_bzCompressEnd(strm); + free(iobuf); + + return total; +} + +int bzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int bzip2_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opt; + + /* standard bzip2 flags + * -d --decompress force decompression + * -z --compress force compression + * -k --keep keep (don't delete) input files + * -f --force overwrite existing output files + * -t --test test compressed file integrity + * -c --stdout output to standard out + * -q --quiet suppress noncritical error messages + * -v --verbose be verbose (a 2nd -v gives more) + * -s --small use less memory (at most 2500k) + * -1 .. -9 set block size to 100k .. 900k + * --fast alias for -1 + * --best alias for -9 + */ + + opt = getopt32(argv, "^" + /* Must match BBUNPK_foo constants! */ + BBUNPK_OPTSTR IF_FEATURE_BZIP2_DECOMPRESS("dt") "zs123456789" + "\0" "s2" /* -s means -2 (compatibility) */ + ); +#if ENABLE_FEATURE_BZIP2_DECOMPRESS /* bunzip2_main may not be visible... */ + if (opt & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)) /* -d and/or -t */ + return bunzip2_main(argc, argv); +#else + /* clear "decompress" and "test" bits (or bbunpack() can get confused) */ + /* in !BZIP2_DECOMPRESS config, these bits are -zs and are unused */ + option_mask32 = opt & ~(BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST); +#endif + + argv += optind; + return bbunpack(argv, compressStream, append_ext, "bz2"); +} diff --git a/busybox-1_37_0/archival/chksum_and_xwrite_tar_header.c b/busybox-1_37_0/archival/chksum_and_xwrite_tar_header.c new file mode 100644 index 000000000..f2d46b9ef --- /dev/null +++ b/busybox-1_37_0/archival/chksum_and_xwrite_tar_header.c @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2021 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//kbuild:lib-$(CONFIG_FEATURE_TAR_CREATE) += chksum_and_xwrite_tar_header.o +//kbuild:lib-$(CONFIG_SMEMCAP) += chksum_and_xwrite_tar_header.o + +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC chksum_and_xwrite_tar_header(int fd, struct tar_header_t *hp) +{ + /* POSIX says that checksum is done on unsigned bytes + * (Sun and HP-UX gets it wrong... more details in + * GNU tar source) */ + const unsigned char *cp; + unsigned int chksum, size; + + strcpy(hp->magic, "ustar "); + + /* Calculate and store the checksum (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 NUL, then a space -- rather than + * digits, followed by a NUL like the other fields... */ + memset(hp->chksum, ' ', sizeof(hp->chksum)); + cp = (const unsigned char *) hp; + chksum = 0; + size = sizeof(*hp); + do { chksum += *cp++; } while (--size); + sprintf(hp->chksum, "%06o", chksum); + + xwrite(fd, hp, sizeof(*hp)); +} diff --git a/busybox-1_37_0/archival/cpio.c b/busybox-1_37_0/archival/cpio.c new file mode 100644 index 000000000..f0d990048 --- /dev/null +++ b/busybox-1_37_0/archival/cpio.c @@ -0,0 +1,581 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cpio implementation for busybox + * + * Copyright (C) 2001 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Limitations: + * Doesn't check CRC's + * Only supports new ASCII and CRC formats + */ +//config:config CPIO +//config: bool "cpio (15 kb)" +//config: default y +//config: help +//config: cpio is an archival utility program used to create, modify, and +//config: extract contents from archives. +//config: cpio has 110 bytes of overheads for every stored file. +//config: +//config: This implementation of cpio can extract cpio archives created in the +//config: "newc" or "crc" format. +//config: +//config: Unless you have a specific application which requires cpio, you +//config: should probably say N here. +//config: +//config:config FEATURE_CPIO_O +//config: bool "Support archive creation" +//config: default y +//config: depends on CPIO +//config: help +//config: This implementation of cpio can create cpio archives in the "newc" +//config: format only. +//config: +//config:config FEATURE_CPIO_P +//config: bool "Support passthrough mode" +//config: default y +//config: depends on FEATURE_CPIO_O +//config: help +//config: Passthrough mode. Rarely used. +//config: +//config:config FEATURE_CPIO_IGNORE_DEVNO +//config: bool "Support --ignore-devno like GNU cpio" +//config: default y +//config: depends on FEATURE_CPIO_O && LONG_OPTS +//config: help +//config: Optionally ignore device numbers when creating archives. +//config: +//config:config FEATURE_CPIO_RENUMBER_INODES +//config: bool "Support --renumber-inodes like GNU cpio" +//config: default y +//config: depends on FEATURE_CPIO_O && LONG_OPTS +//config: help +//config: Optionally renumber inodes when creating archives. + +//applet:IF_CPIO(APPLET(cpio, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CPIO) += cpio.o + +//usage:#define cpio_trivial_usage +//usage: "[-dmvu] [-F FILE] [-R USER[:GRP]]" IF_FEATURE_CPIO_O(" [-H newc]") +//usage: " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") +//usage: " [EXTR_FILE]..." +//usage:#define cpio_full_usage "\n\n" +//usage: "Extract (-i) or list (-t) files from a cpio archive on stdin" +//usage: IF_FEATURE_CPIO_O(", or" +//usage: "\ntake file list from stdin and create an archive (-o)" +//usage: IF_FEATURE_CPIO_P(" or copy files (-p)") +//usage: ) +//usage: "\n" +//usage: "\nMain operation mode:" +//usage: "\n -t List" +//usage: "\n -i Extract EXTR_FILEs (or all)" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -o Create (requires -H newc)" +//usage: ) +//usage: IF_FEATURE_CPIO_P( +//usage: "\n -p DIR Copy files to DIR" +//usage: ) +//usage: "\nOptions:" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -H newc Archive format" +//usage: ) +//usage: "\n -d Make leading directories" +//usage: "\n -m Restore mtime" +//usage: "\n -v Verbose" +//usage: "\n -u Overwrite" +//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" +//usage: "\n -R USER[:GRP] Set owner of created files" +//usage: "\n -L Dereference symlinks" +//usage: "\n -0 NUL terminated input" +//usage: IF_FEATURE_CPIO_IGNORE_DEVNO( +//usage: "\n --ignore-devno" +//usage: ) +//usage: IF_FEATURE_CPIO_RENUMBER_INODES( +//usage: "\n --renumber-inodes" +//usage: ) + +/* GNU cpio 2.9 --help (abridged): + + Modes: + -t, --list List the archive + -i, --extract Extract files from an archive + -o, --create Create the archive + -p, --pass-through Copy-pass mode + + Options valid in any mode: + --block-size=SIZE I/O block size = SIZE * 512 bytes + -B I/O block size = 5120 bytes + -c Use the old portable (ASCII) archive format + -C, --io-size=NUMBER I/O block size in bytes + -f, --nonmatching Only copy files that do not match given pattern + -F, --file=FILE Use FILE instead of standard input or output + -H, --format=FORMAT Use given archive FORMAT + -M, --message=STRING Print STRING when the end of a volume of the + backup media is reached + -n, --numeric-uid-gid If -v, show numeric UID and GID + --quiet Do not print the number of blocks copied + --rsh-command=COMMAND Use remote COMMAND instead of rsh + -v, --verbose Verbosely list the files processed + -V, --dot Print a "." for each file processed + -W, --warning=FLAG Control warning display: 'none','truncate','all'; + multiple options accumulate + + Options valid only in --extract mode: + -b, --swap Swap both halfwords of words and bytes of + halfwords in the data (equivalent to -sS) + -r, --rename Interactively rename files + -s, --swap-bytes Swap the bytes of each halfword in the files + -S, --swap-halfwords Swap the halfwords of each word (4 bytes) + --to-stdout Extract files to standard output + -E, --pattern-file=FILE Read additional patterns specifying filenames to + extract or list from FILE + --only-verify-crc Verify CRC's, don't actually extract the files + + Options valid only in --create mode: + -A, --append Append to an existing archive + -O FILE File to use instead of standard output + + Options valid only in --pass-through mode: + -l, --link Link files instead of copying them, when possible + + Options valid in --extract and --create modes: + --absolute-filenames Do not strip file system prefix components from + the file names + --no-absolute-filenames Create all files relative to the current dir + + Options valid in --create and --pass-through modes: + -0, --null A list of filenames is terminated by a NUL + -a, --reset-access-time Reset the access times of files after reading them + -I FILE File to use instead of standard input + -L, --dereference Dereference symbolic links (copy the files + that they point to instead of copying the links) + -R, --owner=[USER][:.][GRP] Set owner of created files + + Options valid in --extract and --pass-through modes: + -d, --make-directories Create leading directories where needed + -m, --preserve-modification-time Retain mtime when creating files + --no-preserve-owner Do not change the ownership of the files + --sparse Write files with blocks of zeros as sparse files + -u, --unconditional Replace all files unconditionally + */ + +#include "libbb.h" +#include "common_bufsiz.h" +#include "bb_archive.h" + +enum { + OPT_EXTRACT = (1 << 0), + OPT_TEST = (1 << 1), + OPT_NUL_TERMINATED = (1 << 2), + OPT_UNCONDITIONAL = (1 << 3), + OPT_VERBOSE = (1 << 4), + OPT_CREATE_LEADING_DIR = (1 << 5), + OPT_PRESERVE_MTIME = (1 << 6), + OPT_DEREF = (1 << 7), + OPT_FILE = (1 << 8), + OPT_OWNER = (1 << 9), + OPTBIT_OWNER = 9, + IF_FEATURE_CPIO_O(OPTBIT_CREATE ,) + IF_FEATURE_CPIO_O(OPTBIT_FORMAT ,) + IF_FEATURE_CPIO_P(OPTBIT_PASSTHROUGH,) + IF_LONG_OPTS( OPTBIT_QUIET ,) + IF_LONG_OPTS( OPTBIT_2STDOUT ,) + IF_FEATURE_CPIO_IGNORE_DEVNO(OPTBIT_IGNORE_DEVNO,) + IF_FEATURE_CPIO_RENUMBER_INODES(OPTBIT_RENUMBER_INODES,) + OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, + OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, + OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, + OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, + OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, + OPT_IGNORE_DEVNO = IF_FEATURE_CPIO_IGNORE_DEVNO((1 << OPTBIT_IGNORE_DEVNO)) + 0, + OPT_RENUMBER_INODES = IF_FEATURE_CPIO_RENUMBER_INODES((1 << OPTBIT_RENUMBER_INODES)) + 0, +}; + +#define OPTION_STR "it0uvdmLF:R:" + +struct globals { + struct bb_uidgid_t owner_ugid; + ino_t next_inode; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +void BUG_cpio_globals_too_big(void); +#define INIT_G() do { \ + setup_common_bufsiz(); \ + G.owner_ugid.uid = -1L; \ + G.owner_ugid.gid = -1L; \ +} while (0) + +#if ENABLE_FEATURE_CPIO_O +static off_t cpio_pad4(off_t size) +{ + int i; + + i = (- size) & 3; + size += i; + while (--i >= 0) + bb_putchar('\0'); + return size; +} + +/* Return value will become exit code. + * It's ok to exit instead of return. */ +static NOINLINE int cpio_o(void) +{ + struct name_s { + struct name_s *next; + char name[1]; + }; + struct inodes_s { + struct inodes_s *next; + struct name_s *names; + struct stat st; +#if ENABLE_FEATURE_CPIO_RENUMBER_INODES + ino_t mapped_inode; +#endif + }; + + struct inodes_s *links = NULL; + off_t bytes = 0; /* output bytes count */ + + while (1) { + const char *name; + char *line; + struct stat st; + + line = (option_mask32 & OPT_NUL_TERMINATED) + ? bb_get_chunk_from_file(stdin, NULL) + : xmalloc_fgetline(stdin); + + if (line) { + /* Strip leading "./[./]..." from the filename */ + name = line; + while (name[0] == '.' && name[1] == '/') { + while (*++name == '/') + continue; + } + if (!*name) { /* line is empty */ + free(line); + continue; + } + if ((option_mask32 & OPT_DEREF) + ? stat(name, &st) + : lstat(name, &st) + ) { + abort_cpio_o: + bb_simple_perror_msg_and_die(name); + } + + if (G.owner_ugid.uid != (uid_t)-1L) + st.st_uid = G.owner_ugid.uid; + if (G.owner_ugid.gid != (gid_t)-1L) + st.st_gid = G.owner_ugid.gid; + + if (!(S_ISLNK(st.st_mode) || S_ISREG(st.st_mode))) + st.st_size = 0; /* paranoia */ + + /* Store hardlinks for later processing, dont output them */ + if (!S_ISDIR(st.st_mode) && st.st_nlink > 1) { + struct name_s *n; + struct inodes_s *l; + + /* Do we have this hardlink remembered? */ + l = links; + while (1) { + if (l == NULL) { + /* Not found: add new item to "links" list */ + l = xzalloc(sizeof(*l)); + l->st = st; + l->next = links; +#if ENABLE_FEATURE_CPIO_RENUMBER_INODES + if (option_mask32 & OPT_RENUMBER_INODES) + l->mapped_inode = ++G.next_inode; +#endif + links = l; + break; + } + if (l->st.st_ino == st.st_ino) { + /* found */ + break; + } + l = l->next; + } + /* Add new name to "l->names" list */ + n = xmalloc(sizeof(*n) + strlen(name)); + strcpy(n->name, name); + n->next = l->names; + l->names = n; + + free(line); + continue; + } +#if ENABLE_FEATURE_CPIO_RENUMBER_INODES + else if (option_mask32 & OPT_RENUMBER_INODES) { + st.st_ino = ++G.next_inode; + } +#endif + } else { /* line == NULL: EOF */ + next_link: + if (links) { + /* Output hardlink's data */ + st = links->st; + name = links->names->name; + links->names = links->names->next; +#if ENABLE_FEATURE_CPIO_RENUMBER_INODES + if (links->mapped_inode) + st.st_ino = links->mapped_inode; +#endif + /* GNU cpio is reported to emit file data + * only for the last instance. Mimic that. */ + if (links->names == NULL) + links = links->next; + else + st.st_size = 0; + /* NB: we leak links->names and/or links, + * this is intended (we exit soon anyway) */ + } else { + /* If no (more) hardlinks to output, + * output "trailer" entry */ + name = cpio_TRAILER; + /* st.st_size == 0 is a must, but for uniformity + * in the output, we zero out everything */ + memset(&st, 0, sizeof(st)); + /* st.st_nlink = 1; - GNU cpio does this */ + } + } + +#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO + if (option_mask32 & OPT_IGNORE_DEVNO) + st.st_dev = st.st_rdev = 0; +#endif + + bytes += printf("070701" + "%08X%08X%08X%08X%08X%08X%08X" + "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ + /* strlen+1: */ "%08X" + /* chksum: */ "00000000" /* (only for "070702" files) */ + /* name,NUL: */ "%s%c", + (unsigned)(uint32_t) st.st_ino, + (unsigned)(uint32_t) st.st_mode, + (unsigned)(uint32_t) st.st_uid, + (unsigned)(uint32_t) st.st_gid, + (unsigned)(uint32_t) st.st_nlink, + (unsigned)(uint32_t) st.st_mtime, + (unsigned)(uint32_t) st.st_size, + (unsigned)(uint32_t) major(st.st_dev), + (unsigned)(uint32_t) minor(st.st_dev), + (unsigned)(uint32_t) major(st.st_rdev), + (unsigned)(uint32_t) minor(st.st_rdev), + (unsigned)(strlen(name) + 1), + name, '\0'); + bytes = cpio_pad4(bytes); + + if (st.st_size) { + if (S_ISLNK(st.st_mode)) { + char *lpath = xmalloc_readlink_or_warn(name); + if (!lpath) + goto abort_cpio_o; + bytes += printf("%s", lpath); + free(lpath); + } else { /* S_ISREG */ + int fd = xopen(name, O_RDONLY); + fflush_all(); + /* We must abort if file got shorter too! */ + bb_copyfd_exact_size(fd, STDOUT_FILENO, st.st_size); + bytes += st.st_size; + close(fd); + } + bytes = cpio_pad4(bytes); + } + + if (!line) { + if (name != cpio_TRAILER) + goto next_link; + /* TODO: GNU cpio pads trailer to 512 bytes, do we want that? */ + return EXIT_SUCCESS; + } + + free(line); + } /* end of "while (1)" */ +} +#endif + +int cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cpio_main(int argc UNUSED_PARAM, char **argv) +{ + archive_handle_t *archive_handle; + char *cpio_filename; + char *cpio_owner; + IF_FEATURE_CPIO_O(const char *cpio_fmt = "";) + unsigned opt; +#if ENABLE_LONG_OPTS + const char *long_opts = + "extract\0" No_argument "i" + "list\0" No_argument "t" +#if ENABLE_FEATURE_CPIO_O + "create\0" No_argument "o" + "format\0" Required_argument "H" +#if ENABLE_FEATURE_CPIO_P + "pass-through\0" No_argument "p" +#endif +#endif + "owner\0" Required_argument "R" + "verbose\0" No_argument "v" + "null\0" No_argument "0" + "quiet\0" No_argument "\xff" + "to-stdout\0" No_argument "\xfe" +#if ENABLE_FEATURE_CPIO_IGNORE_DEVNO + "ignore-devno\0" No_argument "\xfd" +#endif +#if ENABLE_FEATURE_CPIO_RENUMBER_INODES + "renumber-inodes\0" No_argument "\xfc" +#endif + ; +#endif + + INIT_G(); + archive_handle = init_handle(); + /* archive_handle->src_fd = STDIN_FILENO; - done by init_handle */ + archive_handle->ah_flags = ARCHIVE_EXTRACT_NEWER; + + /* As of now we do not enforce this: */ + /* -i,-t,-o,-p are mutually exclusive */ + /* -u,-d,-m make sense only with -i or -p */ + /* -L makes sense only with -o or -p */ + +#if !ENABLE_FEATURE_CPIO_O + opt = getopt32long(argv, OPTION_STR, long_opts, &cpio_filename, &cpio_owner); +#else + opt = getopt32long(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), long_opts, + &cpio_filename, &cpio_owner, &cpio_fmt); +#endif + argv += optind; + if (opt & OPT_OWNER) { /* -R */ + parse_chown_usergroup_or_die(&G.owner_ugid, cpio_owner); + archive_handle->cpio__owner = G.owner_ugid; + } +#if !ENABLE_FEATURE_CPIO_O + if (opt & OPT_FILE) { /* -F */ + xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); + } +#else + if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */ + xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); + } + if (opt & OPT_PASSTHROUGH) { + pid_t pid; + struct fd_pair pp; + + if (argv[0] == NULL) + bb_show_usage(); + if (opt & OPT_CREATE_LEADING_DIR) + /* GNU cpio 2.13: "cpio -d -p a/b/c" works */ + bb_make_directory(argv[0], -1, FILEUTILS_RECUR); + /* Crude existence check: + * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); + * We can also xopen, fstat, IS_DIR, later fchdir. + * This would check for existence earlier and cleaner. + * As it stands now, if we fail xchdir later, + * child dies on EPIPE, unless it caught + * a diffrerent problem earlier. + * This is good enough for now. + */ +//FIXME: GNU cpio -d -p DIR does not immediately create DIR - +//it just prepends "DIR/" to the names of files to be created. +//The first file (fails to) be copied, and then the -d logic +//triggers and creates all necessary directories. +//IOW: bare "cpio -d -p DIR" + ^C shouldn't create anything. +#if !BB_MMU + pp.rd = 3; + pp.wr = 4; + if (!re_execed) { + close(3); + close(4); + xpiped_pair(pp); + } +#else + xpiped_pair(pp); +#endif + pid = fork_or_rexec(argv - optind); + if (pid == 0) { /* child */ + close(pp.rd); + xmove_fd(pp.wr, STDOUT_FILENO); + goto dump; + } + /* parent */ + xchdir(*argv++); + close(pp.wr); + xmove_fd(pp.rd, STDIN_FILENO); + //opt &= ~OPT_PASSTHROUGH; + opt |= OPT_EXTRACT; + goto skip; + } + /* -o */ + if (opt & OPT_CREATE) { + if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ + bb_show_usage(); + if (opt & OPT_FILE) { + xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); + } + dump: + return cpio_o(); + } + skip: +#endif + + /* One of either extract or test options must be given */ + if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) { + bb_show_usage(); + } + + if (opt & OPT_TEST) { + /* if both extract and test options are given, ignore extract option */ + opt &= ~OPT_EXTRACT; + archive_handle->action_header = header_list; + } + if (opt & OPT_EXTRACT) { + archive_handle->action_data = data_extract_all; + if (opt & OPT_2STDOUT) + archive_handle->action_data = data_extract_to_stdout; + } + if (opt & OPT_UNCONDITIONAL) { + archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; + archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; + } + if (opt & OPT_VERBOSE) { + if (archive_handle->action_header == header_list) { + archive_handle->action_header = header_verbose_list; + } else { + archive_handle->action_header = header_list; + } + } + if (opt & OPT_CREATE_LEADING_DIR) { + archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; + } + if (opt & OPT_PRESERVE_MTIME) { + archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; + } + + while (*argv) { + archive_handle->filter = filter_accept_list; + llist_add_to(&archive_handle->accept, *argv); + argv++; + } + + /* see get_header_cpio */ + archive_handle->cpio__blocks = (off_t)-1; + while (get_header_cpio(archive_handle) == EXIT_SUCCESS) + continue; + + create_links_from_list(archive_handle->link_placeholders); + + if (archive_handle->cpio__blocks != (off_t)-1 + && !(opt & OPT_QUIET) + ) { + fflush_all(); + fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/dpkg.c b/busybox-1_37_0/archival/dpkg.c new file mode 100644 index 000000000..8031956e9 --- /dev/null +++ b/busybox-1_37_0/archival/dpkg.c @@ -0,0 +1,1966 @@ +/* vi: set sw=4 ts=4: */ +/* + * mini dpkg implementation for busybox. + * this is not meant as a replacement for dpkg + * + * written by glenn mcgrath with the help of others + * copyright (c) 2001 by glenn mcgrath + * + * parts of the version comparison code is plucked from the real dpkg + * application which is licensed GPLv2 and + * copyright (c) 1995 Ian Jackson + * + * started life as a busybox implementation of udpkg + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* + * known difference between busybox dpkg and the official dpkg that i don't + * consider important, its worth keeping a note of differences anyway, just to + * make it easier to maintain. + * - the first value for the confflile: field isn't placed on a new line. + * - when installing a package the status: field is placed at the end of the + * section, rather than just after the package: field. + * + * bugs that need to be fixed + * - (unknown, please let me know when you find any) + */ +//config:config DPKG +//config: bool "dpkg (43 kb)" +//config: default y +//config: select FEATURE_SEAMLESS_GZ +//config: help +//config: dpkg is a medium-level tool to install, build, remove and manage +//config: Debian packages. +//config: +//config: This implementation of dpkg has a number of limitations, +//config: you should use the official dpkg if possible. + +//applet:IF_DPKG(APPLET(dpkg, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_DPKG) += dpkg.o + +//usage:#define dpkg_trivial_usage +//usage: "[-ilCPru] [-F OPT] PACKAGE" +//usage:#define dpkg_full_usage "\n\n" +//usage: "Install, remove and manage Debian packages\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--install Install the package" +//usage: "\n -l,--list List of installed packages" +//usage: "\n --configure Configure an unpackaged package" +//usage: "\n -P,--purge Purge all files of a package" +//usage: "\n -r,--remove Remove all but the configuration files for a package" +//usage: "\n --unpack Unpack a package, but don't configure it" +//usage: "\n --force-depends Ignore dependency problems" +//usage: "\n --force-confnew Overwrite existing config files when installing" +//usage: "\n --force-confold Keep old config files when installing" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i Install the package" +//usage: "\n -l List of installed packages" +//usage: "\n -C Configure an unpackaged package" +//usage: "\n -P Purge all files of a package" +//usage: "\n -r Remove all but the configuration files for a package" +//usage: "\n -u Unpack a package, but don't configure it" +//usage: "\n -F depends Ignore dependency problems" +//usage: "\n -F confnew Overwrite existing config files when installing" +//usage: "\n -F confold Keep old config files when installing" +//usage: ) + +#include "libbb.h" +#include +#include "bb_archive.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, 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 + +/* 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 operator:4; /* was:3 */ + unsigned type:4; + unsigned name:16; /* was:14 */ + unsigned version:16; /* was:14 */ +} edge_t; + +typedef struct common_node_s { + unsigned name:16; /* was:14 */ + unsigned version:16; /* was:14 */ + unsigned num_of_edges:16; /* was:14 */ + edge_t **edge; +} common_node_t; + +/* Currently it doesn't 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 leeway here */ +#define STATUS_HASH_PRIME 8191 +typedef struct status_node_s { + unsigned package:16; /* was:14 */ /* has to fit PACKAGE_HASH_PRIME */ + unsigned status:16; /* was:14 */ /* has to fit STATUS_HASH_PRIME */ +} status_node_t; + + +/* Globals */ +struct globals { + char *name_hashtable[NAME_HASH_PRIME + 1]; + common_node_t *package_hashtable[PACKAGE_HASH_PRIME + 1]; + status_node_t *status_hashtable[STATUS_HASH_PRIME + 1]; +}; +#define G (*ptr_to_globals) +#define name_hashtable (G.name_hashtable ) +#define package_hashtable (G.package_hashtable) +#define status_hashtable (G.status_hashtable ) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + + +/* Even numbers are for 'extras', like ored dependencies 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 +}; + +typedef struct deb_file_s { + char *control_file; + char *filename; + unsigned package:16; /* was:14 */ +} deb_file_t; + + +static void make_hash(const char *key, unsigned *start, unsigned *decrement, const int hash_prime) +{ + unsigned long 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, don't want to shift data to where it has + * no effect */ + hash_num += (key[i] + key[i-1]) << ((key[i] * i) % 24); + } + *start = (unsigned) hash_num % hash_prime; + *decrement = (unsigned) 1 + (hash_num % (hash_prime - 1)); +} + +/* this adds the key to the hash table */ +static int search_name_hashtable(const char *key) +{ + unsigned probe_address; + unsigned probe_decrement; + + 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; + } + probe_address -= probe_decrement; + if ((int)probe_address < 0) { + probe_address += NAME_HASH_PRIME; + } + } + name_hashtable[probe_address] = xstrdup(key); + return probe_address; +} + +/* this DOESN'T add the key to the hashtable + * TODO make it consistent with search_name_hashtable + */ +static unsigned search_status_hashtable(const char *key) +{ + unsigned probe_address; + unsigned probe_decrement; + + 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; + } + probe_address -= probe_decrement; + if ((int)probe_address < 0) { + probe_address += STATUS_HASH_PRIME; + } + } + return probe_address; +} + +static int order(char x) +{ + return (x == '~' ? -1 + : x == '\0' ? 0 + : isdigit(x) ? 0 + : isalpha(x) ? x + : (unsigned char)x + 256 + ); +} + +/* This code is taken from dpkg and modified slightly to work with busybox */ +static int version_compare_part(const char *val, const char *ref) +{ + if (!val) val = ""; + if (!ref) ref = ""; + + while (*val || *ref) { + int first_diff; + + while ((*val && !isdigit(*val)) || (*ref && !isdigit(*ref))) { + int vc = order(*val); + int rc = order(*ref); + if (vc != rc) + return vc - rc; + val++; + ref++; + } + + while (*val == '0') + val++; + while (*ref == '0') + ref++; + + first_diff = 0; + while (isdigit(*val) && isdigit(*ref)) { + if (first_diff == 0) + first_diff = *val - *ref; + val++; + ref++; + } + if (isdigit(*val)) + return 1; + if (isdigit(*ref)) + return -1; + if (first_diff) + return first_diff; + } + return 0; +} + +/* if ver1 < ver2 return -1, + * if ver1 = ver2 return 0, + * if ver1 > ver2 return 1, + */ +static int version_compare(const unsigned ver1, const unsigned ver2) +{ + char *ch_ver1 = name_hashtable[ver1]; + char *ch_ver2 = name_hashtable[ver2]; + unsigned epoch1 = 0, epoch2 = 0; + char *colon; + char *deb_ver1, *deb_ver2; + char *upstream_ver1; + char *upstream_ver2; + int result; + + /* Compare epoch */ + colon = strchr(ch_ver1, ':'); + if (colon) { + epoch1 = atoi(ch_ver1); + ch_ver1 = colon + 1; + } + colon = strchr(ch_ver2, ':'); + if (colon) { + epoch2 = atoi(ch_ver2); + ch_ver2 = colon + 1; + } + if (epoch1 < epoch2) { + return -1; + } + if (epoch1 > epoch2) { + return 1; + } + + /* Compare upstream version */ + upstream_ver1 = xstrdup(ch_ver1); + upstream_ver2 = xstrdup(ch_ver2); + + /* 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'; + } + if (deb_ver2) { + *deb_ver2++ = '\0'; + } + result = version_compare_part(upstream_ver1, upstream_ver2); + if (result == 0) { + /* Compare debian versions */ + result = version_compare_part(deb_ver1, deb_ver2); + } + + free(upstream_ver1); + free(upstream_ver2); + return result; +} + +static int test_version(const unsigned version1, const unsigned version2, const unsigned operator) +{ + const int version_result = version_compare(version1, version2); + switch (operator) { + case VER_ANY: + return TRUE; + case VER_EQUAL: + return (version_result == 0); + case VER_LESS: + return (version_result < 0); + case VER_LESS_EQUAL: + return (version_result <= 0); + case VER_MORE: + return (version_result > 0); + case VER_MORE_EQUAL: + return (version_result >= 0); + } + return FALSE; +} + +static int search_package_hashtable(const unsigned name, const unsigned version, const unsigned operator) +{ + unsigned probe_address; + unsigned probe_decrement; + + 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; +} + +/* + * This function searches through the entire package_hashtable looking + * for a package which provides "needle". It returns the index into + * the package_hashtable for the providing package. + * + * needle is the index into name_hashtable of the package we are + * looking for. + * + * start_at is the index in the package_hashtable to start looking + * at. If start_at is -1 then start at the beginning. This is to allow + * for repeated searches since more than one package might provide + * needle. + * + * FIXME: I don't think this is very efficient, but I thought I'd keep + * it simple for now until it proves to be a problem. + */ +static int search_for_provides(int needle, int start_at) +{ + int i, j; + common_node_t *p; + for (i = start_at + 1; i < PACKAGE_HASH_PRIME; i++) { + p = package_hashtable[i]; + if (p == NULL) + continue; + for (j = 0; j < p->num_of_edges; j++) + if (p->edge[j]->type == EDGE_PROVIDES && p->edge[j]->name == needle) + return i; + } + return -1; +} + +/* + * Add an edge to a node + */ +static void add_edge_to_node(common_node_t *node, edge_t *edge) +{ + node->edge = xrealloc_vector(node->edge, 2, node->num_of_edges); + node->edge[node->num_of_edges++] = edge; +} + +/* + * Create one new node and one new edge for every dependency. + * + * Dependencies which contain multiple alternatives are represented as + * an EDGE_OR_PRE_DEPENDS or EDGE_OR_DEPENDS node, followed by a + * number of EDGE_PRE_DEPENDS or EDGE_DEPENDS nodes. The name field of + * the OR edge contains the full dependency string while the version + * field contains the number of EDGE nodes which follow as part of + * this alternative. + */ +static void add_split_dependencies(common_node_t *parent_node, const char *whole_line, unsigned 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; + edge_t *or_edge; + int offset_ch; + + field = strtok_r(line, ",", &line_ptr1); + do { + /* skip leading spaces */ + field += strspn(field, " "); + line2 = xstrdup(field); + field2 = strtok_r(line2, "|", &line_ptr2); + or_edge = NULL; + if ((edge_type == EDGE_DEPENDS || edge_type == EDGE_PRE_DEPENDS) + && (strcmp(field, field2) != 0) + ) { + or_edge = xzalloc(sizeof(edge_t)); + or_edge->type = edge_type + 1; + or_edge->name = search_name_hashtable(field); + //or_edge->version = 0; // tracks the number of alternatives + add_edge_to_node(parent_node, or_edge); + } + + do { + edge = xmalloc(sizeof(edge_t)); + edge->type = edge_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 isn't already in there */ + edge->version = search_name_hashtable("ANY"); + } else { + /* Skip leading ' ' or '(' */ + version += strspn(version, " ("); + /* Calculate length of any operator characters */ + 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 { + bb_simple_error_msg_and_die("illegal operator"); + } + } + /* 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 isn't already in there */ + edge->version = search_name_hashtable(version); + } + + /* Get the dependency name */ + field2[strcspn(field2, " (")] = '\0'; + edge->name = search_name_hashtable(field2); + + if (or_edge) + or_edge->version++; + + add_edge_to_node(parent_node, edge); + field2 = strtok_r(NULL, "|", &line_ptr2); + } while (field2 != NULL); + + free(line2); + field = strtok_r(NULL, ",", &line_ptr1); + } while (field != NULL); + + free(line); +} + +static void free_package(common_node_t *node) +{ + unsigned i; + if (node) { + for (i = 0; i < node->num_of_edges; i++) { + free(node->edge[i]); + } + free(node->edge); + free(node); + } +} + +/* + * Gets the next package field from package_buffer, separated into the field name + * and field value, it returns the int offset to the first character of the next field + */ +static 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 ':' isn't + * 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) { + /* 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++; + } + *field_name = NULL; + if (name_length) { + *field_name = xstrndup(&package_buffer[offset_name_start], name_length); + } + *field_value = NULL; + if (value_length > 0) { + *field_value = xstrndup(&package_buffer[offset_value_start], value_length); + } + return next_offset; +} + +static unsigned fill_package_struct(char *control_buffer) +{ + static const char field_names[] ALIGN1 = + "Package\0""Version\0" + "Pre-Depends\0""Depends\0""Replaces\0""Provides\0" + "Conflicts\0""Suggests\0""Recommends\0""Enhances\0"; + + common_node_t *new_node = xzalloc(sizeof(common_node_t)); + char *field_name; + char *field_value; + 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) { + unsigned field_num; + + field_start += read_package_field(&control_buffer[field_start], + &field_name, &field_value); + + if (field_name == NULL) { + goto fill_package_struct_cleanup; + } + + field_num = index_in_strings(field_names, field_name); + switch (field_num) { + case 0: /* Package */ + new_node->name = search_name_hashtable(field_value); + break; + case 1: /* Version */ + new_node->version = search_name_hashtable(field_value); + break; + case 2: /* Pre-Depends */ + add_split_dependencies(new_node, field_value, EDGE_PRE_DEPENDS); + break; + case 3: /* Depends */ + add_split_dependencies(new_node, field_value, EDGE_DEPENDS); + break; + case 4: /* Replaces */ + add_split_dependencies(new_node, field_value, EDGE_REPLACES); + break; + case 5: /* Provides */ + add_split_dependencies(new_node, field_value, EDGE_PROVIDES); + break; + case 6: /* Conflicts */ + add_split_dependencies(new_node, field_value, EDGE_CONFLICTS); + break; + case 7: /* Suggests */ + add_split_dependencies(new_node, field_value, EDGE_SUGGESTS); + break; + case 8: /* Recommends */ + add_split_dependencies(new_node, field_value, EDGE_RECOMMENDS); + break; + case 9: /* Enhances */ + add_split_dependencies(new_node, field_value, EDGE_ENHANCES); + break; + } + fill_package_struct_cleanup: + 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); + free_package(package_hashtable[num]); + package_hashtable[num] = new_node; + return num; +} + +/* if num = 1, it returns the want status, 2 returns flag, 3 returns status */ +static unsigned get_status(const unsigned status_node, const int num) +{ + char *status_string = name_hashtable[status_hashtable[status_node]->status]; + char *state_sub_string; + unsigned 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 separating spaces */ + status_string += strspn(status_string, " "); + } + len = strcspn(status_string, " \n"); + state_sub_string = xstrndup(status_string, len); + state_sub_num = search_name_hashtable(state_sub_string); + free(state_sub_string); + return state_sub_num; +} + +static void set_status(const unsigned status_node_num, const char *new_value, const int position) +{ + const unsigned new_value_num = search_name_hashtable(new_value); + unsigned want = get_status(status_node_num, 1); + unsigned flag = get_status(status_node_num, 2); + unsigned status = get_status(status_node_num, 3); + char *new_status; + + switch (position) { + case 1: + want = new_value_num; + break; + case 2: + flag = new_value_num; + break; + case 3: + status = new_value_num; + break; + default: + bb_simple_error_msg_and_die("DEBUG ONLY: this shouldnt happen"); + } + + new_status = xasprintf("%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); +} + +static const char *describe_status(int status_num) +{ + int status_want, status_state; + if (status_hashtable[status_num] == NULL || status_hashtable[status_num]->status == 0) + return "is not installed or flagged to be installed"; + + status_want = get_status(status_num, 1); + status_state = get_status(status_num, 3); + + if (status_state == search_name_hashtable("installed")) { + if (status_want == search_name_hashtable("install")) + return "is installed"; + if (status_want == search_name_hashtable("deinstall")) + return "is marked to be removed"; + if (status_want == search_name_hashtable("purge")) + return "is marked to be purged"; + } + if (status_want == search_name_hashtable("unknown")) + return "is in an indeterminate state"; + if (status_want == search_name_hashtable("install")) + return "is marked to be installed"; + + return "is not installed or flagged to be installed"; +} + +static void index_status_file(const char *filename) +{ + FILE *status_file; + char *control_buffer; + char *status_line; + status_node_t *status_node = NULL; + unsigned status_num; + + status_file = xfopen_for_read(filename); + while ((control_buffer = xmalloc_fgetline_str(status_file, "\n\n")) != NULL) { + const unsigned package_num = fill_package_struct(control_buffer); + if (package_num != -1) { + status_node = xmalloc(sizeof(status_node_t)); + /* fill_package_struct doesn't 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")); + 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); +} + +static 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); + } + } +} + +/* This could do with a cleanup */ +static void write_status_file(deb_file_t **deb_file) +{ + FILE *old_status_file = xfopen_for_read("/var/lib/dpkg/status"); + FILE *new_status_file = xfopen_for_write("/var/lib/dpkg/status.udeb"); + 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 = xmalloc_fgetline_str(old_status_file, "\n\n")) != NULL) { + tmp_string = strstr(control_buffer, "Package:"); + if (tmp_string == NULL) { + continue; + } + + tmp_string += 8; + tmp_string += strspn(tmp_string, " \n\t"); + package_name = xstrndup(tmp_string, strcspn(tmp_string, "\n")); + write_flag = FALSE; + tmp_string = strstr(control_buffer, "Status:"); + if (tmp_string != NULL) { + /* Separate 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 isn't 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) { + bb_error_msg_and_die("ALERT: cannot 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 wasn't handle above, do it now*/ + if (!write_flag) { + fprintf(new_status_file, "%s\n\n", control_buffer); + } + + 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 separate backfile to dpkg */ + if (rename("/var/lib/dpkg/status", "/var/lib/dpkg/status.udeb.bak") == -1) { + if (errno != ENOENT) + bb_simple_error_msg_and_die("can't create backup status file"); + /* Its ok if renaming the status file fails because status + * file doesn't exist, maybe we are starting from scratch */ + bb_simple_error_msg("no status file found, creating new one"); + } + + xrename("/var/lib/dpkg/status.udeb", "/var/lib/dpkg/status"); +} + +/* This function returns TRUE if the given package can satisfy a + * dependency of type depend_type. + * + * A pre-depends is satisfied only if a package is already installed, + * which a regular depends can be satisfied by a package which we want + * to install. + */ +static int package_satisfies_dependency(int package, int depend_type) +{ + int status_num = search_status_hashtable(name_hashtable[package_hashtable[package]->name]); + + /* status could be unknown if package is a pure virtual + * provides which cannot satisfy any dependency by itself. + */ + if (status_hashtable[status_num] == NULL) + return 0; + + switch (depend_type) { + case EDGE_PRE_DEPENDS: return get_status(status_num, 3) == search_name_hashtable("installed"); + case EDGE_DEPENDS: return get_status(status_num, 1) == search_name_hashtable("install"); + } + return 0; +} + +static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count - ?? */) +{ + int *conflicts = NULL; + int conflicts_num = 0; + int i = deb_start; + int j; + + /* 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 package_num = deb_file[i]->package; + conflicts = xrealloc_vector(conflicts, 2, conflicts_num); + 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 = xzalloc(sizeof(common_node_t)); + new_node->name = package_hashtable[package_num]->edge[j]->name; + new_node->version = package_hashtable[package_num]->edge[j]->version; + package_hashtable[conflicts_package_num] = new_node; + } + conflicts = xrealloc_vector(conflicts, 2, conflicts_num); + conflicts[conflicts_num] = conflicts_package_num; + conflicts_num++; + } + } + i++; + } + + /* Check conflicts */ + i = 0; + while (deb_file[i] != NULL) { + const common_node_t *package_node = package_hashtable[deb_file[i]->package]; + int status_num = 0; + status_num = search_status_hashtable(name_hashtable[package_node->name]); + + if (get_status(status_num, 3) == search_name_hashtable("installed")) { + i++; + continue; + } + + for (j = 0; j < package_node->num_of_edges; j++) { + const edge_t *package_edge = package_node->edge[j]; + + if (package_edge->type == EDGE_CONFLICTS) { + const unsigned package_num = + search_package_hashtable(package_edge->name, + package_edge->version, + package_edge->operator); + int result = 0; + if (package_hashtable[package_num] != NULL) { + status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); + + if (get_status(status_num, 1) == search_name_hashtable("install")) { + result = test_version(package_hashtable[deb_file[i]->package]->version, + package_edge->version, package_edge->operator); + } + } + + if (result) { + bb_error_msg_and_die("package %s conflicts with %s", + name_hashtable[package_node->name], + name_hashtable[package_edge->name]); + } + } + } + i++; + } + + + /* Check dependentcies */ + for (i = 0; i < PACKAGE_HASH_PRIME; i++) { + int status_num = 0; + int number_of_alternatives = 0; + const edge_t * root_of_alternatives = NULL; + const common_node_t *package_node = package_hashtable[i]; + + /* If the package node does not exist then this + * package is a virtual one. In which case there are + * no dependencies to check. + */ + if (package_node == NULL) continue; + + status_num = search_status_hashtable(name_hashtable[package_node->name]); + + /* If there is no status then this package is a + * virtual one provided by something else. In which + * case there are no dependencies to check. + */ + if (status_hashtable[status_num] == NULL) continue; + + /* If we don't want this package installed then we may + * as well ignore it's dependencies. + */ + if (get_status(status_num, 1) != search_name_hashtable("install")) { + continue; + } + + /* This code is tested only for EDGE_DEPENDS, since I + * have no suitable pre-depends available. There is no + * reason that it shouldn't work though :-) + */ + for (j = 0; j < package_node->num_of_edges; j++) { + const edge_t *package_edge = package_node->edge[j]; + unsigned package_num; + + if (package_edge->type == EDGE_OR_PRE_DEPENDS + || package_edge->type == EDGE_OR_DEPENDS + ) { + /* start an EDGE_OR_ list */ + number_of_alternatives = package_edge->version; + root_of_alternatives = package_edge; + continue; + } + if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ + number_of_alternatives = 1; + root_of_alternatives = NULL; + } + + package_num = search_package_hashtable(package_edge->name, package_edge->version, package_edge->operator); + + if (package_edge->type == EDGE_PRE_DEPENDS + || package_edge->type == EDGE_DEPENDS + ) { + int result = 1; + status_num = 0; + + /* If we are inside an alternative then check + * this edge is the right type. + * + * EDGE_DEPENDS == OR_DEPENDS -1 + * EDGE_PRE_DEPENDS == OR_PRE_DEPENDS -1 + */ + if (root_of_alternatives && package_edge->type != root_of_alternatives->type - 1) + bb_error_msg_and_die("fatal error, package dependencies corrupt: %d != %d - 1", + package_edge->type, root_of_alternatives->type); + + if (package_hashtable[package_num] != NULL) + result = !package_satisfies_dependency(package_num, package_edge->type); + + if (result) { /* check for other package which provide what we are looking for */ + int provider = -1; + + while ((provider = search_for_provides(package_edge->name, provider)) > -1) { + if (package_hashtable[provider] == NULL) { + puts("Have a provider but no package information for it"); + continue; + } + result = !package_satisfies_dependency(provider, package_edge->type); + + if (result == 0) + break; + } + } + + /* It must be already installed, or to be installed */ + number_of_alternatives--; + if (result && number_of_alternatives == 0) { + if (root_of_alternatives) + bb_error_msg_and_die( + "package %s %sdepends on %s, which %s", + name_hashtable[package_node->name], + package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", + name_hashtable[root_of_alternatives->name], + "cannot be satisfied"); + bb_error_msg_and_die( + "package %s %sdepends on %s, which %s", + name_hashtable[package_node->name], + package_edge->type == EDGE_PRE_DEPENDS ? "pre-" : "", + name_hashtable[package_edge->name], + describe_status(status_num)); + } + if (result == 0 && number_of_alternatives) { + /* we've found a package which + * satisfies the dependency, + * so skip over the rest of + * the alternatives. + */ + j += number_of_alternatives; + number_of_alternatives = 0; + } + } + } + } + free(conflicts); + return TRUE; +} + +static char **create_list(const char *filename) +{ + FILE *list_stream; + char **file_list; + char *line; + int count; + + /* don't use [xw]fopen here, handle error ourself */ + list_stream = fopen_for_read(filename); + if (list_stream == NULL) { + return NULL; + } + + file_list = NULL; + count = 0; + while ((line = xmalloc_fgetline(list_stream)) != NULL) { + file_list = xrealloc_vector(file_list, 2, count); + file_list[count++] = line; + /*file_list[count] = NULL; - xrealloc_vector did it */ + } + fclose(list_stream); + + return file_list; +} + +/** This tests if the filename is an "important" directory, which might be symlinked. + * Debians dpkg test if directories are used by other packages, this + * implementation doesn't and would remove for ex. an lib -> usr/lib symlink. + */ +static int is_builtin_exclude(const char *name) +{ + if (*name++ != '/') + return 0; + if (index_in_strings(".\0" "etc\0" "opt\0" "srv\0" "var\0" "var/lib\0", + name) >= 0) + return 1; + if (is_prefixed_with(name, "usr/")) { + name += sizeof("usr/") - 1; + if (is_prefixed_with(name, "local/")) + name += sizeof("local/") - 1; + } + + return index_in_strings("bin\0" "lib\0" "lib32\0" "lib64\0" "sbin\0", + name) >= 0; +} + +/* maybe i should try and hook this into remove_file.c somehow */ +static int remove_file_array(char **remove_names, char **exclude_names) +{ + struct stat path_stat; + int remove_flag = 1; /* not removed anything yet */ + int i, j; + + if (remove_names == NULL) { + return 0; + } + for (i = 0; remove_names[i] != NULL; i++) { + if (is_builtin_exclude(remove_names[i])) + continue; + if (exclude_names != NULL) { + for (j = 0; exclude_names[j] != NULL; j++) { + if (strcmp(remove_names[i], exclude_names[j]) == 0) { + goto skip; + } + } + } + /* TODO: why we are checking lstat? we can just try rm/rmdir */ + if (lstat(remove_names[i], &path_stat) < 0) { + continue; + } + if (S_ISDIR(path_stat.st_mode)) { + remove_flag &= rmdir(remove_names[i]); /* 0 if no error */ + } else { + remove_flag &= unlink(remove_names[i]); /* 0 if no error */ + } + skip: + continue; + } + return (remove_flag == 0); +} + +static void run_package_script_or_die(const char *package_name, const char *script_type) +{ + char *script_path; + int result; + + script_path = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, script_type); + + /* If the file doesn't exist it isn't fatal */ + result = access(script_path, F_OK) ? EXIT_SUCCESS : system(script_path); + free(script_path); + if (result) + bb_error_msg_and_die("%s failed, exit code %d", script_type, result); +} + +/* +The policy manual defines what scripts get called when and with +what arguments. I realize that busybox does not support all of +these scenarios, but it does support some of them; it does not, +however, run them with any parameters in run_package_script_or_die(). +Here are the scripts: + +preinst install +preinst install +preinst upgrade +preinst abort_upgrade +postinst configure +postinst abort-upgade +postinst abort-remove +postinst abort-remove in-favour +postinst abort-deconfigure in-favor removing +prerm remove +prerm upgrade +prerm failed-upgrade +prerm remove in-favor +prerm deconfigure in-favour removing +postrm remove +postrm purge +postrm upgrade +postrm failed-upgrade +postrm abort-install +postrm abort-install +postrm abort-upgrade +postrm disappear +*/ +static const char *const all_control_files[] ALIGN_PTR = { + "preinst", "postinst", "prerm", "postrm", + "list", "md5sums", "shlibs", "conffiles", + "config", "templates" +}; + +static char **all_control_list(const char *package_name) +{ + unsigned i = 0; + char **remove_files; + + /* Create a list of all /var/lib/dpkg/info/ files */ + remove_files = xzalloc(sizeof(all_control_files) + sizeof(char*)); + while (i < ARRAY_SIZE(all_control_files)) { + remove_files[i] = xasprintf("/var/lib/dpkg/info/%s.%s", + package_name, all_control_files[i]); + i++; + } + + return remove_files; +} + +static void free_array(char **array) +{ + if (array) { + unsigned i = 0; + while (array[i]) { + free(array[i]); + i++; + } + free(array); + } +} + +/* This function lists information on the installed packages. It loops through + * the status_hashtable to retrieve the info. This results in smaller code than + * scanning the status file. The resulting list, however, is unsorted. + */ +static void list_packages(const char *pattern) +{ + int i; + + puts(" Name Version"); + puts("+++-==============-=============="); + + /* go through status hash, dereference package hash and finally strings */ + for (i = 0; i < STATUS_HASH_PRIME+1; i++) { + if (status_hashtable[i]) { + const char *stat_str; /* status string */ + const char *name_str; /* package name */ + const char *vers_str; /* version */ + char s1, s2; /* status abbreviations */ + int spccnt; /* space count */ + int j; + + stat_str = name_hashtable[status_hashtable[i]->status]; + name_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->name]; + vers_str = name_hashtable[package_hashtable[status_hashtable[i]->package]->version]; + + if (pattern && fnmatch(pattern, name_str, 0) != 0) + continue; + + /* get abbreviation for status field 1 */ + s1 = stat_str[0] == 'i' ? 'i' : 'r'; + + /* get abbreviation for status field 2 */ + for (j = 0, spccnt = 0; stat_str[j] && spccnt < 2; j++) { + if (stat_str[j] == ' ') spccnt++; + } + s2 = stat_str[j]; + + /* print out the line formatted like Debian dpkg */ + printf("%c%c %-14s %s\n", s1, s2, name_str, vers_str); + } + } +} + +static void remove_package(const unsigned package_num, int noisy) +{ + const char *package_name = name_hashtable[package_hashtable[package_num]->name]; + const char *package_version = name_hashtable[package_hashtable[package_num]->version]; + const unsigned 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]; + + if (noisy) + printf("Removing %s (%s)...\n", package_name, package_version); + + /* Run prerm script */ + run_package_script_or_die(package_name, "prerm"); + + /* Create a list of files to remove, and a separate list of those to keep */ + sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); + remove_files = create_list(list_name); + + sprintf(conffile_name, "/var/lib/dpkg/info/%s.%s", package_name, "conffiles"); + exclude_files = create_list(conffile_name); + + /* Some directories can't be removed straight away, so do multiple passes */ + while (remove_file_array(remove_files, exclude_files)) + continue; + free_array(exclude_files); + free_array(remove_files); + + /* Create a list of files in /var/lib/dpkg/info/.* to keep */ + exclude_files = xzalloc(sizeof(exclude_files[0]) * 3); + exclude_files[0] = xstrdup(conffile_name); + exclude_files[1] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); + + /* Create a list of all /var/lib/dpkg/info/ files */ + remove_files = all_control_list(package_name); + + remove_file_array(remove_files, exclude_files); + free_array(remove_files); + free_array(exclude_files); + + /* rename .conffiles to .list + * The conffiles control file isn't required in Debian packages, so don't + * error out if it's missing. */ + rename(conffile_name, list_name); + + /* Change package status */ + set_status(status_num, "config-files", 3); +} + +static void purge_package(const unsigned package_num) +{ + const char *package_name = name_hashtable[package_hashtable[package_num]->name]; + const char *package_version = name_hashtable[package_hashtable[package_num]->version]; + const unsigned status_num = search_status_hashtable(package_name); + char **remove_files; + char **exclude_files; + char list_name[strlen(package_name) + 25]; + + printf("Purging %s (%s)...\n", package_name, package_version); + + /* Run prerm script */ + run_package_script_or_die(package_name, "prerm"); + + /* Create a list of files to remove */ + sprintf(list_name, "/var/lib/dpkg/info/%s.%s", package_name, "list"); + remove_files = create_list(list_name); + + /* Some directories cant be removed straight away, so do multiple passes */ + while (remove_file_array(remove_files, NULL)) + continue; + free_array(remove_files); + + /* Create a list of all /var/lib/dpkg/info/ files */ + remove_files = all_control_list(package_name); + + /* Delete all of them except the postrm script */ + exclude_files = xzalloc(sizeof(exclude_files[0]) * 2); + exclude_files[0] = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "postrm"); + remove_file_array(remove_files, exclude_files); + free_array(exclude_files); + + /* Run and remove postrm script */ + run_package_script_or_die(package_name, "postrm"); + remove_file_array(remove_files, NULL); + + free_array(remove_files); + + /* Change package status */ + set_status(status_num, "not-installed", 3); +} + +static archive_handle_t *init_archive_deb_ar(const char *filename) +{ + archive_handle_t *ar_handle; + + /* Setup an ar archive handle that refers to the gzip sub archive */ + ar_handle = init_handle(); + ar_handle->filter = filter_accept_list_reassign; + ar_handle->src_fd = xopen(filename, O_RDONLY); + + return ar_handle; +} + +static void init_archive_deb_control(archive_handle_t *ar_handle) +{ + archive_handle_t *tar_handle; + + /* Setup the tar archive handle */ + tar_handle = init_handle(); + tar_handle->src_fd = ar_handle->src_fd; + + /* We don't care about data.tar.* or debian-binary, just control.tar.* */ + llist_add_to(&(ar_handle->accept), (char*)"control.tar"); +#if ENABLE_FEATURE_SEAMLESS_GZ + llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); +#endif +#if ENABLE_FEATURE_SEAMLESS_BZ2 + llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); +#endif +#if ENABLE_FEATURE_SEAMLESS_XZ + llist_add_to(&(ar_handle->accept), (char*)"control.tar.xz"); +#endif + + /* Assign the tar handle as a subarchive of the ar handle */ + ar_handle->dpkg__sub_archive = tar_handle; +} + +static void init_archive_deb_data(archive_handle_t *ar_handle) +{ + archive_handle_t *tar_handle; + + /* Setup the tar archive handle */ + tar_handle = init_handle(); + tar_handle->src_fd = ar_handle->src_fd; + + /* We don't care about control.tar.* or debian-binary, just data.tar.* */ + llist_add_to(&(ar_handle->accept), (char*)"data.tar"); +#if ENABLE_FEATURE_SEAMLESS_GZ + llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); +#endif +#if ENABLE_FEATURE_SEAMLESS_BZ2 + llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); +#endif +#if ENABLE_FEATURE_SEAMLESS_LZMA + llist_add_to(&(ar_handle->accept), (char*)"data.tar.lzma"); +#endif +#if ENABLE_FEATURE_SEAMLESS_XZ + llist_add_to(&(ar_handle->accept), (char*)"data.tar.xz"); +#endif + + /* Assign the tar handle as a subarchive of the ar handle */ + ar_handle->dpkg__sub_archive = tar_handle; +} + +static void FAST_FUNC data_extract_to_buffer(archive_handle_t *archive_handle) +{ + unsigned size = archive_handle->file_header->size; + + archive_handle->dpkg__buffer = xzalloc(size + 1); + xread(archive_handle->src_fd, archive_handle->dpkg__buffer, size); +} + +static char *deb_extract_control_file_to_buffer(archive_handle_t *ar_handle, llist_t *myaccept) +{ + ar_handle->dpkg__sub_archive->action_data = data_extract_to_buffer; + ar_handle->dpkg__sub_archive->accept = myaccept; + ar_handle->dpkg__sub_archive->filter = filter_accept_list; + + unpack_ar_archive(ar_handle); + close(ar_handle->src_fd); + + return ar_handle->dpkg__sub_archive->dpkg__buffer; +} + +static void append_control_file_to_llist(const char *package_name, const char *control_name, llist_t **ll) +{ + FILE *fp; + char *filename, *line; + + filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, control_name); + fp = fopen_for_read(filename); + free(filename); + if (fp != NULL) { + while ((line = xmalloc_fgetline(fp)) != NULL) + llist_add_to(ll, line); + fclose(fp); + } +} + +static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) +{ + int fd; + char *name_ptr = archive_handle->file_header->name + 1; + + /* Is this file marked as config file? */ + if (!find_list_entry(archive_handle->accept, name_ptr)) + return EXIT_SUCCESS; /* no */ + + fd = open(name_ptr, O_RDONLY); + if (fd >= 0) { + md5_ctx_t md5; + char *md5line, *buf; + int count; + + /* Calculate MD5 of existing file */ + buf = xmalloc(4096); + md5_begin(&md5); + while ((count = safe_read(fd, buf, 4096)) > 0) + md5_hash(&md5, buf, count); + md5_end(&md5, buf); /* using buf as result storage */ + close(fd); + + md5line = xmalloc(16 * 2 + 2 + strlen(name_ptr) + 1); + sprintf(bin2hex(md5line, buf, 16), " %s", name_ptr); + free(buf); + + /* Is it changed after install? */ + if (find_list_entry(archive_handle->accept, md5line) == NULL) { + printf("Warning: Creating %s as %s.dpkg-new\n", name_ptr, name_ptr); + archive_handle->file_header->name = xasprintf("%s.dpkg-new", archive_handle->file_header->name); + } + free(md5line); + } + return EXIT_SUCCESS; +} + +static void FAST_FUNC data_extract_all_prefix(archive_handle_t *archive_handle) +{ + char *name_ptr = archive_handle->file_header->name; + + /* Skip all leading "/" */ + while (*name_ptr == '/') + name_ptr++; + /* Skip all leading "./" and "../" */ + while (name_ptr[0] == '.') { + if (name_ptr[1] == '.') + name_ptr++; + if (name_ptr[1] != '/') + break; + name_ptr += 2; + } + + if (name_ptr[0] != '\0') { + archive_handle->file_header->name = xasprintf("%s%s", archive_handle->dpkg__buffer, name_ptr); + data_extract_all(archive_handle); + if (fnmatch("*.dpkg-new", archive_handle->file_header->name, 0) == 0) { + /* remove .dpkg-new suffix */ + archive_handle->file_header->name[strlen(archive_handle->file_header->name) - 9] = '\0'; + } + } +} + +enum { + /* Commands */ + OPT_configure = (1 << 0), + OPT_install = (1 << 1), + OPT_list_installed = (1 << 2), + OPT_purge = (1 << 3), + OPT_remove = (1 << 4), + OPT_unpack = (1 << 5), + OPTMASK_cmd = (1 << 6) - 1, + /* Options */ + OPT_force = (1 << 6), + OPT_force_ignore_depends = (1 << 7), + OPT_force_confnew = (1 << 8), + OPT_force_confold = (1 << 9), +}; + +static void unpack_package(deb_file_t *deb_file) +{ + const char *package_name = name_hashtable[package_hashtable[deb_file->package]->name]; + const unsigned status_num = search_status_hashtable(package_name); + const unsigned status_package_num = status_hashtable[status_num]->package; + char *info_prefix; + char *list_filename; + archive_handle_t *archive_handle; + FILE *out_stream; + llist_t *accept_list; + llist_t *conffile_list; + int i; + + /* If existing version, remove it first */ + conffile_list = NULL; + 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); + + /* Read md5sums from old package */ + if (!(option_mask32 & OPT_force_confold)) + append_control_file_to_llist(package_name, "md5sums", &conffile_list); + + remove_package(status_package_num, 0); + } else { + printf("Unpacking %s (from %s)...\n", package_name, deb_file->filename); + } + + /* Extract control.tar.gz to /var/lib/dpkg/info/.filename */ + info_prefix = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, ""); + archive_handle = init_archive_deb_ar(deb_file->filename); + init_archive_deb_control(archive_handle); + + accept_list = NULL; + i = 0; + while (i < ARRAY_SIZE(all_control_files)) { + char *c = xasprintf("./%s", all_control_files[i]); + llist_add_to(&accept_list, c); + i++; + } + archive_handle->dpkg__sub_archive->accept = accept_list; + archive_handle->dpkg__sub_archive->filter = filter_accept_list; + archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; + archive_handle->dpkg__sub_archive->dpkg__buffer = info_prefix; + archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; + unpack_ar_archive(archive_handle); + + /* Run the preinst prior to extracting */ + run_package_script_or_die(package_name, "preinst"); + + /* Don't overwrite existing config files */ + if (!(option_mask32 & OPT_force_confnew)) + append_control_file_to_llist(package_name, "conffiles", &conffile_list); + + /* Extract data.tar.gz to the root directory */ + archive_handle = init_archive_deb_ar(deb_file->filename); + init_archive_deb_data(archive_handle); + archive_handle->dpkg__sub_archive->accept = conffile_list; + /* Why ARCHIVE_REMEMBER_NAMES? + * We want names collected in ->passed list even if conffile_list + * is NULL (otherwise get_header_tar may optimize name saving out): + */ + archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_REMEMBER_NAMES | ARCHIVE_UNLINK_OLD; + archive_handle->dpkg__sub_archive->filter = filter_rename_config; + archive_handle->dpkg__sub_archive->action_data = data_extract_all_prefix; + archive_handle->dpkg__sub_archive->dpkg__buffer = (char*)"/"; /* huh? */ + unpack_ar_archive(archive_handle); + + /* Create the list file */ + list_filename = xasprintf("/var/lib/dpkg/info/%s.%s", package_name, "list"); + out_stream = xfopen_for_write(list_filename); + archive_handle->dpkg__sub_archive->passed = llist_rev(archive_handle->dpkg__sub_archive->passed); + while (archive_handle->dpkg__sub_archive->passed) { + char *filename = llist_pop(&archive_handle->dpkg__sub_archive->passed); + /* the leading . has been stripped by data_extract_all_prefix already */ + fprintf(out_stream, "%s\n", filename); + free(filename); + } + fclose(out_stream); + + /* change status */ + set_status(status_num, "install", 1); + set_status(status_num, "unpacked", 3); + + free(info_prefix); + free(list_filename); +} + +static 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); + + printf("Setting up %s (%s)...\n", package_name, package_version); + + /* Run the postinst script */ + /* TODO: handle failure gracefully */ + run_package_script_or_die(package_name, "postinst"); + + /* Change status to reflect success */ + set_status(status_num, "install", 1); + set_status(status_num, "installed", 3); +} + +int dpkg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dpkg_main(int argc UNUSED_PARAM, char **argv) +{ + deb_file_t **deb_file = NULL; + status_node_t *status_node; + char *str_f; + int opt; + int package_num; + int deb_count = 0; + int state_status; + int status_num; + int i; +#if ENABLE_LONG_OPTS + static const char dpkg_longopts[] ALIGN1 = +// FIXME: we use -C non-compatibly, should be: +// "-C|--audit Check for broken package(s)" + "configure\0" No_argument "C" + "force\0" Required_argument "F" + "install\0" No_argument "i" + "list\0" No_argument "l" + "purge\0" No_argument "P" + "remove\0" No_argument "r" + "unpack\0" No_argument "u" + "force-depends\0" No_argument "\xff" + "force-confnew\0" No_argument "\xfe" + "force-confold\0" No_argument "\xfd" + ; +#endif + + INIT_G(); + + opt = getopt32long(argv, "CilPruF:", dpkg_longopts, &str_f); + argv += optind; + //if (opt & OPT_configure) ... // -C + if (opt & OPT_force) { // -F (--force in official dpkg) + if (strcmp(str_f, "depends") == 0) + opt |= OPT_force_ignore_depends; + else if (strcmp(str_f, "confnew") == 0) + opt |= OPT_force_confnew; + else if (strcmp(str_f, "confold") == 0) + opt |= OPT_force_confold; + else + bb_show_usage(); + option_mask32 = opt; + } + //if (opt & OPT_install) ... // -i + //if (opt & OPT_list_installed) ... // -l + //if (opt & OPT_purge) ... // -P + //if (opt & OPT_remove) ... // -r + //if (opt & OPT_unpack) ... // -u (--unpack in official dpkg) + if (!(opt & OPTMASK_cmd) /* no cmd */ + || ((opt & OPTMASK_cmd) & ((opt & OPTMASK_cmd)-1)) /* more than one cmd */ + ) { + bb_show_usage(); + } + +/* puts("(Reading database ... xxxxx files and directories installed.)"); */ + index_status_file("/var/lib/dpkg/status"); + + /* if the list action was given print the installed packages and exit */ + if (opt & OPT_list_installed) { + list_packages(argv[0]); /* param can be NULL */ + return EXIT_SUCCESS; + } + + /* Read arguments and store relevant info in structs */ + while (*argv) { + /* deb_count = nb_elem - 1 and we need nb_elem + 1 to allocate terminal node [NULL pointer] */ + deb_file = xrealloc_vector(deb_file, 2, deb_count); + deb_file[deb_count] = xzalloc(sizeof(deb_file[0][0])); + if (opt & (OPT_install | OPT_unpack)) { + /* -i/-u: require filename */ + archive_handle_t *archive_handle; + llist_t *control_list = NULL; + + /* Extract the control file */ + llist_add_to(&control_list, (char*)"./control"); + archive_handle = init_archive_deb_ar(argv[0]); + init_archive_deb_control(archive_handle); + deb_file[deb_count]->control_file = deb_extract_control_file_to_buffer(archive_handle, control_list); + if (deb_file[deb_count]->control_file == NULL) { + bb_simple_error_msg_and_die("can't extract control file"); + } + deb_file[deb_count]->filename = xstrdup(argv[0]); + package_num = fill_package_struct(deb_file[deb_count]->control_file); + + if (package_num == -1) { + bb_error_msg("invalid control file in %s", argv[0]); + argv++; + continue; + } + deb_file[deb_count]->package = (unsigned) package_num; + + /* Add the package to the status hashtable */ + if (opt & (OPT_unpack | OPT_install)) { + /* Try and find a currently installed version of this package */ + status_num = search_status_hashtable(name_hashtable[package_hashtable[deb_file[deb_count]->package]->name]); + /* If no previous entry was found initialise a new entry */ + if (status_hashtable[status_num] == NULL + || status_hashtable[status_num]->status == 0 + ) { + status_node = xmalloc(sizeof(status_node_t)); + status_node->package = deb_file[deb_count]->package; + /* reinstreq isn't 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_hashtable[status_num] = status_node; + } else { + set_status(status_num, "install", 1); + set_status(status_num, "reinstreq", 2); + } + } + } else if (opt & (OPT_configure | OPT_purge | OPT_remove)) { + /* -C/-p/-r: require package name */ + deb_file[deb_count]->package = search_package_hashtable( + search_name_hashtable(argv[0]), + search_name_hashtable("ANY"), VER_ANY); + if (package_hashtable[deb_file[deb_count]->package] == NULL) { + bb_error_msg_and_die("package %s is uninstalled or unknown", argv[0]); + } + package_num = deb_file[deb_count]->package; + status_num = search_status_hashtable(name_hashtable[package_hashtable[package_num]->name]); + state_status = get_status(status_num, 3); + + /* check package status is "installed" */ + if (opt & OPT_remove) { + if (strcmp(name_hashtable[state_status], "not-installed") == 0 + || strcmp(name_hashtable[state_status], "config-files") == 0 + ) { + bb_error_msg_and_die("%s is already removed", name_hashtable[package_hashtable[package_num]->name]); + } + set_status(status_num, "deinstall", 1); + } else if (opt & OPT_purge) { + /* if package status is "conf-files" then its ok */ + if (strcmp(name_hashtable[state_status], "not-installed") == 0) { + bb_error_msg_and_die("%s is already purged", name_hashtable[package_hashtable[package_num]->name]); + } + set_status(status_num, "purge", 1); + } + } + deb_count++; + argv++; + } + if (!deb_count) + bb_simple_error_msg_and_die("no package files specified"); + deb_file[deb_count] = NULL; + + /* Check that the deb file arguments are installable */ + if (!(opt & OPT_force_ignore_depends)) { + if (!check_deps(deb_file, 0 /*, deb_count*/)) { + bb_simple_error_msg_and_die("dependency check failed"); + } + } + + /* TODO: install or remove packages in the correct dependency order */ + for (i = 0; i < deb_count; i++) { + /* Remove or purge packages */ + if (opt & OPT_remove) { + remove_package(deb_file[i]->package, 1); + } + else if (opt & OPT_purge) { + purge_package(deb_file[i]->package); + } + else if (opt & OPT_unpack) { + unpack_package(deb_file[i]); + } + else if (opt & OPT_install) { + unpack_package(deb_file[i]); + /* package is configured in second pass below */ + } + else if (opt & OPT_configure) { + configure_package(deb_file[i]); + } + } + /* configure installed packages */ + if (opt & OPT_install) { + for (i = 0; i < deb_count; i++) + configure_package(deb_file[i]); + } + + write_status_file(deb_file); + + if (ENABLE_FEATURE_CLEAN_UP) { + 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++) { + 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++) { + free(status_hashtable[i]); + } + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/dpkg_deb.c b/busybox-1_37_0/archival/dpkg_deb.c new file mode 100644 index 000000000..dda931169 --- /dev/null +++ b/busybox-1_37_0/archival/dpkg_deb.c @@ -0,0 +1,134 @@ +/* vi: set sw=4 ts=4: */ +/* + * dpkg-deb packs, unpacks and provides information about Debian archives. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DPKG_DEB +//config: bool "dpkg-deb (29 kb)" +//config: default y +//config: select FEATURE_SEAMLESS_GZ +//config: help +//config: dpkg-deb unpacks and provides information about Debian archives. +//config: +//config: This implementation of dpkg-deb cannot pack archives. +//config: +//config: Unless you have a specific application which requires dpkg-deb, +//config: say N here. + +//applet:IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, BB_DIR_USR_BIN, BB_SUID_DROP, dpkg_deb)) + +//kbuild:lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o + +//usage:#define dpkg_deb_trivial_usage +//usage: "[-cefxX] FILE [DIR]" +//usage:#define dpkg_deb_full_usage "\n\n" +//usage: "Perform actions on Debian packages (.deb)\n" +//usage: "\n -c List files" +//usage: "\n -f Print control fields" +//usage: "\n -e Extract control files to DIR (default: ./DEBIAN)" +//usage: "\n -x Extract files to DIR (no default)" +//usage: "\n -X Verbose extract" +//usage: +//usage:#define dpkg_deb_example_usage +//usage: "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" + +#include "libbb.h" +#include "bb_archive.h" + +#define DPKG_DEB_OPT_CONTENTS 1 +#define DPKG_DEB_OPT_CONTROL 2 +#define DPKG_DEB_OPT_FIELD 4 +#define DPKG_DEB_OPT_EXTRACT_VERBOSE 8 +#define DPKG_DEB_OPT_EXTRACT 16 + +int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dpkg_deb_main(int argc UNUSED_PARAM, char **argv) +{ + archive_handle_t *ar_archive; + archive_handle_t *tar_archive; + llist_t *control_tar_llist = NULL; + unsigned opt; + const char *extract_dir; + + /* Setup the tar archive handle */ + tar_archive = init_handle(); + + /* Setup an ar archive handle that refers to the gzip sub archive */ + ar_archive = init_handle(); + ar_archive->dpkg__sub_archive = tar_archive; + ar_archive->filter = filter_accept_list_reassign; + + llist_add_to(&ar_archive->accept, (char*)"data.tar"); + llist_add_to(&control_tar_llist, (char*)"control.tar"); +#if ENABLE_FEATURE_SEAMLESS_GZ + llist_add_to(&ar_archive->accept, (char*)"data.tar.gz"); + llist_add_to(&control_tar_llist, (char*)"control.tar.gz"); +#endif +#if ENABLE_FEATURE_SEAMLESS_BZ2 + llist_add_to(&ar_archive->accept, (char*)"data.tar.bz2"); + llist_add_to(&control_tar_llist, (char*)"control.tar.bz2"); +#endif +#if ENABLE_FEATURE_SEAMLESS_LZMA + llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma"); + llist_add_to(&control_tar_llist, (char*)"control.tar.lzma"); +#endif +#if ENABLE_FEATURE_SEAMLESS_XZ + llist_add_to(&ar_archive->accept, (char*)"data.tar.xz"); + llist_add_to(&control_tar_llist, (char*)"control.tar.xz"); +#endif + + /* Must have 1 or 2 args */ + opt = getopt32(argv, "^" "cefXx" + "\0" "-1:?2:c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX" + ); + argv += optind; + //argc -= optind; + + extract_dir = argv[1]; + if (opt & DPKG_DEB_OPT_CONTENTS) { // -c + tar_archive->action_header = header_verbose_list; + if (extract_dir) + bb_show_usage(); + } + if (opt & DPKG_DEB_OPT_FIELD) { // -f + /* Print the entire control file */ +//TODO: standard tool accepts an optional list of fields to print + ar_archive->accept = control_tar_llist; + llist_add_to(&(tar_archive->accept), (char*)"./control"); + tar_archive->filter = filter_accept_list; + tar_archive->action_data = data_extract_to_stdout; + if (extract_dir) + bb_show_usage(); + } + if (opt & DPKG_DEB_OPT_CONTROL) { // -e + ar_archive->accept = control_tar_llist; + tar_archive->action_data = data_extract_all; + if (!extract_dir) + extract_dir = "./DEBIAN"; + } + if (opt & (DPKG_DEB_OPT_EXTRACT_VERBOSE | DPKG_DEB_OPT_EXTRACT)) { // -Xx + if (opt & DPKG_DEB_OPT_EXTRACT_VERBOSE) + tar_archive->action_header = header_list; + tar_archive->action_data = data_extract_all; + if (!extract_dir) + bb_show_usage(); + } + + /* Standard tool supports "-" */ + tar_archive->src_fd = ar_archive->src_fd = xopen_stdin(argv[0]); + + if (extract_dir) { + mkdir(extract_dir, 0777); /* bb_make_directory(extract_dir, 0777, 0) */ + xchdir(extract_dir); + } + + /* Do it */ + unpack_ar_archive(ar_archive); + + /* Cleanup */ + if (ENABLE_FEATURE_CLEAN_UP) + close(ar_archive->src_fd); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/gzip.c b/busybox-1_37_0/archival/gzip.c new file mode 100644 index 000000000..91bd4d09d --- /dev/null +++ b/busybox-1_37_0/archival/gzip.c @@ -0,0 +1,2258 @@ +/* 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. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* TODO: full support for -v for DESKTOP + * "/usr/bin/gzip -v a bogus aa" should say: +a: 85.1% -- replaced with a.gz +gzip: bogus: No such file or directory +aa: 85.1% -- replaced with aa.gz +*/ +//config:config GZIP +//config: bool "gzip (17 kb)" +//config: default y +//config: help +//config: gzip is used to compress files. +//config: It's probably the most widely used UNIX compression program. +//config: +//config:config FEATURE_GZIP_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on GZIP && LONG_OPTS +//config: +//config:config GZIP_FAST +//config: int "Trade memory for speed (0:small,slow - 2:fast,big)" +//config: default 0 +//config: range 0 2 +//config: depends on GZIP +//config: help +//config: Enable big memory options for gzip. +//config: 0: small buffers, small hash-tables +//config: 1: larger buffers, larger hash-tables +//config: 2: larger buffers, largest hash-tables +//config: Larger models may give slightly better compression +//config: +//config:config FEATURE_GZIP_LEVELS +//config: bool "Enable compression levels" +//config: default n +//config: depends on GZIP +//config: help +//config: Enable support for compression levels 4-9. The default level +//config: is 6. If levels 1-3 are specified, 4 is used. +//config: If this option is not selected, -N options are ignored and -6 +//config: is used. +//config: +//config:config FEATURE_GZIP_DECOMPRESS +//config: bool "Enable decompression" +//config: default y +//config: depends on GZIP || GUNZIP || ZCAT +//config: help +//config: Enable -d (--decompress) and -t (--test) options for gzip. +//config: This will be automatically selected if gunzip or zcat is +//config: enabled. + +//applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_GZIP) += gzip.o + +//usage:#define gzip_trivial_usage +//usage: "[-cfk" IF_FEATURE_GZIP_DECOMPRESS("dt") IF_FEATURE_GZIP_LEVELS("123456789") "] [FILE]..." +//usage:#define gzip_full_usage "\n\n" +//usage: "Compress FILEs (or stdin)\n" +//usage: IF_FEATURE_GZIP_LEVELS( +//usage: "\n -1..9 Compression level" +//usage: ) +//usage: IF_FEATURE_GZIP_DECOMPRESS( +//usage: "\n -d Decompress" +//usage: ) +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -k Keep input files" +//usage: IF_FEATURE_GZIP_DECOMPRESS( +//usage: "\n -t Test integrity" +//usage: ) +//usage: +//usage:#define gzip_example_usage +//usage: "$ ls -la /tmp/busybox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" +//usage: "$ gzip /tmp/busybox.tar\n" +//usage: "$ ls -la /tmp/busybox*\n" +//usage: "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" + +#include "libbb.h" +#include "bb_archive.h" + +/* =========================================================================== + */ +//#define DEBUG 1 +/* Diagnostic functions */ +#ifdef DEBUG +static int verbose; +# define Assert(cond,msg) { if (!(cond)) bb_simple_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 + +/* =========================================================================== + */ +#if CONFIG_GZIP_FAST == 0 +# define SMALL_MEM +#elif CONFIG_GZIP_FAST == 1 +# define MEDIUM_MEM +#elif CONFIG_GZIP_FAST == 2 +# define BIG_MEM +#else +# error "Invalid CONFIG_GZIP_FAST value" +#endif + +#ifndef INBUFSIZ +# ifdef SMALL_MEM +# define INBUFSIZ 0x2000 /* input buffer size */ +# else +# define INBUFSIZ 0x8000 /* input buffer size */ +# endif +#endif + +#ifndef OUTBUFSIZ +# ifdef SMALL_MEM +# define OUTBUFSIZ 8192 /* output buffer size */ +# else +# define OUTBUFSIZ 16384 /* output buffer size */ +# endif +#endif + +#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 + +/* 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. + */ + +#ifndef MAX_PATH_LEN +# define MAX_PATH_LEN 1024 /* max pathname length */ +#endif + +#define seekable() 0 /* force sequential output */ +#define translate_eol 0 /* no option -a yet */ + +#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". + */ + +#ifdef MAX_EXT_CHARS +# define MAX_SUFFIX MAX_EXT_CHARS +#else +# define MAX_SUFFIX 30 +#endif + +/* =========================================================================== + * 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 + +#define HASH_SIZE (unsigned)(1<= 4. + */ + + 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. + */ + + good_match = 8, +/* 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. + */ + + nice_match = 128, /* 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. + */ +#endif /* ENABLE_FEATURE_GZIP_LEVELS */ +}; + +struct globals { +/* =========================================================================== */ +/* global buffers, allocated once */ + +#define DECLARE(type, array, size) \ + type * array +#define ALLOC(type, array, size) \ + array = xzalloc((size_t)(((size)+1L)/2) * 2*sizeof(type)) +#define FREE(array) \ + do { free(array); array = NULL; } while (0) + + /* buffer for literals or lengths */ + /* DECLARE(uch, l_buf, LIT_BUFSIZE); */ + DECLARE(uch, l_buf, INBUFSIZ); + + DECLARE(ush, d_buf, DIST_BUFSIZE); + DECLARE(uch, outbuf, OUTBUFSIZ); + +/* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least WSIZE + * bytes. With this organization, matches are limited to a distance of + * WSIZE-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: limit the window size to WSIZE+BSZ if SMALL_MEM (the code would + * be less efficient). + */ + DECLARE(uch, window, 2L * WSIZE); + +/* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + /* DECLARE(Pos, prev, WSIZE); */ + DECLARE(ush, prev, 1L << BITS); + +/* Heads of the hash chains or 0. */ + /* DECLARE(Pos, head, 1<= HASH_BITS + */ +#define H_SHIFT ((HASH_BITS+MIN_MATCH-1) / MIN_MATCH) + +/* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + unsigned prev_length; + + unsigned strstart; /* start of string to insert */ + unsigned match_start; /* start of matching string */ + unsigned lookahead; /* number of valid bytes ahead in window */ + +/* number of input bytes */ + ulg isize; /* only 32 bits stored in .gz file */ + +/* bbox always use stdin/stdout */ +#define ifd STDIN_FILENO /* input file descriptor */ +#define ofd STDOUT_FILENO /* output file descriptor */ + +#ifdef DEBUG + unsigned insize; /* valid bytes in l_buf */ +#endif + unsigned outcnt; /* bytes in output buffer */ + smallint eofile; /* flag set at end of input file */ + +/* =========================================================================== + * Local data used by the "bit string" routines. + */ + +/* Output buffer. bits are inserted starting at the bottom (least significant + * bits). + */ + unsigned bi_buf; /* was unsigned short */ + +#undef BUF_SIZE +#define BUF_SIZE (int)(8 * sizeof(G1.bi_buf)) + +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + unsigned bi_valid; + +#ifdef DEBUG + ulg bits_sent; /* bit length of the compressed data */ +# define DEBUG_bits_sent(v) (void)(G1.bits_sent v) +#else +# define DEBUG_bits_sent(v) ((void)0) +#endif +}; + +#define G1 (*(ptr_to_globals - 1)) + +/* =========================================================================== + * Write the output buffer outbuf[0..outcnt-1] and update bytes_out. + * (used for the compressed data only) + */ +static void flush_outbuf(void) +{ + if (G1.outcnt == 0) + return; + + xwrite(ofd, (char *) G1.outbuf, G1.outcnt); + G1.outcnt = 0; +} + +/* =========================================================================== + */ +/* put_8bit is used for the compressed output */ +#define put_8bit(c) \ +do { \ + G1.outbuf[G1.outcnt++] = (c); \ + if (G1.outcnt == OUTBUFSIZ) \ + flush_outbuf(); \ +} while (0) + +/* Output a 16 bit value, lsb first */ +static void put_16bit(ush w) +{ + /* GCC 4.2.1 won't optimize out redundant loads of G1.outcnt + * (probably because of fear of aliasing with G1.outbuf[] + * stores), do it explicitly: + */ + unsigned outcnt = G1.outcnt; + uch *dst = &G1.outbuf[outcnt]; + +#if BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN + if (outcnt < OUTBUFSIZ-2) { + /* Common case */ + ush *dst16 = (void*) dst; + *dst16 = w; /* unaligned LSB 16-bit store */ + G1.outcnt = outcnt + 2; + return; + } + *dst = (uch)w; + w >>= 8; + G1.outcnt = ++outcnt; +#else + *dst = (uch)w; + w >>= 8; + if (outcnt < OUTBUFSIZ-2) { + /* Common case */ + dst[1] = w; + G1.outcnt = outcnt + 2; + return; + } + G1.outcnt = ++outcnt; +#endif + + /* Slowpath: we will need to do flush_outbuf() */ + if (outcnt == OUTBUFSIZ) + flush_outbuf(); /* here */ + put_8bit(w); /* or here */ +} + +#define OPTIMIZED_PUT_32BIT (CONFIG_GZIP_FAST > 0 && BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN) +static void put_32bit(ulg n) +{ + if (OPTIMIZED_PUT_32BIT) { + unsigned outcnt = G1.outcnt; + if (outcnt < OUTBUFSIZ-4) { + /* Common case */ + ulg *dst32 = (void*) &G1.outbuf[outcnt]; + *dst32 = n; /* unaligned LSB 32-bit store */ + //bb_error_msg("%p", dst32); // store alignment debugging + G1.outcnt = outcnt + 4; + return; + } + } + put_16bit(n); + put_16bit(n >> 16); +} +static ALWAYS_INLINE void flush_outbuf_if_32bit_optimized(void) +{ + /* If put_32bit() performs 32bit stores && it is used in send_bits() */ + if (OPTIMIZED_PUT_32BIT && BUF_SIZE > 16) + flush_outbuf(); +} + +/* =========================================================================== + * 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 void updcrc(uch *s, unsigned n) +{ + G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); +} + +/* =========================================================================== + * 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 unsigned file_read(void *buf, unsigned size) +{ + unsigned len; + + Assert(G1.insize == 0, "l_buf not empty"); + + len = safe_read(ifd, buf, size); + if (len == (unsigned)(-1) || len == 0) + return len; + + updcrc(buf, len); + G1.isize += len; + return len; +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +static void send_bits(unsigned value, unsigned length) +{ + unsigned new_buf; + +#ifdef DEBUG + Tracev((stderr, " l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + DEBUG_bits_sent(+= length); +#endif + BUILD_BUG_ON(BUF_SIZE != 32 && BUF_SIZE != 16); + + new_buf = G1.bi_buf | (value << G1.bi_valid); + /* NB: the above may sometimes do "<< 32" shift (undefined) + * if check below is changed to "length > BUF_SIZE" instead of >= */ + length += G1.bi_valid; + + /* If bi_buf is full */ + if (length >= BUF_SIZE) { + /* ...use (valid) bits from bi_buf and + * (BUF_SIZE - bi_valid) bits from value, + * leaving (width - (BUF_SIZE-bi_valid)) unused bits in value. + */ + value >>= (BUF_SIZE - G1.bi_valid); + if (BUF_SIZE == 32) { + put_32bit(new_buf); + } else { /* 16 */ + put_16bit(new_buf); + } + new_buf = value; + length -= BUF_SIZE; + } + G1.bi_buf = new_buf; + G1.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) +{ + unsigned res = 0; + + while (1) { + res |= code & 1; + if (--len <= 0) return res; + code >>= 1; + res <<= 1; + } +} + +/* =========================================================================== + * Write out any remaining bits in an incomplete byte. + */ +static void bi_windup(void) +{ + unsigned bits = G1.bi_buf; + int cnt = G1.bi_valid; + + while (cnt > 0) { + put_8bit(bits); + bits >>= 8; + cnt -= 8; + } + G1.bi_buf = 0; + G1.bi_valid = 0; + DEBUG_bits_sent(= (G1.bits_sent + 7) & ~7); +} + +/* =========================================================================== + * Copy a stored block to the zip file, storing first the length and its + * one's complement if requested. + */ +static void copy_block(const char *buf, unsigned len, int header) +{ + bi_windup(); /* align on byte boundary */ + + if (header) { + unsigned v = ((uint16_t)len) | ((~len) << 16); + put_32bit(v); + DEBUG_bits_sent(+= 2 * 16); + } + DEBUG_bits_sent(+= (ulg) len << 3); + while (len--) { + put_8bit(*buf++); + } + /* The above can 32-bit misalign outbuf */ + if (G1.outcnt & 3) /* syscalls are expensive, is it really misaligned? */ + flush_outbuf_if_32bit_optimized(); +} + +/* =========================================================================== + * 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(void) +{ + unsigned n, m; + unsigned more = WINDOW_SIZE - G1.lookahead - G1.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) -1) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + } else if (G1.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 == 2 * WSIZE, "no sliding with BIG_MEM"); + + memcpy(G1.window, G1.window + WSIZE, WSIZE); + G1.match_start -= WSIZE; + G1.strstart -= WSIZE; /* we now have strstart >= MAX_DIST: */ + + G1.block_start -= WSIZE; + + for (n = 0; n < HASH_SIZE; n++) { + m = head[n]; + head[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0); + } + for (n = 0; n < WSIZE; n++) { + m = G1.prev[n]; + G1.prev[n] = (Pos) (m >= WSIZE ? m - WSIZE : 0); + /* 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 (!G1.eofile) { + n = file_read(G1.window + G1.strstart + G1.lookahead, more); + if (n == 0 || n == (unsigned) -1) { + G1.eofile = 1; + } else { + G1.lookahead += n; + } + } +} +/* Both users fill window with the same loop: */ +static void fill_window_if_needed(void) +{ + while (G1.lookahead < MIN_LOOKAHEAD && !G1.eofile) + fill_window(); +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 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 */ + uch *scan = G1.window + G1.strstart; /* current string */ + uch *match; /* matched string */ + int len; /* length of current match */ + int best_len = G1.prev_length; /* best match length so far */ + IPos limit = G1.strstart > (IPos) MAX_DIST ? G1.strstart - (IPos) MAX_DIST : 0; + /* 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 + uch *strend = G1.window + G1.strstart + MAX_MATCH; + uch scan_end1 = scan[best_len - 1]; + uch scan_end = scan[best_len]; + + /* Do not waste too much time if we already have a good match: */ + if (G1.prev_length >= good_match) { + chain_length >>= 2; + } + Assert(G1.strstart <= WINDOW_SIZE - MIN_LOOKAHEAD, "insufficient lookahead"); + + do { + Assert(cur_match < G1.strstart, "no future"); + match = G1.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) { + G1.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 = G1.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(G1.window + match, G1.window + start, length) != 0) { + bb_error_msg(" start %d, match %d, length %d", start, match, length); + bb_simple_error_msg("invalid match"); + } + if (verbose > 1) { + bb_error_msg("\\[%d,%d]", start - match, length); + do { + bb_putchar_stderr(G1.window[start++]); + } while (--length != 0); + } +} +#else +# define check_match(start, match, length) ((void)0) +#endif + + +/* 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() + * Allocate the match buffer, initialize the various tables [and save + * the location of the internal file attribute (ascii/binary) and + * method (DEFLATE/STORE) -- deleted in bbox] + * + * void ct_tally(int dist, int lc); + * Save the match info and tally the frequency counts. + * + * ulg 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. + */ + +#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 */ + +/* extra bits for each length code */ +static const uint8_t extra_lbits[LENGTH_CODES] ALIGN1 = { + 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 +}; + +/* extra bits for each distance code */ +static const uint8_t extra_dbits[D_CODES] ALIGN1 = { + 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 +}; + +/* extra bits for each bit length code */ +static const uint8_t extra_blbits[BL_CODES] ALIGN1 = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7 }; + +/* number of codes at each bit length for an optimal tree */ +static const uint8_t bl_order[BL_CODES] ALIGN1 = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; + +#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. + */ +#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) */ + +/* =========================================================================== +*/ +/* 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 */ + +typedef struct tree_desc { + ct_data *dyn_tree; /* the dynamic tree */ + ct_data *static_tree; /* corresponding static tree or NULL */ + const uint8_t *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; + +struct globals2 { + + ush heap[HEAP_SIZE]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + 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. + */ + + ct_data dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + ct_data dyn_dtree[2 * D_CODES + 1]; /* distance tree */ + + 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). + */ + + ct_data static_dtree[D_CODES]; + +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + + ct_data bl_tree[2 * BL_CODES + 1]; + +/* Huffman tree for the bit lengths */ + + tree_desc l_desc; + tree_desc d_desc; + tree_desc bl_desc; + + /* was "ush", but "unsigned" results in smaller code */ + unsigned bl_count[MAX_BITS + 1]; + +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + + uch depth[2 * L_CODES + 1]; + +/* Depth of each subtree used as tie breaker for trees of equal frequency */ + + uch length_code[MAX_MATCH - MIN_MATCH + 1]; + +/* length code for each normalized match length (0 == MIN_MATCH) */ + + 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. + */ + + int base_length[LENGTH_CODES]; + +/* First normalized length for each code (0 = MIN_MATCH) */ + + int base_dist[D_CODES]; + +/* First normalized distance for each code (0 = distance of 1) */ + + 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. + */ + + unsigned last_lit; /* running index in l_buf */ + unsigned last_dist; /* running index in d_buf */ + unsigned last_flags; /* running index in flag_buf */ + uch flags; /* current flags not yet saved in flag_buf */ + 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. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + +// ulg compressed_len; /* total bit length of compressed file */ +}; + +#define G2ptr ((struct globals2*)(ptr_to_globals)) +#define G2 (*G2ptr) + +/* =========================================================================== + */ +#ifndef DEBUG +/* Send a code of the given tree. c and tree must not have side effects */ +# define SEND_CODE(c, tree) send_bits(tree[c].Code, tree[c].Len) +#else +# define SEND_CODE(c, tree) \ +{ \ + if (verbose > 1) bb_error_msg("\ncd %3d ", (c)); \ + send_bits(tree[c].Code, tree[c].Len); \ +} +#endif + +#define D_CODE(dist) \ + ((dist) < 256 ? G2.dist_code[dist] : G2.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. + */ + +/* =========================================================================== + * Initialize a new block. + */ +static void init_block(void) +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) + G2.dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) + G2.dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) + G2.bl_tree[n].Freq = 0; + + G2.dyn_ltree[END_BLOCK].Freq = 1; + G2.opt_len = G2.static_len = 0; + G2.last_lit = G2.last_dist = G2.last_flags = 0; + G2.flags = 0; + G2.flag_bit = 1; +} + +/* =========================================================================== + * 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). + */ + +/* 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 && G2.depth[n] <= G2.depth[m])) + +static void pqdownheap(const ct_data *tree, int k) +{ + int v = G2.heap[k]; + int j = k << 1; /* left son of k */ + + while (j <= G2.heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < G2.heap_len && SMALLER(tree, G2.heap[j + 1], G2.heap[j])) + j++; + + /* Exit if v is smaller than both sons */ + if (SMALLER(tree, v, G2.heap[j])) + break; + + /* Exchange v with the smallest son */ + G2.heap[k] = G2.heap[j]; + k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + G2.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(const tree_desc *desc) +{ +#define tree desc->dyn_tree + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int overflow; /* number of elements with bit length too large */ + + for (bits = 0; bits < ARRAY_SIZE(G2.bl_count); bits++) + G2.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[G2.heap[G2.heap_max]].Len = 0; /* root of the heap */ + + overflow = 0; + for (h = G2.heap_max + 1; h < HEAP_SIZE; h++) { + ulg f; /* frequency */ + int xbits; /* extra bits */ + + n = G2.heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > desc->max_length) { + bits = desc->max_length; + overflow++; + } + tree[n].Len = (ush) bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > desc->max_code) + continue; /* not a leaf node */ + + G2.bl_count[bits]++; + xbits = 0; + if (n >= desc->extra_base) + xbits = desc->extra_bits[n - desc->extra_base]; + f = tree[n].Freq; + G2.opt_len += f * (bits + xbits); + + if (desc->static_tree) + G2.static_len += f * (desc->static_tree[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 = desc->max_length - 1; + while (G2.bl_count[bits] == 0) + bits--; + G2.bl_count[bits]--; /* move one leaf down the tree */ + G2.bl_count[bits + 1] += 2; /* move one overflow item as its brother */ + G2.bl_count[desc->max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[desc->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 = desc->max_length; bits != 0; bits--) { + n = G2.bl_count[bits]; + while (n != 0) { + m = G2.heap[--h]; + if (m > desc->max_code) + continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr, "code %d bits %d->%d\n", m, tree[m].Len, bits)); + G2.opt_len += ((int32_t) bits - tree[m].Len) * tree[m].Freq; + tree[m].Len = bits; + } + n--; + } + } +#undef tree +} + +/* =========================================================================== + * 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) +{ + /* next_code[] and code used to be "ush", but "unsigned" results in smaller code */ + unsigned next_code[MAX_BITS + 1]; /* next code value for each bit length */ + unsigned 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 + G2.bl_count[bits - 1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert(code + G2.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 != G2.static_ltree, + (stderr, "\nn %3d %c l %2d c %4x (%x) ", n, + (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. + */ + +/* Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. */ + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + +#define PQREMOVE(tree, top) \ +do { \ + top = G2.heap[SMALLEST]; \ + G2.heap[SMALLEST] = G2.heap[G2.heap_len--]; \ + pqdownheap(tree, SMALLEST); \ +} while (0) + +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. + */ + G2.heap_len = 0; + G2.heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + G2.heap[++G2.heap_len] = max_code = n; + G2.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 (G2.heap_len < 2) { + int new = G2.heap[++G2.heap_len] = (max_code < 2 ? ++max_code : 0); + + tree[new].Freq = 1; + G2.depth[new] = 0; + G2.opt_len--; + if (stree) + G2.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 = G2.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 = G2.heap[SMALLEST]; /* m = node of next least frequency */ + + G2.heap[--G2.heap_max] = n; /* keep the nodes sorted by frequency */ + G2.heap[--G2.heap_max] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + G2.depth[node] = MAX(G2.depth[n], G2.depth[m]) + 1; + tree[n].Dad = tree[m].Dad = (ush) node; +#ifdef DUMP_BL_TREE + if (tree == G2.bl_tree) { + bb_error_msg("\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 */ + G2.heap[SMALLEST] = node++; + pqdownheap(tree, SMALLEST); + } while (G2.heap_len >= 2); + + G2.heap[--G2.heap_max] = G2.heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes(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 = 0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; + nextlen = tree[n + 1].Len; + if (++count < max_count && curlen == nextlen) + continue; + + if (count < min_count) { + G2.bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) + G2.bl_tree[curlen].Freq++; + G2.bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + G2.bl_tree[REPZ_3_10].Freq++; + } else { + G2.bl_tree[REPZ_11_138].Freq++; + } + count = 0; + prevlen = curlen; + + max_count = 7; + min_count = 4; + if (nextlen == 0) { + max_count = 138; + min_count = 3; + } else if (curlen == nextlen) { + max_count = 6; + min_count = 3; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +static void send_tree(const 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, G2.bl_tree); + } while (--count); + } else if (curlen != 0) { + if (curlen != prevlen) { + SEND_CODE(curlen, G2.bl_tree); + count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + SEND_CODE(REP_3_6, G2.bl_tree); + send_bits(count - 3, 2); + } else if (count <= 10) { + SEND_CODE(REPZ_3_10, G2.bl_tree); + send_bits(count - 3, 3); + } else { + SEND_CODE(REPZ_11_138, G2.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 int build_bl_tree(void) +{ + 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(G2.dyn_ltree, G2.l_desc.max_code); + scan_tree(G2.dyn_dtree, G2.d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(&G2.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 (G2.bl_tree[bl_order[max_blindex]].Len != 0) + break; + } + /* Update opt_len to include the bit length tree and counts */ + G2.opt_len += 3 * (max_blindex + 1) + 5 + 5 + 4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.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(G2.bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", (long)G1.bits_sent)); + + send_tree((ct_data *) G2.dyn_ltree, lcodes - 1); /* send the literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", (long)G1.bits_sent)); + + send_tree((ct_data *) G2.dyn_dtree, dcodes - 1); /* send the distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", (long)G1.bits_sent)); +} + +/* =========================================================================== + * 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) +{ + G1.l_buf[G2.last_lit++] = lc; + if (dist == 0) { + /* lc is the unmatched char */ + G2.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" + ); + + G2.dyn_ltree[G2.length_code[lc] + LITERALS + 1].Freq++; + G2.dyn_dtree[D_CODE(dist)].Freq++; + + G1.d_buf[G2.last_dist++] = dist; + G2.flags |= G2.flag_bit; + } + G2.flag_bit <<= 1; + + /* Output the flags if they fill a byte: */ + if ((G2.last_lit & 7) == 0) { + G2.flag_buf[G2.last_flags++] = G2.flags; + G2.flags = 0; + G2.flag_bit = 1; + } + /* Try to guess if it is profitable to stop the current block here */ + if ((G2.last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = G2.last_lit * 8L; + ulg in_length = (ulg) G1.strstart - G1.block_start; + int dcode; + + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += G2.dyn_dtree[dcode].Freq * (5L + extra_dbits[dcode]); + } + out_length >>= 3; + Trace((stderr, + "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + G2.last_lit, G2.last_dist, + (long)in_length, (long)out_length, + 100L - out_length * 100L / in_length)); + if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2) + return 1; + } + return (G2.last_lit == LIT_BUFSIZE - 1 || G2.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(const ct_data *ltree, const 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 (G2.last_lit != 0) do { + if ((lx & 7) == 0) + flag = G2.flag_buf[fx++]; + lc = G1.l_buf[lx++]; + if ((flag & 1) == 0) { + SEND_CODE(lc, ltree); /* send a literal byte */ + Tracecv(lc > ' ', (stderr, " '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = G2.length_code[lc]; + SEND_CODE(code + LITERALS + 1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= G2.base_length[code]; + send_bits(lc, extra); /* send the extra length bits */ + } + dist = G1.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 -= G2.base_dist[code]; + send_bits(dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + flag >>= 1; + } while (lx < G2.last_lit); + + SEND_CODE(END_BLOCK, ltree); +} + +/* =========================================================================== + * 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 void flush_block(const 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 */ + + G2.flag_buf[G2.last_flags] = G2.flags; /* Save the flags for the last 8 items */ + + /* Construct the literal and distance trees */ + build_tree(&G2.l_desc); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.static_len)); + + build_tree(&G2.d_desc); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", (long)G2.opt_len, (long)G2.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 = (G2.opt_len + 3 + 7) >> 3; + static_lenb = (G2.static_len + 3 + 7) >> 3; + + Trace((stderr, + "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + (unsigned long)opt_lenb, (unsigned long)G2.opt_len, + (unsigned long)static_lenb, (unsigned long)G2.static_len, + (unsigned long)stored_len, + G2.last_lit, G2.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: + */ +// seekable() is constant FALSE in busybox, and G2.compressed_len is disabled +// (this was the only user) +// if (stored_len <= opt_lenb && eof && G2.compressed_len == 0L && seekable()) { +// /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ +// if (buf == NULL) +// bb_error_msg("block vanished"); +// +// G2.compressed_len = stored_len << 3; +// copy_block(buf, (unsigned) stored_len, 0); /* without header */ +// } else + if (stored_len + 4 <= opt_lenb && buf != NULL) { + /* 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 */ +// G2.compressed_len = ((G2.compressed_len + 3 + 7) & ~7L) +// + ((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 *) G2.static_ltree, (ct_data *) G2.static_dtree); +// G2.compressed_len += 3 + G2.static_len; + } else { + send_bits((DYN_TREES << 1) + eof, 3); + send_all_trees(G2.l_desc.max_code + 1, G2.d_desc.max_code + 1, + max_blindex + 1); + compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree); +// G2.compressed_len += 3 + G2.opt_len; + } +// Assert(G2.compressed_len == G1.bits_sent, "bad compressed size"); + init_block(); + + if (eof) { + bi_windup(); +// G2.compressed_len += 7; /* align on byte boundary */ + } +// Tracev((stderr, "\ncomprlen %lu(%lu) ", +// (unsigned long)G2.compressed_len >> 3, +// (unsigned long)G2.compressed_len - 7 * eof)); + + return; /* was "return G2.compressed_len >> 3;" */ +} + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls 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)<= 0L \ + ? (char*)&G1.window[(unsigned)G1.block_start] \ + : (char*)NULL, \ + (ulg)G1.strstart - G1.block_start, \ + (eof) \ + ) + +/* Insert string s in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of s are valid + * (except for the last MIN_MATCH-1 bytes of the input file). */ +#define INSERT_STRING(s, match_head) \ +do { \ + UPDATE_HASH(G1.ins_h, G1.window[(s) + MIN_MATCH-1]); \ + G1.prev[(s) & WMASK] = match_head = head[G1.ins_h]; \ + head[G1.ins_h] = (s); \ +} while (0) + +static NOINLINE void deflate(void) +{ + 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 */ + unsigned match_length = MIN_MATCH - 1; /* length of best match */ + + /* Process the input block. */ + while (G1.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(G1.strstart, hash_head); + + /* Find the longest match, discarding those <= prev_length. + */ + G1.prev_length = match_length; + prev_match = G1.match_start; + match_length = MIN_MATCH - 1; + + if (hash_head != 0 && G1.prev_length < max_lazy_match + && G1.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 > G1.lookahead) + match_length = G1.lookahead; + + /* Ignore a length 3 match if it is too distant: */ + if (match_length == MIN_MATCH && G1.strstart - G1.match_start > TOO_FAR) { + /* If prev_match is also MIN_MATCH, G1.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 (G1.prev_length >= MIN_MATCH && match_length <= G1.prev_length) { + check_match(G1.strstart - 1, prev_match, G1.prev_length); + flush = ct_tally(G1.strstart - 1 - prev_match, G1.prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. + */ + G1.lookahead -= G1.prev_length - 1; + G1.prev_length -= 2; + do { + G1.strstart++; + INSERT_STRING(G1.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 (--G1.prev_length != 0); + match_available = 0; + match_length = MIN_MATCH - 1; + G1.strstart++; + if (flush) { + FLUSH_BLOCK(0); + G1.block_start = G1.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", G1.window[G1.strstart - 1])); + if (ct_tally(0, G1.window[G1.strstart - 1])) { + FLUSH_BLOCK(0); + G1.block_start = G1.strstart; + } + G1.strstart++; + G1.lookahead--; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + match_available = 1; + G1.strstart++; + G1.lookahead--; + } + Assert(G1.strstart <= G1.isize && G1.lookahead <= G1.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. + */ + fill_window_if_needed(); + } + if (match_available) + ct_tally(0, G1.window[G1.strstart - 1]); + + FLUSH_BLOCK(1); /* eof */ +} + +/* =========================================================================== + * Initialize the bit string routines. + */ +static void bi_init(void) +{ + //G1.bi_buf = 0; // globals are zeroed in pack_gzip() + //G1.bi_valid = 0; // globals are zeroed in pack_gzip() + //DEBUG_bits_sent(= 0L); // globals are zeroed in pack_gzip() +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new file + */ +static void lm_init(void) +{ + unsigned j; + + /* Initialize the hash table. */ + memset(head, 0, HASH_SIZE * sizeof(*head)); + /* prev will be initialized on the fly */ + + /* ??? reduce max_chain_length for binary files */ + + //G1.strstart = 0; // globals are zeroed in pack_gzip() + //G1.block_start = 0L; // globals are zeroed in pack_gzip() + + G1.lookahead = file_read(G1.window, + sizeof(int) <= 2 ? (unsigned) WSIZE : 2 * WSIZE); + + if (G1.lookahead == 0 || G1.lookahead == (unsigned) -1) { + G1.eofile = 1; + G1.lookahead = 0; + return; + } + //G1.eofile = 0; // globals are zeroed in pack_gzip() + + /* Make sure that we always have enough lookahead. This is important + * if input comes from a device such as a tty. + */ + fill_window_if_needed(); + + //G1.ins_h = 0; // globals are zeroed in pack_gzip() + for (j = 0; j < MIN_MATCH - 1; j++) + UPDATE_HASH(G1.ins_h, G1.window[j]); + /* If lookahead < MIN_MATCH, ins_h is garbage, but this is + * not important since only literal bytes will be emitted. + */ +} + +/* =========================================================================== + * Allocate the match buffer, initialize the various tables and save the + * location of the internal file attribute (ascii/binary) and method + * (DEFLATE/STORE). + * One callsite in zip() + */ +static void ct_init(void) +{ + int n; /* iterates over tree elements */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + +// //G2.compressed_len = 0L; // globals are zeroed in pack_gzip() + +#ifdef NOT_NEEDED + if (G2.static_dtree[0].Len != 0) + return; /* ct_init already called */ +#endif + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES - 1; code++) { + G2.base_length[code] = length; + for (n = 0; n < (1 << extra_lbits[code]); n++) { + G2.length_code[length++] = 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: + */ + G2.length_code[length - 1] = code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0; code < 16; code++) { + G2.base_dist[code] = dist; + for (n = 0; n < (1 << extra_dbits[code]); n++) { + G2.dist_code[dist++] = code; + } + } + Assert(dist == 256, "ct_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for (; code < D_CODES; code++) { + G2.base_dist[code] = dist << 7; + for (n = 0; n < (1 << (extra_dbits[code] - 7)); n++) { + G2.dist_code[256 + dist++] = code; + } + } + Assert(dist == 256, "ct_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + //for (n = 0; n <= MAX_BITS; n++) // globals are zeroed in pack_gzip() + // G2.bl_count[n] = 0; + + n = 0; + while (n <= 143) { + G2.static_ltree[n++].Len = 8; + //G2.bl_count[8]++; + } + //G2.bl_count[8] = 143 + 1; + while (n <= 255) { + G2.static_ltree[n++].Len = 9; + //G2.bl_count[9]++; + } + //G2.bl_count[9] = 255 - 143; + while (n <= 279) { + G2.static_ltree[n++].Len = 7; + //G2.bl_count[7]++; + } + //G2.bl_count[7] = 279 - 255; + while (n <= 287) { + G2.static_ltree[n++].Len = 8; + //G2.bl_count[8]++; + } + //G2.bl_count[8] += 287 - 279; + G2.bl_count[7] = 279 - 255; + G2.bl_count[8] = (143 + 1) + (287 - 279); + G2.bl_count[9] = 255 - 143; + /* 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 *) G2.static_ltree, L_CODES + 1); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + G2.static_dtree[n].Len = 5; + G2.static_dtree[n].Code = bi_reverse(n, 5); + } + + /* Initialize the first block of the first file: */ + init_block(); +} + +/* =========================================================================== + * Deflate in to out. + * IN assertions: the input and output buffers are cleared. + */ +static void zip(void) +{ + unsigned deflate_flags; + + //G1.outcnt = 0; // globals are zeroed in pack_gzip() + + /* Write the header to the gzip file. See algorithm.doc for the format */ + /* magic header for gzip files: 1F 8B */ + /* compression method: 8 (DEFLATED) */ + /* general flags: 0 */ + put_32bit(0x00088b1f); + put_32bit(0); /* Unix timestamp */ + + /* Write deflated file to zip file */ + G1.crc = ~0; + + bi_init(); + ct_init(); + lm_init(); + + deflate_flags = 0x300; /* extra flags. OS id = 3 (Unix) */ +#if ENABLE_FEATURE_GZIP_LEVELS + /* Note that comp_level < 4 do not exist in this version of gzip */ + if (comp_level_minus4 == 9 - 4) { + deflate_flags |= 0x02; /* SLOW flag */ + } +#endif + put_16bit(deflate_flags); + + /* The above 32-bit misaligns outbuf (10 bytes are stored), flush it */ + flush_outbuf_if_32bit_optimized(); + + deflate(); + + /* Write the crc and uncompressed size */ + put_32bit(~G1.crc); + put_32bit(G1.isize); + + flush_outbuf(); +} + +/* ======================================================================== */ +static +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM) +{ + /* Reinit G1.xxx except pointers to allocated buffers, and entire G2 */ + memset(&G1.crc, 0, (sizeof(G1) - offsetof(struct globals, crc)) + sizeof(G2)); + + /* Clear input and output buffers */ + //G1.outcnt = 0; +#ifdef DEBUG + //G1.insize = 0; +#endif + //G1.isize = 0; + + /* Reinit G2.xxx */ + G2.l_desc.dyn_tree = G2.dyn_ltree; + G2.l_desc.static_tree = G2.static_ltree; + G2.l_desc.extra_bits = extra_lbits; + G2.l_desc.extra_base = LITERALS + 1; + G2.l_desc.elems = L_CODES; + G2.l_desc.max_length = MAX_BITS; + //G2.l_desc.max_code = 0; + G2.d_desc.dyn_tree = G2.dyn_dtree; + G2.d_desc.static_tree = G2.static_dtree; + G2.d_desc.extra_bits = extra_dbits; + //G2.d_desc.extra_base = 0; + G2.d_desc.elems = D_CODES; + G2.d_desc.max_length = MAX_BITS; + //G2.d_desc.max_code = 0; + G2.bl_desc.dyn_tree = G2.bl_tree; + //G2.bl_desc.static_tree = NULL; + G2.bl_desc.extra_bits = extra_blbits, + //G2.bl_desc.extra_base = 0; + G2.bl_desc.elems = BL_CODES; + G2.bl_desc.max_length = MAX_BL_BITS; + //G2.bl_desc.max_code = 0; + +#if 0 + /* Saving of timestamp is disabled. Why? + * - it is not Y2038-safe. + * - some people want deterministic results + * (normally they'd use -n, but our -n is a nop). + * - it's bloat. + * Per RFC 1952, gzfile.time=0 is "no timestamp". + * If users will demand this to be reinstated, + * implement -n "don't save timestamp". + */ + struct stat s; + s.st_ctime = 0; + fstat(STDIN_FILENO, &s); + zip(s.st_ctime); +#else + zip(); +#endif + return 0; +} + +#if ENABLE_FEATURE_GZIP_LONG_OPTIONS +static const char gzip_longopts[] ALIGN1 = + "stdout\0" No_argument "c" + "to-stdout\0" No_argument "c" + "force\0" No_argument "f" + "verbose\0" No_argument "v" +#if ENABLE_FEATURE_GZIP_DECOMPRESS + "decompress\0" No_argument "d" + "uncompress\0" No_argument "d" + "test\0" No_argument "t" +#endif + "quiet\0" No_argument "q" + "fast\0" No_argument "1" + "best\0" No_argument "9" + "no-name\0" No_argument "n" + ; +#endif + +/* + * Linux kernel build uses gzip -d -n. We accept and ignore -n. + * Man page says: + * -n --no-name + * gzip: do not save the original file name and time stamp. + * (The original name is always saved if the name had to be truncated.) + * gunzip: do not restore the original file name/time even if present + * (remove only the gzip suffix from the compressed file name). + * This option is the default when decompressing. + * -N --name + * gzip: always save the original file name and time stamp (this is the default) + * gunzip: restore the original file name and time stamp if present. + */ + +int gzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +#if ENABLE_FEATURE_GZIP_DECOMPRESS +int gzip_main(int argc, char **argv) +#else +int gzip_main(int argc UNUSED_PARAM, char **argv) +#endif +{ + unsigned opt; +#if ENABLE_FEATURE_GZIP_LEVELS + static const struct { + uint8_t good; + uint8_t chain_shift; + uint8_t lazy2; + uint8_t nice2; + } gzip_level_config[6] = { + {4, 4, 4/2, 16/2}, /* Level 4 */ + {8, 5, 16/2, 32/2}, /* Level 5 */ + {8, 7, 16/2, 128/2}, /* Level 6 */ + {8, 8, 32/2, 128/2}, /* Level 7 */ + {32, 10, 128/2, 258/2}, /* Level 8 */ + {32, 12, 258/2, 258/2}, /* Level 9 */ + }; +#endif + + SET_PTR_TO_GLOBALS((char *)xzalloc(sizeof(struct globals)+sizeof(struct globals2)) + + sizeof(struct globals)); + + /* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */ +#if ENABLE_FEATURE_GZIP_LONG_OPTIONS + opt = getopt32long(argv, BBUNPK_OPTSTR IF_FEATURE_GZIP_DECOMPRESS("dt") "n123456789", gzip_longopts); +#else + opt = getopt32(argv, BBUNPK_OPTSTR IF_FEATURE_GZIP_DECOMPRESS("dt") "n123456789"); +#endif +#if ENABLE_FEATURE_GZIP_DECOMPRESS /* gunzip_main may not be visible... */ + if (opt & (BBUNPK_OPT_DECOMPRESS|BBUNPK_OPT_TEST)) /* -d and/or -t */ + return gunzip_main(argc, argv); +#endif +#if ENABLE_FEATURE_GZIP_LEVELS + opt >>= (BBUNPK_OPTSTRLEN IF_FEATURE_GZIP_DECOMPRESS(+ 2) + 1); /* drop cfkvq[dt]n bits */ + if (opt == 0) + opt = 1 << 5; /* default: 6 */ + opt = ffs(opt >> 4); /* Maps -1..-4 to [0], -5 to [1] ... -9 to [5] */ + + comp_level_minus4 = opt; + + max_chain_length = 1 << gzip_level_config[opt].chain_shift; + good_match = gzip_level_config[opt].good; + max_lazy_match = gzip_level_config[opt].lazy2 * 2; + nice_match = gzip_level_config[opt].nice2 * 2; +#endif + option_mask32 &= BBUNPK_OPTSTRMASK; /* retain only -cfkvq */ + + /* Allocate all global buffers (for DYN_ALLOC option) */ + ALLOC(uch, G1.l_buf, INBUFSIZ); + ALLOC(uch, G1.outbuf, OUTBUFSIZ); + ALLOC(ush, G1.d_buf, DIST_BUFSIZE); + ALLOC(uch, G1.window, 2L * WSIZE); + ALLOC(ush, G1.prev, 1L << BITS); + + /* Initialize the CRC32 table */ + global_crc32_new_table_le(); + + argv += optind; + return bbunpack(argv, pack_gzip, append_ext, "gz"); +} diff --git a/busybox-1_37_0/archival/libarchive/Kbuild.src b/busybox-1_37_0/archival/libarchive/Kbuild.src new file mode 100644 index 000000000..d2f284b08 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/Kbuild.src @@ -0,0 +1,98 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2004 by Erik Andersen +# +# Licensed under GPLv2 or later, see file LICENSE in this source tree. + +lib-y:= common.o + +COMMON_FILES:= \ +\ + data_skip.o \ + data_extract_all.o \ + data_extract_to_stdout.o \ +\ + unsafe_symlink_target.o \ +\ + filter_accept_all.o \ + filter_accept_list.o \ + filter_accept_reject_list.o \ +\ + header_skip.o \ + header_list.o \ + header_verbose_list.o \ +\ + seek_by_read.o \ + seek_by_jump.o \ +\ + data_align.o \ + find_list_entry.o \ + init_handle.o + +DPKG_FILES:= \ + unpack_ar_archive.o \ + filter_accept_list_reassign.o \ + unsafe_prefix.o \ + get_header_ar.o \ + get_header_tar.o \ + get_header_tar_gz.o \ + get_header_tar_bz2.o \ + get_header_tar_lzma.o \ + get_header_tar_xz.o \ + +INSERT + +lib-$(CONFIG_DPKG) += $(DPKG_FILES) +lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) + +lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o +lib-$(CONFIG_CPIO) += get_header_cpio.o +lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o +lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o +lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o +lib-$(CONFIG_UNLZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o +lib-$(CONFIG_LZOPCAT) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o +lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o +# 'bzip2 -d', bunzip2 or bzcat selects FEATURE_BZIP2_DECOMPRESS +lib-$(CONFIG_FEATURE_BZIP2_DECOMPRESS) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_UNZIP_BZIP2) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_LZCAT) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_LZMA) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_FEATURE_UNZIP_LZMA) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_XZCAT) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_XZ) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_FEATURE_UNZIP_XZ) += open_transformer.o decompress_unxz.o +# 'gzip -d', gunzip or zcat selects FEATURE_GZIP_DECOMPRESS +lib-$(CONFIG_FEATURE_GZIP_DECOMPRESS) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o +lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.o unsafe_prefix.o +lib-$(CONFIG_RPM2CPIO) += open_transformer.o decompress_gunzip.o get_header_cpio.o +lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o +lib-$(CONFIG_GZIP) += open_transformer.o +lib-$(CONFIG_BZIP2) += open_transformer.o +lib-$(CONFIG_LZOP) += open_transformer.o +lib-$(CONFIG_MAN) += open_transformer.o +lib-$(CONFIG_SETFONT) += open_transformer.o +lib-$(CONFIG_FEATURE_2_4_MODULES) += open_transformer.o +lib-$(CONFIG_MODINFO) += open_transformer.o +lib-$(CONFIG_INSMOD) += open_transformer.o +lib-$(CONFIG_DEPMOD) += open_transformer.o +lib-$(CONFIG_RMMOD) += open_transformer.o +lib-$(CONFIG_LSMOD) += open_transformer.o +lib-$(CONFIG_MODPROBE) += open_transformer.o +lib-$(CONFIG_MODPROBE_SMALL) += open_transformer.o + +lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o +lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_COMPRESS_BBCONFIG) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS) += open_transformer.o decompress_bunzip2.o + +ifneq ($(lib-y),) +lib-y += $(COMMON_FILES) +endif diff --git a/busybox-1_37_0/archival/libarchive/bz/LICENSE b/busybox-1_37_0/archival/libarchive/bz/LICENSE new file mode 100644 index 000000000..da4346520 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/LICENSE @@ -0,0 +1,44 @@ +bzip2 applet in busybox is based on lightly-modified source +of bzip2 version 1.0.4. bzip2 source is distributed +under the following conditions (copied verbatim from LICENSE file) +=========================================================== + + +This program, "bzip2", the associated library "libbzip2", and all +documentation, are copyright (C) 1996-2006 Julian R Seward. 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. The origin of this software must not be misrepresented; you must + not claim that you wrote the original software. If you use this + software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + +3. Altered source versions must be plainly marked as such, and must + not be misrepresented as being the original software. + +4. The name of the author may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS +OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR 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. + +Julian Seward, Cambridge, UK. +jseward@bzip.org +bzip2/libbzip2 version 1.0.4 of 20 December 2006 diff --git a/busybox-1_37_0/archival/libarchive/bz/README b/busybox-1_37_0/archival/libarchive/bz/README new file mode 100644 index 000000000..fffd47b8a --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/README @@ -0,0 +1,90 @@ +This file is an abridged version of README from bzip2 1.0.4 +Build instructions (which are not relevant to busyboxed bzip2) +are removed. +=========================================================== + + +This is the README for bzip2/libzip2. +This version is fully compatible with the previous public releases. + +------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in this file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ + +Please read and be aware of the following: + + +WARNING: + + This program and library (attempts to) compress data by + performing several non-trivial transformations on it. + Unless you are 100% familiar with *all* the algorithms + contained herein, and with the consequences of modifying them, + you should NOT meddle with the compression or decompression + machinery. Incorrect changes can and very likely *will* + lead to disastrous loss of data. + + +DISCLAIMER: + + I TAKE NO RESPONSIBILITY FOR ANY LOSS OF DATA ARISING FROM THE + USE OF THIS PROGRAM/LIBRARY, HOWSOEVER CAUSED. + + Every compression of a file implies an assumption that the + compressed file can be decompressed to reproduce the original. + Great efforts in design, coding and testing have been made to + ensure that this program works correctly. However, the complexity + of the algorithms, and, in particular, the presence of various + special cases in the code which occur with very low but non-zero + probability make it impossible to rule out the possibility of bugs + remaining in the program. DO NOT COMPRESS ANY DATA WITH THIS + PROGRAM UNLESS YOU ARE PREPARED TO ACCEPT THE POSSIBILITY, HOWEVER + SMALL, THAT THE DATA WILL NOT BE RECOVERABLE. + + That is not to say this program is inherently unreliable. + Indeed, I very much hope the opposite is true. bzip2/libbzip2 + has been carefully constructed and extensively tested. + + +PATENTS: + + To the best of my knowledge, bzip2/libbzip2 does not use any + patented algorithms. However, I do not have the resources + to carry out a patent search. Therefore I cannot give any + guarantee of the above statement. + + +I hope you find bzip2 useful. Feel free to contact me at + jseward@bzip.org +if you have any suggestions or queries. Many people mailed me with +comments, suggestions and patches after the releases of bzip-0.15, +bzip-0.21, and bzip2 versions 0.1pl2, 0.9.0, 0.9.5, 1.0.0, 1.0.1, +1.0.2 and 1.0.3, and the changes in bzip2 are largely a result of this +feedback. I thank you for your comments. + +bzip2's "home" is http://www.bzip.org/ + +Julian Seward +jseward@bzip.org +Cambridge, UK. + +18 July 1996 (version 0.15) +25 August 1996 (version 0.21) + 7 August 1997 (bzip2, version 0.1) +29 August 1997 (bzip2, version 0.1pl2) +23 August 1998 (bzip2, version 0.9.0) + 8 June 1999 (bzip2, version 0.9.5) + 4 Sept 1999 (bzip2, version 0.9.5d) + 5 May 2000 (bzip2, version 1.0pre8) +30 December 2001 (bzip2, version 1.0.2pre1) +15 February 2005 (bzip2, version 1.0.3) +20 December 2006 (bzip2, version 1.0.4) diff --git a/busybox-1_37_0/archival/libarchive/bz/blocksort.c b/busybox-1_37_0/archival/libarchive/bz/blocksort.c new file mode 100644 index 000000000..74f957544 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/blocksort.c @@ -0,0 +1,1079 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Block sorting machinery ---*/ +/*--- blocksort.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib_private.h" */ + +#define mswap(zz1, zz2) \ +{ \ + int32_t zztmp = zz1; \ + zz1 = zz2; \ + zz2 = zztmp; \ +} + +static +/* No measurable speed gain with inlining */ +/* ALWAYS_INLINE */ +void mvswap(uint32_t* ptr, int32_t zzp1, int32_t zzp2, int32_t zzn) +{ + while (zzn > 0) { + mswap(ptr[zzp1], ptr[zzp2]); + zzp1++; + zzp2++; + zzn--; + } +} + +static +ALWAYS_INLINE +int32_t mmin(int32_t a, int32_t b) +{ + return (a < b) ? a : b; +} + + +/*---------------------------------------------*/ +/*--- Fallback O(N log(N)^2) sorting ---*/ +/*--- algorithm, for repetitive blocks ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +inline +void fallbackSimpleSort(uint32_t* fmap, + uint32_t* eclass, + int32_t lo, + int32_t hi) +{ + int32_t i, j, tmp; + uint32_t ec_tmp; + + if (lo == hi) return; + + if (hi - lo > 3) { + for (i = hi-4; i >= lo; i--) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for (j = i+4; j <= hi && ec_tmp > eclass[fmap[j]]; j += 4) + fmap[j-4] = fmap[j]; + fmap[j-4] = tmp; + } + } + + for (i = hi-1; i >= lo; i--) { + tmp = fmap[i]; + ec_tmp = eclass[tmp]; + for (j = i+1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) + fmap[j-1] = fmap[j]; + fmap[j-1] = tmp; + } +} + + +/*---------------------------------------------*/ +#define fpush(lz,hz) { \ + stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + sp++; \ +} + +#define fpop(lz,hz) { \ + sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ +} + +#define FALLBACK_QSORT_SMALL_THRESH 10 +#define FALLBACK_QSORT_STACK_SIZE 100 + +static NOINLINE +void fallbackQSort3(uint32_t* fmap, + uint32_t* eclass, + int32_t loSt, + int32_t hiSt) +{ + int32_t sp; + uint32_t r; + int32_t stackLo[FALLBACK_QSORT_STACK_SIZE]; + int32_t stackHi[FALLBACK_QSORT_STACK_SIZE]; + + r = 0; + + sp = 0; + fpush(loSt, hiSt); + + while (sp > 0) { + int32_t unLo, unHi, ltLo, gtHi, n, m; + int32_t lo, hi; + uint32_t med; + uint32_t r3; + + AssertH(sp < FALLBACK_QSORT_STACK_SIZE - 1, 1004); + + fpop(lo, hi); + if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) { + fallbackSimpleSort(fmap, eclass, lo, hi); + continue; + } + + /* Random partitioning. Median of 3 sometimes fails to + * avoid bad cases. Median of 9 seems to help but + * looks rather expensive. This too seems to work but + * is cheaper. Guidance for the magic constants + * 7621 and 32768 is taken from Sedgewick's algorithms + * book, chapter 35. + */ + r = ((r * 7621) + 1) % 32768; + r3 = r % 3; + if (r3 == 0) + med = eclass[fmap[lo]]; + else if (r3 == 1) + med = eclass[fmap[(lo+hi)>>1]]; + else + med = eclass[fmap[hi]]; + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) break; + n = (int32_t)eclass[fmap[unLo]] - (int32_t)med; + if (n == 0) { + mswap(fmap[unLo], fmap[ltLo]); + ltLo++; + unLo++; + continue; + } + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) break; + n = (int32_t)eclass[fmap[unHi]] - (int32_t)med; + if (n == 0) { + mswap(fmap[unHi], fmap[gtHi]); + gtHi--; unHi--; + continue; + } + if (n < 0) break; + unHi--; + } + if (unLo > unHi) break; + mswap(fmap[unLo], fmap[unHi]); unLo++; unHi--; + } + + AssertD(unHi == unLo-1, "fallbackQSort3(2)"); + + if (gtHi < ltLo) continue; + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(fmap, lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(fmap, unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + if (n - lo > hi - m) { + fpush(lo, n); + fpush(m, hi); + } else { + fpush(m, hi); + fpush(lo, n); + } + } +} + +#undef fpush +#undef fpop +#undef FALLBACK_QSORT_SMALL_THRESH +#undef FALLBACK_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + * nblock > 0 + * eclass exists for [0 .. nblock-1] + * ((uint8_t*)eclass) [0 .. nblock-1] holds block + * ptr exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)eclass) [0 .. nblock-1] holds block + * All other areas of eclass destroyed + * fmap [0 .. nblock-1] holds sorted order + * bhtab[0 .. 2+(nblock/32)] destroyed +*/ + +#define SET_BH(zz) bhtab[(zz) >> 5] |= (1 << ((zz) & 31)) +#define CLEAR_BH(zz) bhtab[(zz) >> 5] &= ~(1 << ((zz) & 31)) +#define ISSET_BH(zz) (bhtab[(zz) >> 5] & (1 << ((zz) & 31))) +#define WORD_BH(zz) bhtab[(zz) >> 5] +#define UNALIGNED_BH(zz) ((zz) & 0x01f) + +static +void fallbackSort(EState* state) +{ + int32_t ftab[257]; + int32_t ftabCopy[256]; + int32_t H, i, j, k, l, r, cc, cc1; + int32_t nNotDone; + int32_t nBhtab; + /* params */ + uint32_t *const fmap = state->arr1; + uint32_t *const eclass = state->arr2; +#define eclass8 ((uint8_t*)eclass) + uint32_t *const bhtab = state->ftab; + const int32_t nblock = state->nblock; + + /* + * Initial 1-char radix sort to generate + * initial fmap and initial BH bits. + */ + for (i = 0; i < 257; i++) ftab[i] = 0; + for (i = 0; i < nblock; i++) ftab[eclass8[i]]++; + for (i = 0; i < 256; i++) ftabCopy[i] = ftab[i]; + + j = ftab[0]; /* bbox: optimized */ + for (i = 1; i < 257; i++) { + j += ftab[i]; + ftab[i] = j; + } + + for (i = 0; i < nblock; i++) { + j = eclass8[i]; + k = ftab[j] - 1; + ftab[j] = k; + fmap[k] = i; + } + + nBhtab = 2 + ((uint32_t)nblock / 32); /* bbox: unsigned div is easier */ + for (i = 0; i < nBhtab; i++) bhtab[i] = 0; + for (i = 0; i < 256; i++) SET_BH(ftab[i]); + + /* + * Inductively refine the buckets. Kind-of an + * "exponential radix sort" (!), inspired by the + * Manber-Myers suffix array construction algorithm. + */ + + /*-- set sentinel bits for block-end detection --*/ + for (i = 0; i < 32; i++) { + SET_BH(nblock + 2*i); + CLEAR_BH(nblock + 2*i + 1); + } + + /*-- the log(N) loop --*/ + H = 1; + while (1) { + j = 0; + for (i = 0; i < nblock; i++) { + if (ISSET_BH(i)) + j = i; + k = fmap[i] - H; + if (k < 0) + k += nblock; + eclass[k] = j; + } + + nNotDone = 0; + r = -1; + while (1) { + + /*-- find the next non-singleton bucket --*/ + k = r + 1; + while (ISSET_BH(k) && UNALIGNED_BH(k)) + k++; + if (ISSET_BH(k)) { + while (WORD_BH(k) == 0xffffffff) k += 32; + while (ISSET_BH(k)) k++; + } + l = k - 1; + if (l >= nblock) + break; + while (!ISSET_BH(k) && UNALIGNED_BH(k)) + k++; + if (!ISSET_BH(k)) { + while (WORD_BH(k) == 0x00000000) k += 32; + while (!ISSET_BH(k)) k++; + } + r = k - 1; + if (r >= nblock) + break; + + /*-- now [l, r] bracket current bucket --*/ + if (r > l) { + nNotDone += (r - l + 1); + fallbackQSort3(fmap, eclass, l, r); + + /*-- scan bucket and generate header bits-- */ + cc = -1; + for (i = l; i <= r; i++) { + cc1 = eclass[fmap[i]]; + if (cc != cc1) { + SET_BH(i); + cc = cc1; + } + } + } + } + + H *= 2; + if (H > nblock || nNotDone == 0) + break; + } + + /* + * Reconstruct the original block in + * eclass8 [0 .. nblock-1], since the + * previous phase destroyed it. + */ + j = 0; + for (i = 0; i < nblock; i++) { + while (ftabCopy[j] == 0) + j++; + ftabCopy[j]--; + eclass8[fmap[i]] = (uint8_t)j; + } + AssertH(j < 256, 1005); +#undef eclass8 +} + +#undef SET_BH +#undef CLEAR_BH +#undef ISSET_BH +#undef WORD_BH +#undef UNALIGNED_BH + + +/*---------------------------------------------*/ +/*--- The main, O(N^2 log(N)) sorting ---*/ +/*--- algorithm. Faster for "normal" ---*/ +/*--- non-repetitive blocks. ---*/ +/*---------------------------------------------*/ + +/*---------------------------------------------*/ +static +NOINLINE +int mainGtU(EState* state, + uint32_t i1, + uint32_t i2) +{ + int32_t k; + uint8_t c1, c2; + uint16_t s1, s2; + + uint8_t *const block = state->block; + uint16_t *const quadrant = state->quadrant; + const int32_t nblock = state->nblock; + +/* Loop unrolling here is actually very useful + * (generated code is much simpler), + * code size increase is only 270 bytes (i386) + * but speeds up compression 10% overall + */ + +#if BZIP2_SPEED >= 1 + +#define TIMES_8(code) \ + code; code; code; code; \ + code; code; code; code; +#define TIMES_12(code) \ + code; code; code; code; \ + code; code; code; code; \ + code; code; code; code; + +#else + +#define TIMES_8(code) \ +{ \ + int nn = 8; \ + do { \ + code; \ + } while (--nn); \ +} +#define TIMES_12(code) \ +{ \ + int nn = 12; \ + do { \ + code; \ + } while (--nn); \ +} + +#endif + + AssertD(i1 != i2, "mainGtU"); + TIMES_12( + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + i1++; i2++; + ) + + k = nblock + 8; + + do { + TIMES_8( + c1 = block[i1]; c2 = block[i2]; + if (c1 != c2) return (c1 > c2); + s1 = quadrant[i1]; s2 = quadrant[i2]; + if (s1 != s2) return (s1 > s2); + i1++; i2++; + ) + + if (i1 >= nblock) i1 -= nblock; + if (i2 >= nblock) i2 -= nblock; + + state->budget--; + k -= 8; + } while (k >= 0); + + return False; +} +#undef TIMES_8 +#undef TIMES_12 + +/*---------------------------------------------*/ +/* + * Knuth's increments seem to work better + * than Incerpi-Sedgewick here. Possibly + * because the number of elems to sort is + * usually small, typically <= 20. + */ +static +const uint32_t incs[14] ALIGN4 = { + 1, 4, 13, 40, 121, 364, 1093, 3280, + 9841, 29524, 88573, 265720, + 797161, 2391484 +}; + +static +void mainSimpleSort(EState* state, + int32_t lo, + int32_t hi, + int32_t d) +{ + uint32_t *const ptr = state->ptr; + + /* At which increment to start? */ + int hp = 0; + { + int bigN = hi - lo; + if (bigN <= 0) + return; + while (incs[hp] <= bigN) + hp++; + hp--; + } + + for (; hp >= 0; hp--) { + int32_t i; + unsigned h; + + h = incs[hp]; + i = lo + h; + while (1) { + unsigned j; + unsigned v; + + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(state, ptr[j-h]+d, v+d)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + +/* 1.5% overall speedup, +290 bytes */ +#if BZIP2_SPEED >= 3 + /*-- copy 2 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(state, ptr[j-h]+d, v+d)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; + /*-- copy 3 --*/ + if (i > hi) break; + v = ptr[i]; + j = i; + while (mainGtU(state, ptr[j-h]+d, v+d)) { + ptr[j] = ptr[j-h]; + j = j - h; + if (j <= (lo + h - 1)) break; + } + ptr[j] = v; + i++; +#endif + if (state->budget < 0) return; + } + } +} + + +/*---------------------------------------------*/ +/* + * The following is an implementation of + * an elegant 3-way quicksort for strings, + * described in a paper "Fast Algorithms for + * Sorting and Searching Strings", by Robert + * Sedgewick and Jon L. Bentley. + */ + +static +ALWAYS_INLINE +uint8_t mmed3(uint8_t a, uint8_t b, uint8_t c) +{ + uint8_t t; + if (a > b) { + t = a; + a = b; + b = t; + } + /* here b >= a */ + if (b > c) { + b = c; + if (a > b) + b = a; + } + return b; +} + +#define mpush(lz,hz,dz) \ +{ \ + stackLo[sp] = lz; \ + stackHi[sp] = hz; \ + stackD [sp] = dz; \ + sp++; \ +} + +#define mpop(lz,hz,dz) \ +{ \ + sp--; \ + lz = stackLo[sp]; \ + hz = stackHi[sp]; \ + dz = stackD [sp]; \ +} + +#define mnextsize(az) (nextHi[az] - nextLo[az]) + +#define mnextswap(az,bz) \ +{ \ + int32_t tz; \ + tz = nextLo[az]; nextLo[az] = nextLo[bz]; nextLo[bz] = tz; \ + tz = nextHi[az]; nextHi[az] = nextHi[bz]; nextHi[bz] = tz; \ + tz = nextD [az]; nextD [az] = nextD [bz]; nextD [bz] = tz; \ +} + +#define MAIN_QSORT_SMALL_THRESH 20 +#define MAIN_QSORT_DEPTH_THRESH (BZ_N_RADIX + BZ_N_QSORT) +#define MAIN_QSORT_STACK_SIZE 100 + +static NOINLINE +void mainQSort3(EState* state, + int32_t loSt, + int32_t hiSt + /*int32_t dSt*/) +{ + enum { dSt = BZ_N_RADIX }; + int32_t unLo, unHi, ltLo, gtHi, n, m, med; + int32_t sp, lo, hi, d; + + int32_t stackLo[MAIN_QSORT_STACK_SIZE]; + int32_t stackHi[MAIN_QSORT_STACK_SIZE]; + int32_t stackD [MAIN_QSORT_STACK_SIZE]; + + int32_t nextLo[3]; + int32_t nextHi[3]; + int32_t nextD [3]; + + uint32_t *const ptr = state->ptr; + uint8_t *const block = state->block; + + sp = 0; + mpush(loSt, hiSt, dSt); + + while (sp > 0) { + AssertH(sp < MAIN_QSORT_STACK_SIZE - 2, 1001); + + mpop(lo, hi, d); + if (hi - lo < MAIN_QSORT_SMALL_THRESH + || d > MAIN_QSORT_DEPTH_THRESH + ) { + mainSimpleSort(state, lo, hi, d); + if (state->budget < 0) + return; + continue; + } + med = (int32_t) mmed3(block[ptr[lo ] + d], + block[ptr[hi ] + d], + block[ptr[(lo+hi) >> 1] + d]); + + unLo = ltLo = lo; + unHi = gtHi = hi; + + while (1) { + while (1) { + if (unLo > unHi) + break; + n = ((int32_t)block[ptr[unLo]+d]) - med; + if (n == 0) { + mswap(ptr[unLo], ptr[ltLo]); + ltLo++; + unLo++; + continue; + } + if (n > 0) break; + unLo++; + } + while (1) { + if (unLo > unHi) + break; + n = ((int32_t)block[ptr[unHi]+d]) - med; + if (n == 0) { + mswap(ptr[unHi], ptr[gtHi]); + gtHi--; + unHi--; + continue; + } + if (n < 0) break; + unHi--; + } + if (unLo > unHi) + break; + mswap(ptr[unLo], ptr[unHi]); + unLo++; + unHi--; + } + + AssertD(unHi == unLo-1, "mainQSort3(2)"); + + if (gtHi < ltLo) { + mpush(lo, hi, d + 1); + continue; + } + + n = mmin(ltLo-lo, unLo-ltLo); mvswap(ptr, lo, unLo-n, n); + m = mmin(hi-gtHi, gtHi-unHi); mvswap(ptr, unLo, hi-m+1, m); + + n = lo + unLo - ltLo - 1; + m = hi - (gtHi - unHi) + 1; + + nextLo[0] = lo; nextHi[0] = n; nextD[0] = d; + nextLo[1] = m; nextHi[1] = hi; nextD[1] = d; + nextLo[2] = n+1; nextHi[2] = m-1; nextD[2] = d+1; + + if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); + if (mnextsize(1) < mnextsize(2)) mnextswap(1, 2); + if (mnextsize(0) < mnextsize(1)) mnextswap(0, 1); + + AssertD (mnextsize(0) >= mnextsize(1), "mainQSort3(8)"); + AssertD (mnextsize(1) >= mnextsize(2), "mainQSort3(9)"); + + mpush(nextLo[0], nextHi[0], nextD[0]); + mpush(nextLo[1], nextHi[1], nextD[1]); + mpush(nextLo[2], nextHi[2], nextD[2]); + } +} + +#undef mpush +#undef mpop +#undef mnextsize +#undef mnextswap +#undef MAIN_QSORT_SMALL_THRESH +#undef MAIN_QSORT_DEPTH_THRESH +#undef MAIN_QSORT_STACK_SIZE + + +/*---------------------------------------------*/ +/* Pre: + * nblock > N_OVERSHOOT + * block32 exists for [0 .. nblock-1 +N_OVERSHOOT] + * ((uint8_t*)block32) [0 .. nblock-1] holds block + * ptr exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)block32) [0 .. nblock-1] holds block + * All other areas of block32 destroyed + * ftab[0 .. 65536] destroyed + * ptr [0 .. nblock-1] holds sorted order + * if (*budget < 0), sorting was abandoned + */ + +#define BIGFREQ(b) (ftab[((b)+1) << 8] - ftab[(b) << 8]) +#define SETMASK (1 << 21) +#define CLEARMASK (~(SETMASK)) + +static NOINLINE +void mainSort(EState* state) +{ + int32_t i, j; + Bool bigDone[256]; + uint8_t runningOrder[256]; + /* bbox: moved to EState to save stack + int32_t copyStart[256]; + int32_t copyEnd [256]; + */ +#define copyStart (state->mainSort__copyStart) +#define copyEnd (state->mainSort__copyEnd) + + uint32_t *const ptr = state->ptr; + uint8_t *const block = state->block; + uint32_t *const ftab = state->ftab; + const int32_t nblock = state->nblock; + uint16_t *const quadrant = state->quadrant; + + /*-- set up the 2-byte frequency table --*/ + /* was: for (i = 65536; i >= 0; i--) ftab[i] = 0; */ + memset(ftab, 0, 65537 * sizeof(ftab[0])); + + j = block[0] << 8; + i = nblock - 1; +/* 3%, +300 bytes */ +#if BZIP2_SPEED >= 2 + for (; i >= 3; i -= 4) { + quadrant[i] = 0; + j = (j >> 8) | (((unsigned)block[i]) << 8); + ftab[j]++; + quadrant[i-1] = 0; + j = (j >> 8) | (((unsigned)block[i-1]) << 8); + ftab[j]++; + quadrant[i-2] = 0; + j = (j >> 8) | (((unsigned)block[i-2]) << 8); + ftab[j]++; + quadrant[i-3] = 0; + j = (j >> 8) | (((unsigned)block[i-3]) << 8); + ftab[j]++; + } +#endif + for (; i >= 0; i--) { + quadrant[i] = 0; + j = (j >> 8) | (((unsigned)block[i]) << 8); + ftab[j]++; + } + + /*-- (emphasises close relationship of block & quadrant) --*/ + for (i = 0; i < BZ_N_OVERSHOOT; i++) { + block [nblock+i] = block[i]; + quadrant[nblock+i] = 0; + } + + /*-- Complete the initial radix sort --*/ + j = ftab[0]; /* bbox: optimized */ + for (i = 1; i <= 65536; i++) { + j += ftab[i]; + ftab[i] = j; + } + + { + unsigned s; + s = block[0] << 8; + i = nblock - 1; +#if BZIP2_SPEED >= 2 + for (; i >= 3; i -= 4) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i; + s = (s >> 8) | (block[i-1] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-1; + s = (s >> 8) | (block[i-2] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-2; + s = (s >> 8) | (block[i-3] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i-3; + } +#endif + for (; i >= 0; i--) { + s = (s >> 8) | (block[i] << 8); + j = ftab[s] - 1; + ftab[s] = j; + ptr[j] = i; + } + } + + /* + * Now ftab contains the first loc of every small bucket. + * Calculate the running order, from smallest to largest + * big bucket. + */ + for (i = 0; i <= 255; i++) { + bigDone [i] = False; + runningOrder[i] = i; + } + + { + /* bbox: was: int32_t h = 1; */ + /* do h = 3 * h + 1; while (h <= 256); */ + unsigned h = 364; + + do { + /*h = h / 3;*/ + h = (h * 171) >> 9; /* bbox: fast h/3 */ + for (i = h; i <= 255; i++) { + unsigned vv, jh; + vv = runningOrder[i]; /* uint8[] */ + j = i; + while (jh = j - h, BIGFREQ(runningOrder[jh]) > BIGFREQ(vv)) { + runningOrder[j] = runningOrder[jh]; + j = jh; + if (j < h) + break; + } + runningOrder[j] = vv; + } + } while (h != 1); + } + + /* + * The main sorting loop. + */ + + for (i = 0; /*i <= 255*/; i++) { + unsigned ss; + + /* + * Process big buckets, starting with the least full. + * Basically this is a 3-step process in which we call + * mainQSort3 to sort the small buckets [ss, j], but + * also make a big effort to avoid the calls if we can. + */ + ss = runningOrder[i]; + + /* + * Step 1: + * Complete the big bucket [ss] by quicksorting + * any unsorted small buckets [ss, j], for j != ss. + * Hopefully previous pointer-scanning phases have already + * completed many of the small buckets [ss, j], so + * we don't have to sort them at all. + */ + for (j = 0; j <= 255; j++) { + if (j != ss) { + unsigned sb; + sb = (ss << 8) + j; + if (!(ftab[sb] & SETMASK)) { + int32_t lo = ftab[sb] /*& CLEARMASK (redundant)*/; + int32_t hi = (ftab[sb+1] & CLEARMASK) - 1; + if (hi > lo) { + mainQSort3(state, lo, hi /*,BZ_N_RADIX*/); + if (state->budget < 0) return; + } + } + ftab[sb] |= SETMASK; + } + } + + AssertH(!bigDone[ss], 1006); + + /* + * Step 2: + * Now scan this big bucket [ss] so as to synthesise the + * sorted order for small buckets [t, ss] for all t, + * including, magically, the bucket [ss,ss] too. + * This will avoid doing Real Work in subsequent Step 1's. + */ + { + for (j = 0; j <= 255; j++) { + copyStart[j] = ftab[(j << 8) + ss] & CLEARMASK; + copyEnd [j] = (ftab[(j << 8) + ss + 1] & CLEARMASK) - 1; + } + for (j = ftab[ss << 8] & CLEARMASK; j < copyStart[ss]; j++) { + unsigned c1; + int32_t k; + k = ptr[j] - 1; + if (k < 0) + k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[copyStart[c1]++] = k; + } + for (j = (ftab[(ss+1) << 8] & CLEARMASK) - 1; j > copyEnd[ss]; j--) { + unsigned c1; + int32_t k; + k = ptr[j]-1; + if (k < 0) + k += nblock; + c1 = block[k]; + if (!bigDone[c1]) + ptr[copyEnd[c1]--] = k; + } + } + + /* Extremely rare case missing in bzip2-1.0.0 and 1.0.1. + * Necessity for this case is demonstrated by compressing + * a sequence of approximately 48.5 million of character + * 251; 1.0.0/1.0.1 will then die here. */ + AssertH((copyStart[ss]-1 == copyEnd[ss]) \ + || (copyStart[ss] == 0 && copyEnd[ss] == nblock-1), 1007); + + for (j = 0; j <= 255; j++) + ftab[(j << 8) + ss] |= SETMASK; + + if (i == 255) + break; + + /* + * Step 3: + * The [ss] big bucket is now done. Record this fact, + * and update the quadrant descriptors. Remember to + * update quadrants in the overshoot area too, if + * necessary. The "if (i < 255)" test merely skips + * this updating for the last bucket processed, since + * updating for the last bucket is pointless. + * + * The quadrant array provides a way to incrementally + * cache sort orderings, as they appear, so as to + * make subsequent comparisons in fullGtU() complete + * faster. For repetitive blocks this makes a big + * difference (but not big enough to be able to avoid + * the fallback sorting mechanism, exponential radix sort). + * + * The precise meaning is: at all times: + * + * for 0 <= i < nblock and 0 <= j <= nblock + * + * if block[i] != block[j], + * + * then the relative values of quadrant[i] and + * quadrant[j] are meaningless. + * + * else { + * if quadrant[i] < quadrant[j] + * then the string starting at i lexicographically + * precedes the string starting at j + * + * else if quadrant[i] > quadrant[j] + * then the string starting at j lexicographically + * precedes the string starting at i + * + * else + * the relative ordering of the strings starting + * at i and j has not yet been determined. + * } + */ + bigDone[ss] = True; + + { + unsigned bbStart = ftab[ss << 8] & CLEARMASK; + unsigned bbSize = (ftab[(ss+1) << 8] & CLEARMASK) - bbStart; + unsigned shifts = 0; + + while ((bbSize >> shifts) > 65534) shifts++; + + for (j = bbSize-1; j >= 0; j--) { + unsigned a2update = ptr[bbStart + j]; /* uint32[] */ + uint16_t qVal = (uint16_t)(j >> shifts); + quadrant[a2update] = qVal; + if (a2update < BZ_N_OVERSHOOT) + quadrant[a2update + nblock] = qVal; + } + AssertH(((bbSize-1) >> shifts) <= 65535, 1002); + } + } +#undef runningOrder +#undef copyStart +#undef copyEnd +} + +#undef BIGFREQ +#undef SETMASK +#undef CLEARMASK + + +/*---------------------------------------------*/ +/* Pre: + * nblock > 0 + * arr2 exists for [0 .. nblock-1 +N_OVERSHOOT] + * ((uint8_t*)arr2)[0 .. nblock-1] holds block + * arr1 exists for [0 .. nblock-1] + * + * Post: + * ((uint8_t*)arr2) [0 .. nblock-1] holds block + * All other areas of block destroyed + * ftab[0 .. 65536] destroyed + * arr1[0 .. nblock-1] holds sorted order + */ +static NOINLINE +int32_t BZ2_blockSort(EState* state) +{ + /* In original bzip2 1.0.4, it's a parameter, but 30 + * (which was the default) should work ok. */ + enum { wfact = 30 }; + unsigned i; + int32_t origPtr = origPtr; + + if (state->nblock >= 10000) { + /* Calculate the location for quadrant, remembering to get + * the alignment right. Assumes that &(block[0]) is at least + * 2-byte aligned -- this should be ok since block is really + * the first section of arr2. + */ + i = state->nblock + BZ_N_OVERSHOOT; + if (i & 1) + i++; + state->quadrant = (uint16_t*) &(state->block[i]); + + /* (wfact-1) / 3 puts the default-factor-30 + * transition point at very roughly the same place as + * with v0.1 and v0.9.0. + * Not that it particularly matters any more, since the + * resulting compressed stream is now the same regardless + * of whether or not we use the main sort or fallback sort. + */ + state->budget = state->nblock * ((wfact-1) / 3); + mainSort(state); + if (state->budget >= 0) + goto good; + } + fallbackSort(state); + good: + +#if BZ_LIGHT_DEBUG + origPtr = -1; +#endif + for (i = 0; i < state->nblock; i++) { + if (state->ptr[i] == 0) { + origPtr = i; + break; + } + } + + AssertH(origPtr != -1, 1003); + return origPtr; +} + + +/*-------------------------------------------------------------*/ +/*--- end blocksort.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/bz/bzlib.c b/busybox-1_37_0/archival/libarchive/bz/bzlib.c new file mode 100644 index 000000000..ef19ae165 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/bzlib.c @@ -0,0 +1,428 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Library top-level functions. ---*/ +/*--- bzlib.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* CHANGES + * 0.9.0 -- original version. + * 0.9.0a/b -- no changes in this file. + * 0.9.0c -- made zero-length BZ_FLUSH work correctly in bzCompress(). + * fixed bzWrite/bzRead to ignore zero-length requests. + * fixed bzread to correctly handle read requests after EOF. + * wrong parameter order in call to bzDecompressInit in + * bzBuffToBuffDecompress. Fixed. + */ + +/* #include "bzlib_private.h" */ + +/*---------------------------------------------------*/ +/*--- Compression stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +#if BZ_LIGHT_DEBUG +static +void bz_assert_fail(int errcode) +{ + /* if (errcode == 1007) bb_error_msg_and_die("probably bad RAM"); */ + bb_error_msg_and_die("internal error %d", errcode); +} +#endif + +/*---------------------------------------------------*/ +static +void prepare_new_block(EState* s) +{ + int i; + s->nblock = 0; + //indexes into s->zbits[], initialzation moved to init of s->zbits + //s->posZ = s->zbits; // was: s->numZ = 0; + //s->state_out_pos = s->zbits; + BZ_INITIALISE_CRC(s->blockCRC); + /* inlined memset would be nice to have here */ + for (i = 0; i < 256; i++) + s->inUse[i] = 0; + s->blockNo++; +} + + +/*---------------------------------------------------*/ +static +ALWAYS_INLINE +void init_RL(EState* s) +{ + s->state_in_ch = 256; + s->state_in_len = 0; +} + + +static +int isempty_RL(EState* s) +{ + return (s->state_in_ch >= 256 || s->state_in_len <= 0); +} + + +/*---------------------------------------------------*/ +static +void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k) +{ + unsigned n; + EState* s; + + s = xzalloc(sizeof(EState)); + s->strm = strm; + + n = 100000 * blockSize100k; + s->arr1 = xmalloc(n * sizeof(uint32_t)); + s->mtfv = (uint16_t*)s->arr1; + s->ptr = (uint32_t*)s->arr1; + s->arr2 = xmalloc((n + BZ_N_OVERSHOOT) * sizeof(uint32_t)); + s->block = (uint8_t*)s->arr2; + + crc32_filltable(s->crc32table, 1); + + s->state = BZ_S_INPUT; + s->mode = BZ_M_RUNNING; + s->blockSize100k = blockSize100k; + s->nblockMAX = n - 19; + + strm->state = s; + /*strm->total_in = 0;*/ + strm->total_out = 0; + init_RL(s); + prepare_new_block(s); +} + + +/*---------------------------------------------------*/ +static +void add_pair_to_block(EState* s) +{ + int32_t i; + uint8_t ch = (uint8_t)(s->state_in_ch); + for (i = 0; i < s->state_in_len; i++) { + BZ_UPDATE_CRC(s, s->blockCRC, ch); + } + s->inUse[s->state_in_ch] = 1; + switch (s->state_in_len) { + case 3: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + /* fall through */ + case 2: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + /* fall through */ + case 1: + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + break; + default: + s->inUse[s->state_in_len - 4] = 1; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)ch; s->nblock++; + s->block[s->nblock] = (uint8_t)(s->state_in_len - 4); + s->nblock++; + break; + } +} + + +/*---------------------------------------------------*/ +static +void flush_RL(EState* s) +{ + if (s->state_in_ch < 256) add_pair_to_block(s); + init_RL(s); +} + + +/*---------------------------------------------------*/ +#define ADD_CHAR_TO_BLOCK(zs, zchh0) \ +{ \ + uint32_t zchh = (uint32_t)(zchh0); \ + /*-- fast track the common case --*/ \ + if (zchh != zs->state_in_ch && zs->state_in_len == 1) { \ + uint8_t ch = (uint8_t)(zs->state_in_ch); \ + BZ_UPDATE_CRC(zs, zs->blockCRC, ch); \ + zs->inUse[zs->state_in_ch] = 1; \ + zs->block[zs->nblock] = (uint8_t)ch; \ + zs->nblock++; \ + zs->state_in_ch = zchh; \ + } \ + else \ + /*-- general, uncommon cases --*/ \ + if (zchh != zs->state_in_ch || zs->state_in_len == 255) { \ + if (zs->state_in_ch < 256) \ + add_pair_to_block(zs); \ + zs->state_in_ch = zchh; \ + zs->state_in_len = 1; \ + } else { \ + zs->state_in_len++; \ + } \ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ copy_input_until_stop(EState* s) +{ + /*Bool progress_in = False;*/ + +#ifdef SAME_CODE_AS_BELOW + if (s->mode == BZ_M_RUNNING) { + /*-- fast track the common case --*/ + while (1) { + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + /*progress_in = True;*/ + ADD_CHAR_TO_BLOCK(s, (uint32_t)(*(uint8_t*)(s->strm->next_in))); + s->strm->next_in++; + s->strm->avail_in--; + /*s->strm->total_in++;*/ + } + } else +#endif + { + /*-- general, uncommon case --*/ + while (1) { + /*-- no input? --*/ + if (s->strm->avail_in == 0) break; + /*-- block full? --*/ + if (s->nblock >= s->nblockMAX) break; + //# /*-- flush/finish end? --*/ + //# if (s->avail_in_expect == 0) break; + /*progress_in = True;*/ + ADD_CHAR_TO_BLOCK(s, *(uint8_t*)(s->strm->next_in)); + s->strm->next_in++; + s->strm->avail_in--; + /*s->strm->total_in++;*/ + //# s->avail_in_expect--; + } + } + /*return progress_in;*/ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ copy_output_until_stop(EState* s) +{ + /*Bool progress_out = False;*/ + + while (1) { + /*-- no output space? --*/ + if (s->strm->avail_out == 0) break; + + /*-- block done? --*/ + if (s->state_out_pos >= s->posZ) break; + + /*progress_out = True;*/ + *(s->strm->next_out) = *s->state_out_pos++; + s->strm->avail_out--; + s->strm->next_out++; + s->strm->total_out++; + } + /*return progress_out;*/ +} + + +/*---------------------------------------------------*/ +static +void /*Bool*/ handle_compress(bz_stream *strm) +{ + /*Bool progress_in = False;*/ + /*Bool progress_out = False;*/ + EState* s = strm->state; + + while (1) { + if (s->state == BZ_S_OUTPUT) { + /*progress_out |=*/ copy_output_until_stop(s); + if (s->state_out_pos < s->posZ) break; + if (s->mode == BZ_M_FINISHING + //# && s->avail_in_expect == 0 + && s->strm->avail_in == 0 + && isempty_RL(s)) + break; + prepare_new_block(s); + s->state = BZ_S_INPUT; +#ifdef FLUSH_IS_UNUSED + if (s->mode == BZ_M_FLUSHING + && s->avail_in_expect == 0 + && isempty_RL(s)) + break; +#endif + } + + if (s->state == BZ_S_INPUT) { + /*progress_in |=*/ copy_input_until_stop(s); + //#if (s->mode != BZ_M_RUNNING && s->avail_in_expect == 0) { + if (s->mode != BZ_M_RUNNING && s->strm->avail_in == 0) { + flush_RL(s); + BZ2_compressBlock(s, (s->mode == BZ_M_FINISHING)); + s->state = BZ_S_OUTPUT; + } else + if (s->nblock >= s->nblockMAX) { + BZ2_compressBlock(s, 0); + s->state = BZ_S_OUTPUT; + } else + if (s->strm->avail_in == 0) { + break; + } + } + } + + /*return progress_in || progress_out;*/ +} + + +/*---------------------------------------------------*/ +static +int BZ2_bzCompress(bz_stream *strm, int action) +{ + /*Bool progress;*/ + EState* s; + + s = strm->state; + + switch (s->mode) { + case BZ_M_RUNNING: + if (action == BZ_RUN) { + /*progress =*/ handle_compress(strm); + /*return progress ? BZ_RUN_OK : BZ_PARAM_ERROR;*/ + return BZ_RUN_OK; + } +#ifdef FLUSH_IS_UNUSED + else + if (action == BZ_FLUSH) { + //#s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FLUSHING; + goto case_BZ_M_FLUSHING; + } +#endif + else + /*if (action == BZ_FINISH)*/ { + //#s->avail_in_expect = strm->avail_in; + s->mode = BZ_M_FINISHING; + goto case_BZ_M_FINISHING; + } + +#ifdef FLUSH_IS_UNUSED + case_BZ_M_FLUSHING: + case BZ_M_FLUSHING: + /*if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR;*/ + /*progress =*/ handle_compress(strm); + if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ) + return BZ_FLUSH_OK; + s->mode = BZ_M_RUNNING; + return BZ_RUN_OK; +#endif + + case_BZ_M_FINISHING: + /*case BZ_M_FINISHING:*/ + default: + /*if (s->avail_in_expect != s->strm->avail_in) + return BZ_SEQUENCE_ERROR;*/ + /*progress =*/ handle_compress(strm); + /*if (!progress) return BZ_SEQUENCE_ERROR;*/ + //#if (s->avail_in_expect > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ) + //# return BZ_FINISH_OK; + if (s->strm->avail_in > 0 || !isempty_RL(s) || s->state_out_pos < s->posZ) + return BZ_FINISH_OK; + /*s->mode = BZ_M_IDLE;*/ + return BZ_STREAM_END; + } + /* return BZ_OK; --not reached--*/ +} + + +/*---------------------------------------------------*/ +static +void BZ2_bzCompressEnd(bz_stream *strm) +{ + EState* s; + + s = strm->state; + free(s->arr1); + free(s->arr2); + //free(s->ftab); // made it array member of s + //free(s->crc32table); // ditto + free(s); +} + + +/*---------------------------------------------------*/ +/*--- Misc convenience stuff ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +#ifdef EXAMPLE_CODE_FOR_MEM_TO_MEM_COMPRESSION +static +int BZ2_bzBuffToBuffCompress(char* dest, + unsigned int* destLen, + char* source, + unsigned int sourceLen, + int blockSize100k) +{ + bz_stream strm; + int ret; + + if (dest == NULL || destLen == NULL + || source == NULL + || blockSize100k < 1 || blockSize100k > 9 + ) { + return BZ_PARAM_ERROR; + } + + BZ2_bzCompressInit(&strm, blockSize100k); + + strm.next_in = source; + strm.next_out = dest; + strm.avail_in = sourceLen; + strm.avail_out = *destLen; + + ret = BZ2_bzCompress(&strm, BZ_FINISH); + if (ret == BZ_FINISH_OK) goto output_overflow; + if (ret != BZ_STREAM_END) goto errhandler; + + /* normal termination */ + *destLen -= strm.avail_out; + BZ2_bzCompressEnd(&strm); + return BZ_OK; + + output_overflow: + BZ2_bzCompressEnd(&strm); + return BZ_OUTBUFF_FULL; + + errhandler: + BZ2_bzCompressEnd(&strm); + return ret; +} +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/bz/bzlib.h b/busybox-1_37_0/archival/libarchive/bz/bzlib.h new file mode 100644 index 000000000..1bb811c4a --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/bzlib.h @@ -0,0 +1,65 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Public header file for the library. ---*/ +/*--- bzlib.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +#define BZ_RUN 0 +#define BZ_FLUSH 1 +#define BZ_FINISH 2 + +#define BZ_OK 0 +#define BZ_RUN_OK 1 +#define BZ_FLUSH_OK 2 +#define BZ_FINISH_OK 3 +#define BZ_STREAM_END 4 +#define BZ_SEQUENCE_ERROR (-1) +#define BZ_PARAM_ERROR (-2) +#define BZ_MEM_ERROR (-3) +#define BZ_DATA_ERROR (-4) +#define BZ_DATA_ERROR_MAGIC (-5) +#define BZ_IO_ERROR (-6) +#define BZ_UNEXPECTED_EOF (-7) +#define BZ_OUTBUFF_FULL (-8) +#define BZ_CONFIG_ERROR (-9) + +typedef struct bz_stream { + void *state; + char *next_in; + char *next_out; + unsigned avail_in; + unsigned avail_out; + /*unsigned long long total_in;*/ + unsigned long long total_out; +} bz_stream; + +/*-- Core (low-level) library functions --*/ + +static void BZ2_bzCompressInit(bz_stream *strm, int blockSize100k); +static int BZ2_bzCompress(bz_stream *strm, int action); +#if ENABLE_FEATURE_CLEAN_UP +static void BZ2_bzCompressEnd(bz_stream *strm); +#endif + +/*-------------------------------------------------------------*/ +/*--- end bzlib.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/bz/bzlib_private.h b/busybox-1_37_0/archival/libarchive/bz/bzlib_private.h new file mode 100644 index 000000000..650444a5c --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/bzlib_private.h @@ -0,0 +1,226 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Private header file for the library. ---*/ +/*--- bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib.h" */ + +/*-- General stuff. --*/ + +typedef unsigned char Bool; + +#define True ((Bool)1) +#define False ((Bool)0) + +#if BZ_LIGHT_DEBUG +static void bz_assert_fail(int errcode) NORETURN; +#define AssertH(cond, errcode) \ +do { \ + if (!(cond)) \ + bz_assert_fail(errcode); \ +} while (0) +#else +#define AssertH(cond, msg) do { } while (0) +#endif + +#if BZ_DEBUG +#define AssertD(cond, msg) \ +do { \ + if (!(cond)) \ + bb_error_msg_and_die("(debug build): internal error %s", msg); \ +} while (0) +#else +#define AssertD(cond, msg) do { } while (0) +#endif + + +/*-- Header bytes. --*/ + +#define BZ_HDR_B 0x42 /* 'B' */ +#define BZ_HDR_Z 0x5a /* 'Z' */ +#define BZ_HDR_h 0x68 /* 'h' */ +#define BZ_HDR_0 0x30 /* '0' */ + +#define BZ_HDR_BZh0 0x425a6830 + +/*-- Constants for the back end. --*/ + +#define BZ_MAX_ALPHA_SIZE 258 +#define BZ_MAX_CODE_LEN 23 + +#define BZ_RUNA 0 +#define BZ_RUNB 1 + +#define BZ_N_GROUPS 6 +#define BZ_G_SIZE 50 +#define BZ_N_ITERS 4 + +#define BZ_MAX_SELECTORS (2 + (900000 / BZ_G_SIZE)) + + +/*-- Stuff for doing CRCs. --*/ + +#define BZ_INITIALISE_CRC(crcVar) \ +{ \ + crcVar = 0xffffffffL; \ +} + +#define BZ_FINALISE_CRC(crcVar) \ +{ \ + crcVar = ~(crcVar); \ +} + +#define BZ_UPDATE_CRC(s, crcVar, cha) \ +{ \ + crcVar = (crcVar << 8) ^ s->crc32table[(crcVar >> 24) ^ ((uint8_t)cha)]; \ +} + + +/*-- States and modes for compression. --*/ + +#define BZ_M_IDLE 1 +#define BZ_M_RUNNING 2 +#define BZ_M_FLUSHING 3 +#define BZ_M_FINISHING 4 + +#define BZ_S_OUTPUT 1 +#define BZ_S_INPUT 2 + +#define BZ_N_RADIX 2 +#define BZ_N_QSORT 12 +#define BZ_N_SHELL 18 +#define BZ_N_OVERSHOOT (BZ_N_RADIX + BZ_N_QSORT + BZ_N_SHELL + 2) + + +/*-- Structure holding all the compression-side stuff. --*/ + +typedef struct EState { + /* pointer back to the struct bz_stream */ + bz_stream *strm; + + /* mode this stream is in, and whether inputting */ + /* or outputting data */ + uint8_t mode; + uint8_t state; + + /* misc administratium */ + uint8_t blockSize100k; + + /* remembers avail_in when flush/finish requested */ +/* bbox: not needed, strm->avail_in always has the same value */ +/* commented out with '//#' throughout the code */ + /* uint32_t avail_in_expect; */ + + /* for doing the block sorting */ + uint32_t *arr1; + uint32_t *arr2; + //uint32_t *ftab; //moved into this struct, see below + + uint16_t *quadrant; + int32_t budget; + + /* aliases for arr1 and arr2 */ + uint32_t *ptr; + uint8_t *block; + uint16_t *mtfv; + uint8_t *zbits; + + /* run-length-encoding of the input */ + uint32_t state_in_ch; + int32_t state_in_len; + + /* input and output limits and current posns */ + int32_t nblock; + int32_t nblockMAX; + //int32_t numZ; // index into s->zbits[], replaced by pointer: + uint8_t *posZ; + uint8_t *state_out_pos; + + /* the buffer for bit stream creation */ + uint32_t bsBuff; + int32_t bsLive; + + /* block and combined CRCs */ + uint32_t blockCRC; + uint32_t combinedCRC; + + /* misc administratium */ + int32_t blockNo; + + /* stuff for coding the MTF values */ + int32_t nMTF; + + /* map of bytes used in block */ + int32_t nInUse; + Bool inUse[256] ALIGNED(sizeof(long)); + uint8_t unseqToSeq[256]; + + /* stuff for coding the MTF values */ + int32_t mtfFreq [BZ_MAX_ALPHA_SIZE]; + uint8_t selector [BZ_MAX_SELECTORS]; + uint8_t selectorMtf[BZ_MAX_SELECTORS]; + + uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + + /* guess what */ + uint32_t crc32table[256]; + + /* for doing the block sorting */ + uint32_t ftab[65537]; + + /* stack-saving measures: these can be local, but they are too big */ + int32_t sendMTFValues__code [BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + int32_t sendMTFValues__rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; +#if BZIP2_SPEED >= 5 + /* second dimension: only 3 needed; 4 makes index calculations faster */ + uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; +#endif + int32_t BZ2_hbMakeCodeLengths__heap [BZ_MAX_ALPHA_SIZE + 2]; + int32_t BZ2_hbMakeCodeLengths__weight[BZ_MAX_ALPHA_SIZE * 2]; + int32_t BZ2_hbMakeCodeLengths__parent[BZ_MAX_ALPHA_SIZE * 2]; + + int32_t mainSort__copyStart[256]; + int32_t mainSort__copyEnd[256]; +} EState; + + +/*-- compression. --*/ + +static int32_t +BZ2_blockSort(EState*); + +static void +BZ2_compressBlock(EState*, int); + +static void +BZ2_bsInitWrite(EState*); + +static void +BZ2_hbAssignCodes(int32_t*, uint8_t*, int32_t, int32_t, int32_t); + +static void +BZ2_hbMakeCodeLengths(EState*, uint8_t*, int32_t*, int32_t, int32_t); + +/*-------------------------------------------------------------*/ +/*--- end bzlib_private.h ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/bz/compress.c b/busybox-1_37_0/archival/libarchive/bz/compress.c new file mode 100644 index 000000000..539ab927e --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/compress.c @@ -0,0 +1,752 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Compression machinery (not incl block sorting) ---*/ +/*--- compress.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* CHANGES + * 0.9.0 -- original version. + * 0.9.0a/b -- no changes in this file. + * 0.9.0c -- changed setting of nGroups in sendMTFValues() + * so as to do a bit better on small files +*/ + +/* #include "bzlib_private.h" */ + +#if BZIP2_SPEED >= 5 +# define ALWAYS_INLINE_5 ALWAYS_INLINE +#else +# define ALWAYS_INLINE_5 /*nothing*/ +#endif + +/*---------------------------------------------------*/ +/*--- Bit stream I/O ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void BZ2_bsInitWrite(EState* s) +{ + s->bsLive = 0; + s->bsBuff = 0; +} + + +/*---------------------------------------------------*/ +static NOINLINE +void bsFinishWrite(EState* s) +{ + while (s->bsLive > 0) { + *s->posZ++ = (uint8_t)(s->bsBuff >> 24); + s->bsBuff <<= 8; + s->bsLive -= 8; + } +} + + +/*---------------------------------------------------*/ +static +/* Helps only on level 5, on other levels hurts. ? */ +ALWAYS_INLINE_5 +void bsW(EState* s, int32_t n, uint32_t v) +{ + while (s->bsLive >= 8) { + *s->posZ++ = (uint8_t)(s->bsBuff >> 24); + s->bsBuff <<= 8; + s->bsLive -= 8; + } + s->bsBuff |= (v << (32 - s->bsLive - n)); + s->bsLive += n; +} +/* Same with n == 16: */ +static +ALWAYS_INLINE_5 +void bsW16(EState* s, uint32_t v) +{ + while (s->bsLive >= 8) { + *s->posZ++ = (uint8_t)(s->bsBuff >> 24); + s->bsBuff <<= 8; + s->bsLive -= 8; + } + s->bsBuff |= (v << (16 - s->bsLive)); + s->bsLive += 16; +} +/* Same with n == 1: */ +static +ALWAYS_INLINE /* one callsite */ +void bsW1_1(EState* s) +{ + /* need space for only 1 bit, no need for loop freeing > 8 bits */ + if (s->bsLive >= 8) { + *s->posZ++ = (uint8_t)(s->bsBuff >> 24); + s->bsBuff <<= 8; + s->bsLive -= 8; + } + s->bsBuff |= (1 << (31 - s->bsLive)); + s->bsLive += 1; +} +static +ALWAYS_INLINE_5 +void bsW1_0(EState* s) +{ + /* need space for only 1 bit, no need for loop freeing > 8 bits */ + if (s->bsLive >= 8) { + *s->posZ++ = (uint8_t)(s->bsBuff >> 24); + s->bsBuff <<= 8; + s->bsLive -= 8; + } + //s->bsBuff |= (0 << (31 - s->bsLive)); + s->bsLive += 1; +} + + +/*---------------------------------------------------*/ +static ALWAYS_INLINE +void bsPutU16(EState* s, unsigned u) +{ + bsW16(s, u); +} + + +/*---------------------------------------------------*/ +static +void bsPutU32(EState* s, unsigned u) +{ + //bsW(s, 32, u); // can't use: may try "uint32 << -n" + bsW16(s, (u >> 16) & 0xffff); + bsW16(s, u & 0xffff); +} + + +/*---------------------------------------------------*/ +/*--- The back end proper ---*/ +/*---------------------------------------------------*/ + +/*---------------------------------------------------*/ +static +void makeMaps_e(EState* s) +{ + int i; + unsigned cnt = 0; + for (i = 0; i < 256; i++) { + if (s->inUse[i]) { + s->unseqToSeq[i] = cnt; + cnt++; + } + } + s->nInUse = cnt; +} + + +/*---------------------------------------------------*/ +/* + * This bit of code is performance-critical. + * On 32bit x86, gcc-6.3.0 was observed to spill ryy_j to stack, + * resulting in abysmal performance (x3 slowdown). + * Forcing it into a separate function alleviates register pressure, + * and spillage no longer happens. + * Other versions of gcc do not exhibit this problem, but out-of-line code + * seems to be helping them too (code is both smaller and faster). + * Therefore NOINLINE is enabled for the entire 32bit x86 arch for now, + * without a check for gcc version. + */ +static +#if defined __i386__ +NOINLINE +#endif +int inner_loop(uint8_t *yy, uint8_t ll_i) +{ + register uint8_t rtmp; + register uint8_t* ryy_j; + rtmp = yy[1]; + yy[1] = yy[0]; + ryy_j = &(yy[1]); + while (ll_i != rtmp) { + register uint8_t rtmp2; + ryy_j++; + rtmp2 = rtmp; + rtmp = *ryy_j; + *ryy_j = rtmp2; + } + yy[0] = rtmp; + return ryy_j - &(yy[0]); +} +static NOINLINE +void generateMTFValues(EState* s) +{ + uint8_t yy[256]; + int i; + int zPend; + int32_t wr; + + /* + * After sorting (eg, here), + * s->arr1[0 .. s->nblock-1] holds sorted order, + * and + * ((uint8_t*)s->arr2)[0 .. s->nblock-1] + * holds the original block data. + * + * The first thing to do is generate the MTF values, + * and put them in ((uint16_t*)s->arr1)[0 .. s->nblock-1]. + * + * Because there are strictly fewer or equal MTF values + * than block values, ptr values in this area are overwritten + * with MTF values only when they are no longer needed. + * + * The final compressed bitstream is generated into the + * area starting at &((uint8_t*)s->arr2)[s->nblock] + * + * These storage aliases are set up in bzCompressInit(), + * except for the last one, which is arranged in + * compressBlock(). + */ + uint32_t* ptr = s->ptr; + + makeMaps_e(s); + + wr = 0; + zPend = 0; + for (i = 0; i <= s->nInUse+1; i++) + s->mtfFreq[i] = 0; + + for (i = 0; i < s->nInUse; i++) + yy[i] = (uint8_t) i; + + for (i = 0; i < s->nblock; i++) { + uint8_t ll_i = ll_i; /* gcc 4.3.1 thinks it may be used w/o init */ + int32_t j; + + AssertD(wr <= i, "generateMTFValues(1)"); + j = ptr[i] - 1; + if (j < 0) + j += s->nblock; + ll_i = s->unseqToSeq[s->block[j]]; + AssertD(ll_i < s->nInUse, "generateMTFValues(2a)"); + + if (yy[0] == ll_i) { + zPend++; + continue; + } + + if (zPend > 0) { + process_zPend: + zPend--; + while (1) { +#if 0 + if (zPend & 1) { + s->mtfv[wr] = BZ_RUNB; wr++; + s->mtfFreq[BZ_RUNB]++; + } else { + s->mtfv[wr] = BZ_RUNA; wr++; + s->mtfFreq[BZ_RUNA]++; + } +#else /* same as above, since BZ_RUNA is 0 and BZ_RUNB is 1 */ + unsigned run = zPend & 1; + s->mtfv[wr] = run; + wr++; + s->mtfFreq[run]++; +#endif + zPend -= 2; + if (zPend < 0) + break; + zPend = (unsigned)zPend / 2; + /* bbox: unsigned div is easier */ + } + if (i < 0) /* came via "goto process_zPend"? exit */ + goto end; + zPend = 0; + } + j = inner_loop(yy, ll_i); + s->mtfv[wr] = j+1; + wr++; + s->mtfFreq[j+1]++; + } + + i = -1; + if (zPend > 0) + goto process_zPend; /* "process it and come back here" */ + end: + s->mtfv[wr] = s->nInUse+1; + wr++; + s->mtfFreq[s->nInUse+1]++; + + s->nMTF = wr; +} + + +/*---------------------------------------------------*/ +#define BZ_LESSER_ICOST 0 +#define BZ_GREATER_ICOST 15 + +static NOINLINE +void sendMTFValues(EState* s) +{ + int32_t t, i; + unsigned iter; + unsigned gs; + int32_t alphaSize; + unsigned nSelectors, selCtr; + int32_t nGroups; + + /* + * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * is a global since the decoder also needs it. + * + * int32_t code[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * int32_t rfreq[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; + * are also globals only used in this proc. + * Made global to keep stack frame size small. + */ +#define code sendMTFValues__code +#define rfreq sendMTFValues__rfreq +#define len_pack sendMTFValues__len_pack + + unsigned /*uint16_t*/ cost[BZ_N_GROUPS]; + + uint16_t* mtfv = s->mtfv; + + alphaSize = s->nInUse + 2; + for (t = 0; t < BZ_N_GROUPS; t++) { + unsigned v; + for (v = 0; v < alphaSize; v++) + s->len[t][v] = BZ_GREATER_ICOST; + } + + /*--- Decide how many coding tables to use ---*/ + AssertH(s->nMTF > 0, 3001); + // 1..199 = 2 + // 200..599 = 3 + // 600..1199 = 4 + // 1200..2399 = 5 + // 2400..99999 = 6 + nGroups = 2; + nGroups += (s->nMTF >= 200); + nGroups += (s->nMTF >= 600); + nGroups += (s->nMTF >= 1200); + nGroups += (s->nMTF >= 2400); + + /*--- Generate an initial set of coding tables ---*/ + { + unsigned nPart, remF; + + nPart = nGroups; + remF = s->nMTF; + gs = 0; + while (nPart > 0) { + unsigned v; + unsigned ge; + unsigned tFreq, aFreq; + + tFreq = remF / nPart; + ge = gs; + aFreq = 0; + while (aFreq < tFreq && ge < alphaSize) { + aFreq += s->mtfFreq[ge++]; + } + ge--; + + if (ge > gs + && nPart != nGroups && nPart != 1 + && ((nGroups - nPart) % 2 == 1) /* bbox: can this be replaced by x & 1? */ + ) { + aFreq -= s->mtfFreq[ge]; + ge--; + } + + for (v = 0; v < alphaSize; v++) + if (v >= gs && v <= ge) + s->len[nPart-1][v] = BZ_LESSER_ICOST; + else + s->len[nPart-1][v] = BZ_GREATER_ICOST; + + nPart--; + gs = ge + 1; + remF -= aFreq; + } + } + + /* + * Iterate up to BZ_N_ITERS times to improve the tables. + */ + for (iter = 0; iter < BZ_N_ITERS; iter++) { + for (t = 0; t < nGroups; t++) { + unsigned v; + for (v = 0; v < alphaSize; v++) + s->rfreq[t][v] = 0; + } + +#if BZIP2_SPEED >= 5 + /* + * Set up an auxiliary length table which is used to fast-track + * the common case (nGroups == 6). + */ + if (nGroups == 6) { + unsigned v; + for (v = 0; v < alphaSize; v++) { + s->len_pack[v][0] = (s->len[1][v] << 16) | s->len[0][v]; + s->len_pack[v][1] = (s->len[3][v] << 16) | s->len[2][v]; + s->len_pack[v][2] = (s->len[5][v] << 16) | s->len[4][v]; + } + } +#endif + nSelectors = 0; + gs = 0; + while (1) { + unsigned ge; + unsigned bt, bc; + + /*--- Set group start & end marks. --*/ + if (gs >= s->nMTF) + break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) + ge = s->nMTF-1; + + /* + * Calculate the cost of this group as coded + * by each of the coding tables. + */ + for (t = 0; t < nGroups; t++) + cost[t] = 0; +#if BZIP2_SPEED >= 5 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + register uint32_t cost01, cost23, cost45; + register uint16_t icv; + cost01 = cost23 = cost45 = 0; +#define BZ_ITER(nn) \ + icv = mtfv[gs+(nn)]; \ + cost01 += s->len_pack[icv][0]; \ + cost23 += s->len_pack[icv][1]; \ + cost45 += s->len_pack[icv][2]; + BZ_ITER(0); BZ_ITER(1); BZ_ITER(2); BZ_ITER(3); BZ_ITER(4); + BZ_ITER(5); BZ_ITER(6); BZ_ITER(7); BZ_ITER(8); BZ_ITER(9); + BZ_ITER(10); BZ_ITER(11); BZ_ITER(12); BZ_ITER(13); BZ_ITER(14); + BZ_ITER(15); BZ_ITER(16); BZ_ITER(17); BZ_ITER(18); BZ_ITER(19); + BZ_ITER(20); BZ_ITER(21); BZ_ITER(22); BZ_ITER(23); BZ_ITER(24); + BZ_ITER(25); BZ_ITER(26); BZ_ITER(27); BZ_ITER(28); BZ_ITER(29); + BZ_ITER(30); BZ_ITER(31); BZ_ITER(32); BZ_ITER(33); BZ_ITER(34); + BZ_ITER(35); BZ_ITER(36); BZ_ITER(37); BZ_ITER(38); BZ_ITER(39); + BZ_ITER(40); BZ_ITER(41); BZ_ITER(42); BZ_ITER(43); BZ_ITER(44); + BZ_ITER(45); BZ_ITER(46); BZ_ITER(47); BZ_ITER(48); BZ_ITER(49); +#undef BZ_ITER + cost[0] = cost01 & 0xffff; cost[1] = cost01 >> 16; + cost[2] = cost23 & 0xffff; cost[3] = cost23 >> 16; + cost[4] = cost45 & 0xffff; cost[5] = cost45 >> 16; + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + for (i = gs; i <= ge; i++) { + unsigned /*uint16_t*/ icv = mtfv[i]; + for (t = 0; t < nGroups; t++) + cost[t] += s->len[t][icv]; + } + } + /* + * Find the coding table which is best for this group, + * and record its identity in the selector table. + */ + /*bc = 999999999;*/ + /*bt = -1;*/ + bc = cost[0]; + bt = 0; + for (t = 1 /*0*/; t < nGroups; t++) { + if (cost[t] < bc) { + bc = cost[t]; + bt = t; + } + } + s->selector[nSelectors] = bt; + nSelectors++; + + /* + * Increment the symbol frequencies for the selected table. + */ +/* 1% faster compress. +800 bytes */ +#if BZIP2_SPEED >= 4 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ +#define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ + BZ_ITUR(0); BZ_ITUR(1); BZ_ITUR(2); BZ_ITUR(3); BZ_ITUR(4); + BZ_ITUR(5); BZ_ITUR(6); BZ_ITUR(7); BZ_ITUR(8); BZ_ITUR(9); + BZ_ITUR(10); BZ_ITUR(11); BZ_ITUR(12); BZ_ITUR(13); BZ_ITUR(14); + BZ_ITUR(15); BZ_ITUR(16); BZ_ITUR(17); BZ_ITUR(18); BZ_ITUR(19); + BZ_ITUR(20); BZ_ITUR(21); BZ_ITUR(22); BZ_ITUR(23); BZ_ITUR(24); + BZ_ITUR(25); BZ_ITUR(26); BZ_ITUR(27); BZ_ITUR(28); BZ_ITUR(29); + BZ_ITUR(30); BZ_ITUR(31); BZ_ITUR(32); BZ_ITUR(33); BZ_ITUR(34); + BZ_ITUR(35); BZ_ITUR(36); BZ_ITUR(37); BZ_ITUR(38); BZ_ITUR(39); + BZ_ITUR(40); BZ_ITUR(41); BZ_ITUR(42); BZ_ITUR(43); BZ_ITUR(44); + BZ_ITUR(45); BZ_ITUR(46); BZ_ITUR(47); BZ_ITUR(48); BZ_ITUR(49); +#undef BZ_ITUR + gs = ge + 1; + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + while (gs <= ge) { + s->rfreq[bt][mtfv[gs]]++; + gs++; + } + /* already is: gs = ge + 1; */ + } + } + + /* + * Recompute the tables based on the accumulated frequencies. + */ + /* maxLen was changed from 20 to 17 in bzip2-1.0.3. See + * comment in huffman.c for details. */ + for (t = 0; t < nGroups; t++) + BZ2_hbMakeCodeLengths(s, &(s->len[t][0]), &(s->rfreq[t][0]), alphaSize, 17 /*20*/); + } + + AssertH(nGroups < 8, 3002); + AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); + + /*--- Compute MTF values for the selectors. ---*/ + { + uint8_t pos[BZ_N_GROUPS], ll_i, tmp2, tmp; + + for (i = 0; i < nGroups; i++) + pos[i] = i; + for (i = 0; i < nSelectors; i++) { + unsigned j; + ll_i = s->selector[i]; + j = 0; + tmp = pos[j]; + while (ll_i != tmp) { + j++; + tmp2 = tmp; + tmp = pos[j]; + pos[j] = tmp2; + } + pos[0] = tmp; + s->selectorMtf[i] = j; + } + } + + /*--- Assign actual codes for the tables. --*/ + for (t = 0; t < nGroups; t++) { + unsigned minLen = 32; //todo: s->len[t][0]; + unsigned maxLen = 0; //todo: s->len[t][0]; + for (i = 0; i < alphaSize; i++) { + if (s->len[t][i] > maxLen) maxLen = s->len[t][i]; + if (s->len[t][i] < minLen) minLen = s->len[t][i]; + } + AssertH(!(maxLen > 17 /*20*/), 3004); + AssertH(!(minLen < 1), 3005); + BZ2_hbAssignCodes(&(s->code[t][0]), &(s->len[t][0]), minLen, maxLen, alphaSize); + } + + /*--- Transmit the mapping table. ---*/ + { + /* bbox: optimized a bit more than in bzip2 */ + int inUse16 = 0; + for (i = 0; i < 16; i++) { + if (sizeof(long) <= 4) { + inUse16 = inUse16*2 + + ((*(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 0]) + | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 4]) + | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 8]) + | *(bb__aliased_uint32_t*)&(s->inUse[i * 16 + 12])) != 0); + } else { /* Our CPU can do better */ + inUse16 = inUse16*2 + + ((*(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 0]) + | *(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 8])) != 0); + } + } + + bsW16(s, inUse16); + + inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ + for (i = 0; i < 16; i++) { + if (inUse16 < 0) { + unsigned v16 = 0; + unsigned j; + for (j = 0; j < 16; j++) + v16 = v16*2 + s->inUse[i * 16 + j]; + bsW16(s, v16); + } + inUse16 <<= 1; + } + } + + /*--- Now the selectors. ---*/ + bsW(s, 3, nGroups); + bsW(s, 15, nSelectors); + for (i = 0; i < nSelectors; i++) { + unsigned j; + for (j = 0; j < s->selectorMtf[i]; j++) + bsW1_1(s); + bsW1_0(s); + } + + /*--- Now the coding tables. ---*/ + for (t = 0; t < nGroups; t++) { + unsigned curr = s->len[t][0]; + bsW(s, 5, curr); + for (i = 0; i < alphaSize; i++) { + while (curr < s->len[t][i]) { bsW(s, 2, 2); curr++; /* 10 */ } + while (curr > s->len[t][i]) { bsW(s, 2, 3); curr--; /* 11 */ } + bsW1_0(s); + } + } + + /*--- And finally, the block data proper ---*/ + selCtr = 0; + gs = 0; + while (1) { + unsigned ge; + + if (gs >= s->nMTF) + break; + ge = gs + BZ_G_SIZE - 1; + if (ge >= s->nMTF) + ge = s->nMTF-1; + AssertH(s->selector[selCtr] < nGroups, 3006); + +/* Costs 1300 bytes and is _slower_ (on Intel Core 2) */ +#if 0 + if (nGroups == 6 && 50 == ge-gs+1) { + /*--- fast track the common case ---*/ + uint16_t mtfv_i; + uint8_t* s_len_sel_selCtr = &(s->len[s->selector[selCtr]][0]); + int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); +#define BZ_ITAH(nn) \ + mtfv_i = mtfv[gs+(nn)]; \ + bsW(s, s_len_sel_selCtr[mtfv_i], s_code_sel_selCtr[mtfv_i]) + BZ_ITAH(0); BZ_ITAH(1); BZ_ITAH(2); BZ_ITAH(3); BZ_ITAH(4); + BZ_ITAH(5); BZ_ITAH(6); BZ_ITAH(7); BZ_ITAH(8); BZ_ITAH(9); + BZ_ITAH(10); BZ_ITAH(11); BZ_ITAH(12); BZ_ITAH(13); BZ_ITAH(14); + BZ_ITAH(15); BZ_ITAH(16); BZ_ITAH(17); BZ_ITAH(18); BZ_ITAH(19); + BZ_ITAH(20); BZ_ITAH(21); BZ_ITAH(22); BZ_ITAH(23); BZ_ITAH(24); + BZ_ITAH(25); BZ_ITAH(26); BZ_ITAH(27); BZ_ITAH(28); BZ_ITAH(29); + BZ_ITAH(30); BZ_ITAH(31); BZ_ITAH(32); BZ_ITAH(33); BZ_ITAH(34); + BZ_ITAH(35); BZ_ITAH(36); BZ_ITAH(37); BZ_ITAH(38); BZ_ITAH(39); + BZ_ITAH(40); BZ_ITAH(41); BZ_ITAH(42); BZ_ITAH(43); BZ_ITAH(44); + BZ_ITAH(45); BZ_ITAH(46); BZ_ITAH(47); BZ_ITAH(48); BZ_ITAH(49); +#undef BZ_ITAH + gs = ge+1; + } else +#endif + { + /*--- slow version which correctly handles all situations ---*/ + /* code is bit bigger, but moves multiply out of the loop */ + uint8_t* s_len_sel_selCtr = &(s->len [s->selector[selCtr]][0]); + int32_t* s_code_sel_selCtr = &(s->code[s->selector[selCtr]][0]); + while (gs <= ge) { + bsW(s, + s_len_sel_selCtr[mtfv[gs]], + s_code_sel_selCtr[mtfv[gs]] + ); + gs++; + } + /* already is: gs = ge+1; */ + } + selCtr++; + } + AssertH(selCtr == nSelectors, 3007); +#undef code +#undef rfreq +#undef len_pack +} + + +/*---------------------------------------------------*/ +static +void BZ2_compressBlock(EState* s, int is_last_block) +{ + int32_t origPtr = origPtr; + + if (s->nblock > 0) { + BZ_FINALISE_CRC(s->blockCRC); + s->combinedCRC = (s->combinedCRC << 1) | (s->combinedCRC >> 31); + s->combinedCRC ^= s->blockCRC; + if (s->blockNo > 1) + s->posZ = s->zbits; // was: s->numZ = 0; + + origPtr = BZ2_blockSort(s); + } + + s->zbits = &((uint8_t*)s->arr2)[s->nblock]; + s->posZ = s->zbits; + s->state_out_pos = s->zbits; + + /*-- If this is the first block, create the stream header. --*/ + if (s->blockNo == 1) { + BZ2_bsInitWrite(s); + /*bsPutU8(s, BZ_HDR_B);*/ + /*bsPutU8(s, BZ_HDR_Z);*/ + /*bsPutU8(s, BZ_HDR_h);*/ + /*bsPutU8(s, BZ_HDR_0 + s->blockSize100k);*/ + bsPutU32(s, BZ_HDR_BZh0 + s->blockSize100k); + } + + if (s->nblock > 0) { + /*bsPutU8(s, 0x31);*/ + /*bsPutU8(s, 0x41);*/ + /*bsPutU8(s, 0x59);*/ + /*bsPutU8(s, 0x26);*/ + bsPutU32(s, 0x31415926); + /*bsPutU8(s, 0x53);*/ + /*bsPutU8(s, 0x59);*/ + bsPutU16(s, 0x5359); + + /*-- Now the block's CRC, so it is in a known place. --*/ + bsPutU32(s, s->blockCRC); + + /* + * Now a single bit indicating (non-)randomisation. + * As of version 0.9.5, we use a better sorting algorithm + * which makes randomisation unnecessary. So always set + * the randomised bit to 'no'. Of course, the decoder + * still needs to be able to handle randomised blocks + * so as to maintain backwards compatibility with + * older versions of bzip2. + */ + bsW1_0(s); + + bsW(s, 24, origPtr); + generateMTFValues(s); + sendMTFValues(s); + } + + /*-- If this is the last block, add the stream trailer. --*/ + if (is_last_block) { + /*bsPutU8(s, 0x17);*/ + /*bsPutU8(s, 0x72);*/ + /*bsPutU8(s, 0x45);*/ + /*bsPutU8(s, 0x38);*/ + bsPutU32(s, 0x17724538); + /*bsPutU8(s, 0x50);*/ + /*bsPutU8(s, 0x90);*/ + bsPutU16(s, 0x5090); + bsPutU32(s, s->combinedCRC); + bsFinishWrite(s); + } +} + + +/*-------------------------------------------------------------*/ +/*--- end compress.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/bz/huffman.c b/busybox-1_37_0/archival/libarchive/bz/huffman.c new file mode 100644 index 000000000..dc851cd3f --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/bz/huffman.c @@ -0,0 +1,229 @@ +/* + * bzip2 is written by Julian Seward . + * Adapted for busybox by Denys Vlasenko . + * See README and LICENSE files in this directory for more information. + */ + +/*-------------------------------------------------------------*/ +/*--- Huffman coding low-level stuff ---*/ +/*--- huffman.c ---*/ +/*-------------------------------------------------------------*/ + +/* ------------------------------------------------------------------ +This file is part of bzip2/libbzip2, a program and library for +lossless, block-sorting data compression. + +bzip2/libbzip2 version 1.0.4 of 20 December 2006 +Copyright (C) 1996-2006 Julian Seward + +Please read the WARNING, DISCLAIMER and PATENTS sections in the +README file. + +This program is released under the terms of the license contained +in the file LICENSE. +------------------------------------------------------------------ */ + +/* #include "bzlib_private.h" */ + +/*---------------------------------------------------*/ +#define WEIGHTOF(zz0) ((zz0) & 0xffffff00) +#define DEPTHOF(zz1) ((zz1) & 0x000000ff) +#define MYMAX(zz2,zz3) ((zz2) > (zz3) ? (zz2) : (zz3)) + +#define ADDWEIGHTS(zw1,zw2) \ + (WEIGHTOF(zw1)+WEIGHTOF(zw2)) | \ + (1 + MYMAX(DEPTHOF(zw1),DEPTHOF(zw2))) + +#define UPHEAP(z) \ +{ \ + int32_t zz, tmp; \ + zz = z; \ + tmp = heap[zz]; \ + while (weight[tmp] < weight[heap[zz >> 1]]) { \ + heap[zz] = heap[zz >> 1]; \ + zz >>= 1; \ + } \ + heap[zz] = tmp; \ +} + + +/* 90 bytes, 0.3% of overall compress speed */ +#if BZIP2_SPEED >= 1 + +/* macro works better than inline (gcc 4.2.1) */ +#define DOWNHEAP1(heap, weight, Heap) \ +{ \ + int32_t zz, yy, tmp; \ + zz = 1; \ + tmp = heap[zz]; \ + while (1) { \ + yy = zz << 1; \ + if (yy > nHeap) \ + break; \ + if (yy < nHeap \ + && weight[heap[yy+1]] < weight[heap[yy]]) \ + yy++; \ + if (weight[tmp] < weight[heap[yy]]) \ + break; \ + heap[zz] = heap[yy]; \ + zz = yy; \ + } \ + heap[zz] = tmp; \ +} + +#else + +static +void DOWNHEAP1(int32_t *heap, int32_t *weight, int32_t nHeap) +{ + int32_t zz, yy, tmp; + zz = 1; + tmp = heap[zz]; + while (1) { + yy = zz << 1; + if (yy > nHeap) + break; + if (yy < nHeap + && weight[heap[yy + 1]] < weight[heap[yy]]) + yy++; + if (weight[tmp] < weight[heap[yy]]) + break; + heap[zz] = heap[yy]; + zz = yy; + } + heap[zz] = tmp; +} + +#endif + +/*---------------------------------------------------*/ +static +void BZ2_hbMakeCodeLengths(EState *s, + uint8_t *len, + int32_t *freq, + int32_t alphaSize, + int32_t maxLen) +{ + /* + * Nodes and heap entries run from 1. Entry 0 + * for both the heap and nodes is a sentinel. + */ + int32_t nNodes, nHeap, n1, n2, i, j, k; + Bool tooLong; + + /* bbox: moved to EState to save stack + int32_t heap [BZ_MAX_ALPHA_SIZE + 2]; + int32_t weight[BZ_MAX_ALPHA_SIZE * 2]; + int32_t parent[BZ_MAX_ALPHA_SIZE * 2]; + */ +#define heap (s->BZ2_hbMakeCodeLengths__heap) +#define weight (s->BZ2_hbMakeCodeLengths__weight) +#define parent (s->BZ2_hbMakeCodeLengths__parent) + + for (i = 0; i < alphaSize; i++) + weight[i+1] = (freq[i] == 0 ? 1 : freq[i]) << 8; + + while (1) { + nNodes = alphaSize; + nHeap = 0; + + heap[0] = 0; + weight[0] = 0; + parent[0] = -2; + + for (i = 1; i <= alphaSize; i++) { + parent[i] = -1; + nHeap++; + heap[nHeap] = i; + UPHEAP(nHeap); + } + + AssertH(nHeap < (BZ_MAX_ALPHA_SIZE+2), 2001); + + while (nHeap > 1) { + n1 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); + n2 = heap[1]; heap[1] = heap[nHeap]; nHeap--; DOWNHEAP1(heap, weight, nHeap); + nNodes++; + parent[n1] = parent[n2] = nNodes; + weight[nNodes] = ADDWEIGHTS(weight[n1], weight[n2]); + parent[nNodes] = -1; + nHeap++; + heap[nHeap] = nNodes; + UPHEAP(nHeap); + } + + AssertH(nNodes < (BZ_MAX_ALPHA_SIZE * 2), 2002); + + tooLong = False; + for (i = 1; i <= alphaSize; i++) { + j = 0; + k = i; + while (parent[k] >= 0) { + k = parent[k]; + j++; + } + len[i-1] = j; + if (j > maxLen) + tooLong = True; + } + + if (!tooLong) + break; + + /* 17 Oct 04: keep-going condition for the following loop used + to be 'i < alphaSize', which missed the last element, + theoretically leading to the possibility of the compressor + looping. However, this count-scaling step is only needed if + one of the generated Huffman code words is longer than + maxLen, which up to and including version 1.0.2 was 20 bits, + which is extremely unlikely. In version 1.0.3 maxLen was + changed to 17 bits, which has minimal effect on compression + ratio, but does mean this scaling step is used from time to + time, enough to verify that it works. + + This means that bzip2-1.0.3 and later will only produce + Huffman codes with a maximum length of 17 bits. However, in + order to preserve backwards compatibility with bitstreams + produced by versions pre-1.0.3, the decompressor must still + handle lengths of up to 20. */ + + for (i = 1; i <= alphaSize; i++) { + j = weight[i] >> 8; + /* bbox: yes, it is a signed division. + * don't replace with shift! */ + j = 1 + (j / 2); + weight[i] = j << 8; + } + } +#undef heap +#undef weight +#undef parent +} + + +/*---------------------------------------------------*/ +static +void BZ2_hbAssignCodes(int32_t *code, + uint8_t *length, + int32_t minLen, + int32_t maxLen, + int32_t alphaSize) +{ + int32_t n, vec, i; + + vec = 0; + for (n = minLen; n <= maxLen; n++) { + for (i = 0; i < alphaSize; i++) { + if (length[i] == n) { + code[i] = vec; + vec++; + } + } + vec <<= 1; + } +} + + +/*-------------------------------------------------------------*/ +/*--- end huffman.c ---*/ +/*-------------------------------------------------------------*/ diff --git a/busybox-1_37_0/archival/libarchive/common.c b/busybox-1_37_0/archival/libarchive/common.c new file mode 100644 index 000000000..25c7bddad --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/common.c @@ -0,0 +1,8 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +const char cpio_TRAILER[] ALIGN1 = "TRAILER!!!"; diff --git a/busybox-1_37_0/archival/libarchive/data_align.c b/busybox-1_37_0/archival/libarchive/data_align.c new file mode 100644 index 000000000..f61fdd93f --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/data_align.c @@ -0,0 +1,14 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) +{ + unsigned skip_amount = (boundary - (archive_handle->offset % boundary)) % boundary; + + archive_handle->seek(archive_handle->src_fd, skip_amount); + archive_handle->offset += skip_amount; +} diff --git a/busybox-1_37_0/archival/libarchive/data_extract_all.c b/busybox-1_37_0/archival/libarchive/data_extract_all.c new file mode 100644 index 000000000..049c2c156 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/data_extract_all.c @@ -0,0 +1,259 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + int dst_fd; + int res; + char *hard_link; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + char *dst_name; +#else +# define dst_name (file_header->name) +#endif + +#if ENABLE_FEATURE_TAR_SELINUX + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; + if (!sctx) + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; + if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ + setfscreatecon(sctx); + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; + } +#endif + + /* Hard links are encoded as regular files of size 0 + * with a nonempty link field */ + hard_link = NULL; + if (S_ISREG(file_header->mode) && file_header->size == 0) + hard_link = file_header->link_target; + +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + dst_name = file_header->name; + if (archive_handle->tar__strip_components) { + unsigned n = archive_handle->tar__strip_components; + do { + dst_name = strchr(dst_name, '/'); + if (!dst_name || dst_name[1] == '\0') { + data_skip(archive_handle); + goto ret; + } + dst_name++; + /* + * Link target is shortened only for hardlinks: + * softlinks restored unchanged. + */ + if (hard_link) { +// GNU tar 1.26 does not check that we reached end of link name: +// if "dir/hardlink" is hardlinked to "file", +// tar xvf a.tar --strip-components=1 says: +// tar: hardlink: Cannot hard link to '': No such file or directory +// and continues processing. We silently skip such entries. + hard_link = strchr(hard_link, '/'); + if (!hard_link || hard_link[1] == '\0') { + data_skip(archive_handle); + goto ret; + } + hard_link++; + } + } while (--n != 0); + } +#endif + + if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { + char *slash = strrchr(dst_name, '/'); + if (slash) { + *slash = '\0'; + bb_make_directory(dst_name, -1, FILEUTILS_RECUR); + *slash = '/'; + } + } + + if (archive_handle->ah_flags & ARCHIVE_UNLINK_OLD) { + /* Remove the entry if it exists */ + if (!S_ISDIR(file_header->mode)) { + if (hard_link) { + /* Ugly special case: + * tar cf t.tar hardlink1 hardlink2 hardlink1 + * results in this tarball structure: + * hardlink1 + * hardlink2 -> hardlink1 + * hardlink1 -> hardlink1 <== !!! + */ + if (strcmp(hard_link, dst_name) == 0) + goto ret; + } + /* Proceed with deleting */ + if (unlink(dst_name) == -1 + && errno != ENOENT + ) { + bb_perror_msg_and_die("can't remove old file %s", + dst_name); + } + } + } + else if (archive_handle->ah_flags & ARCHIVE_EXTRACT_NEWER) { + /* Remove the existing entry if its older than the extracted entry */ + struct stat existing_sb; + if (lstat(dst_name, &existing_sb) == -1) { + if (errno != ENOENT) { + bb_simple_perror_msg_and_die("can't stat old file"); + } + } + else if (existing_sb.st_mtime >= file_header->mtime) { + if (!S_ISDIR(file_header->mode)) { + bb_error_msg("%s not created: newer or " + "same age file exists", dst_name); + } + data_skip(archive_handle); + goto ret; + } + else if ((unlink(dst_name) == -1) && (errno != EISDIR)) { + bb_perror_msg_and_die("can't remove old file %s", + dst_name); + } + } + + /* Handle hard links separately */ + if (hard_link) { + create_or_remember_link(&archive_handle->link_placeholders, + hard_link, + dst_name, + 1); + /* Hardlinks have no separate mode/ownership, skip chown/chmod */ + goto ret; + } + + /* Create the filesystem entry */ + switch (file_header->mode & S_IFMT) { + case S_IFREG: { + /* Regular file */ + char *dst_nameN; + int flags = O_WRONLY | O_CREAT | O_EXCL; + if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) + flags = O_WRONLY | O_CREAT | O_TRUNC; + dst_nameN = dst_name; +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) + /* rpm-style temp file name */ + dst_nameN = xasprintf("%s;%x", dst_name, (int)getpid()); +#endif + dst_fd = xopen3(dst_nameN, + flags, + file_header->mode + ); + bb_copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size); + close(dst_fd); +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { + xrename(dst_nameN, dst_name); + free(dst_nameN); + } +#endif + break; + } + case S_IFDIR: +//TODO: this causes problems if tarball contains a r-xr-xr-x directory: +// we create this directory, and then fail to create files inside it +// (if tar xf isn't run as root). +// GNU tar works around this by chmod-ing directories *after* all files are extracted. + res = mkdir(dst_name, file_header->mode); + if ((res != 0) + && (errno != EISDIR) /* btw, Linux doesn't return this */ + && (errno != EEXIST) + ) { + bb_perror_msg("can't make dir %s", dst_name); + } + break; + case S_IFLNK: + /* Symlink */ +//TODO: what if file_header->link_target == NULL (say, corrupted tarball?) + + /* To avoid a directory traversal attack via symlinks, + * do not restore symlinks with ".." components + * or symlinks starting with "/", unless a magic + * envvar is set. + * + * For example, consider a .tar created via: + * $ tar cvf bug.tar anything.txt + * $ ln -s /tmp symlink + * $ tar --append -f bug.tar symlink + * $ rm symlink + * $ mkdir symlink + * $ tar --append -f bug.tar symlink/evil.py + * + * This will result in an archive that contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink [-> /tmp] + * symlink/evil.py + * + * Untarring bug.tar would otherwise place evil.py in '/tmp'. + */ + create_or_remember_link(&archive_handle->link_placeholders, + file_header->link_target, + dst_name, + 0); + break; + case S_IFSOCK: + case S_IFBLK: + case S_IFCHR: + case S_IFIFO: + res = mknod(dst_name, file_header->mode, file_header->device); + if (res != 0) { + bb_perror_msg("can't create node %s", dst_name); + } + break; + default: + bb_simple_error_msg_and_die("unrecognized file type"); + } + + if (!S_ISLNK(file_header->mode)) { + if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_OWNER)) { + uid_t uid = file_header->uid; + gid_t gid = file_header->gid; +#if ENABLE_FEATURE_TAR_UNAME_GNAME + if (!(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)) { + if (file_header->tar__uname) { +//TODO: cache last name/id pair? + struct passwd *pwd = getpwnam(file_header->tar__uname); + if (pwd) uid = pwd->pw_uid; + } + if (file_header->tar__gname) { + struct group *grp = getgrnam(file_header->tar__gname); + if (grp) gid = grp->gr_gid; + } + } +#endif + /* GNU tar 1.15.1 uses chown, not lchown */ + chown(dst_name, uid, gid); + } + /* uclibc has no lchmod, glibc is even stranger - + * it has lchmod which seems to do nothing! + * so we use chmod... */ + if (!(archive_handle->ah_flags & ARCHIVE_DONT_RESTORE_PERM)) { + chmod(dst_name, file_header->mode); + } + if (archive_handle->ah_flags & ARCHIVE_RESTORE_DATE) { + struct timeval t[2]; + + t[1].tv_sec = t[0].tv_sec = file_header->mtime; + t[1].tv_usec = t[0].tv_usec = 0; + utimes(dst_name, t); + } + } + + ret: ; +#if ENABLE_FEATURE_TAR_SELINUX + if (sctx) { + /* reset the context after creating an entry */ + setfscreatecon(NULL); + } +#endif +} diff --git a/busybox-1_37_0/archival/libarchive/data_extract_to_command.c b/busybox-1_37_0/archival/libarchive/data_extract_to_command.c new file mode 100644 index 000000000..f8b2ff8d2 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/data_extract_to_command.c @@ -0,0 +1,136 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +enum { + //TAR_FILETYPE, + TAR_MODE, + TAR_FILENAME, + TAR_REALNAME, +#if ENABLE_FEATURE_TAR_UNAME_GNAME + TAR_UNAME, + TAR_GNAME, +#endif + TAR_SIZE, + TAR_UID, + TAR_GID, + TAR_MAX, +}; + +static const char *const tar_var[] ALIGN_PTR = { + // "FILETYPE", + "MODE", + "FILENAME", + "REALNAME", +#if ENABLE_FEATURE_TAR_UNAME_GNAME + "UNAME", + "GNAME", +#endif + "SIZE", + "UID", + "GID", +}; + +static void xputenv(char *str) +{ + if (putenv(str)) + bb_die_memory_exhausted(); +} + +static void str2env(char *env[], int idx, const char *str) +{ + env[idx] = xasprintf("TAR_%s=%s", tar_var[idx], str); + xputenv(env[idx]); +} + +static void dec2env(char *env[], int idx, unsigned long long val) +{ + env[idx] = xasprintf("TAR_%s=%llu", tar_var[idx], val); + xputenv(env[idx]); +} + +static void oct2env(char *env[], int idx, unsigned long val) +{ + env[idx] = xasprintf("TAR_%s=%lo", tar_var[idx], val); + xputenv(env[idx]); +} + +void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + +#if 0 /* do we need this? ENABLE_FEATURE_TAR_SELINUX */ + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; + if (!sctx) + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; + if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ + setfscreatecon(sctx); + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; + } +#endif + + if ((file_header->mode & S_IFMT) == S_IFREG) { + pid_t pid; + int p[2], status; + char *tar_env[TAR_MAX]; + + memset(tar_env, 0, sizeof(tar_env)); + + xpipe(p); + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { + /* Child */ + /* str2env(tar_env, TAR_FILETYPE, "f"); - parent should do it once */ + oct2env(tar_env, TAR_MODE, file_header->mode); + str2env(tar_env, TAR_FILENAME, file_header->name); + str2env(tar_env, TAR_REALNAME, file_header->name); +#if ENABLE_FEATURE_TAR_UNAME_GNAME + str2env(tar_env, TAR_UNAME, file_header->tar__uname); + str2env(tar_env, TAR_GNAME, file_header->tar__gname); +#endif + dec2env(tar_env, TAR_SIZE, file_header->size); + dec2env(tar_env, TAR_UID, file_header->uid); + dec2env(tar_env, TAR_GID, file_header->gid); + close(p[1]); + xdup2(p[0], STDIN_FILENO); + signal(SIGPIPE, SIG_DFL); + execl(archive_handle->tar__to_command_shell, + archive_handle->tar__to_command_shell, + "-c", + archive_handle->tar__to_command, + (char *)0); + bb_perror_msg_and_die("can't execute '%s'", archive_handle->tar__to_command_shell); + } + close(p[0]); + /* Our caller is expected to do signal(SIGPIPE, SIG_IGN) + * so that we don't die if child don't read all the input: */ + bb_copyfd_exact_size(archive_handle->src_fd, p[1], -file_header->size); + close(p[1]); + + status = wait_for_exitstatus(pid); + if (WIFEXITED(status) && WEXITSTATUS(status)) + bb_error_msg_and_die("'%s' returned status %d", + archive_handle->tar__to_command, WEXITSTATUS(status)); + if (WIFSIGNALED(status)) + bb_error_msg_and_die("'%s' terminated by signal %d", + archive_handle->tar__to_command, WTERMSIG(status)); + + if (!BB_MMU) { + int i; + for (i = 0; i < TAR_MAX; i++) { + if (tar_env[i]) + bb_unsetenv_and_free(tar_env[i]); + } + } + } + +#if 0 /* ENABLE_FEATURE_TAR_SELINUX */ + if (sctx) + /* reset the context after creating an entry */ + setfscreatecon(NULL); +#endif +} diff --git a/busybox-1_37_0/archival/libarchive/data_extract_to_stdout.c b/busybox-1_37_0/archival/libarchive/data_extract_to_stdout.c new file mode 100644 index 000000000..520041329 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/data_extract_to_stdout.c @@ -0,0 +1,13 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) +{ + bb_copyfd_exact_size(archive_handle->src_fd, + STDOUT_FILENO, + archive_handle->file_header->size); +} diff --git a/busybox-1_37_0/archival/libarchive/data_skip.c b/busybox-1_37_0/archival/libarchive/data_skip.c new file mode 100644 index 000000000..1a608227e --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/data_skip.c @@ -0,0 +1,11 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC data_skip(archive_handle_t *archive_handle) +{ + archive_handle->seek(archive_handle->src_fd, archive_handle->file_header->size); +} diff --git a/busybox-1_37_0/archival/libarchive/decompress_bunzip2.c b/busybox-1_37_0/archival/libarchive/decompress_bunzip2.c new file mode 100644 index 000000000..4a2b668aa --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/decompress_bunzip2.c @@ -0,0 +1,900 @@ +/* vi: set sw=4 ts=4: */ +/* + * Small bzip2 deflate implementation, by Rob Landley (rob@landley.net). + * + * Based on bzip2 decompression code by Julian R Seward (jseward@acm.org), + * which also acknowledges contributions by Mike Burrows, David Wheeler, + * Peter Fenwick, Alistair Moffat, Radford Neal, Ian H. Witten, + * Robert Sedgewick, and Jon L. Bentley. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* + Size and speed optimizations by Manuel Novoa III (mjn3@codepoet.org). + + More efficient reading of Huffman codes, a streamlined read_bunzip() + function, and various other tweaks. In (limited) tests, approximately + 20% faster than bzcat on x86 and about 10% faster on arm. + + Note that about 2/3 of the time is spent in read_bunzip() reversing + the Burrows-Wheeler transformation. Much of that time is delay + resulting from cache misses. + + (2010 update by vda: profiled "bzcat <84mbyte.bz2 >/dev/null" + on x86-64 CPU with L2 > 1M: get_next_block is hotter than read_bunzip: + %time seconds calls function + 71.01 12.69 444 get_next_block + 28.65 5.12 93065 read_bunzip + 00.22 0.04 7736490 get_bits + 00.11 0.02 47 dealloc_bunzip + 00.00 0.00 93018 full_write + ...) + + + I would ask that anyone benefiting from this work, especially those + using it in commercial products, consider making a donation to my local + non-profit hospice organization (www.hospiceacadiana.com) in the name of + the woman I loved, Toni W. Hagan, who passed away Feb. 12, 2003. + + Manuel + */ +#include "libbb.h" +#include "bb_archive.h" + +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + +/* Constants for Huffman coding */ +#define MAX_GROUPS 6 +#define GROUP_SIZE 50 /* 64 would have been more efficient */ +#define MAX_HUFCODE_BITS 20 /* Longest Huffman code allowed */ +#define MAX_SYMBOLS 258 /* 256 literals + RUNA + RUNB */ +#define SYMBOL_RUNA 0 +#define SYMBOL_RUNB 1 + +/* Status return values */ +#define RETVAL_OK 0 +#define RETVAL_LAST_BLOCK (dbg("%d", __LINE__), -1) +#define RETVAL_NOT_BZIP_DATA (dbg("%d", __LINE__), -2) +#define RETVAL_UNEXPECTED_INPUT_EOF (dbg("%d", __LINE__), -3) +#define RETVAL_SHORT_WRITE (dbg("%d", __LINE__), -4) +#define RETVAL_DATA_ERROR (dbg("%d", __LINE__), -5) +#define RETVAL_OUT_OF_MEMORY (dbg("%d", __LINE__), -6) +#define RETVAL_OBSOLETE_INPUT (dbg("%d", __LINE__), -7) + +/* Other housekeeping constants */ +#define IOBUF_SIZE 4096 + +/* This is what we know about each Huffman coding group */ +struct group_data { + /* We have an extra slot at the end of limit[] for a sentinel value. */ + int limit[MAX_HUFCODE_BITS+1], base[MAX_HUFCODE_BITS], permute[MAX_SYMBOLS]; + int minLen, maxLen; +}; + +/* Structure holding all the housekeeping data, including IO buffers and + * memory that persists between calls to bunzip + * Found the most used member: + * cat this_file.c | sed -e 's/"/ /g' -e "s/'/ /g" | xargs -n1 \ + * | grep 'bd->' | sed 's/^.*bd->/bd->/' | sort | $PAGER + * and moved it (inbufBitCount) to offset 0. + */ +struct bunzip_data { + /* I/O tracking data (file handles, buffers, positions, etc.) */ + unsigned inbufBitCount, inbufBits; + int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; + uint8_t *inbuf /*,*outbuf*/; + + /* State for interrupting output loop */ + int writeCopies, writePos, writeRunCountdown, writeCount; + int writeCurrent; /* actually a uint8_t */ + + /* The CRC values stored in the block header and calculated from the data */ + uint32_t headerCRC, totalCRC, writeCRC; + + /* Intermediate buffer and its size (in bytes) */ + uint32_t *dbuf; + unsigned dbufSize; + + /* For I/O error handling */ + jmp_buf *jmpbuf; + + /* Big things go last (register-relative addressing can be larger for big offsets) */ + uint32_t crc32Table[256]; + uint8_t selectors[32768]; /* nSelectors=15 bits */ + struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ +}; +typedef struct bunzip_data bunzip_data; + + +/* Return the next nnn bits of input. All reads from the compressed input + are done through this function. All reads are big endian */ +static unsigned get_bits(bunzip_data *bd, int bits_wanted) +{ + unsigned bits = 0; + /* Cache bd->inbufBitCount in a CPU register (hopefully): */ + int bit_count = bd->inbufBitCount; + + /* If we need to get more data from the byte buffer, do so. (Loop getting + one byte at a time to enforce endianness and avoid unaligned access.) */ + while (bit_count < bits_wanted) { + + /* If we need to read more data from file into byte buffer, do so */ + if (bd->inbufPos == bd->inbufCount) { + /* if "no input fd" case: in_fd == -1, read fails, we jump */ + bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE); + if (bd->inbufCount <= 0) + longjmp(*bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF); + bd->inbufPos = 0; + } + + /* Avoid 32-bit overflow (dump bit buffer to top of output) */ + if (bit_count >= 24) { + bits = bd->inbufBits & ((1U << bit_count) - 1); + bits_wanted -= bit_count; + bits <<= bits_wanted; + bit_count = 0; + } + + /* Grab next 8 bits of input from buffer. */ + bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; + bit_count += 8; + } + + /* Calculate result */ + bit_count -= bits_wanted; + bd->inbufBitCount = bit_count; + bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1); + + return bits; +} +//#define get_bits(bd, n) (dbg("%d:get_bits()", __LINE__), get_bits(bd, n)) + +/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ +static int get_next_block(bunzip_data *bd) +{ + int groupCount, selector, + i, j, symCount, symTotal, nSelectors, byteCount[256]; + uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; + uint32_t *dbuf; + unsigned origPtr, t; + unsigned dbufCount, runPos; + unsigned runCnt = runCnt; /* for compiler */ + + dbuf = bd->dbuf; + selectors = bd->selectors; + +/* In bbox, we are ok with aborting through setjmp which is set up in start_bunzip */ +#if 0 + /* Reset longjmp I/O error handling */ + i = setjmp(bd->jmpbuf); + if (i) return i; +#endif + + /* Read in header signature and CRC, then validate signature. + (last block signature means CRC is for whole file, return now) */ + i = get_bits(bd, 24); + j = get_bits(bd, 24); + bd->headerCRC = get_bits(bd, 32); + if ((i == 0x177245) && (j == 0x385090)) + return RETVAL_LAST_BLOCK; + if ((i != 0x314159) || (j != 0x265359)) + return RETVAL_NOT_BZIP_DATA; + + /* We can add support for blockRandomised if anybody complains. There was + some code for this in busybox 1.0.0-pre3, but nobody ever noticed that + it didn't actually work. */ + if (get_bits(bd, 1)) + return RETVAL_OBSOLETE_INPUT; + origPtr = get_bits(bd, 24); + if (origPtr > bd->dbufSize) + return RETVAL_DATA_ERROR; + + /* mapping table: if some byte values are never used (encoding things + like ascii text), the compression code removes the gaps to have fewer + symbols to deal with, and writes a sparse bitfield indicating which + values were present. We make a translation table to convert the symbols + back to the corresponding bytes. */ + symTotal = 0; + i = 0; + t = get_bits(bd, 16); + do { + if (t & (1 << 15)) { + unsigned inner_map = get_bits(bd, 16); + do { + if (inner_map & (1 << 15)) + symToByte[symTotal++] = i; + inner_map <<= 1; + i++; + } while (i & 15); + i -= 16; + } + t <<= 1; + i += 16; + } while (i < 256); + + /* How many different Huffman coding groups does this block use? */ + groupCount = get_bits(bd, 3); + if (groupCount < 2 || groupCount > MAX_GROUPS) + return RETVAL_DATA_ERROR; + + /* nSelectors: Every GROUP_SIZE many symbols we select a new Huffman coding + group. Read in the group selector list, which is stored as MTF encoded + bit runs. (MTF=Move To Front, as each value is used it's moved to the + start of the list.) */ + for (i = 0; i < groupCount; i++) + mtfSymbol[i] = i; + nSelectors = get_bits(bd, 15); + if (!nSelectors) + return RETVAL_DATA_ERROR; + for (i = 0; i < nSelectors; i++) { + uint8_t tmp_byte; + /* Get next value */ + int n = 0; + while (get_bits(bd, 1)) { + n++; + if (n >= groupCount) + return RETVAL_DATA_ERROR; + } + /* Decode MTF to get the next selector */ + tmp_byte = mtfSymbol[n]; + while (--n >= 0) + mtfSymbol[n + 1] = mtfSymbol[n]; +//We catch it later, in the second loop where we use selectors[i]. +//Maybe this is a better place, though? +// if (tmp_byte >= groupCount) { +// dbg("%d: selectors[%d]:%d groupCount:%d", +// __LINE__, i, tmp_byte, groupCount); +// return RETVAL_DATA_ERROR; +// } + mtfSymbol[0] = selectors[i] = tmp_byte; + } + + /* Read the Huffman coding tables for each group, which code for symTotal + literal symbols, plus two run symbols (RUNA, RUNB) */ + symCount = symTotal + 2; + for (j = 0; j < groupCount; j++) { + uint8_t length[MAX_SYMBOLS]; + /* 8 bits is ALMOST enough for temp[], see below */ + unsigned temp[MAX_HUFCODE_BITS+1]; + struct group_data *hufGroup; + int *base, *limit; + int minLen, maxLen, pp, len_m1; + + /* Read Huffman code lengths for each symbol. They're stored in + a way similar to mtf; record a starting value for the first symbol, + and an offset from the previous value for every symbol after that. + (Subtracting 1 before the loop and then adding it back at the end is + an optimization that makes the test inside the loop simpler: symbol + length 0 becomes negative, so an unsigned inequality catches it.) */ + len_m1 = get_bits(bd, 5) - 1; + for (i = 0; i < symCount; i++) { + for (;;) { + int two_bits; + if ((unsigned)len_m1 > (MAX_HUFCODE_BITS-1)) + return RETVAL_DATA_ERROR; + + /* If first bit is 0, stop. Else second bit indicates whether + to increment or decrement the value. Optimization: grab 2 + bits and unget the second if the first was 0. */ + two_bits = get_bits(bd, 2); + if (two_bits < 2) { + bd->inbufBitCount++; + break; + } + + /* Add one if second bit 1, else subtract 1. Avoids if/else */ + len_m1 += (((two_bits+1) & 2) - 1); + } + + /* Correct for the initial -1, to get the final symbol length */ + length[i] = len_m1 + 1; + } + + /* Find largest and smallest lengths in this group */ + minLen = maxLen = length[0]; + for (i = 1; i < symCount; i++) { + if (length[i] > maxLen) + maxLen = length[i]; + else if (length[i] < minLen) + minLen = length[i]; + } + + /* Calculate permute[], base[], and limit[] tables from length[]. + * + * permute[] is the lookup table for converting Huffman coded symbols + * into decoded symbols. base[] is the amount to subtract from the + * value of a Huffman symbol of a given length when using permute[]. + * + * limit[] indicates the largest numerical value a symbol with a given + * number of bits can have. This is how the Huffman codes can vary in + * length: each code with a value>limit[length] needs another bit. + */ + hufGroup = bd->groups + j; + hufGroup->minLen = minLen; + hufGroup->maxLen = maxLen; + + /* Note that minLen can't be smaller than 1, so we adjust the base + and limit array pointers so we're not always wasting the first + entry. We do this again when using them (during symbol decoding). */ + base = hufGroup->base - 1; + limit = hufGroup->limit - 1; + + /* Calculate permute[]. Concurrently, initialize temp[] and limit[]. */ + pp = 0; + for (i = minLen; i <= maxLen; i++) { + int k; + temp[i] = limit[i] = 0; + for (k = 0; k < symCount; k++) + if (length[k] == i) + hufGroup->permute[pp++] = k; + } + + /* Count symbols coded for at each bit length */ + /* NB: in pathological cases, temp[8] can end ip being 256. + * That's why uint8_t is too small for temp[]. */ + for (i = 0; i < symCount; i++) + temp[length[i]]++; + + /* Calculate limit[] (the largest symbol-coding value at each bit + * length, which is (previous limit<<1)+symbols at this level), and + * base[] (number of symbols to ignore at each bit length, which is + * limit minus the cumulative count of symbols coded for already). */ + pp = t = 0; + for (i = minLen; i < maxLen;) { + unsigned temp_i = temp[i]; + + pp += temp_i; + + /* We read the largest possible symbol size and then unget bits + after determining how many we need, and those extra bits could + be set to anything. (They're noise from future symbols.) At + each level we're really only interested in the first few bits, + so here we set all the trailing to-be-ignored bits to 1 so they + don't affect the value>limit[length] comparison. */ + limit[i] = (pp << (maxLen - i)) - 1; + pp <<= 1; + t += temp_i; + base[++i] = pp - t; + } + limit[maxLen] = pp + temp[maxLen] - 1; + limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ + base[minLen] = 0; + } + + /* We've finished reading and digesting the block header. Now read this + block's Huffman coded symbols from the file and undo the Huffman coding + and run length encoding, saving the result into dbuf[dbufCount++] = uc */ + + /* Initialize symbol occurrence counters and symbol Move To Front table */ + /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */ + for (i = 0; i < 256; i++) { + byteCount[i] = 0; + mtfSymbol[i] = (uint8_t)i; + } + + /* Loop through compressed symbols. */ + + runPos = dbufCount = selector = 0; + for (;;) { + struct group_data *hufGroup; + int *base, *limit; + int nextSym; + uint8_t ngrp; + + /* Fetch next Huffman coding group from list. */ + symCount = GROUP_SIZE - 1; + if (selector >= nSelectors) + return RETVAL_DATA_ERROR; + ngrp = selectors[selector++]; + if (ngrp >= groupCount) { + dbg("%d selectors[%d]:%d groupCount:%d", + __LINE__, selector-1, ngrp, groupCount); + return RETVAL_DATA_ERROR; + } + hufGroup = bd->groups + ngrp; + base = hufGroup->base - 1; + limit = hufGroup->limit - 1; + + continue_this_group: + /* Read next Huffman-coded symbol. */ + + /* Note: It is far cheaper to read maxLen bits and back up than it is + to read minLen bits and then add additional bit at a time, testing + as we go. Because there is a trailing last block (with file CRC), + there is no danger of the overread causing an unexpected EOF for a + valid compressed file. + */ + if (1) { + /* As a further optimization, we do the read inline + (falling back to a call to get_bits if the buffer runs dry). + */ + int new_cnt; + while ((new_cnt = bd->inbufBitCount - hufGroup->maxLen) < 0) { + /* bd->inbufBitCount < hufGroup->maxLen */ + if (bd->inbufPos == bd->inbufCount) { + nextSym = get_bits(bd, hufGroup->maxLen); + goto got_huff_bits; + } + bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; + bd->inbufBitCount += 8; + }; + bd->inbufBitCount = new_cnt; /* "bd->inbufBitCount -= hufGroup->maxLen;" */ + nextSym = (bd->inbufBits >> new_cnt) & ((1 << hufGroup->maxLen) - 1); + got_huff_bits: ; + } else { /* unoptimized equivalent */ + nextSym = get_bits(bd, hufGroup->maxLen); + } + /* Figure how many bits are in next symbol and unget extras */ + i = hufGroup->minLen; + while (nextSym > limit[i]) + ++i; + j = hufGroup->maxLen - i; + if (j < 0) + return RETVAL_DATA_ERROR; + bd->inbufBitCount += j; + + /* Huffman decode value to get nextSym (with bounds checking) */ + nextSym = (nextSym >> j) - base[i]; + if ((unsigned)nextSym >= MAX_SYMBOLS) + return RETVAL_DATA_ERROR; + nextSym = hufGroup->permute[nextSym]; + + /* We have now decoded the symbol, which indicates either a new literal + byte, or a repeated run of the most recent literal byte. First, + check if nextSym indicates a repeated run, and if so loop collecting + how many times to repeat the last literal. */ + if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ + + /* If this is the start of a new run, zero out counter */ + if (runPos == 0) { + runPos = 1; + runCnt = 0; + } + + /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at + each bit position, add 1 or 2 instead. For example, + 1011 is 1<<0 + 1<<1 + 2<<2. 1010 is 2<<0 + 2<<1 + 1<<2. + You can make any bit pattern that way using 1 less symbol than + the basic or 0/1 method (except all bits 0, which would use no + symbols, but a run of length 0 doesn't mean anything in this + context). Thus space is saved. */ + runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ +//The 32-bit overflow of runCnt wasn't yet seen, but probably can happen. +//This would be the fix (catches too large count way before it can overflow): +// if (runCnt > bd->dbufSize) { +// dbg("runCnt:%u > dbufSize:%u RETVAL_DATA_ERROR", +// runCnt, bd->dbufSize); +// return RETVAL_DATA_ERROR; +// } + if (runPos < bd->dbufSize) runPos <<= 1; + goto end_of_huffman_loop; + } + + /* When we hit the first non-run symbol after a run, we now know + how many times to repeat the last literal, so append that many + copies to our buffer of decoded symbols (dbuf) now. (The last + literal used is the one at the head of the mtfSymbol array.) */ + if (runPos != 0) { + uint8_t tmp_byte; + if (dbufCount + runCnt > bd->dbufSize) { + dbg("dbufCount:%u+runCnt:%u %u > dbufSize:%u RETVAL_DATA_ERROR", + dbufCount, runCnt, dbufCount + runCnt, bd->dbufSize); + return RETVAL_DATA_ERROR; + } + tmp_byte = symToByte[mtfSymbol[0]]; + byteCount[tmp_byte] += runCnt; + while ((int)--runCnt >= 0) + dbuf[dbufCount++] = (uint32_t)tmp_byte; + runPos = 0; + } + + /* Is this the terminating symbol? */ + if (nextSym > symTotal) break; + + /* At this point, nextSym indicates a new literal character. Subtract + one to get the position in the MTF array at which this literal is + currently to be found. (Note that the result can't be -1 or 0, + because 0 and 1 are RUNA and RUNB. But another instance of the + first symbol in the mtf array, position 0, would have been handled + as part of a run above. Therefore 1 unused mtf position minus + 2 non-literal nextSym values equals -1.) */ + if (dbufCount >= bd->dbufSize) return RETVAL_DATA_ERROR; + i = nextSym - 1; + uc = mtfSymbol[i]; + + /* Adjust the MTF array. Since we typically expect to move only a + * small number of symbols, and are bound by 256 in any case, using + * memmove here would typically be bigger and slower due to function + * call overhead and other assorted setup costs. */ + do { + mtfSymbol[i] = mtfSymbol[i-1]; + } while (--i); + mtfSymbol[0] = uc; + uc = symToByte[uc]; + + /* We have our literal byte. Save it into dbuf. */ + byteCount[uc]++; + dbuf[dbufCount++] = (uint32_t)uc; + + /* Skip group initialization if we're not done with this group. Done + * this way to avoid compiler warning. */ + end_of_huffman_loop: + if (--symCount >= 0) goto continue_this_group; + } + + /* At this point, we've read all the Huffman-coded symbols (and repeated + runs) for this block from the input stream, and decoded them into the + intermediate buffer. There are dbufCount many decoded bytes in dbuf[]. + Now undo the Burrows-Wheeler transform on dbuf. + See http://dogma.net/markn/articles/bwt/bwt.htm + */ + + /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ + j = 0; + for (i = 0; i < 256; i++) { + int tmp_count = j + byteCount[i]; + byteCount[i] = j; + j = tmp_count; + } + + /* Figure out what order dbuf would be in if we sorted it. */ + for (i = 0; i < dbufCount; i++) { + uint8_t tmp_byte = (uint8_t)dbuf[i]; + int tmp_count = byteCount[tmp_byte]; + dbuf[tmp_count] |= (i << 8); + byteCount[tmp_byte] = tmp_count + 1; + } + + /* Decode first byte by hand to initialize "previous" byte. Note that it + doesn't get output, and if the first three characters are identical + it doesn't qualify as a run (hence writeRunCountdown=5). */ + if (dbufCount) { + uint32_t tmp; + if ((int)origPtr >= dbufCount) return RETVAL_DATA_ERROR; + tmp = dbuf[origPtr]; + bd->writeCurrent = (uint8_t)tmp; + bd->writePos = (tmp >> 8); + bd->writeRunCountdown = 5; + } + bd->writeCount = dbufCount; + + return RETVAL_OK; +} + +/* Undo Burrows-Wheeler transform on intermediate buffer to produce output. + If start_bunzip was initialized with out_fd=-1, then up to len bytes of + data are written to outbuf. Return value is number of bytes written or + error (all errors are negative numbers). If out_fd!=-1, outbuf and len + are ignored, data is written to out_fd and return is RETVAL_OK or error. + + NB: read_bunzip returns < 0 on error, or the number of *unfilled* bytes + in outbuf. IOW: on EOF returns len ("all bytes are not filled"), not 0. + (Why? This allows to get rid of one local variable) +*/ +static int read_bunzip(bunzip_data *bd, char *outbuf, int len) +{ + const uint32_t *dbuf; + int pos, current, previous; + uint32_t CRC; + + /* If we already have error/end indicator, return it */ + if (bd->writeCount < 0) + return bd->writeCount; + + dbuf = bd->dbuf; + + /* Register-cached state (hopefully): */ + pos = bd->writePos; + current = bd->writeCurrent; + CRC = bd->writeCRC; /* small loss on x86-32 (not enough regs), win on x86-64 */ + + /* We will always have pending decoded data to write into the output + buffer unless this is the very first call (in which case we haven't + Huffman-decoded a block into the intermediate buffer yet). */ + if (bd->writeCopies) { + + dec_writeCopies: + /* Inside the loop, writeCopies means extra copies (beyond 1) */ + --bd->writeCopies; + + /* Loop outputting bytes */ + for (;;) { + + /* If the output buffer is full, save cached state and return */ + if (--len < 0) { + /* Unlikely branch. + * Use of "goto" instead of keeping code here + * helps compiler to realize this. */ + goto outbuf_full; + } + + /* Write next byte into output buffer, updating CRC */ + *outbuf++ = current; + CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; + + /* Loop now if we're outputting multiple copies of this byte */ + if (bd->writeCopies) { + /* Unlikely branch */ + /*--bd->writeCopies;*/ + /*continue;*/ + /* Same, but (ab)using other existing --writeCopies operation + * (and this if() compiles into just test+branch pair): */ + goto dec_writeCopies; + } + decode_next_byte: + if (--bd->writeCount < 0) + break; /* input block is fully consumed, need next one */ + + /* Follow sequence vector to undo Burrows-Wheeler transform */ + previous = current; + pos = dbuf[pos]; + current = (uint8_t)pos; + pos >>= 8; + + /* After 3 consecutive copies of the same byte, the 4th + * is a repeat count. We count down from 4 instead + * of counting up because testing for non-zero is faster */ + if (--bd->writeRunCountdown != 0) { + if (current != previous) + bd->writeRunCountdown = 4; + } else { + /* Unlikely branch */ + /* We have a repeated run, this byte indicates the count */ + bd->writeCopies = current; + current = previous; + bd->writeRunCountdown = 5; + + /* Sometimes there are just 3 bytes (run length 0) */ + if (!bd->writeCopies) goto decode_next_byte; + + /* Subtract the 1 copy we'd output anyway to get extras */ + --bd->writeCopies; + } + } /* for (;;) */ + + /* Decompression of this input block completed successfully */ + bd->writeCRC = CRC = ~CRC; + bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ CRC; + + /* If this block had a CRC error, force file level CRC error */ + if (CRC != bd->headerCRC) { + bd->totalCRC = bd->headerCRC + 1; + return RETVAL_LAST_BLOCK; + } + } + + /* Refill the intermediate buffer by Huffman-decoding next block of input */ + { + int r = get_next_block(bd); + if (r) { /* error/end */ + bd->writeCount = r; + return (r != RETVAL_LAST_BLOCK) ? r : len; + } + } + + CRC = ~0; + pos = bd->writePos; + current = bd->writeCurrent; + goto decode_next_byte; + + outbuf_full: + /* Output buffer is full, save cached state and return */ + bd->writePos = pos; + bd->writeCurrent = current; + bd->writeCRC = CRC; + + bd->writeCopies++; + + return 0; +} + +/* Allocate the structure, read file header. If in_fd==-1, inbuf must contain + a complete bunzip file (len bytes long). If in_fd!=-1, inbuf and len are + ignored, and data is read from file handle into temporary buffer. */ + +/* Because bunzip2 is used for help text unpacking, and because bb_show_usage() + should work for NOFORK applets too, we must be extremely careful to not leak + any allocations! */ +static int FAST_FUNC start_bunzip( + void *jmpbuf, + bunzip_data **bdp, + int in_fd, + const void *inbuf, int len) +{ + bunzip_data *bd; + unsigned i; + enum { + BZh0 = ('B' << 24) + ('Z' << 16) + ('h' << 8) + '0', + h0 = ('h' << 8) + '0', + }; + + /* Figure out how much data to allocate */ + i = sizeof(bunzip_data); + if (in_fd != -1) + i += IOBUF_SIZE; + + /* Allocate bunzip_data. Most fields initialize to zero. */ + bd = *bdp = xzalloc(i); + + bd->jmpbuf = jmpbuf; + + /* Setup input buffer */ + bd->in_fd = in_fd; + if (-1 == in_fd) { + /* in this case, bd->inbuf is read-only */ + bd->inbuf = (void*)inbuf; /* cast away const-ness */ + } else { + bd->inbuf = (uint8_t*)(bd + 1); + memcpy(bd->inbuf, inbuf, len); + } + bd->inbufCount = len; + + /* Init the CRC32 table (big endian) */ + crc32_filltable(bd->crc32Table, 1); + + /* Ensure that file starts with "BZh['1'-'9']." */ + /* Update: now caller verifies 1st two bytes, makes .gz/.bz2 + * integration easier */ + /* was: */ + /* i = get_bits(bd, 32); */ + /* if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; */ + i = get_bits(bd, 16); + if ((unsigned)(i - h0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA; + + /* Fourth byte (ascii '1'-'9') indicates block size in units of 100k of + uncompressed data. Allocate intermediate buffer for block. */ + /* bd->dbufSize = 100000 * (i - BZh0); */ + bd->dbufSize = 100000 * (i - h0); + + /* Cannot use xmalloc - may leak bd in NOFORK case! */ + bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0])); + if (!bd->dbuf) { + free(bd); + xfunc_die(); + } + return RETVAL_OK; +} + +static void FAST_FUNC dealloc_bunzip(bunzip_data *bd) +{ + free(bd->dbuf); + free(bd); +} + + +/* Decompress src_fd to dst_fd. Stops at end of bzip data, not end of file. */ +IF_DESKTOP(long long) int FAST_FUNC +unpack_bz2_stream(transformer_state_t *xstate) +{ + IF_DESKTOP(long long total_written = 0;) + bunzip_data *bd; + char *outbuf; + int i; + unsigned len; + + if (check_signature16(xstate, BZIP2_MAGIC)) + return -1; + + outbuf = xmalloc(IOBUF_SIZE); + len = 0; + while (1) { /* "Process one BZ... stream" loop */ + jmp_buf jmpbuf; + + /* Setup for I/O error handling via longjmp */ + i = setjmp(jmpbuf); + if (i == 0) + i = start_bunzip(&jmpbuf, &bd, xstate->src_fd, outbuf + 2, len); + + if (i == 0) { + while (1) { /* "Produce some output bytes" loop */ + i = read_bunzip(bd, outbuf, IOBUF_SIZE); + if (i < 0) /* error? */ + break; + i = IOBUF_SIZE - i; /* number of bytes produced */ + if (i == 0) /* EOF? */ + break; + if (i != transformer_write(xstate, outbuf, i)) { + i = RETVAL_SHORT_WRITE; + goto release_mem; + } + IF_DESKTOP(total_written += i;) + } + } + + if (i != RETVAL_LAST_BLOCK + /* Observed case when i == RETVAL_OK: + * "bzcat z.bz2", where "z.bz2" is a bzipped zero-length file + * (to be exact, z.bz2 is exactly these 14 bytes: + * 42 5a 68 39 17 72 45 38 50 90 00 00 00 00). + */ + && i != RETVAL_OK + ) { + bb_error_msg("bunzip error %d", i); + break; + } + if (bd->headerCRC != bd->totalCRC) { + bb_simple_error_msg("CRC error"); + break; + } + + /* Successfully unpacked one BZ stream */ + i = RETVAL_OK; + + /* Do we have "BZ..." after last processed byte? + * pbzip2 (parallelized bzip2) produces such files. + */ + len = bd->inbufCount - bd->inbufPos; + memcpy(outbuf, &bd->inbuf[bd->inbufPos], len); + if (len < 2) { + if (safe_read(xstate->src_fd, outbuf + len, 2 - len) != 2 - len) + break; + len = 2; + } + if (*(uint16_t*)outbuf != BZIP2_MAGIC) /* "BZ"? */ + break; + dealloc_bunzip(bd); + len -= 2; + } + + release_mem: + dealloc_bunzip(bd); + free(outbuf); + + return i ? i : IF_DESKTOP(total_written) + 0; +} + +char* FAST_FUNC +unpack_bz2_data(const char *packed, int packed_len, int unpacked_len) +{ + char *outbuf = NULL; + bunzip_data *bd; + int i; + jmp_buf jmpbuf; + + /* Setup for I/O error handling via longjmp */ + i = setjmp(jmpbuf); + if (i == 0) { + i = start_bunzip(&jmpbuf, + &bd, + /* src_fd: */ -1, + /* inbuf: */ packed, + /* len: */ packed_len + ); + } + /* read_bunzip can longjmp and end up here with i != 0 + * on read data errors! Not trivial */ + if (i == 0) { + /* Cannot use xmalloc: will leak bd in NOFORK case! */ + outbuf = malloc_or_warn(unpacked_len); + if (outbuf) + read_bunzip(bd, outbuf, unpacked_len); + } + dealloc_bunzip(bd); + return outbuf; +} + +#ifdef TESTING + +static char *const bunzip_errors[] = { + NULL, "Bad file checksum", "Not bzip data", + "Unexpected input EOF", "Unexpected output EOF", "Data error", + "Out of memory", "Obsolete (pre 0.9.5) bzip format not supported" +}; + +/* Dumb little test thing, decompress stdin to stdout */ +int main(int argc, char **argv) +{ + char c; + + int i = unpack_bz2_stream(0, 1); + if (i < 0) + fprintf(stderr, "%s\n", bunzip_errors[-i]); + else if (read(STDIN_FILENO, &c, 1)) + fprintf(stderr, "Trailing garbage ignored\n"); + return -i; +} +#endif diff --git a/busybox-1_37_0/archival/libarchive/decompress_gunzip.c b/busybox-1_37_0/archival/libarchive/decompress_gunzip.c new file mode 100644 index 000000000..d051ecb81 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/decompress_gunzip.c @@ -0,0 +1,1299 @@ +/* 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 + * + * read_gz interface + associated hacking by Laurence Anderson + * + * Fixed huft_build() so decoding end-of-block code does not grab more bits + * than necessary (this is required by unzip applet), added inflate_cleanup() + * to free leaked bytebuffer memory (used in unzip.c), and some minor style + * guide cleanups by Ed Clark + * + * 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 file algorithm.doc for the compression algorithms and file formats. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +typedef struct huft_t { + unsigned char e; /* number of extra bits or operation */ + unsigned char b; /* number of bits in this code or subcode */ + union { + unsigned n; /* literal, length base, or distance base */ + /* ^^^^^ was "unsigned short", but that results in larger code */ + struct huft_t *t; /* pointer to next level of table */ + } v; +} huft_t; + +enum { + /* gunzip_window size--must be a power of two, and + * at least 32K for zip's deflate method */ + GUNZIP_WSIZE = 0x8000, + /* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ + BMAX = 16, /* maximum bit length of any code (16 for explode) */ + N_MAX = 288, /* maximum number of codes in any set */ +}; + + +/* This is somewhat complex-looking arrangement, but it allows + * to place decompressor state either in bss or in + * malloc'ed space simply by changing #defines below. + * Sizes on i386: + * text data bss dec hex + * 5256 0 108 5364 14f4 - bss + * 4915 0 0 4915 1333 - malloc + */ +#define STATE_IN_BSS 0 +#define STATE_IN_MALLOC 1 + + +typedef struct state_t { + off_t gunzip_bytes_out; /* number of output bytes */ + uint32_t gunzip_crc; + + int gunzip_src_fd; + unsigned gunzip_outbuf_count; /* bytes in output buffer */ + + unsigned char *gunzip_window; + + uint32_t *gunzip_crc_table; + + /* bitbuffer */ + unsigned gunzip_bb; /* bit buffer */ + unsigned char gunzip_bk; /* bits in bit buffer */ + + /* input (compressed) data */ + unsigned char *bytebuffer; /* buffer itself */ + off_t to_read; /* compressed bytes to read (unzip only, -1 for gunzip) */ +// unsigned bytebuffer_max; /* buffer size */ + unsigned bytebuffer_offset; /* buffer position */ + unsigned bytebuffer_size; /* how much data is there (size <= max) */ + + /* private data of inflate_codes() */ + unsigned inflate_codes_ml; /* masks for bl and bd bits */ + unsigned inflate_codes_md; /* masks for bl and bd bits */ + unsigned inflate_codes_bb; /* bit buffer */ + unsigned inflate_codes_k; /* number of bits in bit buffer */ + unsigned inflate_codes_w; /* current gunzip_window position */ + huft_t *inflate_codes_tl; + huft_t *inflate_codes_td; + unsigned inflate_codes_bl; + unsigned inflate_codes_bd; + unsigned inflate_codes_nn; /* length and index for copy */ + unsigned inflate_codes_dd; + + smallint resume_copy; + + /* private data of inflate_get_next_window() */ + smallint method; /* method == -1 for stored, -2 for codes */ + smallint need_another_block; + smallint end_reached; + + /* private data of inflate_stored() */ + unsigned inflate_stored_n; + unsigned inflate_stored_b; + unsigned inflate_stored_k; + unsigned inflate_stored_w; + + const char *error_msg; + jmp_buf error_jmp; +} state_t; +#define gunzip_bytes_out (S()gunzip_bytes_out ) +#define gunzip_crc (S()gunzip_crc ) +#define gunzip_src_fd (S()gunzip_src_fd ) +#define gunzip_outbuf_count (S()gunzip_outbuf_count) +#define gunzip_window (S()gunzip_window ) +#define gunzip_crc_table (S()gunzip_crc_table ) +#define gunzip_bb (S()gunzip_bb ) +#define gunzip_bk (S()gunzip_bk ) +#define to_read (S()to_read ) +// #define bytebuffer_max (S()bytebuffer_max ) +// Both gunzip and unzip can use constant buffer size now (16k): +#define bytebuffer_max 0x4000 +#define bytebuffer (S()bytebuffer ) +#define bytebuffer_offset (S()bytebuffer_offset ) +#define bytebuffer_size (S()bytebuffer_size ) +#define inflate_codes_ml (S()inflate_codes_ml ) +#define inflate_codes_md (S()inflate_codes_md ) +#define inflate_codes_bb (S()inflate_codes_bb ) +#define inflate_codes_k (S()inflate_codes_k ) +#define inflate_codes_w (S()inflate_codes_w ) +#define inflate_codes_tl (S()inflate_codes_tl ) +#define inflate_codes_td (S()inflate_codes_td ) +#define inflate_codes_bl (S()inflate_codes_bl ) +#define inflate_codes_bd (S()inflate_codes_bd ) +#define inflate_codes_nn (S()inflate_codes_nn ) +#define inflate_codes_dd (S()inflate_codes_dd ) +#define resume_copy (S()resume_copy ) +#define method (S()method ) +#define need_another_block (S()need_another_block ) +#define end_reached (S()end_reached ) +#define inflate_stored_n (S()inflate_stored_n ) +#define inflate_stored_b (S()inflate_stored_b ) +#define inflate_stored_k (S()inflate_stored_k ) +#define inflate_stored_w (S()inflate_stored_w ) +#define error_msg (S()error_msg ) +#define error_jmp (S()error_jmp ) + +/* This is a generic part */ +#if STATE_IN_BSS /* Use global data segment */ +#define DECLARE_STATE /*nothing*/ +#define ALLOC_STATE /*nothing*/ +#define DEALLOC_STATE ((void)0) +#define S() state. +#define PASS_STATE /*nothing*/ +#define PASS_STATE_ONLY /*nothing*/ +#define STATE_PARAM /*nothing*/ +#define STATE_PARAM_ONLY void +static state_t state; +#endif + +#if STATE_IN_MALLOC /* Use malloc space */ +#define DECLARE_STATE state_t *state +#define ALLOC_STATE (state = xzalloc(sizeof(*state))) +#define DEALLOC_STATE free(state) +#define S() state-> +#define PASS_STATE state, +#define PASS_STATE_ONLY state +#define STATE_PARAM state_t *state, +#define STATE_PARAM_ONLY state_t *state +#endif + + +static const uint16_t mask_bits[] ALIGN2 = { + 0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* Put lengths/offsets and extra bits in a struct of arrays + * to make calls to huft_build() have one fewer parameter. + */ +struct cp_ext { + uint16_t cp[31]; + uint8_t ext[31]; +}; +/* Copy lengths and extra bits for literal codes 257..285 */ +/* note: see note #13 above about the 258 in this list. */ +static const struct cp_ext lit ALIGN2 = { + /*257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 */ + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 */ + { 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 }, + { 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 */ +}; +/* Copy offsets and extra bits for distance codes 0..29 */ +static const struct cp_ext dist ALIGN2 = { + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 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 }, + { 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 } +}; + +/* Tables for deflate from PKZIP's appnote.txt. */ +/* Order of the bit length code lengths */ +static const uint8_t border[] ALIGN1 = { + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 +}; + + +/* + * 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 + */ +#define BAD_HUFT(p) ((uintptr_t)(p) & 1) +#define ERR_RET ((huft_t*)(uintptr_t)1) +static void huft_free(huft_t *p) +{ + huft_t *q; + + /* + * If 'p' has the error bit set we have to clear it, otherwise we might run + * into a segmentation fault or an invalid pointer to free(p) + */ + //if (BAD_HUFT(p)) // commented out, since bit clearing has effect only if condition is true + p = (huft_t*)((uintptr_t)p & ~(uintptr_t)ERR_RET); + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p) { + q = (--p)->v.t; + free(p); + p = q; + } +} + +static void huft_free_all(STATE_PARAM_ONLY) +{ + huft_free(inflate_codes_tl); + huft_free(inflate_codes_td); + inflate_codes_tl = NULL; + inflate_codes_td = NULL; +} + +static void abort_unzip(STATE_PARAM_ONLY) NORETURN; +static void abort_unzip(STATE_PARAM_ONLY) +{ + huft_free_all(PASS_STATE_ONLY); + longjmp(error_jmp, 1); +} + +static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current, const unsigned required) +{ + while (*current < required) { + if (bytebuffer_offset >= bytebuffer_size) { + unsigned sz = bytebuffer_max - 4; + if (to_read >= 0 && to_read < sz) /* unzip only */ + sz = to_read; + /* Leave the first 4 bytes empty so we can always unwind the bitbuffer + * to the front of the bytebuffer */ + bytebuffer_size = safe_read(gunzip_src_fd, &bytebuffer[4], sz); + if ((int)bytebuffer_size < 1) { + error_msg = "unexpected end of file"; + abort_unzip(PASS_STATE_ONLY); + } + if (to_read >= 0) /* unzip only */ + to_read -= bytebuffer_size; + bytebuffer_size += 4; + bytebuffer_offset = 4; + } + bitbuffer |= ((unsigned) bytebuffer[bytebuffer_offset]) << *current; + bytebuffer_offset++; + *current += 8; + } + return bitbuffer; +} + + +/* Given a list of code lengths and a maximum table size, make a set of + * tables to decode that set of codes. + * + * b: code lengths in bits (all assumed <= BMAX) + * n: number of codes (assumed <= N_MAX) + * s: number of simple-valued codes (0..s-1) + * cp_ext->cp,ext: list of base values/extra bits for non-simple codes + * m: maximum lookup bits, returns actual + * result: starting table + * + * On error, returns a value with lowest-bit set on error. + * It can be just the value of 0x1, + * or a valid pointer to a Huffman table, ORed with 0x1 if incompete table + * is given: "fixed inflate" decoder feeds us such data. + */ +static huft_t* huft_build(const unsigned *b, const unsigned n, + const unsigned s, const struct cp_ext *cp_ext, + unsigned *m) +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX + 1]; /* bit length count table */ + unsigned eob_len; /* length of end-of-block code (value 256) */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int htl; /* table level */ + unsigned i; /* counter, current code */ + unsigned j; /* counter */ + int k; /* number of bits in current code */ + const unsigned *p; /* pointer into c[], b[], or v[] */ + 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 + 1]; /* values in order of bit length. last v[] is never used */ + int ws[BMAX + 1]; /* bits decoded stack */ + int w; /* bits decoded */ + 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 */ + huft_t *result; + huft_t **t; + + /* Length of EOB code, if any */ + eob_len = n > 256 ? b[256] : BMAX; + + /* Generate counts for each bit length */ + memset(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 */ + q = xzalloc(3 * sizeof(*q)); + //q[0].v.t = NULL; + q[1].e = 99; /* invalid code marker */ + q[1].b = 1; + q[2].e = 99; /* invalid code marker */ + q[2].b = 1; + *m = 1; + return q + 1; + } + + /* Find minimum and maximum length, bound *m by those */ + for (j = 1; (j <= BMAX) && (c[j] == 0); j++) + continue; + k = j; /* minimum code length */ + for (i = BMAX; (c[i] == 0) && i; i--) + continue; + g = i; /* maximum code length */ + *m = (*m < j) ? j : ((*m > i) ? i : *m); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) { + y -= c[j]; + if (y < 0) + return ERR_RET; /* bad input: more codes than bits */ + } + y -= c[i]; + if (y < 0) + return ERR_RET; + 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 */ + j += *p++; + *xp++ = j; + } + + /* Make a table of values in order of bit lengths. + * To detect bad input, unused v[i]'s are set to invalid value UINT_MAX. + * In particular, last v[i] is never filled and must not be accessed. + */ + memset(v, 0xff, sizeof(v)); + p = b; + i = 0; + do { + j = *p++; + if (j != 0) { + v[x[j]++] = i; + } + } while (++i < n); + + /* Generate the Huffman codes and for each, make the table entries */ + result = ERR_RET; + t = &result; + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + htl = -1; /* no tables yet--level -1 */ + w = ws[0] = 0; /* bits decoded */ + u[0] = NULL; /* just to keep compilers happy */ + q = 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 > ws[htl + 1]) { + w = ws[++htl]; + + /* compute minimum size table less than or equal to *m bits */ + z = g - w; + z = z > *m ? *m : z; /* upper limit on table size */ + j = k - w; + f = 1 << j; + if (f > 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 */ + f <<= 1; + if (f <= *++xp) { + break; /* enough codes to use up j bits */ + } + f -= *xp; /* else deduct codes from patterns */ + } + } + j = (w + j > eob_len && w < eob_len) ? eob_len - w : j; /* make EOB code end at table */ + z = 1 << j; /* table entries for j-bit table */ + ws[htl+1] = w + j; /* set bits decoded in stack */ + + /* allocate and link in new table */ + q = xzalloc((z + 1) * sizeof(huft_t)); + *t = q + 1; /* link to list for huft_free() */ + t = &(q->v.t); + u[htl] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (htl) { + x[htl] = i; /* save pattern for backing up */ + r.b = (unsigned char) (w - ws[htl - 1]); /* 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 & ((1 << w) - 1)) >> ws[htl - 1]; + u[htl - 1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.b = (unsigned char) (k - w); + if (/*p >= v + n || -- redundant, caught by the second check: */ + *p == UINT_MAX /* do we access uninited v[i]? (see memset(v))*/ + ) { + r.e = 99; /* out of values--invalid code */ + } else if (*p < s) { + r.e = (unsigned char) (*p < 256 ? 16 : 15); /* 256 is EOB code */ + r.v.n = (unsigned short) (*p++); /* simple code is just the value */ + } else { + r.e = (unsigned char) cp_ext->ext[*p - s]; /* non-simple--look up in lists */ + r.v.n = cp_ext->cp[*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[htl]) { + w = ws[--htl]; + } + } + } + + /* return actual size of base table */ + *m = ws[1]; + + if (y != 0 && g != 1) /* we were given an incomplete table */ + /* return "result" ORed with 1 */ + return (void*)((uintptr_t)result | 1); + + return result; +} + + +/* + * 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[] + */ +/* called once from inflate_block */ + +/* map formerly local static variables to globals */ +#define ml inflate_codes_ml +#define md inflate_codes_md +#define bb inflate_codes_bb +#define k inflate_codes_k +#define w inflate_codes_w +#define tl inflate_codes_tl +#define td inflate_codes_td +#define bl inflate_codes_bl +#define bd inflate_codes_bd +#define nn inflate_codes_nn +#define dd inflate_codes_dd +static void inflate_codes_setup(STATE_PARAM unsigned my_bl, unsigned my_bd) +{ + bl = my_bl; + bd = my_bd; + /* make local copies of globals */ + bb = gunzip_bb; /* initialize bit buffer */ + k = gunzip_bk; + w = gunzip_outbuf_count; /* initialize gunzip_window position */ + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; +} +/* called once from inflate_get_next_window */ +static NOINLINE int inflate_codes(STATE_PARAM_ONLY) +{ + unsigned e; /* table entry flag/number of extra bits */ + huft_t *t; /* pointer to table entry */ + + if (resume_copy) + goto do_copy; + + while (1) { /* do until end of block */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bl); + t = tl + ((unsigned) bb & ml); + e = t->e; + if (e > 16) + do { + if (e == 99) { + abort_unzip(PASS_STATE_ONLY); + } + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + if (e == 16) { /* then it's a literal */ + gunzip_window[w++] = (unsigned char) t->v.n; + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + //flush_gunzip_window(); + w = 0; + return 1; // We have a block to read + } + } else { /* it's an EOB or a length */ + /* exit if end of block */ + if (e == 15) { + break; + } + + /* get length of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + nn = t->v.n + ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* decode distance of block to copy */ + bb = fill_bitbuffer(PASS_STATE bb, &k, bd); + t = td + ((unsigned) bb & md); + e = t->e; + if (e > 16) + do { + if (e == 99) { + abort_unzip(PASS_STATE_ONLY); + } + bb >>= t->b; + k -= t->b; + e -= 16; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + t = t->v.t + ((unsigned) bb & mask_bits[e]); + e = t->e; + } while (e > 16); + bb >>= t->b; + k -= t->b; + bb = fill_bitbuffer(PASS_STATE bb, &k, e); + dd = w - t->v.n - ((unsigned) bb & mask_bits[e]); + bb >>= e; + k -= e; + + /* do the copy */ + do_copy: + do { + /* Was: nn -= (e = (e = GUNZIP_WSIZE - ((dd &= GUNZIP_WSIZE - 1) > w ? dd : w)) > nn ? nn : e); */ + /* Who wrote THAT?? rewritten as: */ + unsigned delta; + + dd &= GUNZIP_WSIZE - 1; + e = GUNZIP_WSIZE - (dd > w ? dd : w); + delta = w > dd ? w - dd : dd - w; + if (e > nn) e = nn; + nn -= e; + + /* copy to new buffer to prevent possible overwrite */ + if (delta >= e) { + memcpy(gunzip_window + w, gunzip_window + dd, e); + w += e; + dd += e; + } else { + /* do it slow to avoid memcpy() overlap */ + /* !NOMEMCPY */ + do { + gunzip_window[w++] = gunzip_window[dd++]; + } while (--e); + } + if (w == GUNZIP_WSIZE) { + gunzip_outbuf_count = w; + resume_copy = (nn != 0); + //flush_gunzip_window(); + w = 0; + return 1; + } + } while (nn); + resume_copy = 0; + } + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = w; /* restore global gunzip_window pointer */ + gunzip_bb = bb; /* restore global bit buffer */ + gunzip_bk = k; + + /* normally just after call to inflate_codes, but save code by putting it here */ + /* free the decoding tables (tl and td), return */ + huft_free_all(PASS_STATE_ONLY); + + /* done */ + return 0; +} +#undef ml +#undef md +#undef bb +#undef k +#undef w +#undef tl +#undef td +#undef bl +#undef bd +#undef nn +#undef dd + + +/* called once from inflate_block */ +static void inflate_stored_setup(STATE_PARAM int my_n, int my_b, int my_k) +{ + inflate_stored_n = my_n; + inflate_stored_b = my_b; + inflate_stored_k = my_k; + /* initialize gunzip_window position */ + inflate_stored_w = gunzip_outbuf_count; +} +/* called once from inflate_get_next_window */ +static int inflate_stored(STATE_PARAM_ONLY) +{ + /* read and output the compressed data */ + while (inflate_stored_n--) { + inflate_stored_b = fill_bitbuffer(PASS_STATE inflate_stored_b, &inflate_stored_k, 8); + gunzip_window[inflate_stored_w++] = (unsigned char) inflate_stored_b; + if (inflate_stored_w == GUNZIP_WSIZE) { + gunzip_outbuf_count = inflate_stored_w; + //flush_gunzip_window(); + inflate_stored_w = 0; + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + return 1; /* We have a block */ + } + inflate_stored_b >>= 8; + inflate_stored_k -= 8; + } + + /* restore the globals from the locals */ + gunzip_outbuf_count = inflate_stored_w; /* restore global gunzip_window pointer */ + gunzip_bb = inflate_stored_b; /* restore global bit buffer */ + gunzip_bk = inflate_stored_k; + return 0; /* Finished */ +} + + +/* + * decompress an inflated block + * e: last block flag + * + * GLOBAL VARIABLES: bb, kk, + */ +/* Return values: -1 = inflate_stored, -2 = inflate_codes */ +/* One callsite in inflate_get_next_window */ +static int inflate_block(STATE_PARAM smallint *e) +{ + unsigned ll[286 + 30]; /* literal/length and distance code lengths */ + unsigned t; /* block type */ + unsigned b; /* bit buffer */ + unsigned k; /* number of bits in bit buffer */ + + /* make local bit buffer */ + + b = gunzip_bb; + k = gunzip_bk; + + /* read in last block bit */ + b = fill_bitbuffer(PASS_STATE b, &k, 1); + *e = b & 1; + b >>= 1; + k -= 1; + + /* read in block type */ + b = fill_bitbuffer(PASS_STATE b, &k, 2); + t = (unsigned) b & 3; + b >>= 2; + k -= 2; + + /* restore the global bit buffer */ + gunzip_bb = b; + gunzip_bk = k; + + /* Do we see block type 1 often? Yes! + * TODO: fix performance problem (see below) */ + //bb_error_msg("blktype %d", t); + + /* inflate that block type */ + switch (t) { + case 0: /* Inflate stored */ + { + unsigned n; /* number of bytes in block */ + unsigned b_stored; /* bit buffer */ + unsigned k_stored; /* number of bits in bit buffer */ + + /* make local copies of globals */ + b_stored = gunzip_bb; /* initialize bit buffer */ + k_stored = gunzip_bk; + + /* go to byte boundary */ + n = k_stored & 7; + b_stored >>= n; + k_stored -= n; + + /* get the length and its complement */ + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + n = ((unsigned) b_stored & 0xffff); + b_stored >>= 16; + k_stored -= 16; + + b_stored = fill_bitbuffer(PASS_STATE b_stored, &k_stored, 16); + if (n != (unsigned) ((~b_stored) & 0xffff)) { + abort_unzip(PASS_STATE_ONLY); /* error in compressed data */ + } + b_stored >>= 16; + k_stored -= 16; + + inflate_stored_setup(PASS_STATE n, b_stored, k_stored); + + return -1; + } + 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. TODO */ + { + int i; /* temporary variable */ + unsigned bl; /* lookup bits for tl */ + unsigned bd; /* lookup bits for td */ + /* gcc 4.2.1 is too dumb to reuse stackspace. Moved up... */ + //unsigned ll[288]; /* length list for huft_build */ + + /* set up literal table */ + for (i = 0; i < 144; i++) + ll[i] = 8; + for (; i < 256; i++) + ll[i] = 9; + for (; i < 280; i++) + ll[i] = 7; + for (; i < 288; i++) /* make a complete, but wrong code set */ + ll[i] = 8; + bl = 7; + inflate_codes_tl = huft_build(ll, 288, 257, &lit, &bl); + /* ^^^ never returns error here - we use known data */ + + /* set up distance table */ + for (i = 0; i < 30; i++) /* make an incomplete code set */ + ll[i] = 5; + bd = 5; + inflate_codes_td = huft_build(ll, 30, 0, &dist, &bd); + /* ^^^ does return error here! (lsb bit is set) - we gave it incomplete code set */ + /* clearing error bit: */ + inflate_codes_td = (void*)((uintptr_t)inflate_codes_td & ~(uintptr_t)1); + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + case 2: /* Inflate dynamic */ + { + enum { dbits = 6 }; /* bits in base distance lookup table */ + enum { lbits = 9 }; /* bits in base literal/length lookup table */ + + huft_t *td; /* distance code table */ + unsigned i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + unsigned bl; /* lookup bits for tl */ + unsigned 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 */ + unsigned b_dynamic; /* bit buffer */ + unsigned k_dynamic; /* number of bits in bit buffer */ + + /* make local bit buffer */ + b_dynamic = gunzip_bb; + k_dynamic = gunzip_bk; + + /* read in table lengths */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nl = 257 + ((unsigned) b_dynamic & 0x1f); /* number of literal/length codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 5); + nd = 1 + ((unsigned) b_dynamic & 0x1f); /* number of distance codes */ + + b_dynamic >>= 5; + k_dynamic -= 5; + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 4); + nb = 4 + ((unsigned) b_dynamic & 0xf); /* number of bit length codes */ + + b_dynamic >>= 4; + k_dynamic -= 4; + if (nl > 286 || nd > 30) { + abort_unzip(PASS_STATE_ONLY); /* bad lengths */ + } + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + 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; + inflate_codes_tl = huft_build(ll, 19, 19, NULL, &bl); + if (BAD_HUFT(inflate_codes_tl)) { + abort_unzip(PASS_STATE_ONLY); /* incomplete code set */ + } + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned) i < n) { + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, (unsigned)bl); + td = inflate_codes_tl + ((unsigned) b_dynamic & m); + j = td->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 */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 2); + j = 3 + ((unsigned) b_dynamic & 3); + b_dynamic >>= 2; + k_dynamic -= 2; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = l; + } + } else if (j == 17) { /* 3 to 10 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 3); + j = 3 + ((unsigned) b_dynamic & 7); + b_dynamic >>= 3; + k_dynamic -= 3; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } else { /* j == 18: 11 to 138 zero length codes */ + b_dynamic = fill_bitbuffer(PASS_STATE b_dynamic, &k_dynamic, 7); + j = 11 + ((unsigned) b_dynamic & 0x7f); + b_dynamic >>= 7; + k_dynamic -= 7; + if ((unsigned) i + j > n) { + abort_unzip(PASS_STATE_ONLY); //return 1; + } + while (j--) { + ll[i++] = 0; + } + l = 0; + } + } + + /* free decoding table for trees */ + huft_free(inflate_codes_tl); + + /* restore the global bit buffer */ + gunzip_bb = b_dynamic; + gunzip_bk = k_dynamic; + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + inflate_codes_tl = huft_build(ll, nl, 257, &lit, &bl); + if (BAD_HUFT(inflate_codes_tl)) { + abort_unzip(PASS_STATE_ONLY); + } + bd = dbits; + inflate_codes_td = huft_build(ll + nl, nd, 0, &dist, &bd); + if (BAD_HUFT(inflate_codes_td)) { + abort_unzip(PASS_STATE_ONLY); + } + + /* set up data for inflate_codes() */ + inflate_codes_setup(PASS_STATE bl, bd); + + /* huft_free code moved into inflate_codes */ + + return -2; + } + default: + abort_unzip(PASS_STATE_ONLY); + } +} + +/* Two callsites, both in inflate_get_next_window */ +static void calculate_gunzip_crc(STATE_PARAM_ONLY) +{ + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); + gunzip_bytes_out += gunzip_outbuf_count; +} + +/* One callsite in inflate_unzip_internal */ +static int inflate_get_next_window(STATE_PARAM_ONLY) +{ + gunzip_outbuf_count = 0; + + while (1) { + int ret; + + if (need_another_block) { + if (end_reached) { + calculate_gunzip_crc(PASS_STATE_ONLY); + end_reached = 0; + /* NB: need_another_block is still set */ + return 0; /* Last block */ + } + method = inflate_block(PASS_STATE &end_reached); + need_another_block = 0; + } + + switch (method) { + case -1: + ret = inflate_stored(PASS_STATE_ONLY); + break; + case -2: + ret = inflate_codes(PASS_STATE_ONLY); + break; + default: /* cannot happen */ + abort_unzip(PASS_STATE_ONLY); + } + + if (ret == 1) { + calculate_gunzip_crc(PASS_STATE_ONLY); + return 1; /* more data left */ + } + need_another_block = 1; /* end of that block */ + } + /* Doesnt get here */ +} + + +/* Called from unpack_gz_stream() and inflate_unzip() */ +static IF_DESKTOP(long long) int +inflate_unzip_internal(STATE_PARAM transformer_state_t *xstate) +{ + IF_DESKTOP(long long) int n = 0; + ssize_t nwrote; + + /* Allocate all global buffers (for DYN_ALLOC option) */ + gunzip_window = xmalloc(GUNZIP_WSIZE); + gunzip_outbuf_count = 0; + gunzip_bytes_out = 0; + gunzip_src_fd = xstate->src_fd; + + /* (re) initialize state */ + method = -1; + need_another_block = 1; + resume_copy = 0; + gunzip_bk = 0; + gunzip_bb = 0; + + /* Create the crc table */ + gunzip_crc_table = crc32_new_table_le(); + gunzip_crc = ~0; + + error_msg = "corrupted data"; + if (setjmp(error_jmp)) { + /* Error from deep inside zip machinery */ + bb_simple_error_msg(error_msg); + n = -1; + goto ret; + } + + while (1) { + int r = inflate_get_next_window(PASS_STATE_ONLY); + nwrote = transformer_write(xstate, gunzip_window, gunzip_outbuf_count); + if (nwrote == (ssize_t)-1) { + n = -1; + goto ret; + } + IF_DESKTOP(n += nwrote;) + if (r == 0) break; + } + + /* Store unused bytes in a global buffer so calling applets can access it */ + if (gunzip_bk >= 8) { + /* Undo too much lookahead. The next read will be byte aligned + * so we can discard unused bits in the last meaningful byte. */ + bytebuffer_offset--; + bytebuffer[bytebuffer_offset] = gunzip_bb & 0xff; + gunzip_bb >>= 8; + gunzip_bk -= 8; + } + ret: + /* Cleanup */ + free(gunzip_window); + free(gunzip_crc_table); + return n; +} + + +/* External entry points */ + +/* For unzip */ + +IF_DESKTOP(long long) int FAST_FUNC +inflate_unzip(transformer_state_t *xstate) +{ + IF_DESKTOP(long long) int n; + DECLARE_STATE; + + ALLOC_STATE; + + to_read = xstate->bytes_in; +// bytebuffer_max = 0x8000; + bytebuffer_offset = 4; + bytebuffer = xmalloc(bytebuffer_max); + n = inflate_unzip_internal(PASS_STATE xstate); + free(bytebuffer); + + xstate->crc32 = gunzip_crc; + xstate->bytes_out = gunzip_bytes_out; + DEALLOC_STATE; + return n; +} + + +/* For gunzip */ + +/* helpers first */ + +/* Top up the input buffer with at least n bytes. */ +static int top_up(STATE_PARAM unsigned n) +{ + int count = bytebuffer_size - bytebuffer_offset; + + if (count < (int)n) { + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], count); + bytebuffer_offset = 0; + bytebuffer_size = full_read(gunzip_src_fd, &bytebuffer[count], bytebuffer_max - count); + if ((int)bytebuffer_size < 0) { + bb_simple_error_msg(bb_msg_read_error); + return 0; + } + bytebuffer_size += count; + if (bytebuffer_size < n) + return 0; + } + return 1; +} + +static uint16_t buffer_read_le_u16(STATE_PARAM_ONLY) +{ + uint16_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned16(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; +#endif + bytebuffer_offset += 2; + return res; +} + +static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) +{ + uint32_t res; +#if BB_LITTLE_ENDIAN + move_from_unaligned32(res, &bytebuffer[bytebuffer_offset]); +#else + res = bytebuffer[bytebuffer_offset]; + res |= bytebuffer[bytebuffer_offset + 1] << 8; + res |= bytebuffer[bytebuffer_offset + 2] << 16; + res |= bytebuffer[bytebuffer_offset + 3] << 24; +#endif + bytebuffer_offset += 4; + return res; +} + +static int check_header_gzip(STATE_PARAM transformer_state_t *xstate) +{ + union { + unsigned char raw[8]; + struct { + uint8_t gz_method; + uint8_t flags; + uint32_t mtime; + uint8_t xtra_flags_UNUSED; + uint8_t os_flags_UNUSED; + } PACKED formatted; + } header; + + BUILD_BUG_ON(sizeof(header) != 8); + + /* + * Rewind bytebuffer. We use the beginning because the header has 8 + * bytes, leaving enough for unwinding afterwards. + */ + bytebuffer_size -= bytebuffer_offset; + memmove(bytebuffer, &bytebuffer[bytebuffer_offset], bytebuffer_size); + bytebuffer_offset = 0; + + if (!top_up(PASS_STATE 8)) + return 0; + memcpy(header.raw, &bytebuffer[bytebuffer_offset], 8); + bytebuffer_offset += 8; + + /* Check the compression method */ + if (header.formatted.gz_method != 8) { + return 0; + } + + if (header.formatted.flags & 0x04) { + /* bit 2 set: extra field present */ + unsigned extra_short; + + if (!top_up(PASS_STATE 2)) + return 0; + extra_short = buffer_read_le_u16(PASS_STATE_ONLY); + if (!top_up(PASS_STATE extra_short)) + return 0; + /* Ignore extra field */ + bytebuffer_offset += extra_short; + } + + /* Discard original name and file comment if any */ + /* bit 3 set: original file name present */ + /* bit 4 set: file comment present */ + if (header.formatted.flags & 0x18) { + while (1) { + do { + if (!top_up(PASS_STATE 1)) + return 0; + } while (bytebuffer[bytebuffer_offset++] != 0); + if ((header.formatted.flags & 0x18) != 0x18) + break; + header.formatted.flags &= ~0x18; + } + } + + xstate->mtime = SWAP_LE32(header.formatted.mtime); + + /* Read the header checksum */ + if (header.formatted.flags & 0x02) { + if (!top_up(PASS_STATE 2)) + return 0; + bytebuffer_offset += 2; + } + return 1; +} + +IF_DESKTOP(long long) int FAST_FUNC +unpack_gz_stream(transformer_state_t *xstate) +{ + uint32_t v32; + IF_DESKTOP(long long) int total, n; + DECLARE_STATE; + +#if !ENABLE_FEATURE_SEAMLESS_Z + if (check_signature16(xstate, GZIP_MAGIC)) + return -1; +#else + if (!xstate->signature_skipped) { + uint16_t magic2; + + if (full_read(xstate->src_fd, &magic2, 2) != 2) { + bad_magic: + bb_simple_error_msg("invalid magic"); + return -1; + } + if (magic2 == COMPRESS_MAGIC) { + xstate->signature_skipped = 2; + return unpack_Z_stream(xstate); + } + if (magic2 != GZIP_MAGIC) + goto bad_magic; + } +#endif + + total = 0; + + ALLOC_STATE; + to_read = -1; +// bytebuffer_max = 0x8000; + bytebuffer = xmalloc(bytebuffer_max); + gunzip_src_fd = xstate->src_fd; + + again: + if (!check_header_gzip(PASS_STATE xstate)) { + bb_simple_error_msg("corrupted data"); + total = -1; + goto ret; + } + + n = inflate_unzip_internal(PASS_STATE xstate); + if (n < 0) { + total = -1; + goto ret; + } + total += n; + + if (!top_up(PASS_STATE 8)) { + bb_simple_error_msg("corrupted data"); + total = -1; + goto ret; + } + + /* Validate decompression - crc */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((~gunzip_crc) != v32) { + bb_simple_error_msg("crc error"); + total = -1; + goto ret; + } + + /* Validate decompression - size */ + v32 = buffer_read_le_u32(PASS_STATE_ONLY); + if ((uint32_t)gunzip_bytes_out != v32) { + bb_simple_error_msg("incorrect length"); + total = -1; + } + + if (!top_up(PASS_STATE 2)) + goto ret; /* EOF */ + + if (bytebuffer[bytebuffer_offset] == 0x1f + && bytebuffer[bytebuffer_offset + 1] == 0x8b + ) { + bytebuffer_offset += 2; + goto again; + } + /* GNU gzip says: */ + /*bb_error_msg("decompression OK, trailing garbage ignored");*/ + + ret: + free(bytebuffer); + DEALLOC_STATE; + return total; +} diff --git a/busybox-1_37_0/archival/libarchive/decompress_uncompress.c b/busybox-1_37_0/archival/libarchive/decompress_uncompress.c new file mode 100644 index 000000000..2725a7f09 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/decompress_uncompress.c @@ -0,0 +1,312 @@ +/* vi: set sw=4 ts=4: */ +/* + * uncompress for busybox -- (c) 2002 Robert Griebl + * + * based on the original compress42.c source + * (see disclaimer below) + */ +/* (N)compress42.c - File compression ala IEEE Computer, Mar 1992. + * + * Authors: + * Spencer W. Thomas (decvax!harpo!utah-cs!utah-gr!thomas) + * Jim McKie (decvax!mcvax!jim) + * Steve Davies (decvax!vax135!petsd!peora!srd) + * Ken Turkowski (decvax!decwrl!turtlevax!ken) + * James A. Woods (decvax!ihnp4!ames!jaw) + * Joe Orost (decvax!vax135!petsd!joe) + * Dave Mack (csu@alembic.acs.com) + * Peter Jannesen, Network Communication Systems + * (peter@ncs.nl) + * + * marc@suse.de : a small security fix for a buffer overflow + * + * [... History snipped ...] + */ +#include "libbb.h" +#include "bb_archive.h" + + +/* Default input buffer size */ +#define IBUFSIZ 2048 + +/* Default output buffer size */ +#define OBUFSIZ 2048 + +/* Defines for third byte of header */ +#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ + /* Masks 0x20 and 0x40 are free. */ + /* I think 0x20 should mean that there is */ + /* a fourth header byte (for expansion). */ +#define BLOCK_MODE 0x80 /* Block compression if table is full and */ + /* compression rate is dropping flush tables */ + /* the next two codes should not be changed lightly, as they must not */ + /* lie within the contiguous general code space. */ +#define FIRST 257 /* first free entry */ +#define CLEAR 256 /* table clear output code */ + +#define INIT_BITS 9 /* initial number of bits/code */ + + +/* machine variants which require cc -Dmachine: pdp11, z8000, DOS */ +#define HBITS 17 /* 50% occupancy */ +#define HSIZE (1<src_fd, inbuf, 1) != 1) { + bb_simple_error_msg("short read"); + goto err; + } + + maxbits = inbuf[0] & BIT_MASK; + block_mode = inbuf[0] & BLOCK_MODE; + maxmaxcode = MAXCODE(maxbits); + + if (maxbits > BITS) { + bb_error_msg("compressed with %d bits, can only handle " + BITS_STR" bits", maxbits); + goto err; + } + + n_bits = INIT_BITS; + maxcode = MAXCODE(INIT_BITS) - 1; + bitmask = (1 << INIT_BITS) - 1; + oldcode = -1; + finchar = 0; + outpos = 0; + posbits = 0 << 3; + + free_ent = ((block_mode) ? FIRST : 256); + + /* As above, initialize the first 256 entries in the table. */ + /*clear_tab_prefixof(); - done by xzalloc */ + + { + int i; + for (i = 255; i >= 0; --i) + tab_suffixof(i) = (unsigned char) i; + } + + do { + resetbuf: + { + int i; + int e; + int o; + + o = posbits >> 3; + e = insize - o; + + for (i = 0; i < e; ++i) + inbuf[i] = inbuf[i + o]; + + insize = e; + posbits = 0; + } + + if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { + rsize = safe_read(xstate->src_fd, inbuf + insize, IBUFSIZ); + if (rsize < 0) + bb_simple_error_msg_and_die(bb_msg_read_error); + insize += rsize; + } + + inbits = ((rsize > 0) ? (insize - insize % n_bits) << 3 : + (insize << 3) - (n_bits - 1)); + + while (inbits > posbits) { + long code; + + if (free_ent > maxcode) { + posbits = + ((posbits - 1) + + ((n_bits << 3) - + (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); + ++n_bits; + if (n_bits == maxbits) { + maxcode = maxmaxcode; + } else { + maxcode = MAXCODE(n_bits) - 1; + } + bitmask = (1 << n_bits) - 1; + goto resetbuf; + } + { + unsigned char *p = &inbuf[posbits >> 3]; + code = ((p[0] + | ((long) (p[1]) << 8) + | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; + } + posbits += n_bits; + + if (oldcode == -1) { + if (code >= 256) + bb_simple_error_msg_and_die("corrupted data"); /* %ld", code); */ + oldcode = code; + finchar = (int) oldcode; + outbuf[outpos++] = (unsigned char) finchar; + continue; + } + + if (code == CLEAR && block_mode) { + clear_tab_prefixof(); + free_ent = FIRST - 1; + posbits = + ((posbits - 1) + + ((n_bits << 3) - + (posbits - 1 + (n_bits << 3)) % (n_bits << 3))); + n_bits = INIT_BITS; + maxcode = MAXCODE(INIT_BITS) - 1; + bitmask = (1 << INIT_BITS) - 1; + goto resetbuf; + } + + incode = code; + stackp = de_stack; + + /* Special case for KwKwK string. */ + if (code >= free_ent) { + if (code > free_ent) { +/* + unsigned char *p; + + posbits -= n_bits; + p = &inbuf[posbits >> 3]; + bb_error_msg + ("insize:%d posbits:%d inbuf:%02X %02X %02X %02X %02X (%d)", + insize, posbits, p[-1], p[0], p[1], p[2], p[3], + (posbits & 07)); +*/ + bb_simple_error_msg("corrupted data"); + goto err; + } + + *--stackp = (unsigned char) finchar; + code = oldcode; + } + + /* Generate output characters in reverse order */ + while (code >= 256) { + if (stackp <= &htabof(0)) + bb_simple_error_msg_and_die("corrupted data"); + *--stackp = tab_suffixof(code); + code = tab_prefixof(code); + } + + finchar = tab_suffixof(code); + *--stackp = (unsigned char) finchar; + + /* And put them out in forward order */ + { + int i; + + i = de_stack - stackp; + if (outpos + i >= OBUFSIZ) { + do { + if (i > OBUFSIZ - outpos) { + i = OBUFSIZ - outpos; + } + + if (i > 0) { + memcpy(outbuf + outpos, stackp, i); + outpos += i; + } + + if (outpos >= OBUFSIZ) { + xtransformer_write(xstate, outbuf, outpos); + IF_DESKTOP(total_written += outpos;) + outpos = 0; + } + stackp += i; + i = de_stack - stackp; + } while (i > 0); + } else { + memcpy(outbuf + outpos, stackp, i); + outpos += i; + } + } + + /* Generate the new entry. */ + if (free_ent < maxmaxcode) { + tab_prefixof(free_ent) = (unsigned short) oldcode; + tab_suffixof(free_ent) = (unsigned char) finchar; + free_ent++; + } + + /* Remember previous code. */ + oldcode = incode; + } + } while (rsize > 0); + + if (outpos > 0) { + xtransformer_write(xstate, outbuf, outpos); + IF_DESKTOP(total_written += outpos;) + } + + retval = IF_DESKTOP(total_written) + 0; + err: + free(inbuf); + free(outbuf); + free(htab); + free(codetab); + return retval; +} diff --git a/busybox-1_37_0/archival/libarchive/decompress_unlzma.c b/busybox-1_37_0/archival/libarchive/decompress_unlzma.c new file mode 100644 index 000000000..fb5aac8fe --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/decompress_unlzma.c @@ -0,0 +1,527 @@ +/* vi: set sw=4 ts=4: */ +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs + * + * Based on LzmaDecode.c from the LZMA SDK 4.22 (http://www.7-zip.org/) + * Copyright (C) 1999-2005 Igor Pavlov + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + + +#if ENABLE_FEATURE_LZMA_FAST +# define speed_inline ALWAYS_INLINE +# define size_inline +#else +# define speed_inline +# define size_inline ALWAYS_INLINE +#endif + + +typedef struct { + int fd; + uint8_t *ptr; + +/* Was keeping rc on stack in unlzma and separately allocating buffer, + * but with "buffer 'attached to' allocated rc" code is smaller: */ + /* uint8_t *buffer; */ +#define RC_BUFFER ((uint8_t*)(rc+1)) + + uint8_t *buffer_end; + +/* Had provisions for variable buffer, but we don't need it here */ + /* int buffer_size; */ +#define RC_BUFFER_SIZE 0x10000 + + uint32_t code; + uint32_t range; + uint32_t bound; +} rc_t; + +#define RC_TOP_BITS 24 +#define RC_MOVE_BITS 5 +#define RC_MODEL_TOTAL_BITS 11 + + +/* Called once in rc_do_normalize() */ +static void rc_read(rc_t *rc) +{ + int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE); +//TODO: return -1 instead +//This will make unlzma delete broken unpacked file on unpack errors + if (buffer_size <= 0) + bb_simple_error_msg_and_die("unexpected EOF"); + rc->buffer_end = RC_BUFFER + buffer_size; + rc->ptr = RC_BUFFER; +} + +/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */ +static void rc_do_normalize(rc_t *rc) +{ + if (rc->ptr >= rc->buffer_end) + rc_read(rc); + rc->range <<= 8; + rc->code = (rc->code << 8) | *rc->ptr++; +} +static ALWAYS_INLINE void rc_normalize(rc_t *rc) +{ + if (rc->range < (1 << RC_TOP_BITS)) { + rc_do_normalize(rc); + } +} + +/* Called once */ +static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ +{ + int i; + rc_t *rc; + + rc = xzalloc(sizeof(*rc) + RC_BUFFER_SIZE); + + rc->fd = fd; + /* rc->ptr = rc->buffer_end; */ + + for (i = 0; i < 5; i++) { + rc_do_normalize(rc); + } + rc->range = 0xffffffff; + return rc; +} + +/* Called once */ +static ALWAYS_INLINE void rc_free(rc_t *rc) +{ + free(rc); +} + +/* rc_is_bit_1 is called 9 times */ +static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) +{ + rc_normalize(rc); + rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS); + if (rc->code < rc->bound) { + rc->range = rc->bound; + *p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS; + return 0; + } + rc->range -= rc->bound; + rc->code -= rc->bound; + *p -= *p >> RC_MOVE_BITS; + return 1; +} + +/* Called 4 times in unlzma loop */ +static ALWAYS_INLINE int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) +{ + int ret = rc_is_bit_1(rc, p); + *symbol = *symbol * 2 + ret; + return ret; +} + +/* Called once */ +static ALWAYS_INLINE int rc_direct_bit(rc_t *rc) +{ + rc_normalize(rc); + rc->range >>= 1; + if (rc->code >= rc->range) { + rc->code -= rc->range; + return 1; + } + return 0; +} + +/* Called twice */ +static speed_inline void +rc_bit_tree_decode(rc_t *rc, uint16_t *p, int num_levels, int *symbol) +{ + int i = num_levels; + + *symbol = 1; + while (i--) + rc_get_bit(rc, p + *symbol, symbol); + *symbol -= 1 << num_levels; +} + + +typedef struct { + uint8_t pos; + uint32_t dict_size; + uint64_t dst_size; +} PACKED lzma_header_t; + + +/* #defines will force compiler to compute/optimize each one with each usage. + * Have heart and use enum instead. */ +enum { + LZMA_BASE_SIZE = 1846, + LZMA_LIT_SIZE = 768, + + LZMA_NUM_POS_BITS_MAX = 4, + + LZMA_LEN_NUM_LOW_BITS = 3, + LZMA_LEN_NUM_MID_BITS = 3, + LZMA_LEN_NUM_HIGH_BITS = 8, + + LZMA_LEN_CHOICE = 0, + LZMA_LEN_CHOICE_2 = (LZMA_LEN_CHOICE + 1), + LZMA_LEN_LOW = (LZMA_LEN_CHOICE_2 + 1), + LZMA_LEN_MID = (LZMA_LEN_LOW \ + + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_LOW_BITS))), + LZMA_LEN_HIGH = (LZMA_LEN_MID \ + + (1 << (LZMA_NUM_POS_BITS_MAX + LZMA_LEN_NUM_MID_BITS))), + LZMA_NUM_LEN_PROBS = (LZMA_LEN_HIGH + (1 << LZMA_LEN_NUM_HIGH_BITS)), + + LZMA_NUM_STATES = 12, + LZMA_NUM_LIT_STATES = 7, + + LZMA_START_POS_MODEL_INDEX = 4, + LZMA_END_POS_MODEL_INDEX = 14, + LZMA_NUM_FULL_DISTANCES = (1 << (LZMA_END_POS_MODEL_INDEX >> 1)), + + LZMA_NUM_POS_SLOT_BITS = 6, + LZMA_NUM_LEN_TO_POS_STATES = 4, + + LZMA_NUM_ALIGN_BITS = 4, + + LZMA_MATCH_MIN_LEN = 2, + + LZMA_IS_MATCH = 0, + LZMA_IS_REP = (LZMA_IS_MATCH + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), + LZMA_IS_REP_G0 = (LZMA_IS_REP + LZMA_NUM_STATES), + LZMA_IS_REP_G1 = (LZMA_IS_REP_G0 + LZMA_NUM_STATES), + LZMA_IS_REP_G2 = (LZMA_IS_REP_G1 + LZMA_NUM_STATES), + LZMA_IS_REP_0_LONG = (LZMA_IS_REP_G2 + LZMA_NUM_STATES), + LZMA_POS_SLOT = (LZMA_IS_REP_0_LONG \ + + (LZMA_NUM_STATES << LZMA_NUM_POS_BITS_MAX)), + LZMA_SPEC_POS = (LZMA_POS_SLOT \ + + (LZMA_NUM_LEN_TO_POS_STATES << LZMA_NUM_POS_SLOT_BITS)), + LZMA_ALIGN = (LZMA_SPEC_POS \ + + LZMA_NUM_FULL_DISTANCES - LZMA_END_POS_MODEL_INDEX), + LZMA_LEN_CODER = (LZMA_ALIGN + (1 << LZMA_NUM_ALIGN_BITS)), + LZMA_REP_LEN_CODER = (LZMA_LEN_CODER + LZMA_NUM_LEN_PROBS), + LZMA_LITERAL = (LZMA_REP_LEN_CODER + LZMA_NUM_LEN_PROBS), +}; + + +IF_DESKTOP(long long) int FAST_FUNC +unpack_lzma_stream(transformer_state_t *xstate) +{ + IF_DESKTOP(long long total_written = 0;) + lzma_header_t header; + int lc, pb, lp; + uint32_t pos_state_mask; + uint32_t literal_pos_mask; + uint16_t *p; + rc_t *rc; + int i; + uint8_t *buffer; + uint32_t buffer_size; + uint8_t previous_byte = 0; + size_t buffer_pos = 0, global_pos = 0; + int len = 0; + int state = 0; + uint32_t rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1; + + if (full_read(xstate->src_fd, &header, sizeof(header)) != sizeof(header) + || header.pos >= (9 * 5 * 5) + ) { + bb_simple_error_msg("bad lzma header"); + return -1; + } + + i = header.pos / 9; + lc = header.pos % 9; + pb = i / 5; + lp = i % 5; + pos_state_mask = (1 << pb) - 1; + literal_pos_mask = (1 << lp) - 1; + + /* Example values from linux-3.3.4.tar.lzma: + * dict_size: 64M, dst_size: 2^64-1 + */ + header.dict_size = SWAP_LE32(header.dict_size); + header.dst_size = SWAP_LE64(header.dst_size); + + if (header.dict_size == 0) + header.dict_size++; + + buffer_size = MIN(header.dst_size, header.dict_size); + buffer = xmalloc(buffer_size); + + { + int num_probs; + + num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)); + p = xmalloc(num_probs * sizeof(*p)); + num_probs += LZMA_LITERAL - LZMA_BASE_SIZE; + for (i = 0; i < num_probs; i++) + p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1; + } + + rc = rc_init(xstate->src_fd); /*, RC_BUFFER_SIZE); */ + + while (global_pos + buffer_pos < header.dst_size) { + int pos_state = (buffer_pos + global_pos) & pos_state_mask; + uint16_t *prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state; + + if (!rc_is_bit_1(rc, prob)) { + static const char next_state[LZMA_NUM_STATES] = + { 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5 }; + int mi = 1; + + prob = (p + LZMA_LITERAL + + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc) + + (previous_byte >> (8 - lc)) + ) + ) + ); + + if (state >= LZMA_NUM_LIT_STATES) { + int match_byte; + uint32_t pos; + + pos = buffer_pos - rep0; + if ((int32_t)pos < 0) { + pos += header.dict_size; + if ((int32_t)pos < 0) + goto bad; + } + match_byte = buffer[pos]; + do { + int bit; + + match_byte <<= 1; + bit = match_byte & 0x100; + bit ^= (rc_get_bit(rc, prob + 0x100 + bit + mi, &mi) << 8); /* 0x100 or 0 */ + if (bit) + break; + } while (mi < 0x100); + } + while (mi < 0x100) { + rc_get_bit(rc, prob + mi, &mi); + } + + state = next_state[state]; + + previous_byte = (uint8_t) mi; +#if ENABLE_FEATURE_LZMA_FAST + one_byte1: + buffer[buffer_pos++] = previous_byte; + if (buffer_pos == header.dict_size) { + buffer_pos = 0; + global_pos += header.dict_size; + if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size) + goto bad; + IF_DESKTOP(total_written += header.dict_size;) + } +#else + len = 1; + goto one_byte2; +#endif + } else { + int num_bits; + int offset; + uint16_t *prob2; +#define prob_len prob2 + + prob2 = p + LZMA_IS_REP + state; + if (!rc_is_bit_1(rc, prob2)) { + rep3 = rep2; + rep2 = rep1; + rep1 = rep0; + state = state < LZMA_NUM_LIT_STATES ? 0 : 3; + prob2 = p + LZMA_LEN_CODER; + } else { + prob2 += LZMA_IS_REP_G0 - LZMA_IS_REP; + if (!rc_is_bit_1(rc, prob2)) { + prob2 = (p + LZMA_IS_REP_0_LONG + + (state << LZMA_NUM_POS_BITS_MAX) + + pos_state + ); + if (!rc_is_bit_1(rc, prob2)) { +#if ENABLE_FEATURE_LZMA_FAST + uint32_t pos; + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; + + pos = buffer_pos - rep0; + if ((int32_t)pos < 0) { + pos += header.dict_size; + /* see unzip_bad_lzma_2.zip: */ + if (pos >= buffer_size) { + dbg("%d pos:%d buffer_size:%d", __LINE__, pos, buffer_size); + goto bad; + } + } + previous_byte = buffer[pos]; + goto one_byte1; +#else + state = state < LZMA_NUM_LIT_STATES ? 9 : 11; + len = 1; + goto string; +#endif + } + } else { + uint32_t distance; + + prob2 += LZMA_IS_REP_G1 - LZMA_IS_REP_G0; + distance = rep1; + if (rc_is_bit_1(rc, prob2)) { + prob2 += LZMA_IS_REP_G2 - LZMA_IS_REP_G1; + distance = rep2; + if (rc_is_bit_1(rc, prob2)) { + distance = rep3; + rep3 = rep2; + } + rep2 = rep1; + } + rep1 = rep0; + rep0 = distance; + } + state = state < LZMA_NUM_LIT_STATES ? 8 : 11; + prob2 = p + LZMA_REP_LEN_CODER; + } + + prob_len = prob2 + LZMA_LEN_CHOICE; + num_bits = LZMA_LEN_NUM_LOW_BITS; + if (!rc_is_bit_1(rc, prob_len)) { + prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE + + (pos_state << LZMA_LEN_NUM_LOW_BITS); + offset = 0; + } else { + prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE; + if (!rc_is_bit_1(rc, prob_len)) { + prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2 + + (pos_state << LZMA_LEN_NUM_MID_BITS); + offset = 1 << LZMA_LEN_NUM_LOW_BITS; + num_bits += LZMA_LEN_NUM_MID_BITS - LZMA_LEN_NUM_LOW_BITS; + } else { + prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2; + offset = ((1 << LZMA_LEN_NUM_LOW_BITS) + + (1 << LZMA_LEN_NUM_MID_BITS)); + num_bits += LZMA_LEN_NUM_HIGH_BITS - LZMA_LEN_NUM_LOW_BITS; + } + } + rc_bit_tree_decode(rc, prob_len, num_bits, &len); + len += offset; + + if (state < 4) { + int pos_slot; + uint16_t *prob3; + + state += LZMA_NUM_LIT_STATES; + prob3 = p + LZMA_POS_SLOT + + ((len < LZMA_NUM_LEN_TO_POS_STATES ? len : + LZMA_NUM_LEN_TO_POS_STATES - 1) + << LZMA_NUM_POS_SLOT_BITS); + rc_bit_tree_decode(rc, prob3, + LZMA_NUM_POS_SLOT_BITS, &pos_slot); + rep0 = pos_slot; + if (pos_slot >= LZMA_START_POS_MODEL_INDEX) { + int i2, mi2, num_bits2 = (pos_slot >> 1) - 1; + rep0 = 2 | (pos_slot & 1); + if (pos_slot < LZMA_END_POS_MODEL_INDEX) { + rep0 <<= num_bits2; + prob3 = p + LZMA_SPEC_POS + rep0 - pos_slot - 1; + } else { + for (; num_bits2 != LZMA_NUM_ALIGN_BITS; num_bits2--) + rep0 = (rep0 << 1) | rc_direct_bit(rc); + rep0 <<= LZMA_NUM_ALIGN_BITS; + // Note: (int32_t)rep0 may be < 0 here + // (I have linux-3.3.4.tar.lzma which has it). + // I moved the check after "++rep0 == 0" check below. + prob3 = p + LZMA_ALIGN; + } + i2 = 1; + mi2 = 1; + while (num_bits2--) { + if (rc_get_bit(rc, prob3 + mi2, &mi2)) + rep0 |= i2; + i2 <<= 1; + } + } + rep0++; + if ((int32_t)rep0 <= 0) { + if (rep0 == 0) + break; + dbg("%d rep0:%d", __LINE__, rep0); + goto bad; + } + } + + len += LZMA_MATCH_MIN_LEN; + /* + * LZMA SDK has this optimized: + * it precalculates size and copies many bytes + * in a loop with simpler checks, a-la: + * do + * *(dest) = *(dest + ofs); + * while (++dest != lim); + * and + * do { + * buffer[buffer_pos++] = buffer[pos]; + * if (++pos == header.dict_size) + * pos = 0; + * } while (--cur_len != 0); + * Our code is slower (more checks per byte copy): + */ + IF_NOT_FEATURE_LZMA_FAST(string:) + do { + uint32_t pos = buffer_pos - rep0; + if ((int32_t)pos < 0) { + pos += header.dict_size; + /* bug 10436 has an example file where this triggers: */ + //if ((int32_t)pos < 0) + // goto bad; + /* more stringent test (see unzip_bad_lzma_1.zip): */ + if (pos >= buffer_size) + goto bad; + } + previous_byte = buffer[pos]; + IF_NOT_FEATURE_LZMA_FAST(one_byte2:) + buffer[buffer_pos++] = previous_byte; + if (buffer_pos == header.dict_size) { + buffer_pos = 0; + global_pos += header.dict_size; + if (transformer_write(xstate, buffer, header.dict_size) != (ssize_t)header.dict_size) + goto bad; + IF_DESKTOP(total_written += header.dict_size;) + } + len--; + } while (len != 0 && buffer_pos < header.dst_size); + /* FIXME: ...........^^^^^ + * shouldn't it be "global_pos + buffer_pos < header.dst_size"? + * It probably should, but it is a "do we accidentally + * unpack more bytes than expected?" check - which + * never happens for well-formed compression data... + */ + } + } + + { + IF_NOT_DESKTOP(int total_written = 0; /* success */) + IF_DESKTOP(total_written += buffer_pos;) + if (transformer_write(xstate, buffer, buffer_pos) != (ssize_t)buffer_pos) { + bad: + /* One of our users, bbunpack(), expects _us_ to emit + * the error message (since it's the best place to give + * potentially more detailed information). + * Do not fail silently. + */ + bb_simple_error_msg("corrupted data"); + total_written = -1; /* failure */ + } + rc_free(rc); + free(p); + free(buffer); + return total_written; + } +} diff --git a/busybox-1_37_0/archival/libarchive/decompress_unxz.c b/busybox-1_37_0/archival/libarchive/decompress_unxz.c new file mode 100644 index 000000000..3dd9bbf49 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/decompress_unxz.c @@ -0,0 +1,154 @@ +/* + * This file uses XZ Embedded library code which is written + * by Lasse Collin + * and Igor Pavlov + * + * See README file in unxz/ directory for more information. + * + * This file is: + * Copyright (C) 2010 Denys Vlasenko + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +#define XZ_FUNC FAST_FUNC +#define XZ_EXTERN static + +#define XZ_DEC_DYNALLOC + +/* Skip check (rather than fail) of unsupported hash functions */ +#define XZ_DEC_ANY_CHECK 1 + +/* We use our own crc32 function */ +#define XZ_INTERNAL_CRC32 0 +static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) +{ + return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); +} + +/* We use arch-optimized unaligned fixed-endian accessors. + * They have been moved to libbb (proved to be useful elsewhere as well), + * just check that we have them defined: + */ +#if !defined(get_unaligned_le32) \ + || !defined(get_unaligned_be32) \ + || !defined(put_unaligned_le32) \ + || !defined(put_unaligned_be32) +# error get_unaligned_le32 accessors are not defined +#endif + +#include "unxz/xz_dec_bcj.c" +#include "unxz/xz_dec_lzma2.c" +#include "unxz/xz_dec_stream.c" + +IF_DESKTOP(long long) int FAST_FUNC +unpack_xz_stream(transformer_state_t *xstate) +{ + enum xz_ret xz_result; + struct xz_buf iobuf; + struct xz_dec *state; + unsigned char *membuf; + IF_DESKTOP(long long) int total = 0; + + if (!global_crc32_table) + global_crc32_new_table_le(); + + memset(&iobuf, 0, sizeof(iobuf)); + membuf = xmalloc(2 * BUFSIZ); + iobuf.in = membuf; + iobuf.out = membuf + BUFSIZ; + iobuf.out_size = BUFSIZ; + + if (!xstate || xstate->signature_skipped) { + /* Preload XZ file signature */ + strcpy((char*)membuf, HEADER_MAGIC); + iobuf.in_size = HEADER_MAGIC_SIZE; + } /* else: let xz code read & check it */ + + /* Limit memory usage to about 64 MiB. */ + state = xz_dec_init(XZ_DYNALLOC, 64*1024*1024); + + xz_result = X_OK; + while (1) { + if (iobuf.in_pos == iobuf.in_size) { + int rd = safe_read(xstate->src_fd, membuf, BUFSIZ); + if (rd < 0) { + bb_simple_error_msg(bb_msg_read_error); + total = -1; + break; + } + if (rd == 0 && xz_result == XZ_STREAM_END) + break; + iobuf.in_size = rd; + iobuf.in_pos = 0; + } + if (xz_result == XZ_STREAM_END) { + /* + * Try to start decoding next concatenated stream. + * Stream padding must always be a multiple of four + * bytes to preserve four-byte alignment. To keep the + * code slightly smaller, we aren't as strict here as + * the .xz spec requires. We just skip all zero-bytes + * without checking the alignment and thus can accept + * files that aren't valid, e.g. the XZ utils test + * files bad-0pad-empty.xz and bad-0catpad-empty.xz. + */ + do { + if (membuf[iobuf.in_pos] != 0) { + /* There is more data, but is it XZ data? + * Example: dpkg-deb -f busybox_1.30.1-4_amd64.deb + * reads control.tar.xz "control" file + * inside the ar archive, but tar.xz + * extraction code reaches end of xz data, + * reached this code and reads the beginning + * of data.tar.xz's ar header, which isn't xz data, + * and prints "corrupted data". + * The correct solution is to not read + * past nested archive (to simulate EOF). + * This is a workaround: + */ + if (membuf[iobuf.in_pos] != 0xfd) { + /* It's definitely not a xz signature + * (which is 0xfd,"7zXZ",0x00). + */ + goto end; + } + xz_dec_reset(state); + goto do_run; + } + iobuf.in_pos++; + } while (iobuf.in_pos < iobuf.in_size); + } + do_run: +// bb_error_msg(">in pos:%d size:%d out pos:%d size:%d", +// iobuf.in_pos, iobuf.in_size, iobuf.out_pos, iobuf.out_size); + xz_result = xz_dec_run(state, &iobuf); +// bb_error_msg("file_header->name) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/filter_accept_list.c b/busybox-1_37_0/archival/libarchive/filter_accept_list.c new file mode 100644 index 000000000..32f806574 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/filter_accept_list.c @@ -0,0 +1,18 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +/* + * Accept names that are in the accept list, ignoring reject list. + */ +char FAST_FUNC filter_accept_list(archive_handle_t *archive_handle) +{ + if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) + return EXIT_SUCCESS; + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/filter_accept_list_reassign.c b/busybox-1_37_0/archival/libarchive/filter_accept_list_reassign.c new file mode 100644 index 000000000..826c5c29d --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/filter_accept_list_reassign.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +/* Built and used only if ENABLE_DPKG || ENABLE_DPKG_DEB */ + +/* + * Reassign the subarchive metadata parser based on the filename extension + * e.g. if its a .tar.gz modify archive_handle->sub_archive to process a .tar.gz + * or if its a .tar.bz2 make archive_handle->sub_archive handle that + */ +char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle) +{ + /* Check the file entry is in the accept list */ + if (find_list_entry(archive_handle->accept, archive_handle->file_header->name)) { + const char *name_ptr; + + /* Find extension */ + name_ptr = strrchr(archive_handle->file_header->name, '.'); + if (!name_ptr) + return EXIT_FAILURE; + name_ptr++; + + /* Modify the subarchive handler based on the extension */ + if (strcmp(name_ptr, "tar") == 0) { + archive_handle->dpkg__action_data_subarchive = get_header_tar; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_GZ + && strcmp(name_ptr, "gz") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_gz; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && strcmp(name_ptr, "bz2") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_bz2; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_LZMA + && strcmp(name_ptr, "lzma") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma; + return EXIT_SUCCESS; + } + if (ENABLE_FEATURE_SEAMLESS_XZ + && strcmp(name_ptr, "xz") == 0 + ) { + archive_handle->dpkg__action_data_subarchive = get_header_tar_xz; + return EXIT_SUCCESS; + } + } + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/filter_accept_reject_list.c b/busybox-1_37_0/archival/libarchive/filter_accept_reject_list.c new file mode 100644 index 000000000..939e626fa --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/filter_accept_reject_list.c @@ -0,0 +1,37 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +/* + * Accept names that are in the accept list and not in the reject list + */ +char FAST_FUNC filter_accept_reject_list(archive_handle_t *archive_handle) +{ + const char *key; + const llist_t *reject_entry; + const llist_t *accept_entry; + + key = archive_handle->file_header->name; + + /* If the key is in a reject list fail */ + reject_entry = find_list_entry2(archive_handle->reject, key); + if (reject_entry) { + return EXIT_FAILURE; + } + + /* Fail if an accept list was specified and the key wasnt in there */ + if (archive_handle->accept) { + accept_entry = find_list_entry2(archive_handle->accept, key); + if (!accept_entry) { + return EXIT_FAILURE; + } + } + + /* Accepted */ + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/libarchive/find_list_entry.c b/busybox-1_37_0/archival/libarchive/find_list_entry.c new file mode 100644 index 000000000..37726bd3d --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/find_list_entry.c @@ -0,0 +1,53 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2002 by Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include +#include "libbb.h" +#include "bb_archive.h" + +/* Find a string in a shell pattern list */ +const llist_t* FAST_FUNC find_list_entry(const llist_t *list, const char *filename) +{ + while (list) { + if (fnmatch(list->data, filename, 0) == 0) { + return list; + } + list = list->link; + } + return NULL; +} + +/* Same, but compares only path components present in pattern + * (extra trailing path components in filename are assumed to match) + */ +const llist_t* FAST_FUNC find_list_entry2(const llist_t *list, const char *filename) +{ + char buf[PATH_MAX]; + int pattern_slash_cnt; + const char *c; + char *d; + + while (list) { + c = list->data; + pattern_slash_cnt = 0; + while (*c) + if (*c++ == '/') pattern_slash_cnt++; + c = filename; + d = buf; + /* paranoia is better than buffer overflows */ + while (*c && d != buf + sizeof(buf)-1) { + if (*c == '/' && --pattern_slash_cnt < 0) + break; + *d++ = *c++; + } + *d = '\0'; + if (fnmatch(list->data, buf, 0) == 0) { + return list; + } + list = list->link; + } + return NULL; +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_ar.c b/busybox-1_37_0/archival/libarchive/get_header_ar.c new file mode 100644 index 000000000..6bd897392 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_ar.c @@ -0,0 +1,146 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 2001 Glenn McGrath. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" +#include "ar_.h" + +/* WARNING: Clobbers str[len], so fields must be read in reverse order! */ +static unsigned read_num(char *str, int base, int len) +{ + int err; + + /* ar fields are fixed length text strings (padded with spaces). + * Ensure bb_strtou doesn't read past the field in case the full + * width is used. */ + str[len] = 0; + + /* This code works because + * on misformatted numbers bb_strtou returns all-ones */ + err = bb_strtou(str, NULL, base); + if (err == -1) + bb_simple_error_msg_and_die("invalid ar header"); + return err; +} + +char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) +{ + file_header_t *typed = archive_handle->file_header; + unsigned size; + union { + char raw[60]; + struct ar_header formatted; + } ar; + + /* dont use xread as we want to handle the error ourself */ + if (read(archive_handle->src_fd, ar.raw, 60) != 60) { + /* End Of File */ + return EXIT_FAILURE; + } + + /* ar header starts on an even byte (2 byte aligned) + * '\n' is used for padding + */ + if (ar.raw[0] == '\n') { + /* fix up the header, we started reading 1 byte too early */ + memmove(ar.raw, &ar.raw[1], 59); + ar.raw[59] = xread_char(archive_handle->src_fd); + archive_handle->offset++; + } + archive_handle->offset += 60; + + if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') + bb_simple_error_msg_and_die("invalid ar header"); + + /* + * Note that the fields MUST be read in reverse order as + * read_num() clobbers the next byte after the field! + * Order is: name, date, uid, gid, mode, size, magic. + */ + typed->size = size = read_num(ar.formatted.size, 10, + sizeof(ar.formatted.size)); + + /* special filenames have '/' as the first character */ + if (ar.formatted.name[0] == '/') { + if (ar.formatted.name[1] == ' ') { + /* This is the index of symbols in the file for compilers */ + data_skip(archive_handle); + archive_handle->offset += size; + return get_header_ar(archive_handle); /* Return next header */ + } +#if ENABLE_FEATURE_AR_LONG_FILENAMES + if (ar.formatted.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 + */ + archive_handle->ar__long_name_size = size; + free(archive_handle->ar__long_names); + archive_handle->ar__long_names = xzalloc(size + 1); + xread(archive_handle->src_fd, archive_handle->ar__long_names, size); + archive_handle->offset += size; + /* Return next header */ + return get_header_ar(archive_handle); + } +#else + bb_simple_error_msg_and_die("long filenames not supported"); +#endif + } + /* Only size is always present, the rest may be missing in + * long filename pseudo file. Thus we decode the rest + * after dealing with long filename pseudo file. + * + * GNU binutils in deterministic mode hard codes mode to 0644 (NOT + * 0100644). AR archives can only contain files, so force file + * mode. + */ + typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode)) | S_IFREG; + typed->gid = read_num(ar.formatted.gid, 10, sizeof(ar.formatted.gid)); + typed->uid = read_num(ar.formatted.uid, 10, sizeof(ar.formatted.uid)); + typed->mtime = read_num(ar.formatted.date, 10, sizeof(ar.formatted.date)); + +#if ENABLE_FEATURE_AR_LONG_FILENAMES + if (ar.formatted.name[0] == '/') { + unsigned long_offset; + + /* The number after the '/' indicates the offset in the ar data section + * (saved in ar__long_names) that contains the real filename */ + long_offset = read_num(&ar.formatted.name[1], 10, + sizeof(ar.formatted.name) - 1); + if (long_offset >= archive_handle->ar__long_name_size) { + bb_simple_error_msg_and_die("can't resolve long filename"); + } + typed->name = xstrdup(archive_handle->ar__long_names + long_offset); + } else +#endif + { + /* short filenames */ + typed->name = xstrndup(ar.formatted.name, 16); + } + + typed->name[strcspn(typed->name, " /")] = '\0'; + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_header(typed); +#if ENABLE_DPKG || ENABLE_DPKG_DEB + if (archive_handle->dpkg__sub_archive) { + struct archive_handle_t *sa = archive_handle->dpkg__sub_archive; + while (archive_handle->dpkg__action_data_subarchive(sa) == EXIT_SUCCESS) + continue; + create_links_from_list(sa->link_placeholders); + } else +#endif + archive_handle->action_data(archive_handle); + } else { + data_skip(archive_handle); + } + + archive_handle->offset += typed->size; + /* Set the file pointer to the correct spot, we may have been reading a compressed file */ + lseek(archive_handle->src_fd, archive_handle->offset, SEEK_SET); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_cpio.c b/busybox-1_37_0/archival/libarchive/get_header_cpio.c new file mode 100644 index 000000000..9ad0557c2 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_cpio.c @@ -0,0 +1,192 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 2002 Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +typedef struct hardlinks_t { + struct hardlinks_t *next; + int inode; /* TODO: must match maj/min too! */ + int mode ; + int mtime; /* These three are useful only in corner case */ + int uid ; /* of hardlinks with zero size body */ + int gid ; + char name[1]; +} hardlinks_t; + +char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + char cpio_header[111]; + int namesize; + int major, minor, nlink, mode, inode; + unsigned size, uid, gid, mtime; + + /* There can be padding before archive header */ + data_align(archive_handle, 4); + + size = full_read(archive_handle->src_fd, cpio_header, 110); + if (size == 0) { + goto create_hardlinks; + } + if (size != 110) { + bb_simple_error_msg_and_die("short read"); + } + archive_handle->offset += 110; + + if (!is_prefixed_with(&cpio_header[0], "07070") + || (cpio_header[5] != '1' && cpio_header[5] != '2') + ) { + bb_simple_error_msg_and_die("unsupported cpio format, use newc or crc"); + } + + cpio_header[110] = '\0'; /* sscanf may call strlen which may break without this */ + if (sscanf(cpio_header + 6, + "%8x" "%8x" "%8x" "%8x" + "%8x" "%8x" "%8x" /*maj,min:*/ "%*16c" + /*rmaj,rmin:*/"%8x" "%8x" "%8x" /*chksum: "%*8c"*/, + &inode, &mode, &uid, &gid, + &nlink, &mtime, &size, + &major, &minor, &namesize) != 10) + bb_simple_error_msg_and_die("damaged cpio file"); + file_header->mode = mode; + /* "cpio -R USER:GRP" support: */ + if (archive_handle->cpio__owner.uid != (uid_t)-1L) + uid = archive_handle->cpio__owner.uid; + if (archive_handle->cpio__owner.gid != (gid_t)-1L) + gid = archive_handle->cpio__owner.gid; + file_header->uid = uid; + file_header->gid = gid; + file_header->mtime = mtime; + file_header->size = size; + + namesize &= 0x1fff; /* paranoia: limit names to 8k chars */ + file_header->name = xzalloc(namesize + 1); + /* Read in filename */ + xread(archive_handle->src_fd, file_header->name, namesize); + if (file_header->name[0] == '/') { + /* Testcase: echo /etc/hosts | cpio -pvd /tmp + * Without this code, it tries to unpack /etc/hosts + * into "/etc/hosts", not "etc/hosts". + */ + char *p = file_header->name; + do p++; while (*p == '/'); + overlapping_strcpy(file_header->name, p); + } + archive_handle->offset += namesize; + + /* Update offset amount and skip padding before file contents */ + data_align(archive_handle, 4); + + if (strcmp(file_header->name, cpio_TRAILER) == 0) { + /* Always round up. ">> 9" divides by 512 */ + archive_handle->cpio__blocks = (uoff_t)(archive_handle->offset + 511) >> 9; + goto create_hardlinks; + } + + file_header->link_target = NULL; + if (S_ISLNK(file_header->mode)) { + file_header->size &= 0x1fff; /* paranoia: limit names to 8k chars */ + file_header->link_target = xzalloc(file_header->size + 1); + xread(archive_handle->src_fd, file_header->link_target, file_header->size); + archive_handle->offset += file_header->size; + file_header->size = 0; /* Stop possible seeks in future */ + } + +// TODO: data_extract_all can't deal with hardlinks to non-files... +// when fixed, change S_ISREG to !S_ISDIR here + + if (nlink > 1 && S_ISREG(file_header->mode)) { + hardlinks_t *new = xmalloc(sizeof(*new) + namesize); + new->inode = inode; + new->mode = mode ; + new->mtime = mtime; + new->uid = uid ; + new->gid = gid ; + strcpy(new->name, file_header->name); + /* Put file on a linked list for later */ + if (size == 0) { + new->next = archive_handle->cpio__hardlinks_to_create; + archive_handle->cpio__hardlinks_to_create = new; + return EXIT_SUCCESS; /* Skip this one */ + /* TODO: this breaks cpio -t (it does not show hardlinks) */ + } + new->next = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = new; + } + file_header->device = makedev(major, minor); + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_data(archive_handle); +//TODO: run "echo /etc/hosts | cpio -pv /tmp" twice. On 2nd run: +//cpio: etc/hosts not created: newer or same age file exists +//etc/hosts <-- should NOT show it +//2 blocks <-- should say "0 blocks" + archive_handle->action_header(file_header); + } else { + data_skip(archive_handle); + } + + archive_handle->offset += file_header->size; + + free(file_header->link_target); + free(file_header->name); + file_header->link_target = NULL; + file_header->name = NULL; + + return EXIT_SUCCESS; + + create_hardlinks: + free(file_header->link_target); + free(file_header->name); + + while (archive_handle->cpio__hardlinks_to_create) { + hardlinks_t *cur; + hardlinks_t *make_me = archive_handle->cpio__hardlinks_to_create; + + archive_handle->cpio__hardlinks_to_create = make_me->next; + + memset(file_header, 0, sizeof(*file_header)); + file_header->mtime = make_me->mtime; + file_header->name = make_me->name; + file_header->mode = make_me->mode; + file_header->uid = make_me->uid; + file_header->gid = make_me->gid; + /*file_header->size = 0;*/ + /*file_header->link_target = NULL;*/ + + /* Try to find a file we are hardlinked to */ + cur = archive_handle->cpio__created_hardlinks; + while (cur) { + /* TODO: must match maj/min too! */ + if (cur->inode == make_me->inode) { + file_header->link_target = cur->name; + /* link_target != NULL, size = 0: "I am a hardlink" */ + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) + archive_handle->action_data(archive_handle); + free(make_me); + goto next_link; + } + cur = cur->next; + } + /* Oops... no file with such inode was created... do it now + * (happens when hardlinked files are empty (zero length)) */ + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) + archive_handle->action_data(archive_handle); + /* Move to the list of created hardlinked files */ + make_me->next = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = make_me; + next_link: ; + } + + while (archive_handle->cpio__created_hardlinks) { + hardlinks_t *p = archive_handle->cpio__created_hardlinks; + archive_handle->cpio__created_hardlinks = p->next; + free(p); + } + + return EXIT_FAILURE; /* "No more files to process" */ +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_tar.c b/busybox-1_37_0/archival/libarchive/get_header_tar.c new file mode 100644 index 000000000..cc6f3f0ad --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_tar.c @@ -0,0 +1,491 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * FIXME: + * In privileged mode if uname and gname map to a uid and gid then use the + * mapped value instead of the uid/gid values in tar header + * + * References: + * GNU tar and star man pages, + * Opengroup's ustar interchange format, + * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html + */ +#include "libbb.h" +#include "bb_archive.h" + +typedef uint32_t aliased_uint32_t FIX_ALIASING; +typedef off_t aliased_off_t FIX_ALIASING; + +/* NB: _DESTROYS_ str[len] character! */ +static unsigned long long getOctal(char *str, int len) +{ + unsigned long long v; + char *end; + /* NB: leading spaces are allowed. Using strtoull to handle that. + * The downside is that we accept e.g. "-123" too :( + */ + str[len] = '\0'; + v = strtoull(str, &end, 8); + /* std: "Each numeric field is terminated by one or more + * or NUL characters". We must support ' '! */ + if (*end != '\0' && *end != ' ') { + int8_t first = str[0]; + if (!(first & 0x80)) + bb_simple_error_msg_and_die("corrupted octal value in tar header"); + /* + * GNU tar uses "base-256 encoding" for very large numbers. + * Encoding is binary, with highest bit always set as a marker + * and sign in next-highest bit: + * 80 00 .. 00 - zero + * bf ff .. ff - largest positive number + * ff ff .. ff - minus 1 + * c0 00 .. 00 - smallest negative number + * + * Example of tar file with 8914993153 (0x213600001) byte file. + * Field starts at offset 7c: + * 00070 30 30 30 00 30 30 30 30 30 30 30 00 80 00 00 00 |000.0000000.....| + * 00080 00 00 00 02 13 60 00 01 31 31 31 32 30 33 33 36 |.....`..11120336| + * + * NB: tarballs with NEGATIVE unix times encoded that way were seen! + */ + /* Sign-extend 7bit 'first' to 64bit 'v' (that is, using 6th bit as sign): */ + first <<= 1; + first >>= 1; /* now 7th bit = 6th bit */ + v = first; /* sign-extend 8 bits to 64 */ + while (--len != 0) + v = (v << 8) + (uint8_t) *++str; + } + return v; +} +#define GET_OCTAL(a) getOctal((a), sizeof(a)) + +#define TAR_EXTD (ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX) +#if !TAR_EXTD +#define process_pax_hdr(archive_handle, sz, global) \ + process_pax_hdr(archive_handle, sz) +#endif +/* "global" is 0 or 1 */ +static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) +{ +#if !TAR_EXTD + unsigned blk_sz = (sz + 511) & (~511); + seek_by_read(archive_handle->src_fd, blk_sz); +#else + unsigned blk_sz = (sz + 511) & (~511); + char *buf, *p; + + p = buf = xmalloc(blk_sz + 1); + xread(archive_handle->src_fd, buf, blk_sz); + archive_handle->offset += blk_sz; + + /* prevent bb_strtou from running off the buffer */ + buf[sz] = '\0'; + + while (sz != 0) { + char *end, *value; + unsigned len; + + /* Every record has this format: "LEN NAME=VALUE\n" */ + len = bb_strtou(p, &end, 10); + /* expect errno to be EINVAL, because the character + * following the digits should be a space + */ + p += len; + sz -= len; + if ( + /** (int)sz < 0 - not good enough for huge malicious VALUE of 2^32-1 */ + (int)(sz|len) < 0 /* this works */ + || len == 0 + || errno != EINVAL + || *end != ' ' + ) { + bb_simple_error_msg("malformed extended header, skipped"); + // More verbose version: + //bb_error_msg("malformed extended header at %"OFF_FMT"d, skipped", + // archive_handle->offset - (sz + len)); + break; + } + /* overwrite the terminating newline with NUL + * (we do not bother to check that it *was* a newline) + */ + p[-1] = '\0'; + value = end + 1; + +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (!global) { + if (is_prefixed_with(value, "path=")) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = xstrdup(value); + continue; + } + if (is_prefixed_with(value, "linkpath=")) { + value += sizeof("linkpath=") - 1; + free(archive_handle->tar__linkname); + archive_handle->tar__linkname = xstrdup(value); + continue; + } + } +# endif + +# if ENABLE_FEATURE_TAR_SELINUX + /* Scan for SELinux contexts, via "RHT.security.selinux" keyword. + * This is what Red Hat's patched version of tar uses. + */ +# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" + if (is_prefixed_with(value, SELINUX_CONTEXT_KEYWORD"=")) { + value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; + free(archive_handle->tar__sctx[global]); + archive_handle->tar__sctx[global] = xstrdup(value); + continue; + } +# endif + } + + free(buf); +#endif +} + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +static void die_if_bad_fnamesize(off_t sz) +{ + if ((uoff_t)sz > 0xfff) /* more than 4k?! no funny business please */ + bb_simple_error_msg_and_die("bad archive"); +} +#endif + +char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) +{ + file_header_t *file_header = archive_handle->file_header; + struct tar_header_t tar; + char *cp; + int tar_typeflag; /* can be "char", "int" seems give smaller code */ + int i, sum_u, sum; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + int sum_s; +#endif + int parse_names; + + /* Our "private data" */ +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +# define p_longname (archive_handle->tar__longname) +# define p_linkname (archive_handle->tar__linkname) +#else +# define p_longname 0 +# define p_linkname 0 +#endif + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS || ENABLE_FEATURE_TAR_SELINUX + again: +#endif + /* Align header */ + data_align(archive_handle, 512); + + again_after_align: + +#if ENABLE_DESKTOP || ENABLE_FEATURE_TAR_AUTODETECT + /* to prevent misdetection of bz2 sig */ + *(aliased_uint32_t*)&tar = 0; + i = full_read(archive_handle->src_fd, &tar, 512); + /* If GNU tar sees EOF in above read, it says: + * "tar: A lone zero block at N", where N = kilobyte + * where EOF was met (not EOF block, actual EOF!), + * and exits with EXIT_SUCCESS. + * We will mimic exit(EXIT_SUCCESS), although we will not mimic + * the message and we don't check whether we indeed + * saw zero block directly before this. */ + if (i == 0) { + /* GNU tar 1.29 will be silent if tar archive ends abruptly + * (if there are no zero blocks at all, and last read returns zero, + * not short read 0 < len < 512). Complain only if + * the very first read fails. Grrr. + */ + if (archive_handle->offset == 0) + bb_simple_error_msg("short read"); + /* this merely signals end of archive, not exit(1): */ + return EXIT_FAILURE; + } + if (i != 512) { + IF_FEATURE_TAR_AUTODETECT(goto autodetect;) + bb_simple_error_msg_and_die("short read"); + } + +#else + i = 512; + xread(archive_handle->src_fd, &tar, i); +#endif + archive_handle->offset += i; + + /* If there is no filename its an empty header */ + if (tar.name[0] == 0 && tar.prefix[0] == 0 + /* Have seen a tar archive with pax 'x' header supplying UTF8 filename, + * with actual file having all name fields NUL-filled. Check this: */ + && !p_longname + ) { + if (archive_handle->tar__end) { + /* Second consecutive empty header - end of archive. + * Read until the end to empty the pipe from gz or bz2 + */ + while (full_read(archive_handle->src_fd, &tar, 512) == 512) + continue; + return EXIT_FAILURE; /* "end of archive" */ + } + archive_handle->tar__end = 1; + return EXIT_SUCCESS; /* "decoded one header" */ + } + archive_handle->tar__end = 0; + + /* Check header has valid magic, "ustar" is for the proper tar, + * five NULs are for the old tar format */ + if (!is_prefixed_with(tar.magic, "ustar") + && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY + || memcmp(tar.magic, "\0\0\0\0", 5) != 0) + ) { +#if ENABLE_FEATURE_TAR_AUTODETECT + autodetect: + /* Two different causes for lseek() != 0: + * unseekable fd (would like to support that too, but...), + * or not first block (false positive, it's not .gz/.bz2!) */ + if (lseek(archive_handle->src_fd, -i, SEEK_CUR) != 0) + goto err; + if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 0) != 0) + err: + bb_simple_error_msg_and_die("invalid tar magic"); + archive_handle->offset = 0; + goto again_after_align; +#endif + bb_simple_error_msg_and_die("invalid tar magic"); + } + + /* Do checksum on headers. + * POSIX says that checksum is done on unsigned bytes, but + * Sun and HP-UX gets it wrong... more details in + * GNU tar source. */ + sum_u = ' ' * sizeof(tar.chksum); +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s = sum_u; +#endif + for (i = 0; i < 148; i++) { + sum_u += ((unsigned char*)&tar)[i]; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s += ((signed char*)&tar)[i]; +#endif + } + for (i = 156; i < 512; i++) { + sum_u += ((unsigned char*)&tar)[i]; +#if ENABLE_FEATURE_TAR_OLDSUN_COMPATIBILITY + sum_s += ((signed char*)&tar)[i]; +#endif + } + /* Most tarfiles have tar.chksum NUL or space terminated, but + * github.com decided to be "special" and have unterminated field: + * 0090: 30343300 30303031 33323731 30000000 |043.000132710...| + * ^^^^^^^^| + * Need to use GET_OCTAL. This overwrites tar.typeflag ---+ + * (the '0' char immediately after chksum in example above) with NUL. + */ + tar_typeflag = (uint8_t)tar.typeflag; /* save it */ + sum = GET_OCTAL(tar.chksum); + if (sum_u != sum + IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum) + ) { + bb_simple_error_msg_and_die("invalid tar header checksum"); + } + + /* GET_OCTAL trashes subsequent field, therefore we call it + * on fields in reverse order */ + if (tar.devmajor[0]) { + char t = tar.prefix[0]; + /* we trash prefix[0] here, but we DO need it later! */ + unsigned minor = GET_OCTAL(tar.devminor); + unsigned major = GET_OCTAL(tar.devmajor); + file_header->device = makedev(major, minor); + tar.prefix[0] = t; + } + + /* 0 is reserved for high perf file, treat as normal file */ + if (tar_typeflag == '\0') tar_typeflag = '0'; + parse_names = (tar_typeflag >= '0' && tar_typeflag <= '7'); + + file_header->link_target = NULL; + if (!p_linkname && parse_names && tar.linkname[0]) { + file_header->link_target = xstrndup(tar.linkname, sizeof(tar.linkname)); + /* FIXME: what if we have non-link object with link_target? */ + /* Will link_target be free()ed? */ + } +#if ENABLE_FEATURE_TAR_UNAME_GNAME + file_header->tar__uname = tar.uname[0] ? xstrndup(tar.uname, sizeof(tar.uname)) : NULL; + file_header->tar__gname = tar.gname[0] ? xstrndup(tar.gname, sizeof(tar.gname)) : NULL; +#endif + file_header->mtime = GET_OCTAL(tar.mtime); + file_header->size = GET_OCTAL(tar.size); + file_header->gid = GET_OCTAL(tar.gid); + file_header->uid = GET_OCTAL(tar.uid); + /* Set bits 0-11 of the files mode */ + file_header->mode = 07777 & GET_OCTAL(tar.mode); + + file_header->name = NULL; + if (!p_longname && parse_names) { + /* we trash mode[0] here, it's ok */ + //tar.name[sizeof(tar.name)] = '\0'; - gcc 4.3.0 would complain + tar.mode[0] = '\0'; + if (tar.prefix[0]) { + /* and padding[0] */ + //tar.prefix[sizeof(tar.prefix)] = '\0'; - gcc 4.3.0 would complain + tar.padding[0] = '\0'; + file_header->name = concat_path_file(tar.prefix, tar.name); + } else + file_header->name = xstrdup(tar.name); + } + + switch (tar_typeflag) { + case '1': /* hardlink */ + /* we mark hardlinks as regular files with zero size and a link name */ + file_header->mode |= S_IFREG; + /* on size of link fields from star(4) + * ... For tar archives written by pre POSIX.1-1988 + * implementations, the size field usually contains the size of + * the file and needs to be ignored as no data may follow this + * header type. For POSIX.1-1988 compliant archives, the size + * field needs to be 0. For POSIX.1-2001 compliant archives, + * the size field may be non zero, indicating that file data is + * included in the archive. + * i.e; always assume this is zero for safety. + */ + goto size0; + case '7': + /* case 0: */ + case '0': +#if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY + if (file_header->name && last_char_is(file_header->name, '/')) { + goto set_dir; + } +#endif + file_header->mode |= S_IFREG; + break; + case '2': + file_header->mode |= S_IFLNK; + /* have seen tarballs with size field containing + * the size of the link target's name */ + size0: + file_header->size = 0; + break; + case '3': + file_header->mode |= S_IFCHR; + goto size0; /* paranoia */ + case '4': + file_header->mode |= S_IFBLK; + goto size0; + case '5': + IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:) + file_header->mode |= S_IFDIR; + goto size0; + case '6': + file_header->mode |= S_IFIFO; + goto size0; + case 'g': /* pax global header */ + case 'x': { /* pax extended header */ + if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ + goto skip_ext_hdr; + process_pax_hdr(archive_handle, file_header->size, (tar_typeflag == 'g')); + goto again_after_align; +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +/* See http://www.gnu.org/software/tar/manual/html_node/Extensions.html */ + case 'L': + /* free: paranoia: tar with several consecutive longnames */ + free(p_longname); + /* For paranoia reasons we allocate extra NUL char */ + die_if_bad_fnamesize(file_header->size); + p_longname = xzalloc(file_header->size + 1); + /* We read ASCIZ string, including NUL */ + xread(archive_handle->src_fd, p_longname, file_header->size); + archive_handle->offset += file_header->size; + /* return get_header_tar(archive_handle); */ + /* gcc 4.1.1 didn't optimize it into jump */ + /* so we will do it ourself, this also saves stack */ + goto again; + case 'K': + free(p_linkname); + die_if_bad_fnamesize(file_header->size); + p_linkname = xzalloc(file_header->size + 1); + xread(archive_handle->src_fd, p_linkname, file_header->size); + archive_handle->offset += file_header->size; + /* return get_header_tar(archive_handle); */ + goto again; +/* + * case 'S': // Sparse file + * Was seen in the wild. Not supported (yet?). + * See https://www.gnu.org/software/tar/manual/html_section/tar_92.html + * for the format. (An "Old GNU Format" was seen, not PAX formats). + */ +// case 'D': /* GNU dump dir */ +// case 'M': /* Continuation of multi volume archive */ +// case 'N': /* Old GNU for names > 100 characters */ + case 'V': /* Volume header */ + ; /* Fall through to skip it */ +#endif + } + skip_ext_hdr: + { + off_t sz; + bb_error_msg("warning: skipping header '%c'", tar_typeflag); + sz = (file_header->size + 511) & ~(off_t)511; + archive_handle->offset += sz; + sz >>= 9; /* sz /= 512 but w/o contortions for signed div */ + while (sz--) + xread(archive_handle->src_fd, &tar, 512); + /* return get_header_tar(archive_handle); */ + goto again_after_align; + } + default: + bb_error_msg_and_die("unknown typeflag: 0x%x", tar_typeflag); + } + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (p_longname) { + file_header->name = p_longname; + p_longname = NULL; + } + if (p_linkname) { + file_header->link_target = p_linkname; + p_linkname = NULL; + } +#endif + + /* Everything up to and including last ".." component is stripped */ + overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name)); +//TODO: do the same for file_header->link_target? + + /* Strip trailing '/' in directories */ + /* Must be done after mode is set as '/' is used to check if it's a directory */ + cp = last_char_is(file_header->name, '/'); + + if (archive_handle->filter(archive_handle) == EXIT_SUCCESS) { + archive_handle->action_header(/*archive_handle->*/ file_header); + /* Note that we kill the '/' only after action_header() */ + /* (like GNU tar 1.15.1: verbose mode outputs "dir/dir/") */ + if (cp) + *cp = '\0'; + archive_handle->action_data(archive_handle); + if (archive_handle->accept || archive_handle->reject + || (archive_handle->ah_flags & ARCHIVE_REMEMBER_NAMES) + ) { + llist_add_to(&archive_handle->passed, file_header->name); + } else /* Caller isn't interested in list of unpacked files */ + free(file_header->name); + } else { + data_skip(archive_handle); + free(file_header->name); + } + archive_handle->offset += file_header->size; + + free(file_header->link_target); + /* Do not free(file_header->name)! + * It might be inserted in archive_handle->passed - see above */ +#if ENABLE_FEATURE_TAR_UNAME_GNAME + free(file_header->tar__uname); + free(file_header->tar__gname); +#endif + return EXIT_SUCCESS; /* "decoded one header" */ +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_tar_bz2.c b/busybox-1_37_0/archival/libarchive/get_header_tar_bz2.c new file mode 100644 index 000000000..c021720ac --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_tar_bz2.c @@ -0,0 +1,20 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +char FAST_FUNC get_header_tar_bz2(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + fork_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_tar_gz.c b/busybox-1_37_0/archival/libarchive/get_header_tar_gz.c new file mode 100644 index 000000000..793b161a1 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_tar_gz.c @@ -0,0 +1,20 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + fork_transformer_with_sig(archive_handle->src_fd, unpack_gz_stream, "gunzip"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_tar_lzma.c b/busybox-1_37_0/archival/libarchive/get_header_tar_lzma.c new file mode 100644 index 000000000..15d10adb8 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_tar_lzma.c @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: */ +/* + * Small lzma deflate implementation. + * Copyright (C) 2006 Aurelien Jacobs + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +char FAST_FUNC get_header_tar_lzma(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + fork_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/get_header_tar_xz.c b/busybox-1_37_0/archival/libarchive/get_header_tar_xz.c new file mode 100644 index 000000000..852c989ce --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/get_header_tar_xz.c @@ -0,0 +1,20 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +char FAST_FUNC get_header_tar_xz(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + fork_transformer_with_sig(archive_handle->src_fd, unpack_xz_stream, "unxz"); + archive_handle->offset = 0; + while (get_header_tar(archive_handle) == EXIT_SUCCESS) + continue; + + /* Can only do one file at a time */ + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/archival/libarchive/header_list.c b/busybox-1_37_0/archival/libarchive/header_list.c new file mode 100644 index 000000000..0621aa406 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/header_list.c @@ -0,0 +1,12 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC header_list(const file_header_t *file_header) +{ +//TODO: cpio -vp DIR should output "DIR/NAME", not just "NAME" */ + puts(file_header->name); +} diff --git a/busybox-1_37_0/archival/libarchive/header_skip.c b/busybox-1_37_0/archival/libarchive/header_skip.c new file mode 100644 index 000000000..f5987bfe2 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/header_skip.c @@ -0,0 +1,10 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) +{ +} diff --git a/busybox-1_37_0/archival/libarchive/header_verbose_list.c b/busybox-1_37_0/archival/libarchive/header_verbose_list.c new file mode 100644 index 000000000..a575a08a0 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/header_verbose_list.c @@ -0,0 +1,69 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC header_verbose_list(const file_header_t *file_header) +{ + struct tm tm_time; + struct tm *ptm = &tm_time; //localtime(&file_header->mtime); + char modestr[12]; + +#if ENABLE_FEATURE_TAR_UNAME_GNAME + char uid[sizeof(int)*3 + 2]; + /*char gid[sizeof(int)*3 + 2];*/ + char *user; + char *group; + + localtime_r(&file_header->mtime, ptm); + + user = file_header->tar__uname; + if (user == NULL) { + sprintf(uid, "%u", (unsigned)file_header->uid); + user = uid; + } + group = file_header->tar__gname; + if (group == NULL) { + /*sprintf(gid, "%u", (unsigned)file_header->gid);*/ + group = utoa(file_header->gid); + } + printf("%s %s/%s %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + bb_mode_string(modestr, file_header->mode), + user, + group, + file_header->size, + 1900 + ptm->tm_year, + 1 + ptm->tm_mon, + ptm->tm_mday, + ptm->tm_hour, + ptm->tm_min, + ptm->tm_sec, + file_header->name); + +#else /* !FEATURE_TAR_UNAME_GNAME */ + + localtime_r(&file_header->mtime, ptm); + + printf("%s %u/%u %9"OFF_FMT"u %4u-%02u-%02u %02u:%02u:%02u %s", + bb_mode_string(modestr, file_header->mode), + (unsigned)file_header->uid, + (unsigned)file_header->gid, + file_header->size, + 1900 + ptm->tm_year, + 1 + ptm->tm_mon, + ptm->tm_mday, + ptm->tm_hour, + ptm->tm_min, + ptm->tm_sec, + file_header->name); + +#endif /* FEATURE_TAR_UNAME_GNAME */ + + /* NB: GNU tar shows "->" for symlinks and "link to" for hardlinks */ + if (file_header->link_target) { + printf(" -> %s", file_header->link_target); + } + bb_putchar('\n'); +} diff --git a/busybox-1_37_0/archival/libarchive/init_handle.c b/busybox-1_37_0/archival/libarchive/init_handle.c new file mode 100644 index 000000000..4c64dac58 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/init_handle.c @@ -0,0 +1,25 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +archive_handle_t* FAST_FUNC init_handle(void) +{ + archive_handle_t *archive_handle; + + /* Initialize default values */ + archive_handle = xzalloc(sizeof(archive_handle_t)); + archive_handle->file_header = xzalloc(sizeof(file_header_t)); + archive_handle->action_header = header_skip; + archive_handle->action_data = data_skip; + archive_handle->filter = filter_accept_all; + archive_handle->seek = seek_by_jump; +#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM + archive_handle->cpio__owner.uid = (uid_t)-1L; + archive_handle->cpio__owner.gid = (gid_t)-1L; +#endif + + return archive_handle; +} diff --git a/busybox-1_37_0/archival/libarchive/liblzo.h b/busybox-1_37_0/archival/libarchive/liblzo.h new file mode 100644 index 000000000..4596620fe --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/liblzo.h @@ -0,0 +1,95 @@ +/* + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "liblzo_interface.h" + +/* lzo-2.03/src/config1x.h */ +#define M2_MIN_LEN 3 +#define M2_MAX_LEN 8 +#define M3_MAX_LEN 33 +#define M4_MAX_LEN 9 +#define M1_MAX_OFFSET 0x0400 +#define M2_MAX_OFFSET 0x0800 +#define M3_MAX_OFFSET 0x4000 +#define M4_MAX_OFFSET 0xbfff +#define M1_MARKER 0 +#define M3_MARKER 32 +#define M4_MARKER 16 + +#define MX_MAX_OFFSET (M1_MAX_OFFSET + M2_MAX_OFFSET) +#define MIN_LOOKAHEAD (M2_MAX_LEN + 1) + +#define LZO_EOF_CODE + +/* lzo-2.03/src/lzo_dict.h */ +#define GINDEX(m_pos,m_off,dict,dindex,in) m_pos = dict[dindex] +#define DX2(p,s1,s2) \ + (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0]) +//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0]) +//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0]) +#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0]) + +#define D_SIZE (1U << D_BITS) +#define D_MASK ((1U << D_BITS) - 1) +#define D_HIGH ((D_MASK >> 1) + 1) + +#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \ + ( \ + m_pos = ip - (unsigned)(ip - m_pos), \ + ((uintptr_t)m_pos < (uintptr_t)in \ + || (m_off = (unsigned)(ip - m_pos)) <= 0 \ + || m_off > max_offset) \ + ) + +#define DENTRY(p,in) (p) +#define UPDATE_I(dict,drun,index,p,in) dict[index] = DENTRY(p,in) + +#define DMS(v,s) ((unsigned) (((v) & (D_MASK >> (s))) << (s))) +#define DM(v) ((unsigned) ((v) & D_MASK)) +#define DMUL(a,b) ((unsigned) ((a) * (b))) + +/* lzo-2.03/src/lzo_ptr.h */ +#define pd(a,b) ((unsigned)((a)-(b))) + +# define TEST_IP (ip < ip_end) +# define NEED_IP(x) \ + if ((unsigned)(ip_end - ip) < (unsigned)(x)) goto input_overrun +# define TEST_IV(x) if ((x) > (unsigned)0 - (511)) goto input_overrun + +# undef TEST_OP /* don't need both of the tests here */ +# define TEST_OP 1 +# define NEED_OP(x) \ + if ((unsigned)(op_end - op) < (unsigned)(x)) goto output_overrun +# define TEST_OV(x) if ((x) > (unsigned)0 - (511)) goto output_overrun + +#define HAVE_ANY_OP 1 + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) +# define TEST_LB(m_pos) if (m_pos < out || m_pos >= op) goto lookbehind_overrun +//# define TEST_LBO(m_pos,o) if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun +//#else +//# define TEST_LB(m_pos) ((void) 0) +//# define TEST_LBO(m_pos,o) ((void) 0) +//#endif diff --git a/busybox-1_37_0/archival/libarchive/lzo1x_1.c b/busybox-1_37_0/archival/libarchive/lzo1x_1.c new file mode 100644 index 000000000..a88839846 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/lzo1x_1.c @@ -0,0 +1,35 @@ +/* LZO1X-1 compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 14 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_compress + +#include "lzo1x_c.c" diff --git a/busybox-1_37_0/archival/libarchive/lzo1x_1o.c b/busybox-1_37_0/archival/libarchive/lzo1x_1o.c new file mode 100644 index 000000000..3c61253e0 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/lzo1x_1o.c @@ -0,0 +1,35 @@ +/* LZO1X-1(15) compression + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +#define D_BITS 15 +#define D_INDEX1(d,p) d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5) +#define D_INDEX2(d,p) d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f) + +#define DO_COMPRESS lzo1x_1_15_compress + +#include "lzo1x_c.c" diff --git a/busybox-1_37_0/archival/libarchive/lzo1x_9x.c b/busybox-1_37_0/archival/libarchive/lzo1x_9x.c new file mode 100644 index 000000000..df26b375f --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/lzo1x_9x.c @@ -0,0 +1,919 @@ +/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer + Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + + Markus F.X.J. Oberhumer + + http://www.oberhumer.com/opensource/lzo/ +*/ +#include "libbb.h" + +/* The following is probably only safe on Intel-compatible processors ... */ +#define LZO_UNALIGNED_OK_2 +#define LZO_UNALIGNED_OK_4 + +#include "liblzo.h" + +#define LZO_MAX(a,b) ((a) >= (b) ? (a) : (b)) +#define LZO_MIN(a,b) ((a) <= (b) ? (a) : (b)) +#define LZO_MAX3(a,b,c) ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c)) + +/*********************************************************************** +// +************************************************************************/ +#define SWD_N M4_MAX_OFFSET /* size of ring buffer */ +#define SWD_F 2048 /* upper limit for match length */ + +#define SWD_BEST_OFF (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1) + +typedef struct { + int init; + + unsigned look; /* bytes in lookahead buffer */ + + unsigned m_len; + unsigned m_off; + + const uint8_t *bp; + const uint8_t *ip; + const uint8_t *in; + const uint8_t *in_end; + uint8_t *out; + + unsigned r1_lit; +} lzo1x_999_t; + +#define getbyte(c) ((c).ip < (c).in_end ? *((c).ip)++ : (-1)) + +/* lzo_swd.c -- sliding window dictionary */ + +/*********************************************************************** +// +************************************************************************/ +#define SWD_UINT_MAX USHRT_MAX + +#ifndef SWD_HSIZE +# define SWD_HSIZE 16384 +#endif +#ifndef SWD_MAX_CHAIN +# define SWD_MAX_CHAIN 2048 +#endif + +#define HEAD3(b, p) \ + ( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) ) + +#if defined(LZO_UNALIGNED_OK_2) +# define HEAD2(b,p) (* (bb__aliased_uint16_t *) &(b[p])) +#else +# define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) +#endif +#define NIL2 SWD_UINT_MAX + +typedef struct lzo_swd { + /* public - "built-in" */ + + /* public - configuration */ + unsigned max_chain; + int use_best_off; + + /* public - output */ + unsigned m_len; + unsigned m_off; + unsigned look; + int b_char; +#if defined(SWD_BEST_OFF) + unsigned best_off[SWD_BEST_OFF]; +#endif + + /* semi public */ + lzo1x_999_t *c; + unsigned m_pos; +#if defined(SWD_BEST_OFF) + unsigned best_pos[SWD_BEST_OFF]; +#endif + + /* private */ + unsigned ip; /* input pointer (lookahead) */ + unsigned bp; /* buffer pointer */ + unsigned rp; /* remove pointer */ + + unsigned node_count; + unsigned first_rp; + + uint8_t b[SWD_N + SWD_F]; + uint8_t b_wrap[SWD_F]; /* must follow b */ + uint16_t head3[SWD_HSIZE]; + uint16_t succ3[SWD_N + SWD_F]; + uint16_t best3[SWD_N + SWD_F]; + uint16_t llen3[SWD_HSIZE]; +#ifdef HEAD2 + uint16_t head2[65536L]; +#endif +} lzo_swd_t, *lzo_swd_p; + +#define SIZEOF_LZO_SWD_T (sizeof(lzo_swd_t)) + + +/* Access macro for head3. + * head3[key] may be uninitialized, but then its value will never be used. + */ +#define s_get_head3(s,key) s->head3[key] + + +/*********************************************************************** +// +************************************************************************/ +#define B_SIZE (SWD_N + SWD_F) + +static int swd_init(lzo_swd_p s) +{ + /* defaults */ + s->node_count = SWD_N; + + memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE); +#ifdef HEAD2 + memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L); + assert(s->head2[0] == NIL2); +#endif + + s->ip = 0; + s->bp = s->ip; + s->first_rp = s->ip; + + assert(s->ip + SWD_F <= B_SIZE); + s->look = (unsigned) (s->c->in_end - s->c->ip); + if (s->look > 0) { + if (s->look > SWD_F) + s->look = SWD_F; + memcpy(&s->b[s->ip], s->c->ip, s->look); + s->c->ip += s->look; + s->ip += s->look; + } + if (s->ip == B_SIZE) + s->ip = 0; + + s->rp = s->first_rp; + if (s->rp >= s->node_count) + s->rp -= s->node_count; + else + s->rp += B_SIZE - s->node_count; + + return LZO_E_OK; +} + +#define swd_pos2off(s,pos) \ + (s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp)) + + +/*********************************************************************** +// +************************************************************************/ +static void swd_getbyte(lzo_swd_p s) +{ + int c; + + if ((c = getbyte(*(s->c))) < 0) { + if (s->look > 0) + --s->look; + } else { + s->b[s->ip] = c; + if (s->ip < SWD_F) + s->b_wrap[s->ip] = c; + } + if (++s->ip == B_SIZE) + s->ip = 0; + if (++s->bp == B_SIZE) + s->bp = 0; + if (++s->rp == B_SIZE) + s->rp = 0; +} + + +/*********************************************************************** +// remove node from lists +************************************************************************/ +static void swd_remove_node(lzo_swd_p s, unsigned node) +{ + if (s->node_count == 0) { + unsigned key; + + key = HEAD3(s->b,node); + assert(s->llen3[key] > 0); + --s->llen3[key]; + +#ifdef HEAD2 + key = HEAD2(s->b,node); + assert(s->head2[key] != NIL2); + if ((unsigned) s->head2[key] == node) + s->head2[key] = NIL2; +#endif + } else + --s->node_count; +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_accept(lzo_swd_p s, unsigned n) +{ + assert(n <= s->look); + + while (n--) { + unsigned key; + + swd_remove_node(s,s->rp); + + /* add bp into HEAD3 */ + key = HEAD3(s->b, s->bp); + s->succ3[s->bp] = s_get_head3(s, key); + s->head3[key] = s->bp; + s->best3[s->bp] = SWD_F + 1; + s->llen3[key]++; + assert(s->llen3[key] <= SWD_N); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif + + swd_getbyte(s); + } +} + + +/*********************************************************************** +// +************************************************************************/ +static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt) +{ + const uint8_t *p1; + const uint8_t *p2; + const uint8_t *px; + unsigned m_len = s->m_len; + const uint8_t *b = s->b; + const uint8_t *bp = s->b + s->bp; + const uint8_t *bx = s->b + s->bp + s->look; + unsigned char scan_end1; + + assert(s->m_len > 0); + + scan_end1 = bp[m_len - 1]; + for ( ; cnt-- > 0; node = s->succ3[node]) { + p1 = bp; + p2 = b + node; + px = bx; + + assert(m_len < s->look); + + if (p2[m_len - 1] == scan_end1 + && p2[m_len] == p1[m_len] + && p2[0] == p1[0] + && p2[1] == p1[1] + ) { + unsigned i; + assert(lzo_memcmp(bp, &b[node], 3) == 0); + + p1 += 2; p2 += 2; + do {} while (++p1 < px && *p1 == *++p2); + i = p1-bp; + + assert(lzo_memcmp(bp, &b[node], i) == 0); + +#if defined(SWD_BEST_OFF) + if (i < SWD_BEST_OFF) { + if (s->best_pos[i] == 0) + s->best_pos[i] = node + 1; + } +#endif + if (i > m_len) { + s->m_len = m_len = i; + s->m_pos = node; + if (m_len == s->look) + return; + if (m_len >= SWD_F) + return; + if (m_len > (unsigned) s->best3[node]) + return; + scan_end1 = bp[m_len - 1]; + } + } + } +} + + +/*********************************************************************** +// +************************************************************************/ +#ifdef HEAD2 + +static int swd_search2(lzo_swd_p s) +{ + unsigned key; + + assert(s->look >= 2); + assert(s->m_len > 0); + + key = s->head2[HEAD2(s->b, s->bp)]; + if (key == NIL2) + return 0; + assert(lzo_memcmp(&s->b[s->bp], &s->b[key], 2) == 0); +#if defined(SWD_BEST_OFF) + if (s->best_pos[2] == 0) + s->best_pos[2] = key + 1; +#endif + + if (s->m_len < 2) { + s->m_len = 2; + s->m_pos = key; + } + return 1; +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static void swd_findbest(lzo_swd_p s) +{ + unsigned key; + unsigned cnt, node; + unsigned len; + + assert(s->m_len > 0); + + /* get current head, add bp into HEAD3 */ + key = HEAD3(s->b,s->bp); + node = s->succ3[s->bp] = s_get_head3(s, key); + cnt = s->llen3[key]++; + assert(s->llen3[key] <= SWD_N + SWD_F); + if (cnt > s->max_chain) + cnt = s->max_chain; + s->head3[key] = s->bp; + + s->b_char = s->b[s->bp]; + len = s->m_len; + if (s->m_len >= s->look) { + if (s->look == 0) + s->b_char = -1; + s->m_off = 0; + s->best3[s->bp] = SWD_F + 1; + } else { +#ifdef HEAD2 + if (swd_search2(s)) +#endif + if (s->look >= 3) + swd_search(s, node, cnt); + if (s->m_len > len) + s->m_off = swd_pos2off(s,s->m_pos); + s->best3[s->bp] = s->m_len; + +#if defined(SWD_BEST_OFF) + if (s->use_best_off) { + int i; + for (i = 2; i < SWD_BEST_OFF; i++) { + if (s->best_pos[i] > 0) + s->best_off[i] = swd_pos2off(s, s->best_pos[i]-1); + else + s->best_off[i] = 0; + } + } +#endif + } + + swd_remove_node(s,s->rp); + +#ifdef HEAD2 + /* add bp into HEAD2 */ + key = HEAD2(s->b, s->bp); + s->head2[key] = s->bp; +#endif +} + +#undef HEAD3 +#undef HEAD2 +#undef s_get_head3 + + +/*********************************************************************** +// +************************************************************************/ +static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off) +{ + int r; + + assert(!c->init); + c->init = 1; + + s->c = c; + + r = swd_init(s); + if (r != 0) + return r; + + s->use_best_off = use_best_off; + return r; +} + + +/*********************************************************************** +// +************************************************************************/ +static int find_match(lzo1x_999_t *c, lzo_swd_p s, + unsigned this_len, unsigned skip) +{ + assert(c->init); + + if (skip > 0) { + assert(this_len >= skip); + swd_accept(s, this_len - skip); + } else { + assert(this_len <= 1); + } + + s->m_len = 1; +#ifdef SWD_BEST_OFF + if (s->use_best_off) + memset(s->best_pos, 0, sizeof(s->best_pos)); +#endif + swd_findbest(s); + c->m_len = s->m_len; + c->m_off = s->m_off; + + swd_getbyte(s); + + if (s->b_char < 0) { + c->look = 0; + c->m_len = 0; + } else { + c->look = s->look + 1; + } + c->bp = c->ip - c->look; + + return LZO_E_OK; +} + +/* this is a public functions, but there is no prototype in a header file */ +static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off); + + +/*********************************************************************** +// +************************************************************************/ +static uint8_t *code_match(lzo1x_999_t *c, + uint8_t *op, unsigned m_len, unsigned m_off) +{ + assert(op > c->out); + if (m_len == 2) { + assert(m_off <= M1_MAX_OFFSET); + assert(c->r1_lit > 0); + assert(c->r1_lit < 4); + m_off -= 1; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + *op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2); + *op++ = m_off >> 3; + assert(op[-2] >= M2_MARKER); + } else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) { + assert(m_len == 3); + assert(m_off > M2_MAX_OFFSET); + m_off -= 1 + M2_MAX_OFFSET; + *op++ = M1_MARKER | ((m_off & 3) << 2); + *op++ = m_off >> 2; + } else if (m_off <= M3_MAX_OFFSET) { + assert(m_len >= 3); + m_off -= 1; + if (m_len <= M3_MAX_LEN) + *op++ = M3_MARKER | (m_len - 2); + else { + m_len -= M3_MAX_LEN; + *op++ = M3_MARKER | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } else { + unsigned k; + + assert(m_len >= 3); + assert(m_off > 0x4000); + assert(m_off <= 0xbfff); + m_off -= 0x4000; + k = (m_off & 0x4000) >> 11; + if (m_len <= M4_MAX_LEN) + *op++ = M4_MARKER | k | (m_len - 2); + else { + m_len -= M4_MAX_LEN; + *op++ = M4_MARKER | k | 0; + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = m_len; + } + *op++ = m_off << 2; + *op++ = m_off >> 6; + } + + return op; +} + + +static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op, + const uint8_t *ii, unsigned t) +{ + if (op == c->out && t <= 238) { + *op++ = 17 + t; + } else if (t <= 3) { + op[-2] |= t; + } else if (t <= 18) { + *op++ = t - 3; + } else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = tt; + } + do *op++ = *ii++; while (--t > 0); + + return op; +} + + +static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii, + unsigned lit) +{ + if (lit > 0) { + assert(m_len >= 2); + op = STORE_RUN(c, op, ii, lit); + } else { + assert(m_len >= 3); + } + c->r1_lit = lit; + + return op; +} + + +/*********************************************************************** +// +************************************************************************/ +static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) +{ + int n = 4; + + if (m_len < 2) + return -1; + if (m_len == 2) + return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1; + if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) + return 2; + if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4) + return 2; + if (m_off <= M3_MAX_OFFSET) { + if (m_len <= M3_MAX_LEN) + return 3; + m_len -= M3_MAX_LEN; + } else if (m_off <= M4_MAX_OFFSET) { + if (m_len <= M4_MAX_LEN) + return 3; + m_len -= M4_MAX_LEN; + } else + return -1; + while (m_len > 255) { + m_len -= 255; + n++; + } + return n; +} + + +static int min_gain(unsigned ahead, unsigned lit1, + unsigned lit2, int l1, int l2, int l3) +{ + int lazy_match_min_gain = 0; + + assert (ahead >= 1); + lazy_match_min_gain += ahead; + + if (lit1 <= 3) + lazy_match_min_gain += (lit2 <= 3) ? 0 : 2; + else if (lit1 <= 18) + lazy_match_min_gain += (lit2 <= 18) ? 0 : 1; + + lazy_match_min_gain += (l2 - l1) * 2; + if (l3 > 0) + lazy_match_min_gain -= (ahead - l3) * 2; + + if (lazy_match_min_gain < 0) + lazy_match_min_gain = 0; + + return lazy_match_min_gain; +} + + +/*********************************************************************** +// +************************************************************************/ +#if defined(SWD_BEST_OFF) + +static void better_match(const lzo_swd_p swd, + unsigned *m_len, unsigned *m_off) +{ + if (*m_len <= M2_MIN_LEN) + return; + + if (*m_off <= M2_MAX_OFFSET) + return; + + /* M3/M4 -> M2 */ + if (*m_off > M2_MAX_OFFSET + && *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + return; + } + + /* M4 -> M2 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 + && swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET + ) { + *m_len = *m_len - 2; + *m_off = swd->best_off[*m_len]; + return; + } + /* M4 -> M3 */ + if (*m_off > M3_MAX_OFFSET + && *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 + && swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET + ) { + *m_len = *m_len - 1; + *m_off = swd->best_off[*m_len]; + } +} + +#endif + + +/*********************************************************************** +// +************************************************************************/ +static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + unsigned good_length, + unsigned max_lazy, + unsigned max_chain, + uint32_t use_best_off) +{ + uint8_t *op; + const uint8_t *ii; + unsigned lit; + unsigned m_len, m_off; + lzo1x_999_t cc; + lzo1x_999_t *const c = &cc; + const lzo_swd_p swd = (lzo_swd_p) wrkmem; + int r; + + c->init = 0; + c->ip = c->in = in; + c->in_end = in + in_len; + c->out = out; + + op = out; + ii = c->ip; /* point to start of literal run */ + lit = 0; + c->r1_lit = 0; + + r = init_match(c, swd, use_best_off); + if (r != 0) + return r; + swd->max_chain = max_chain; + + r = find_match(c, swd, 0, 0); + if (r != 0) + return r; + + while (c->look > 0) { + unsigned ahead; + unsigned max_ahead; + int l1, l2, l3; + + m_len = c->m_len; + m_off = c->m_off; + + assert(c->bp == c->ip - c->look); + assert(c->bp >= in); + if (lit == 0) + ii = c->bp; + assert(ii + lit == c->bp); + assert(swd->b_char == *(c->bp)); + + if (m_len < 2 + || (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) + /* Do not accept this match for compressed-data compatibility + * with LZO v1.01 and before + * [ might be a problem for decompress() and optimize() ] + */ + || (m_len == 2 && op == out) + || (op == out && lit == 0) + ) { + /* a literal */ + m_len = 0; + } + else if (m_len == M2_MIN_LEN) { + /* compression ratio improves if we code a literal in some cases */ + if (m_off > MX_MAX_OFFSET && lit >= 4) + m_len = 0; + } + + if (m_len == 0) { + /* a literal */ + lit++; + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + assert(r == 0); + continue; + } + + /* a match */ +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &m_len, &m_off); +#endif + + /* shall we try a lazy match ? */ + ahead = 0; + if (m_len >= max_lazy) { + /* no */ + l1 = 0; + max_ahead = 0; + } else { + /* yes, try a lazy match */ + l1 = len_of_coded_match(m_len, m_off, lit); + assert(l1 > 0); + max_ahead = LZO_MIN(2, (unsigned)l1 - 1); + } + + + while (ahead < max_ahead && c->look > m_len) { + int lazy_match_min_gain; + + if (m_len >= good_length) + swd->max_chain = max_chain >> 2; + else + swd->max_chain = max_chain; + r = find_match(c, swd, 1, 0); + ahead++; + + assert(r == 0); + assert(c->look > 0); + assert(ii + lit + ahead == c->bp); + + if (c->m_len < m_len) + continue; + if (c->m_len == m_len && c->m_off >= m_off) + continue; +#if defined(SWD_BEST_OFF) + if (swd->use_best_off) + better_match(swd, &c->m_len, &c->m_off); +#endif + l2 = len_of_coded_match(c->m_len, c->m_off, lit+ahead); + if (l2 < 0) + continue; + + /* compressed-data compatibility [see above] */ + l3 = (op == out) ? -1 : len_of_coded_match(ahead, m_off, lit); + + lazy_match_min_gain = min_gain(ahead, lit, lit+ahead, l1, l2, l3); + if (c->m_len >= m_len + lazy_match_min_gain) { + if (l3 > 0) { + /* code previous run */ + op = code_run(c, op, ii, lit); + lit = 0; + /* code shortened match */ + op = code_match(c, op, ahead, m_off); + } else { + lit += ahead; + assert(ii + lit == c->bp); + } + goto lazy_match_done; + } + } + + assert(ii + lit + ahead == c->bp); + + /* 1 - code run */ + op = code_run(c, op, ii, lit); + lit = 0; + + /* 2 - code match */ + op = code_match(c, op, m_len, m_off); + swd->max_chain = max_chain; + r = find_match(c, swd, m_len, 1+ahead); + assert(r == 0); + + lazy_match_done: ; + } + + /* store final run */ + if (lit > 0) + op = STORE_RUN(c, op, ii, lit); + +#if defined(LZO_EOF_CODE) + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; +#endif + + *out_len = op - out; + + return LZO_E_OK; +} + + +/*********************************************************************** +// +************************************************************************/ +int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len, + void *wrkmem, + int compression_level) +{ + static const struct { + uint16_t good_length; + uint16_t max_lazy; + uint16_t max_chain; + uint16_t use_best_off; + } c[3] = { + { 8, 32, 256, 0 }, + { 32, 128, 2048, 1 }, + { SWD_F, SWD_F, 4096, 1 } /* max. compression */ + }; + + if (compression_level < 7 || compression_level > 9) + return LZO_E_ERROR; + + compression_level -= 7; + return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem, + c[compression_level].good_length, + c[compression_level].max_lazy, + c[compression_level].max_chain, + c[compression_level].use_best_off); +} diff --git a/busybox-1_37_0/archival/libarchive/lzo1x_c.c b/busybox-1_37_0/archival/libarchive/lzo1x_c.c new file mode 100644 index 000000000..8c77072ab --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/lzo1x_c.c @@ -0,0 +1,296 @@ +/* implementation of the LZO1[XY]-1 compression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +/*********************************************************************** +// compress a block of data. +************************************************************************/ +static NOINLINE unsigned +do_compress(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + register const uint8_t* ip; + uint8_t* op; + const uint8_t* const in_end = in + in_len; + const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5; + const uint8_t* ii; + const void* *const dict = (const void**) wrkmem; + + op = out; + ip = in; + ii = ip; + + ip += 4; + for (;;) { + register const uint8_t* m_pos; + unsigned m_off; + unsigned m_len; + unsigned dindex; + + D_INDEX1(dindex,ip); + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; +#if 1 + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + D_INDEX2(dindex,ip); +#endif + GINDEX(m_pos,m_off,dict,dindex,in); + if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET)) + goto literal; + if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3]) + goto try_match; + goto literal; + + try_match: +#if 1 && defined(LZO_UNALIGNED_OK_2) + if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip) +#else + if (m_pos[0] != ip[0] || m_pos[1] != ip[1]) +#endif + { + } else { + if (m_pos[2] == ip[2]) { +#if 0 + if (m_off <= M2_MAX_OFFSET) + goto match; + if (lit <= 3) + goto match; + if (lit == 3) { /* better compression, but slower */ + assert(op - 2 > out); op[-2] |= (uint8_t)(3); + *op++ = *ii++; *op++ = *ii++; *op++ = *ii++; + goto code_match; + } + if (m_pos[3] == ip[3]) +#endif + goto match; + } + else { + /* still need a better way for finding M1 matches */ +#if 0 + /* a M1 match */ +#if 0 + if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3) +#else + if (m_off <= M1_MAX_OFFSET && lit == 3) +#endif + { + register unsigned t; + + t = lit; + assert(op - 2 > out); op[-2] |= (uint8_t)(t); + do *op++ = *ii++; while (--t > 0); + assert(ii == ip); + m_off -= 1; + *op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); + ip += 2; + goto match_done; + } +#endif + } + } + + /* a literal */ + literal: + UPDATE_I(dict, 0, dindex, ip, in); + ++ip; + if (ip >= ip_end) + break; + continue; + + /* a match */ +match: + UPDATE_I(dict, 0, dindex, ip, in); + /* store current literal run */ + if (pd(ip, ii) > 0) { + register unsigned t = pd(ip, ii); + + if (t <= 3) { + assert(op - 2 > out); + op[-2] |= (uint8_t)(t); + } + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + register unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + /* code the match */ + assert(ii == ip); + ip += 3; + if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++ + || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++ +#ifdef LZO1Y + || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++ + || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++ +#endif + ) { + --ip; + m_len = pd(ip, ii); + assert(m_len >= 3); + assert(m_len <= M2_MAX_LEN); + + if (m_off <= M2_MAX_OFFSET) { + m_off -= 1; +#if defined(LZO1X) + *op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2)); + *op++ = (uint8_t)(m_off >> 3); +#elif defined(LZO1Y) + *op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2)); + *op++ = (uint8_t)(m_off >> 2); +#endif + } + else if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + goto m3_m4_offset; + } else { +#if defined(LZO1X) + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + goto m3_m4_offset; +#elif defined(LZO1Y) + goto m4_match; +#endif + } + } + else { + { + const uint8_t* end = in_end; + const uint8_t* m = m_pos + M2_MAX_LEN + 1; + while (ip < end && *m == *ip) + m++, ip++; + m_len = pd(ip, ii); + } + assert(m_len > M2_MAX_LEN); + + if (m_off <= M3_MAX_OFFSET) { + m_off -= 1; + if (m_len <= 33) + *op++ = (uint8_t)(M3_MARKER | (m_len - 2)); + else { + m_len -= 33; + *op++ = M3_MARKER | 0; + goto m3_m4_len; + } + } else { +#if defined(LZO1Y) + m4_match: +#endif + m_off -= 0x4000; + assert(m_off > 0); + assert(m_off <= 0x7fff); + if (m_len <= M4_MAX_LEN) + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2)); + else { + m_len -= M4_MAX_LEN; + *op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11)); + m3_m4_len: + while (m_len > 255) { + m_len -= 255; + *op++ = 0; + } + assert(m_len > 0); + *op++ = (uint8_t)(m_len); + } + } + m3_m4_offset: + *op++ = (uint8_t)((m_off & 63) << 2); + *op++ = (uint8_t)(m_off >> 6); + } +#if 0 + match_done: +#endif + ii = ip; + if (ip >= ip_end) + break; + } + + *out_len = pd(op, out); + return pd(in_end, ii); +} + +/*********************************************************************** +// public entry point +************************************************************************/ +int DO_COMPRESS(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len, + void* wrkmem) +{ + uint8_t* op = out; + unsigned t; + + if (in_len <= M2_MAX_LEN + 5) + t = in_len; + else { + t = do_compress(in,in_len,op,out_len,wrkmem); + op += *out_len; + } + + if (t > 0) { + const uint8_t* ii = in + in_len - t; + + if (op == out && t <= 238) + *op++ = (uint8_t)(17 + t); + else if (t <= 3) + op[-2] |= (uint8_t)(t); + else if (t <= 18) + *op++ = (uint8_t)(t - 3); + else { + unsigned tt = t - 18; + + *op++ = 0; + while (tt > 255) { + tt -= 255; + *op++ = 0; + } + assert(tt > 0); + *op++ = (uint8_t)(tt); + } + do *op++ = *ii++; while (--t > 0); + } + + *op++ = M4_MARKER | 1; + *op++ = 0; + *op++ = 0; + + *out_len = pd(op, out); + return 0; /*LZO_E_OK*/ +} diff --git a/busybox-1_37_0/archival/libarchive/lzo1x_d.c b/busybox-1_37_0/archival/libarchive/lzo1x_d.c new file mode 100644 index 000000000..43cf4a04e --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/lzo1x_d.c @@ -0,0 +1,422 @@ +/* implementation of the LZO1X decompression algorithm + + This file is part of the LZO real-time data compression library. + + Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzo/ + + The LZO library is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + The LZO 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with the LZO library; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +#include "libbb.h" +#include "liblzo.h" + +/*********************************************************************** +// decompress a block of data. +************************************************************************/ +/* safe decompression with overrun testing */ +int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len, + uint8_t* out, unsigned* out_len /*, void* wrkmem */) +{ + register uint8_t* op; + register const uint8_t* ip; + register unsigned t; +#if defined(COPY_DICT) + unsigned m_off; + const uint8_t* dict_end; +#else + register const uint8_t* m_pos = NULL; /* possibly not needed */ +#endif + const uint8_t* const ip_end = in + in_len; +#if defined(HAVE_ANY_OP) + uint8_t* const op_end = out + *out_len; +#endif +#if defined(LZO1Z) + unsigned last_m_off = 0; +#endif + +// LZO_UNUSED(wrkmem); + +#if defined(COPY_DICT) + if (dict) { + if (dict_len > M4_MAX_OFFSET) { + dict += dict_len - M4_MAX_OFFSET; + dict_len = M4_MAX_OFFSET; + } + dict_end = dict + dict_len; + } else { + dict_len = 0; + dict_end = NULL; + } +#endif /* COPY_DICT */ + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) { + t = *ip++ - 17; + if (t < 4) + goto match_next; + assert(t > 0); NEED_OP(t); NEED_IP(t+1); + do *op++ = *ip++; while (--t > 0); + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) { + t = *ip++; + if (t >= 16) + goto match; + /* a literal run */ + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + TEST_IV(t); + t += 15 + *ip++; + } + /* copy literals */ + assert(t > 0); + NEED_OP(t+3); + NEED_IP(t+4); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (PTR_ALIGNED2_4(op, ip)) +# endif + { + COPY4(op, ip); + op += 4; + ip += 4; + if (--t > 0) { + if (t >= 4) { + do { + COPY4(op, ip); + op += 4; + ip += 4; + t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *ip++; while (--t > 0); + } else { + do *op++ = *ip++; while (--t > 0); + } + } + } +# if !defined(LZO_UNALIGNED_OK_4) + else +# endif +#endif +#if !defined(LZO_UNALIGNED_OK_4) + { + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + do *op++ = *ip++; while (--t > 0); + } +#endif + + first_literal_run: + t = *ip++; + if (t >= 16) + goto match; +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(3); + t = 3; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - (1 + M2_MAX_OFFSET); + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(3); + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + + /* handle matches */ + do { + match: + if (t >= 64) { /* a M2 match */ +#if defined(COPY_DICT) +#if defined(LZO1X) + m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3); + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2); + t = (t >> 4) - 3; +#elif defined(LZO1Z) + m_off = t & 0x1f; + if (m_off >= 0x1c) + m_off = last_m_off; + else { + m_off = 1 + (m_off << 6) + (*ip++ >> 2); + last_m_off = m_off; + } + t = (t >> 5) - 1; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1X) + m_pos = op - 1; + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos = op - 1; + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#elif defined(LZO1Z) + { + unsigned off = t & 0x1f; + m_pos = op; + if (off >= 0x1c) { + assert(last_m_off > 0); + m_pos -= last_m_off; + } else { + off = 1 + (off << 6) + (*ip++ >> 2); + m_pos -= off; + last_m_off = off; + } + } + t = (t >> 5) - 1; +#endif + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); + goto copy_match; +#endif /* COPY_DICT */ + } + else if (t >= 32) { /* a M3 match */ + t &= 31; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + TEST_IV(t); + t += 31 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (ip[0] << 6) + (ip[1] >> 2); + last_m_off = m_off; +#else + m_off = 1 + (ip[0] >> 2) + (ip[1] << 6); +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + { + unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2); + m_pos = op - off; + last_m_off = off; + } +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos = op - 1; + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos = op - 1; + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif +#endif /* COPY_DICT */ + ip += 2; + } + else if (t >= 16) { /* a M4 match */ +#if defined(COPY_DICT) + m_off = (t & 8) << 11; +#else /* !COPY_DICT */ + m_pos = op; + m_pos -= (t & 8) << 11; +#endif /* COPY_DICT */ + t &= 7; + if (t == 0) { + NEED_IP(1); + while (*ip == 0) { + t += 255; + ip++; + NEED_IP(1); + } + TEST_IV(t); + t += 7 + *ip++; + } +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off += (ip[0] << 6) + (ip[1] >> 2); +#else + m_off += (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_off == 0) + goto eof_found; + m_off += 0x4000; +#if defined(LZO1Z) + last_m_off = m_off; +#endif +#else /* !COPY_DICT */ +#if defined(LZO1Z) + m_pos -= (ip[0] << 6) + (ip[1] >> 2); +#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN) + m_pos -= (* (const lzo_ushortp) ip) >> 2; +#else + m_pos -= (ip[0] >> 2) + (ip[1] << 6); +#endif + ip += 2; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; +#if defined(LZO1Z) + last_m_off = pd((const uint8_t*)op, m_pos); +#endif +#endif /* COPY_DICT */ + } + else { /* a M1 match */ +#if defined(COPY_DICT) +#if defined(LZO1Z) + m_off = 1 + (t << 6) + (*ip++ >> 2); + last_m_off = m_off; +#else + m_off = 1 + (t >> 2) + (*ip++ << 2); +#endif + NEED_OP(2); + t = 2; COPY_DICT(t,m_off) +#else /* !COPY_DICT */ +#if defined(LZO1Z) + t = 1 + (t << 6) + (*ip++ >> 2); + m_pos = op - t; + last_m_off = t; +#else + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; +#endif + TEST_LB(m_pos); NEED_OP(2); + *op++ = *m_pos++; + *op++ = *m_pos; +#endif /* COPY_DICT */ + goto match_done; + } + + /* copy match */ +#if defined(COPY_DICT) + + NEED_OP(t+3-1); + t += 3-1; COPY_DICT(t,m_off) + +#else /* !COPY_DICT */ + + TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1); +#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4) +# if !defined(LZO_UNALIGNED_OK_4) + if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) { + assert((op - m_pos) >= 4); /* both pointers are aligned */ +# else + if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) { +# endif + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4 - (3 - 1); + do { + COPY4(op,m_pos); + op += 4; m_pos += 4; t -= 4; + } while (t >= 4); + if (t > 0) + do *op++ = *m_pos++; while (--t > 0); + } + else +#endif + { + copy_match: + *op++ = *m_pos++; *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + +#endif /* COPY_DICT */ + + match_done: +#if defined(LZO1Z) + t = ip[-1] & 3; +#else + t = ip[-2] & 3; +#endif + if (t == 0) + break; + + /* copy literals */ + match_next: + assert(t > 0); + assert(t < 4); + NEED_OP(t); + NEED_IP(t+1); +#if 0 + do *op++ = *ip++; while (--t > 0); +#else + *op++ = *ip++; + if (t > 1) { + *op++ = *ip++; + if (t > 2) + *op++ = *ip++; + } +#endif + t = *ip++; + } while (TEST_IP && TEST_OP); + } + +//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP) + /* no EOF code was found */ + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; +//#endif + + eof_found: + assert(t == 1); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); + +//#if defined(HAVE_NEED_IP) + input_overrun: + *out_len = pd(op, out); + return LZO_E_INPUT_OVERRUN; +//#endif + +//#if defined(HAVE_NEED_OP) + output_overrun: + *out_len = pd(op, out); + return LZO_E_OUTPUT_OVERRUN; +//#endif + +//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND) + lookbehind_overrun: + *out_len = pd(op, out); + return LZO_E_LOOKBEHIND_OVERRUN; +//#endif +} diff --git a/busybox-1_37_0/archival/libarchive/open_transformer.c b/busybox-1_37_0/archival/libarchive/open_transformer.c new file mode 100644 index 000000000..44715ef25 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/open_transformer.c @@ -0,0 +1,386 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC init_transformer_state(transformer_state_t *xstate) +{ + memset(xstate, 0, sizeof(*xstate)); +} + +int FAST_FUNC check_signature16(transformer_state_t *xstate, unsigned magic16) +{ + if (!xstate->signature_skipped) { + uint16_t magic2; + if (full_read(xstate->src_fd, &magic2, 2) != 2 || magic2 != magic16) { + bb_simple_error_msg("invalid magic"); + return -1; + } + xstate->signature_skipped = 2; + } + return 0; +} + +ssize_t FAST_FUNC transformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) +{ + ssize_t nwrote; + + if (xstate->mem_output_size_max != 0) { + size_t pos = xstate->mem_output_size; + size_t size; + + size = (xstate->mem_output_size += bufsize); + if (size > xstate->mem_output_size_max) { + free(xstate->mem_output_buf); + xstate->mem_output_buf = NULL; + bb_perror_msg("buffer %u too small", (unsigned)xstate->mem_output_size_max); + nwrote = -1; + goto ret; + } + xstate->mem_output_buf = xrealloc(xstate->mem_output_buf, size + 1); + memcpy(xstate->mem_output_buf + pos, buf, bufsize); + xstate->mem_output_buf[size] = '\0'; + nwrote = bufsize; + } else { + nwrote = full_write(xstate->dst_fd, buf, bufsize); + if (nwrote != (ssize_t)bufsize) { + bb_simple_perror_msg("write"); + nwrote = -1; + goto ret; + } + } + ret: + return nwrote; +} + +ssize_t FAST_FUNC xtransformer_write(transformer_state_t *xstate, const void *buf, size_t bufsize) +{ + ssize_t nwrote = transformer_write(xstate, buf, bufsize); + if (nwrote != (ssize_t)bufsize) { + xfunc_die(); + } + return nwrote; +} + +void check_errors_in_children(int signo) +{ + int status; + + if (!signo) { + /* block waiting for any child */ + if (wait(&status) < 0) +//FIXME: check EINTR? + return; /* probably there are no children */ + goto check_status; + } + + /* Wait for any child without blocking */ + for (;;) { + if (wait_any_nohang(&status) < 0) +//FIXME: check EINTR? + /* wait failed?! I'm confused... */ + return; + check_status: + /*if (WIFEXITED(status) && WEXITSTATUS(status) == 0)*/ + /* On Linux, the above can be checked simply as: */ + if (status == 0) + /* this child exited with 0 */ + continue; + /* Cannot happen: + if (!WIFSIGNALED(status) && !WIFEXITED(status)) ???; + */ + bb_got_signal = 1; + } +} + +/* transformer(), more than meets the eye */ +#if BB_MMU +void FAST_FUNC fork_transformer(int fd, + int signature_skipped, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_state_t *xstate) +) +#else +void FAST_FUNC fork_transformer(int fd, const char *transform_prog) +#endif +{ + struct fd_pair fd_pipe; + int pid; + + xpiped_pair(fd_pipe); + pid = BB_MMU ? xfork() : xvfork(); + if (pid == 0) { + /* Child */ + close(fd_pipe.rd); /* we don't want to read from the parent */ + // FIXME: error check? +#if BB_MMU + { + IF_DESKTOP(long long) int r; + transformer_state_t xstate; + init_transformer_state(&xstate); + xstate.signature_skipped = signature_skipped; + xstate.src_fd = fd; + xstate.dst_fd = fd_pipe.wr; + r = transformer(&xstate); + if (ENABLE_FEATURE_CLEAN_UP) { + close(fd_pipe.wr); /* send EOF */ + close(fd); + } + /* must be _exit! bug was actually seen here */ + _exit(/*error if:*/ r < 0); + } +#else + { + char *argv[4]; + xmove_fd(fd, 0); + xmove_fd(fd_pipe.wr, 1); + argv[0] = (char*)transform_prog; + argv[1] = (char*)"-cf"; + argv[2] = (char*)"-"; + argv[3] = NULL; + BB_EXECVP(transform_prog, argv); + bb_perror_msg_and_die("can't execute '%s'", transform_prog); + } +#endif + /* notreached */ + } + + /* parent process */ + close(fd_pipe.wr); /* don't want to write to the child */ + xmove_fd(fd_pipe.rd, fd); +} + + +#if SEAMLESS_COMPRESSION + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) +{ + transformer_state_t *xstate; + + xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; + + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xstate->signature_skipped = 2; + xread(fd, xstate->magic.b16, 2); + if (ENABLE_FEATURE_SEAMLESS_GZ + && xstate->magic.b16[0] == GZIP_MAGIC + ) { + xstate->xformer = unpack_gz_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "gunzip";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_Z + && xstate->magic.b16[0] == COMPRESS_MAGIC + ) { + xstate->xformer = unpack_Z_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "uncompress";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && xstate->magic.b16[0] == BZIP2_MAGIC + ) { + xstate->xformer = unpack_bz2_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "bunzip2";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_XZ + && xstate->magic.b16[0] == XZ_MAGIC1 + ) { + uint32_t v32; + xstate->signature_skipped = 6; + xread(fd, &xstate->magic.b16[1], 4); + move_from_unaligned32(v32, &xstate->magic.b16[1]); + if (v32 == XZ_MAGIC2) { + xstate->xformer = unpack_xz_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unxz";) + goto found_magic; + } + } + + /* No known magic seen */ + if (fail_if_not_compressed) + bb_simple_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") + " magic"); + + /* Some callers expect this function to "consume" fd + * even if data is not compressed. In this case, + * we return a state with trivial transformer. + */ +// USE_FOR_MMU(xstate->xformer = copy_stream;) +// USE_FOR_NOMMU(xstate->xformer_prog = "cat";) + + found_magic: + return xstate; +} + +static void fork_transformer_and_free(transformer_state_t *xstate) +{ +# if BB_MMU + fork_transformer_with_no_sig(xstate->src_fd, xstate->xformer); +# else + /* NOMMU version of fork_transformer execs + * an external unzipper that wants + * file position at the start of the file. + */ + xlseek(xstate->src_fd, - xstate->signature_skipped, SEEK_CUR); + xstate->signature_skipped = 0; + fork_transformer_with_sig(xstate->src_fd, xstate->xformer, xstate->xformer_prog); +# endif + free(xstate); +} + +/* Used by e.g. rpm which gives us a fd without filename, + * thus we can't guess the format from filename's extension. + */ +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) +{ + transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); + + if (!xstate->xformer) { + free(xstate); + return 1; + } + + fork_transformer_and_free(xstate); + return 0; +} +#if ENABLE_FEATURE_SEAMLESS_LZMA +/* ...and custom version for LZMA */ +void FAST_FUNC setup_lzma_on_fd(int fd) +{ + transformer_state_t *xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; + xstate->xformer = unpack_lzma_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";) + fork_transformer_and_free(xstate); +} +#endif + +static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) +{ + transformer_state_t *xstate; + int fd; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return NULL; + + if (ENABLE_FEATURE_SEAMLESS_LZMA) { + /* .lzma has no header/signature, can only detect it by extension */ + if (is_suffixed_with(fname, ".lzma")) { + xstate = xzalloc(sizeof(*xstate)); + xstate->src_fd = fd; + xstate->xformer = unpack_lzma_stream; + USE_FOR_NOMMU(xstate->xformer_prog = "unlzma";) + return xstate; + } + } + + xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); + + return xstate; +} + +int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) +{ + int fd; + transformer_state_t *xstate; + + xstate = open_transformer(fname, fail_if_not_compressed); + if (!xstate) + return -1; + + fd = xstate->src_fd; +# if BB_MMU + if (xstate->xformer) { + fork_transformer_with_no_sig(fd, xstate->xformer); + } else { + /* the file is not compressed */ + xlseek(fd, - xstate->signature_skipped, SEEK_CUR); + xstate->signature_skipped = 0; + } +# else + /* NOMMU can't avoid the seek :( */ + xlseek(fd, - xstate->signature_skipped, SEEK_CUR); + xstate->signature_skipped = 0; + if (xstate->xformer) { + fork_transformer_with_sig(fd, xstate->xformer, xstate->xformer_prog); + } /* else: the file is not compressed */ +# endif + + free(xstate); + return fd; +} + +void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) +{ +# if 1 + transformer_state_t *xstate; + char *image; + + xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); + if (!xstate) /* file open error */ + return NULL; + + image = NULL; + if (xstate->xformer) { + /* In-memory decompression */ + xstate->mem_output_size_max = maxsz_p ? *maxsz_p : (size_t)(INT_MAX - 4095); + xstate->xformer(xstate); + if (xstate->mem_output_buf) { + image = xstate->mem_output_buf; + if (maxsz_p) + *maxsz_p = xstate->mem_output_size; + } + } else { + /* File is not compressed. + * We already read first few bytes, account for that. + * Example where it happens: + * "modinfo MODULE.ko" (not compressed) + * open("MODULE.ko", O_RDONLY|O_LARGEFILE) = 4 + * read(4, "\177E", 2) = 2 + * fstat64(4, ...) + * mmap(...) + * read(4, "LF\2\1\1\0\0\0\0"... + * ...and we avoided seeking on the fd! :) + */ + image = xmalloc_read_with_initial_buf( + xstate->src_fd, + maxsz_p, + xmemdup(&xstate->magic, xstate->signature_skipped), + xstate->signature_skipped + ); + xstate->signature_skipped = 0; + } + + if (!image) + bb_perror_msg("read error from '%s'", fname); + close(xstate->src_fd); + free(xstate); + return image; +# else + /* This version forks a subprocess - much more expensive */ + int fd; + char *image; + + fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); + if (fd < 0) + return NULL; + + image = xmalloc_read(fd, maxsz_p); + if (!image) + bb_perror_msg("read error from '%s'", fname); + close(fd); + return image; +# endif +} + +#endif /* SEAMLESS_COMPRESSION */ diff --git a/busybox-1_37_0/archival/libarchive/seek_by_jump.c b/busybox-1_37_0/archival/libarchive/seek_by_jump.c new file mode 100644 index 000000000..dddaa3732 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/seek_by_jump.c @@ -0,0 +1,18 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC seek_by_jump(int fd, off_t amount) +{ + if (amount + && lseek(fd, amount, SEEK_CUR) == (off_t) -1 + ) { + if (errno == ESPIPE) + seek_by_read(fd, amount); + else + bb_simple_perror_msg_and_die("seek failure"); + } +} diff --git a/busybox-1_37_0/archival/libarchive/seek_by_read.c b/busybox-1_37_0/archival/libarchive/seek_by_read.c new file mode 100644 index 000000000..df2346354 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/seek_by_read.c @@ -0,0 +1,15 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +/* If we are reading through a pipe, or from stdin then we can't lseek, + * we must read and discard the data to skip over it. + */ +void FAST_FUNC seek_by_read(int fd, off_t amount) +{ + if (amount) + bb_copyfd_exact_size(fd, -1, amount); +} diff --git a/busybox-1_37_0/archival/libarchive/unpack_ar_archive.c b/busybox-1_37_0/archival/libarchive/unpack_ar_archive.c new file mode 100644 index 000000000..125d424c9 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unpack_ar_archive.c @@ -0,0 +1,21 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" +#include "ar_.h" + +void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) +{ + char magic[7]; + + xread(ar_archive->src_fd, magic, AR_MAGIC_LEN); + if (!is_prefixed_with(magic, AR_MAGIC)) { + bb_simple_error_msg_and_die("invalid ar magic"); + } + ar_archive->offset += AR_MAGIC_LEN; + + while (get_header_ar(ar_archive) == EXIT_SUCCESS) + continue; +} diff --git a/busybox-1_37_0/archival/libarchive/unsafe_prefix.c b/busybox-1_37_0/archival/libarchive/unsafe_prefix.c new file mode 100644 index 000000000..33e487bf9 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unsafe_prefix.c @@ -0,0 +1,35 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +const char* FAST_FUNC strip_unsafe_prefix(const char *str) +{ + const char *cp = str; + while (1) { + char *cp2; + if (*cp == '/') { + cp++; + continue; + } + if (is_prefixed_with(cp, "/../"+1)) { + cp += 3; + continue; + } + cp2 = strstr(cp, "/../"); + if (!cp2) + break; + cp = cp2 + 4; + } + if (cp != str) { + static smallint warned = 0; + if (!warned) { + warned = 1; + bb_error_msg("removing leading '%.*s' from member names", + (int)(cp - str), str); + } + } + return cp; +} diff --git a/busybox-1_37_0/archival/libarchive/unsafe_symlink_target.c b/busybox-1_37_0/archival/libarchive/unsafe_symlink_target.c new file mode 100644 index 000000000..f8dc8033d --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unsafe_symlink_target.c @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include "bb_archive.h" + +void FAST_FUNC create_or_remember_link(llist_t **link_placeholders, + const char *target, + const char *linkname, + int hard_link) +{ + if (hard_link || target[0] == '/' || strstr(target, "..")) { + llist_add_to_end(link_placeholders, + xasprintf("%c%s%c%s", hard_link, linkname, '\0', target) + ); + return; + } + if (symlink(target, linkname) != 0) { + /* shared message */ + bb_perror_msg_and_die("can't create %slink '%s' to '%s'", + "sym", linkname, target + ); + } +} + +void FAST_FUNC create_links_from_list(llist_t *list) +{ + while (list) { + char *target; + + target = list->data + 1 + strlen(list->data + 1) + 1; + if ((*list->data ? link : symlink) (target, list->data + 1)) { + /* shared message */ + bb_error_msg_and_die("can't create %slink '%s' to '%s'", + *list->data ? "hard" : "sym", + list->data + 1, target + ); + } + list = list->link; + } +} diff --git a/busybox-1_37_0/archival/libarchive/unxz/README b/busybox-1_37_0/archival/libarchive/unxz/README new file mode 100644 index 000000000..a84912035 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/README @@ -0,0 +1,135 @@ + +XZ Embedded +=========== + + XZ Embedded is a relatively small, limited implementation of the .xz + file format. Currently only decoding is implemented. + + XZ Embedded was written for use in the Linux kernel, but the code can + be easily used in other environments too, including regular userspace + applications. See userspace/xzminidec.c for an example program. + + This README contains information that is useful only when the copy + of XZ Embedded isn't part of the Linux kernel tree. You should also + read linux/Documentation/xz.txt even if you aren't using XZ Embedded + as part of Linux; information in that file is not repeated in this + README. + +Compiling the Linux kernel module + + The xz_dec module depends on crc32 module, so make sure that you have + it enabled (CONFIG_CRC32). + + Building the xz_dec and xz_dec_test modules without support for BCJ + filters: + + cd linux/lib/xz + make -C /path/to/kernel/source \ + KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ + CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m + + Building the xz_dec and xz_dec_test modules with support for BCJ + filters: + + cd linux/lib/xz + make -C /path/to/kernel/source \ + KCPPFLAGS=-I"$(pwd)/../../include" M="$(pwd)" \ + CONFIG_XZ_DEC=m CONFIG_XZ_DEC_TEST=m CONFIG_XZ_DEC_BCJ=y \ + CONFIG_XZ_DEC_X86=y CONFIG_XZ_DEC_POWERPC=y \ + CONFIG_XZ_DEC_IA64=y CONFIG_XZ_DEC_ARM=y \ + CONFIG_XZ_DEC_ARMTHUMB=y CONFIG_XZ_DEC_SPARC=y + + If you want only one or a few of the BCJ filters, omit the appropriate + variables. CONFIG_XZ_DEC_BCJ=y is always required to build the support + code shared between all BCJ filters. + + Most people don't need the xz_dec_test module. You can skip building + it by omitting CONFIG_XZ_DEC_TEST=m from the make command line. + +Compiler requirements + + XZ Embedded should compile as either GNU-C89 (used in the Linux + kernel) or with any C99 compiler. Getting the code to compile with + non-GNU C89 compiler or a C++ compiler should be quite easy as + long as there is a data type for unsigned 64-bit integer (or the + code is modified not to support large files, which needs some more + care than just using 32-bit integer instead of 64-bit). + + If you use GCC, try to use a recent version. For example, on x86-32, + xz_dec_lzma2.c compiled with GCC 3.3.6 is 15-25 % slower than when + compiled with GCC 4.3.3. + +Embedding into userspace applications + + To embed the XZ decoder, copy the following files into a single + directory in your source code tree: + + linux/include/linux/xz.h + linux/lib/xz/xz_crc32.c + linux/lib/xz/xz_dec_lzma2.c + linux/lib/xz/xz_dec_stream.c + linux/lib/xz/xz_lzma2.h + linux/lib/xz/xz_private.h + linux/lib/xz/xz_stream.h + userspace/xz_config.h + + Alternatively, xz.h may be placed into a different directory but then + that directory must be in the compiler include path when compiling + the .c files. + + Your code should use only the functions declared in xz.h. The rest of + the .h files are meant only for internal use in XZ Embedded. + + You may want to modify xz_config.h to be more suitable for your build + environment. Probably you should at least skim through it even if the + default file works as is. + +BCJ filter support + + If you want support for one or more BCJ filters, you need to copy also + linux/lib/xz/xz_dec_bcj.c into your application, and use appropriate + #defines in xz_config.h or in compiler flags. You don't need these + #defines in the code that just uses XZ Embedded via xz.h, but having + them always #defined doesn't hurt either. + + #define Instruction set BCJ filter endianness + XZ_DEC_X86 x86-32 or x86-64 Little endian only + XZ_DEC_POWERPC PowerPC Big endian only + XZ_DEC_IA64 Itanium (IA-64) Big or little endian + XZ_DEC_ARM ARM Little endian only + XZ_DEC_ARMTHUMB ARM-Thumb Little endian only + XZ_DEC_SPARC SPARC Big or little endian + + While some architectures are (partially) bi-endian, the endianness + setting doesn't change the endianness of the instructions on all + architectures. That's why Itanium and SPARC filters work for both big + and little endian executables (Itanium has little endian instructions + and SPARC has big endian instructions). + + There currently is no filter for little endian PowerPC or big endian + ARM or ARM-Thumb. Implementing filters for them can be considered if + there is a need for such filters in real-world applications. + +Notes about shared libraries + + If you are including XZ Embedded into a shared library, you very + probably should rename the xz_* functions to prevent symbol + conflicts in case your library is linked against some other library + or application that also has XZ Embedded in it (which may even be + a different version of XZ Embedded). TODO: Provide an easy way + to do this. + + Please don't create a shared library of XZ Embedded itself unless + it is fine to rebuild everything depending on that shared library + everytime you upgrade to a newer version of XZ Embedded. There are + no API or ABI stability guarantees between different versions of + XZ Embedded. + +Specifying the calling convention + + XZ_FUNC macro was included to support declaring functions with __init + in Linux. Outside Linux, it can be used to specify the calling + convention on systems that support multiple calling conventions. + For example, on Windows, you may make all functions use the stdcall + calling convention by defining XZ_FUNC=__stdcall when building and + using the functions from XZ Embedded. diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz.h b/busybox-1_37_0/archival/libarchive/unxz/xz.h new file mode 100644 index 000000000..e0b22db56 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz.h @@ -0,0 +1,280 @@ +/* + * XZ decompressor + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_H +#define XZ_H + +#ifdef __KERNEL__ +# include +# include +#else +# include +# include +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* In Linux, this is used to make extern functions static when needed. */ +#ifndef XZ_EXTERN +# define XZ_EXTERN extern +#endif + +/* In Linux, this is used to mark the functions with __init when needed. */ +#ifndef XZ_FUNC +# define XZ_FUNC +#endif + +/** + * enum xz_mode - Operation mode + * + * @XZ_SINGLE: Single-call mode. This uses less RAM than + * than multi-call modes, because the LZMA2 + * dictionary doesn't need to be allocated as + * part of the decoder state. All required data + * structures are allocated at initialization, + * so xz_dec_run() cannot return XZ_MEM_ERROR. + * @XZ_PREALLOC: Multi-call mode with preallocated LZMA2 + * dictionary buffer. All data structures are + * allocated at initialization, so xz_dec_run() + * cannot return XZ_MEM_ERROR. + * @XZ_DYNALLOC: Multi-call mode. The LZMA2 dictionary is + * allocated once the required size has been + * parsed from the stream headers. If the + * allocation fails, xz_dec_run() will return + * XZ_MEM_ERROR. + * + * It is possible to enable support only for a subset of the above + * modes at compile time by defining XZ_DEC_SINGLE, XZ_DEC_PREALLOC, + * or XZ_DEC_DYNALLOC. The xz_dec kernel module is always compiled + * with support for all operation modes, but the preboot code may + * be built with fewer features to minimize code size. + */ +enum xz_mode { + XZ_SINGLE, + XZ_PREALLOC, + XZ_DYNALLOC +}; + +/** + * enum xz_ret - Return codes + * @XZ_OK: Everything is OK so far. More input or more + * output space is required to continue. This + * return code is possible only in multi-call mode + * (XZ_PREALLOC or XZ_DYNALLOC). + * @XZ_STREAM_END: Operation finished successfully. + * @XZ_UNSUPPORTED_CHECK: Integrity check type is not supported. Decoding + * is still possible in multi-call mode by simply + * calling xz_dec_run() again. + * Note that this return value is used only if + * XZ_DEC_ANY_CHECK was defined at build time, + * which is not used in the kernel. Unsupported + * check types return XZ_OPTIONS_ERROR if + * XZ_DEC_ANY_CHECK was not defined at build time. + * @XZ_MEM_ERROR: Allocating memory failed. This return code is + * possible only if the decoder was initialized + * with XZ_DYNALLOC. The amount of memory that was + * tried to be allocated was no more than the + * dict_max argument given to xz_dec_init(). + * @XZ_MEMLIMIT_ERROR: A bigger LZMA2 dictionary would be needed than + * allowed by the dict_max argument given to + * xz_dec_init(). This return value is possible + * only in multi-call mode (XZ_PREALLOC or + * XZ_DYNALLOC); the single-call mode (XZ_SINGLE) + * ignores the dict_max argument. + * @XZ_FORMAT_ERROR: File format was not recognized (wrong magic + * bytes). + * @XZ_OPTIONS_ERROR: This implementation doesn't support the requested + * compression options. In the decoder this means + * that the header CRC32 matches, but the header + * itself specifies something that we don't support. + * @XZ_DATA_ERROR: Compressed data is corrupt. + * @XZ_BUF_ERROR: Cannot make any progress. Details are slightly + * different between multi-call and single-call + * mode; more information below. + * + * In multi-call mode, XZ_BUF_ERROR is returned when two consecutive calls + * to XZ code cannot consume any input and cannot produce any new output. + * This happens when there is no new input available, or the output buffer + * is full while at least one output byte is still pending. Assuming your + * code is not buggy, you can get this error only when decoding a compressed + * stream that is truncated or otherwise corrupt. + * + * In single-call mode, XZ_BUF_ERROR is returned only when the output buffer + * is too small or the compressed input is corrupt in a way that makes the + * decoder produce more output than the caller expected. When it is + * (relatively) clear that the compressed input is truncated, XZ_DATA_ERROR + * is used instead of XZ_BUF_ERROR. + */ +enum xz_ret { + XZ_OK, + XZ_STREAM_END, + XZ_UNSUPPORTED_CHECK, + XZ_MEM_ERROR, + XZ_MEMLIMIT_ERROR, + XZ_FORMAT_ERROR, + XZ_OPTIONS_ERROR, + XZ_DATA_ERROR, + XZ_BUF_ERROR +}; + +/** + * struct xz_buf - Passing input and output buffers to XZ code + * @in: Beginning of the input buffer. This may be NULL if and only + * if in_pos is equal to in_size. + * @in_pos: Current position in the input buffer. This must not exceed + * in_size. + * @in_size: Size of the input buffer + * @out: Beginning of the output buffer. This may be NULL if and only + * if out_pos is equal to out_size. + * @out_pos: Current position in the output buffer. This must not exceed + * out_size. + * @out_size: Size of the output buffer + * + * Only the contents of the output buffer from out[out_pos] onward, and + * the variables in_pos and out_pos are modified by the XZ code. + */ +struct xz_buf { + const uint8_t *in; + size_t in_pos; + size_t in_size; + + uint8_t *out; + size_t out_pos; + size_t out_size; +}; + +/** + * struct xz_dec - Opaque type to hold the XZ decoder state + */ +struct xz_dec; + +/** + * xz_dec_init() - Allocate and initialize a XZ decoder state + * @mode: Operation mode + * @dict_max: Maximum size of the LZMA2 dictionary (history buffer) for + * multi-call decoding. This is ignored in single-call mode + * (mode == XZ_SINGLE). LZMA2 dictionary is always 2^n bytes + * or 2^n + 2^(n-1) bytes (the latter sizes are less common + * in practice), so other values for dict_max don't make sense. + * In the kernel, dictionary sizes of 64 KiB, 128 KiB, 256 KiB, + * 512 KiB, and 1 MiB are probably the only reasonable values, + * except for kernel and initramfs images where a bigger + * dictionary can be fine and useful. + * + * Single-call mode (XZ_SINGLE): xz_dec_run() decodes the whole stream at + * once. The caller must provide enough output space or the decoding will + * fail. The output space is used as the dictionary buffer, which is why + * there is no need to allocate the dictionary as part of the decoder's + * internal state. + * + * Because the output buffer is used as the workspace, streams encoded using + * a big dictionary are not a problem in single-call mode. It is enough that + * the output buffer is big enough to hold the actual uncompressed data; it + * can be smaller than the dictionary size stored in the stream headers. + * + * Multi-call mode with preallocated dictionary (XZ_PREALLOC): dict_max bytes + * of memory is preallocated for the LZMA2 dictionary. This way there is no + * risk that xz_dec_run() could run out of memory, since xz_dec_run() will + * never allocate any memory. Instead, if the preallocated dictionary is too + * small for decoding the given input stream, xz_dec_run() will return + * XZ_MEMLIMIT_ERROR. Thus, it is important to know what kind of data will be + * decoded to avoid allocating excessive amount of memory for the dictionary. + * + * Multi-call mode with dynamically allocated dictionary (XZ_DYNALLOC): + * dict_max specifies the maximum allowed dictionary size that xz_dec_run() + * may allocate once it has parsed the dictionary size from the stream + * headers. This way excessive allocations can be avoided while still + * limiting the maximum memory usage to a sane value to prevent running the + * system out of memory when decompressing streams from untrusted sources. + * + * On success, xz_dec_init() returns a pointer to struct xz_dec, which is + * ready to be used with xz_dec_run(). If memory allocation fails, + * xz_dec_init() returns NULL. + */ +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max); + +/** + * xz_dec_run() - Run the XZ decoder + * @s: Decoder state allocated using xz_dec_init() + * @b: Input and output buffers + * + * The possible return values depend on build options and operation mode. + * See enum xz_ret for details. + * + * Note that if an error occurs in single-call mode (return value is not + * XZ_STREAM_END), b->in_pos and b->out_pos are not modified and the + * contents of the output buffer from b->out[b->out_pos] onward are + * undefined. This is true even after XZ_BUF_ERROR, because with some filter + * chains, there may be a second pass over the output buffer, and this pass + * cannot be properly done if the output buffer is truncated. Thus, you + * cannot give the single-call decoder a too small buffer and then expect to + * get that amount valid data from the beginning of the stream. You must use + * the multi-call decoder if you don't want to uncompress the whole stream. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b); + +/** + * xz_dec_reset() - Reset an already allocated decoder state + * @s: Decoder state allocated using xz_dec_init() + * + * This function can be used to reset the multi-call decoder state without + * freeing and reallocating memory with xz_dec_end() and xz_dec_init(). + * + * In single-call mode, xz_dec_reset() is always called in the beginning of + * xz_dec_run(). Thus, explicit call to xz_dec_reset() is useful only in + * multi-call mode. + */ +XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s); + +/** + * xz_dec_end() - Free the memory allocated for the decoder state + * @s: Decoder state allocated using xz_dec_init(). If s is NULL, + * this function does nothing. + */ +XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s); + +/* + * Standalone build (userspace build or in-kernel build for boot time use) + * needs a CRC32 implementation. For normal in-kernel use, kernel's own + * CRC32 module is used instead, and users of this module don't need to + * care about the functions below. + */ +#ifndef XZ_INTERNAL_CRC32 +# ifdef __KERNEL__ +# define XZ_INTERNAL_CRC32 0 +# else +# define XZ_INTERNAL_CRC32 1 +# endif +#endif + +#if XZ_INTERNAL_CRC32 +/* + * This must be called before any other xz_* function to initialize + * the CRC32 lookup table. + */ +XZ_EXTERN void XZ_FUNC xz_crc32_init(void); + +/* + * Update CRC32 value using the polynomial from IEEE-802.3. To start a new + * calculation, the third argument must be zero. To continue the calculation, + * the previously returned value is passed as the third argument. + */ +XZ_EXTERN uint32_t XZ_FUNC xz_crc32( + const uint8_t *buf, size_t size, uint32_t crc); +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_config.h b/busybox-1_37_0/archival/libarchive/unxz/xz_config.h new file mode 100644 index 000000000..187e1cbed --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_config.h @@ -0,0 +1,123 @@ +/* + * Private includes and definitions for userspace use of XZ Embedded + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_CONFIG_H +#define XZ_CONFIG_H + +/* Uncomment as needed to enable BCJ filter decoders. */ +/* #define XZ_DEC_X86 */ +/* #define XZ_DEC_POWERPC */ +/* #define XZ_DEC_IA64 */ +/* #define XZ_DEC_ARM */ +/* #define XZ_DEC_ARMTHUMB */ +/* #define XZ_DEC_SPARC */ + +#include +#include +#include + +#include "xz.h" + +#define kmalloc(size, flags) malloc(size) +#define kfree(ptr) free(ptr) +#define vmalloc(size) malloc(size) +#define vfree(ptr) free(ptr) + +#define memeq(a, b, size) (memcmp(a, b, size) == 0) +#define memzero(buf, size) memset(buf, 0, size) + +#undef min +#undef min_t +#define min(x, y) ((x) < (y) ? (x) : (y)) +#define min_t(type, x, y) min(x, y) + +/* + * Some functions have been marked with __always_inline to keep the + * performance reasonable even when the compiler is optimizing for + * small code size. You may be able to save a few bytes by #defining + * __always_inline to plain inline, but don't complain if the code + * becomes slow. + * + * NOTE: System headers on GNU/Linux may #define this macro already, + * so if you want to change it, you need to #undef it first. + */ +#ifndef __always_inline +# ifdef __GNUC__ +# define __always_inline \ + inline __attribute__((__always_inline__)) +# else +# define __always_inline inline +# endif +#endif + +/* + * Some functions are marked to never be inlined to reduce stack usage. + * If you don't care about stack usage, you may want to modify this so + * that noinline_for_stack is #defined to be empty even when using GCC. + * Doing so may save a few bytes in binary size. + */ +#ifndef noinline_for_stack +# ifdef __GNUC__ +# define noinline_for_stack __attribute__((__noinline__)) +# else +# define noinline_for_stack +# endif +#endif + +/* Inline functions to access unaligned unsigned 32-bit integers */ +#ifndef get_unaligned_le32 +static inline uint32_t XZ_FUNC get_unaligned_le32(const uint8_t *buf) +{ + return (uint32_t)buf[0] + | ((uint32_t)buf[1] << 8) + | ((uint32_t)buf[2] << 16) + | ((uint32_t)buf[3] << 24); +} +#endif + +#ifndef get_unaligned_be32 +static inline uint32_t XZ_FUNC get_unaligned_be32(const uint8_t *buf) +{ + return (uint32_t)(buf[0] << 24) + | ((uint32_t)buf[1] << 16) + | ((uint32_t)buf[2] << 8) + | (uint32_t)buf[3]; +} +#endif + +#ifndef put_unaligned_le32 +static inline void XZ_FUNC put_unaligned_le32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)val; + buf[1] = (uint8_t)(val >> 8); + buf[2] = (uint8_t)(val >> 16); + buf[3] = (uint8_t)(val >> 24); +} +#endif + +#ifndef put_unaligned_be32 +static inline void XZ_FUNC put_unaligned_be32(uint32_t val, uint8_t *buf) +{ + buf[0] = (uint8_t)(val >> 24); + buf[1] = (uint8_t)(val >> 16); + buf[2] = (uint8_t)(val >> 8); + buf[3] = (uint8_t)val; +} +#endif + +/* + * Use get_unaligned_le32() also for aligned access for simplicity. On + * little endian systems, #define get_le32(ptr) (*(const uint32_t *)(ptr)) + * could save a few bytes in code size. + */ +#ifndef get_le32 +# define get_le32 get_unaligned_le32 +#endif + +#endif diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_dec_bcj.c b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_bcj.c new file mode 100644 index 000000000..e0f913a94 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_bcj.c @@ -0,0 +1,580 @@ +/* + * Branch/Call/Jump (BCJ) filter decoders + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" + +/* + * The rest of the file is inside this ifdef. It makes things a little more + * convenient when building without support for any BCJ filters. + */ +#ifdef XZ_DEC_BCJ + +struct xz_dec_bcj { + /* Type of the BCJ filter being used */ + enum { + BCJ_X86 = 4, /* x86 or x86-64 */ + BCJ_POWERPC = 5, /* Big endian only */ + BCJ_IA64 = 6, /* Big or little endian */ + BCJ_ARM = 7, /* Little endian only */ + BCJ_ARMTHUMB = 8, /* Little endian only */ + BCJ_SPARC = 9 /* Big or little endian */ + } type; + + /* + * Return value of the next filter in the chain. We need to preserve + * this information across calls, because we must not call the next + * filter anymore once it has returned XZ_STREAM_END. + */ + enum xz_ret ret; + + /* True if we are operating in single-call mode. */ + bool single_call; + + /* + * Absolute position relative to the beginning of the uncompressed + * data (in a single .xz Block). We care only about the lowest 32 + * bits so this doesn't need to be uint64_t even with big files. + */ + uint32_t pos; + + /* x86 filter state */ + uint32_t x86_prev_mask; + + /* Temporary space to hold the variables from struct xz_buf */ + uint8_t *out; + size_t out_pos; + size_t out_size; + + struct { + /* Amount of already filtered data in the beginning of buf */ + size_t filtered; + + /* Total amount of data currently stored in buf */ + size_t size; + + /* + * Buffer to hold a mix of filtered and unfiltered data. This + * needs to be big enough to hold Alignment + 2 * Look-ahead: + * + * Type Alignment Look-ahead + * x86 1 4 + * PowerPC 4 0 + * IA-64 16 0 + * ARM 4 0 + * ARM-Thumb 2 2 + * SPARC 4 0 + */ + uint8_t buf[16]; + } temp; +}; + +#ifdef XZ_DEC_X86 +/* + * This is used to test the most significant byte of a memory address + * in an x86 instruction. + */ +static inline int bcj_x86_test_msbyte(uint8_t b) +{ + return b == 0x00 || b == 0xFF; +} + +static noinline_for_stack size_t XZ_FUNC bcj_x86( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const bool mask_to_allowed_status[8] + = { true, true, true, false, true, false, false, false }; + + static const uint8_t mask_to_bit_num[8] = { 0, 1, 2, 2, 3, 3, 3, 3 }; + + size_t i; + size_t prev_pos = (size_t)-1; + uint32_t prev_mask = s->x86_prev_mask; + uint32_t src; + uint32_t dest; + uint32_t j; + uint8_t b; + + if (size <= 4) + return 0; + + size -= 4; + for (i = 0; i < size; ++i) { + if ((buf[i] & 0xFE) != 0xE8) + continue; + + prev_pos = i - prev_pos; + if (prev_pos > 3) { + prev_mask = 0; + } else { + prev_mask = (prev_mask << (prev_pos - 1)) & 7; + if (prev_mask != 0) { + b = buf[i + 4 - mask_to_bit_num[prev_mask]]; + if (!mask_to_allowed_status[prev_mask] + || bcj_x86_test_msbyte(b)) { + prev_pos = i; + prev_mask = (prev_mask << 1) | 1; + continue; + } + } + } + + prev_pos = i; + + if (bcj_x86_test_msbyte(buf[i + 4])) { + src = get_unaligned_le32(buf + i + 1); + while (true) { + dest = src - (s->pos + (uint32_t)i + 5); + if (prev_mask == 0) + break; + + j = mask_to_bit_num[prev_mask] * 8; + b = (uint8_t)(dest >> (24 - j)); + if (!bcj_x86_test_msbyte(b)) + break; + + src = dest ^ (((uint32_t)1 << (32 - j)) - 1); + } + + dest &= 0x01FFFFFF; + dest |= (uint32_t)0 - (dest & 0x01000000); + put_unaligned_le32(dest, buf + i + 1); + i += 4; + } else { + prev_mask = (prev_mask << 1) | 1; + } + } + + prev_pos = i - prev_pos; + s->x86_prev_mask = prev_pos > 3 ? 0 : prev_mask << (prev_pos - 1); + return i; +} +#endif + +#ifdef XZ_DEC_POWERPC +static noinline_for_stack size_t XZ_FUNC bcj_powerpc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr & 0xFC000003) == 0x48000001) { + instr &= 0x03FFFFFC; + instr -= s->pos + (uint32_t)i; + instr &= 0x03FFFFFC; + instr |= 0x48000001; + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_IA64 +static noinline_for_stack size_t XZ_FUNC bcj_ia64( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + static const uint8_t branch_table[32] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 4, 4, 6, 6, 0, 0, 7, 7, + 4, 4, 0, 0, 4, 4, 0, 0 + }; + + /* + * The local variables take a little bit stack space, but it's less + * than what LZMA2 decoder takes, so it doesn't make sense to reduce + * stack usage here without doing that for the LZMA2 decoder too. + */ + + /* Loop counters */ + size_t i; + size_t j; + + /* Instruction slot (0, 1, or 2) in the 128-bit instruction word */ + uint32_t slot; + + /* Bitwise offset of the instruction indicated by slot */ + uint32_t bit_pos; + + /* bit_pos split into byte and bit parts */ + uint32_t byte_pos; + uint32_t bit_res; + + /* Address part of an instruction */ + uint32_t addr; + + /* Mask used to detect which instructions to convert */ + uint32_t mask; + + /* 41-bit instruction stored somewhere in the lowest 48 bits */ + uint64_t instr; + + /* Instruction normalized with bit_res for easier manipulation */ + uint64_t norm; + + for (i = 0; i + 16 <= size; i += 16) { + mask = branch_table[buf[i] & 0x1F]; + for (slot = 0, bit_pos = 5; slot < 3; ++slot, bit_pos += 41) { + if (((mask >> slot) & 1) == 0) + continue; + + byte_pos = bit_pos >> 3; + bit_res = bit_pos & 7; + instr = 0; + for (j = 0; j < 6; ++j) + instr |= (uint64_t)(buf[i + j + byte_pos]) + << (8 * j); + + norm = instr >> bit_res; + + if (((norm >> 37) & 0x0F) == 0x05 + && ((norm >> 9) & 0x07) == 0) { + addr = (norm >> 13) & 0x0FFFFF; + addr |= ((uint32_t)(norm >> 36) & 1) << 20; + addr <<= 4; + addr -= s->pos + (uint32_t)i; + addr >>= 4; + + norm &= ~((uint64_t)0x8FFFFF << 13); + norm |= (uint64_t)(addr & 0x0FFFFF) << 13; + norm |= (uint64_t)(addr & 0x100000) + << (36 - 20); + + instr &= (1 << bit_res) - 1; + instr |= norm << bit_res; + + for (j = 0; j < 6; j++) + buf[i + j + byte_pos] + = (uint8_t)(instr >> (8 * j)); + } + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARM +static noinline_for_stack size_t XZ_FUNC bcj_arm( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 4) { + if (buf[i + 3] == 0xEB) { + addr = (uint32_t)buf[i] | ((uint32_t)buf[i + 1] << 8) + | ((uint32_t)buf[i + 2] << 16); + addr <<= 2; + addr -= s->pos + (uint32_t)i + 8; + addr >>= 2; + buf[i] = (uint8_t)addr; + buf[i + 1] = (uint8_t)(addr >> 8); + buf[i + 2] = (uint8_t)(addr >> 16); + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_ARMTHUMB +static noinline_for_stack size_t XZ_FUNC bcj_armthumb( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t addr; + + for (i = 0; i + 4 <= size; i += 2) { + if ((buf[i + 1] & 0xF8) == 0xF0 + && (buf[i + 3] & 0xF8) == 0xF8) { + addr = (((uint32_t)buf[i + 1] & 0x07) << 19) + | ((uint32_t)buf[i] << 11) + | (((uint32_t)buf[i + 3] & 0x07) << 8) + | (uint32_t)buf[i + 2]; + addr <<= 1; + addr -= s->pos + (uint32_t)i + 4; + addr >>= 1; + buf[i + 1] = (uint8_t)(0xF0 | ((addr >> 19) & 0x07)); + buf[i] = (uint8_t)(addr >> 11); + buf[i + 3] = (uint8_t)(0xF8 | ((addr >> 8) & 0x07)); + buf[i + 2] = (uint8_t)addr; + i += 2; + } + } + + return i; +} +#endif + +#ifdef XZ_DEC_SPARC +static noinline_for_stack size_t XZ_FUNC bcj_sparc( + struct xz_dec_bcj *s, uint8_t *buf, size_t size) +{ + size_t i; + uint32_t instr; + + for (i = 0; i + 4 <= size; i += 4) { + instr = get_unaligned_be32(buf + i); + if ((instr >> 22) == 0x100 || (instr >> 22) == 0x1FF) { + instr <<= 2; + instr -= s->pos + (uint32_t)i; + instr >>= 2; + instr = ((uint32_t)0x40000000 - (instr & 0x400000)) + | 0x40000000 | (instr & 0x3FFFFF); + put_unaligned_be32(instr, buf + i); + } + } + + return i; +} +#endif + +/* + * Apply the selected BCJ filter. Update *pos and s->pos to match the amount + * of data that got filtered. + * + * NOTE: This is implemented as a switch statement to avoid using function + * pointers, which could be problematic in the kernel boot code, which must + * avoid pointers to static data (at least on x86). + */ +static void XZ_FUNC bcj_apply(struct xz_dec_bcj *s, + uint8_t *buf, size_t *pos, size_t size) +{ + size_t filtered; + + buf += *pos; + size -= *pos; + + switch (s->type) { +#ifdef XZ_DEC_X86 + case BCJ_X86: + filtered = bcj_x86(s, buf, size); + break; +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: + filtered = bcj_powerpc(s, buf, size); + break; +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: + filtered = bcj_ia64(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: + filtered = bcj_arm(s, buf, size); + break; +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: + filtered = bcj_armthumb(s, buf, size); + break; +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: + filtered = bcj_sparc(s, buf, size); + break; +#endif + default: + /* Never reached but silence compiler warnings. */ + filtered = 0; + break; + } + + *pos += filtered; + s->pos += filtered; +} + +/* + * Flush pending filtered data from temp to the output buffer. + * Move the remaining mixture of possibly filtered and unfiltered + * data to the beginning of temp. + */ +static void XZ_FUNC bcj_flush(struct xz_dec_bcj *s, struct xz_buf *b) +{ + size_t copy_size; + + copy_size = min_t(size_t, s->temp.filtered, b->out_size - b->out_pos); + memcpy(b->out + b->out_pos, s->temp.buf, copy_size); + b->out_pos += copy_size; + + s->temp.filtered -= copy_size; + s->temp.size -= copy_size; + memmove(s->temp.buf, s->temp.buf + copy_size, s->temp.size); +} + +/* + * The BCJ filter functions are primitive in sense that they process the + * data in chunks of 1-16 bytes. To hide this issue, this function does + * some buffering. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b) +{ + size_t out_start; + + /* + * Flush pending already filtered data to the output buffer. Return + * immediatelly if we couldn't flush everything, or if the next + * filter in the chain had already returned XZ_STREAM_END. + */ + if (s->temp.filtered > 0) { + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + } + + /* + * If we have more output space than what is currently pending in + * temp, copy the unfiltered data from temp to the output buffer + * and try to fill the output buffer by decoding more data from the + * next filter in the chain. Apply the BCJ filter on the new data + * in the output buffer. If everything cannot be filtered, copy it + * to temp and rewind the output buffer position accordingly. + * + * This needs to be always run when temp.size == 0 to handle a special + * case where the output buffer is full and the next filter has no + * more output coming but hasn't returned XZ_STREAM_END yet. + */ + if (s->temp.size < b->out_size - b->out_pos || s->temp.size == 0) { + out_start = b->out_pos; + memcpy(b->out + b->out_pos, s->temp.buf, s->temp.size); + b->out_pos += s->temp.size; + + s->ret = xz_dec_lzma2_run(lzma2, b); + if (s->ret != XZ_STREAM_END + && (s->ret != XZ_OK || s->single_call)) + return s->ret; + + bcj_apply(s, b->out, &out_start, b->out_pos); + + /* + * As an exception, if the next filter returned XZ_STREAM_END, + * we can do that too, since the last few bytes that remain + * unfiltered are meant to remain unfiltered. + */ + if (s->ret == XZ_STREAM_END) + return XZ_STREAM_END; + + s->temp.size = b->out_pos - out_start; + b->out_pos -= s->temp.size; + memcpy(s->temp.buf, b->out + b->out_pos, s->temp.size); + + /* + * If there wasn't enough input to the next filter to fill + * the output buffer with unfiltered data, there's no point + * to try decoding more data to temp. + */ + if (b->out_pos + s->temp.size < b->out_size) + return XZ_OK; + } + + /* + * We have unfiltered data in temp. If the output buffer isn't full + * yet, try to fill the temp buffer by decoding more data from the + * next filter. Apply the BCJ filter on temp. Then we hopefully can + * fill the actual output buffer by copying filtered data from temp. + * A mix of filtered and unfiltered data may be left in temp; it will + * be taken care on the next call to this function. + */ + if (b->out_pos < b->out_size) { + /* Make b->out{,_pos,_size} temporarily point to s->temp. */ + s->out = b->out; + s->out_pos = b->out_pos; + s->out_size = b->out_size; + b->out = s->temp.buf; + b->out_pos = s->temp.size; + b->out_size = sizeof(s->temp.buf); + + s->ret = xz_dec_lzma2_run(lzma2, b); + + s->temp.size = b->out_pos; + b->out = s->out; + b->out_pos = s->out_pos; + b->out_size = s->out_size; + + if (s->ret != XZ_OK && s->ret != XZ_STREAM_END) + return s->ret; + + bcj_apply(s, s->temp.buf, &s->temp.filtered, s->temp.size); + + /* + * If the next filter returned XZ_STREAM_END, we mark that + * everything is filtered, since the last unfiltered bytes + * of the stream are meant to be left as is. + */ + if (s->ret == XZ_STREAM_END) + s->temp.filtered = s->temp.size; + + bcj_flush(s, b); + if (s->temp.filtered > 0) + return XZ_OK; + } + + return s->ret; +} + +XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call) +{ + struct xz_dec_bcj *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s != NULL) + s->single_call = single_call; + + return s; +} + +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id) +{ + switch (id) { +#ifdef XZ_DEC_X86 + case BCJ_X86: +#endif +#ifdef XZ_DEC_POWERPC + case BCJ_POWERPC: +#endif +#ifdef XZ_DEC_IA64 + case BCJ_IA64: +#endif +#ifdef XZ_DEC_ARM + case BCJ_ARM: +#endif +#ifdef XZ_DEC_ARMTHUMB + case BCJ_ARMTHUMB: +#endif +#ifdef XZ_DEC_SPARC + case BCJ_SPARC: +#endif + break; + + default: + /* Unsupported Filter ID */ + return XZ_OPTIONS_ERROR; + } + + s->type = id; + s->ret = XZ_OK; + s->pos = 0; + s->x86_prev_mask = 0; + s->temp.filtered = 0; + s->temp.size = 0; + + return XZ_OK; +} + +#endif diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_dec_lzma2.c b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_lzma2.c new file mode 100644 index 000000000..bca41e705 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_lzma2.c @@ -0,0 +1,1171 @@ +/* + * LZMA2 decoder + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_lzma2.h" + +/* + * Range decoder initialization eats the first five bytes of each LZMA chunk. + */ +#define RC_INIT_BYTES 5 + +/* + * Minimum number of usable input buffer to safely decode one LZMA symbol. + * The worst case is that we decode 22 bits using probabilities and 26 + * direct bits. This may decode at maximum of 20 bytes of input. However, + * lzma_main() does an extra normalization before returning, thus we + * need to put 21 here. + */ +#define LZMA_IN_REQUIRED 21 + +/* + * Dictionary (history buffer) + * + * These are always true: + * start <= pos <= full <= end + * pos <= limit <= end + * + * In multi-call mode, also these are true: + * end == size + * size <= size_max + * allocated <= size + * + * Most of these variables are size_t to support single-call mode, + * in which the dictionary variables address the actual output + * buffer directly. + */ +struct dictionary { + /* Beginning of the history buffer */ + uint8_t *buf; + + /* Old position in buf (before decoding more data) */ + size_t start; + + /* Position in buf */ + size_t pos; + + /* + * How full dictionary is. This is used to detect corrupt input that + * would read beyond the beginning of the uncompressed stream. + */ + size_t full; + + /* Write limit; we don't write to buf[limit] or later bytes. */ + size_t limit; + + /* + * End of the dictionary buffer. In multi-call mode, this is + * the same as the dictionary size. In single-call mode, this + * indicates the size of the output buffer. + */ + size_t end; + + /* + * Size of the dictionary as specified in Block Header. This is used + * together with "full" to detect corrupt input that would make us + * read beyond the beginning of the uncompressed stream. + */ + uint32_t size; + + /* + * Maximum allowed dictionary size in multi-call mode. + * This is ignored in single-call mode. + */ + uint32_t size_max; + + /* + * Amount of memory currently allocated for the dictionary. + * This is used only with XZ_DYNALLOC. (With XZ_PREALLOC, + * size_max is always the same as the allocated size.) + */ + uint32_t allocated; + + /* Operation mode */ + enum xz_mode mode; +}; + +/* Range decoder */ +struct rc_dec { + uint32_t range; + uint32_t code; + + /* + * Number of initializing bytes remaining to be read + * by rc_read_init(). + */ + uint32_t init_bytes_left; + + /* + * Buffer from which we read our input. It can be either + * temp.buf or the caller-provided input buffer. + */ + const uint8_t *in; + size_t in_pos; + size_t in_limit; +}; + +/* Probabilities for a length decoder. */ +struct lzma_len_dec { + /* Probability of match length being at least 10 */ + uint16_t choice; + + /* Probability of match length being at least 18 */ + uint16_t choice2; + + /* Probabilities for match lengths 2-9 */ + uint16_t low[POS_STATES_MAX][LEN_LOW_SYMBOLS]; + + /* Probabilities for match lengths 10-17 */ + uint16_t mid[POS_STATES_MAX][LEN_MID_SYMBOLS]; + + /* Probabilities for match lengths 18-273 */ + uint16_t high[LEN_HIGH_SYMBOLS]; +}; + +struct lzma_dec { + /* Distances of latest four matches */ + uint32_t rep0; + uint32_t rep1; + uint32_t rep2; + uint32_t rep3; + + /* Types of the most recently seen LZMA symbols */ + enum lzma_state state; + + /* + * Length of a match. This is updated so that dict_repeat can + * be called again to finish repeating the whole match. + */ + uint32_t len; + + /* + * LZMA properties or related bit masks (number of literal + * context bits, a mask dervied from the number of literal + * position bits, and a mask dervied from the number + * position bits) + */ + uint32_t lc; + uint32_t literal_pos_mask; /* (1 << lp) - 1 */ + uint32_t pos_mask; /* (1 << pb) - 1 */ + + /* If 1, it's a match. Otherwise it's a single 8-bit literal. */ + uint16_t is_match[STATES][POS_STATES_MAX]; + + /* If 1, it's a repeated match. The distance is one of rep0 .. rep3. */ + uint16_t is_rep[STATES]; + + /* + * If 0, distance of a repeated match is rep0. + * Otherwise check is_rep1. + */ + uint16_t is_rep0[STATES]; + + /* + * If 0, distance of a repeated match is rep1. + * Otherwise check is_rep2. + */ + uint16_t is_rep1[STATES]; + + /* If 0, distance of a repeated match is rep2. Otherwise it is rep3. */ + uint16_t is_rep2[STATES]; + + /* + * If 1, the repeated match has length of one byte. Otherwise + * the length is decoded from rep_len_decoder. + */ + uint16_t is_rep0_long[STATES][POS_STATES_MAX]; + + /* + * Probability tree for the highest two bits of the match + * distance. There is a separate probability tree for match + * lengths of 2 (i.e. MATCH_LEN_MIN), 3, 4, and [5, 273]. + */ + uint16_t dist_slot[DIST_STATES][DIST_SLOTS]; + + /* + * Probility trees for additional bits for match distance + * when the distance is in the range [4, 127]. + */ + uint16_t dist_special[FULL_DISTANCES - DIST_MODEL_END]; + + /* + * Probability tree for the lowest four bits of a match + * distance that is equal to or greater than 128. + */ + uint16_t dist_align[ALIGN_SIZE]; + + /* Length of a normal match */ + struct lzma_len_dec match_len_dec; + + /* Length of a repeated match */ + struct lzma_len_dec rep_len_dec; + + /* Probabilities of literals */ + uint16_t literal[LITERAL_CODERS_MAX][LITERAL_CODER_SIZE]; +}; + +struct lzma2_dec { + /* Position in xz_dec_lzma2_run(). */ + enum lzma2_seq { + SEQ_CONTROL, + SEQ_UNCOMPRESSED_1, + SEQ_UNCOMPRESSED_2, + SEQ_COMPRESSED_0, + SEQ_COMPRESSED_1, + SEQ_PROPERTIES, + SEQ_LZMA_PREPARE, + SEQ_LZMA_RUN, + SEQ_COPY + } sequence; + + /* Next position after decoding the compressed size of the chunk. */ + enum lzma2_seq next_sequence; + + /* Uncompressed size of LZMA chunk (2 MiB at maximum) */ + uint32_t uncompressed; + + /* + * Compressed size of LZMA chunk or compressed/uncompressed + * size of uncompressed chunk (64 KiB at maximum) + */ + uint32_t compressed; + + /* + * True if dictionary reset is needed. This is false before + * the first chunk (LZMA or uncompressed). + */ + bool need_dict_reset; + + /* + * True if new LZMA properties are needed. This is false + * before the first LZMA chunk. + */ + bool need_props; +}; + +struct xz_dec_lzma2 { + /* + * The order below is important on x86 to reduce code size and + * it shouldn't hurt on other platforms. Everything up to and + * including lzma.pos_mask are in the first 128 bytes on x86-32, + * which allows using smaller instructions to access those + * variables. On x86-64, fewer variables fit into the first 128 + * bytes, but this is still the best order without sacrificing + * the readability by splitting the structures. + */ + struct rc_dec rc; + struct dictionary dict; + struct lzma2_dec lzma2; + struct lzma_dec lzma; + + /* + * Temporary buffer which holds small number of input bytes between + * decoder calls. See lzma2_lzma() for details. + */ + struct { + uint32_t size; + uint8_t buf[3 * LZMA_IN_REQUIRED]; + } temp; +}; + +/************** + * Dictionary * + **************/ + +/* + * Reset the dictionary state. When in single-call mode, set up the beginning + * of the dictionary to point to the actual output buffer. + */ +static void XZ_FUNC dict_reset(struct dictionary *dict, struct xz_buf *b) +{ + if (DEC_IS_SINGLE(dict->mode)) { + dict->buf = b->out + b->out_pos; + dict->end = b->out_size - b->out_pos; + } + + dict->start = 0; + dict->pos = 0; + dict->limit = 0; + dict->full = 0; +} + +/* Set dictionary write limit */ +static void XZ_FUNC dict_limit(struct dictionary *dict, size_t out_max) +{ + if (dict->end - dict->pos <= out_max) + dict->limit = dict->end; + else + dict->limit = dict->pos + out_max; +} + +/* Return true if at least one byte can be written into the dictionary. */ +static __always_inline bool XZ_FUNC dict_has_space(const struct dictionary *dict) +{ + return dict->pos < dict->limit; +} + +/* + * Get a byte from the dictionary at the given distance. The distance is + * assumed to valid, or as a special case, zero when the dictionary is + * still empty. This special case is needed for single-call decoding to + * avoid writing a '\0' to the end of the destination buffer. + */ +static __always_inline uint32_t XZ_FUNC dict_get( + const struct dictionary *dict, uint32_t dist) +{ + size_t offset = dict->pos - dist - 1; + + if (dist >= dict->pos) + offset += dict->end; + + return dict->full > 0 ? dict->buf[offset] : 0; +} + +/* + * Put one byte into the dictionary. It is assumed that there is space for it. + */ +static inline void XZ_FUNC dict_put(struct dictionary *dict, uint8_t byte) +{ + dict->buf[dict->pos++] = byte; + + if (dict->full < dict->pos) + dict->full = dict->pos; +} + +/* + * Repeat given number of bytes from the given distance. If the distance is + * invalid, false is returned. On success, true is returned and *len is + * updated to indicate how many bytes were left to be repeated. + */ +static bool XZ_FUNC dict_repeat( + struct dictionary *dict, uint32_t *len, uint32_t dist) +{ + size_t back; + uint32_t left; + + if (dist >= dict->full || dist >= dict->size) + return false; + + left = min_t(size_t, dict->limit - dict->pos, *len); + *len -= left; + + back = dict->pos - dist - 1; + if (dist >= dict->pos) + back += dict->end; + + do { + dict->buf[dict->pos++] = dict->buf[back++]; + if (back == dict->end) + back = 0; + } while (--left > 0); + + if (dict->full < dict->pos) + dict->full = dict->pos; + + return true; +} + +/* Copy uncompressed data as is from input to dictionary and output buffers. */ +static void XZ_FUNC dict_uncompressed( + struct dictionary *dict, struct xz_buf *b, uint32_t *left) +{ + size_t copy_size; + + while (*left > 0 && b->in_pos < b->in_size + && b->out_pos < b->out_size) { + copy_size = min(b->in_size - b->in_pos, + b->out_size - b->out_pos); + if (copy_size > dict->end - dict->pos) + copy_size = dict->end - dict->pos; + if (copy_size > *left) + copy_size = *left; + + *left -= copy_size; + + memcpy(dict->buf + dict->pos, b->in + b->in_pos, copy_size); + dict->pos += copy_size; + + if (dict->full < dict->pos) + dict->full = dict->pos; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, b->in + b->in_pos, + copy_size); + } + + dict->start = dict->pos; + + b->out_pos += copy_size; + b->in_pos += copy_size; + } +} + +/* + * Flush pending data from dictionary to b->out. It is assumed that there is + * enough space in b->out. This is guaranteed because caller uses dict_limit() + * before decoding data into the dictionary. + */ +static uint32_t XZ_FUNC dict_flush(struct dictionary *dict, struct xz_buf *b) +{ + size_t copy_size = dict->pos - dict->start; + + if (DEC_IS_MULTI(dict->mode)) { + if (dict->pos == dict->end) + dict->pos = 0; + + memcpy(b->out + b->out_pos, dict->buf + dict->start, + copy_size); + } + + dict->start = dict->pos; + b->out_pos += copy_size; + return copy_size; +} + +/***************** + * Range decoder * + *****************/ + +/* Reset the range decoder. */ +static void XZ_FUNC rc_reset(struct rc_dec *rc) +{ + rc->range = (uint32_t)-1; + rc->code = 0; + rc->init_bytes_left = RC_INIT_BYTES; +} + +/* + * Read the first five initial bytes into rc->code if they haven't been + * read already. (Yes, the first byte gets completely ignored.) + */ +static bool XZ_FUNC rc_read_init(struct rc_dec *rc, struct xz_buf *b) +{ + while (rc->init_bytes_left > 0) { + if (b->in_pos == b->in_size) + return false; + + rc->code = (rc->code << 8) + b->in[b->in_pos++]; + --rc->init_bytes_left; + } + + return true; +} + +/* Return true if there may not be enough input for the next decoding loop. */ +static inline bool XZ_FUNC rc_limit_exceeded(const struct rc_dec *rc) +{ + return rc->in_pos > rc->in_limit; +} + +/* + * Return true if it is possible (from point of view of range decoder) that + * we have reached the end of the LZMA chunk. + */ +static inline bool XZ_FUNC rc_is_finished(const struct rc_dec *rc) +{ + return rc->code == 0; +} + +/* Read the next input byte if needed. */ +static __always_inline void XZ_FUNC rc_normalize(struct rc_dec *rc) +{ + if (rc->range < RC_TOP_VALUE) { + rc->range <<= RC_SHIFT_BITS; + rc->code = (rc->code << RC_SHIFT_BITS) + rc->in[rc->in_pos++]; + } +} + +/* + * Decode one bit. In some versions, this function has been split in three + * functions so that the compiler is supposed to be able to more easily avoid + * an extra branch. In this particular version of the LZMA decoder, this + * doesn't seem to be a good idea (tested with GCC 3.3.6, 3.4.6, and 4.3.3 + * on x86). Using a non-split version results in nicer looking code too. + * + * NOTE: This must return an int. Do not make it return a bool or the speed + * of the code generated by GCC 3.x decreases 10-15 %. (GCC 4.3 doesn't care, + * and it generates 10-20 % faster code than GCC 3.x from this file anyway.) + */ +static __always_inline int XZ_FUNC rc_bit(struct rc_dec *rc, uint16_t *prob) +{ + uint32_t bound; + int bit; + + rc_normalize(rc); + bound = (rc->range >> RC_BIT_MODEL_TOTAL_BITS) * *prob; + if (rc->code < bound) { + rc->range = bound; + *prob += (RC_BIT_MODEL_TOTAL - *prob) >> RC_MOVE_BITS; + bit = 0; + } else { + rc->range -= bound; + rc->code -= bound; + *prob -= *prob >> RC_MOVE_BITS; + bit = 1; + } + + return bit; +} + +/* Decode a bittree starting from the most significant bit. */ +static __always_inline uint32_t XZ_FUNC rc_bittree( + struct rc_dec *rc, uint16_t *probs, uint32_t limit) +{ + uint32_t symbol = 1; + + do { + if (rc_bit(rc, &probs[symbol])) + symbol = (symbol << 1) + 1; + else + symbol <<= 1; + } while (symbol < limit); + + return symbol; +} + +/* Decode a bittree starting from the least significant bit. */ +static __always_inline void XZ_FUNC rc_bittree_reverse(struct rc_dec *rc, + uint16_t *probs, uint32_t *dest, uint32_t limit) +{ + uint32_t symbol = 1; + uint32_t i = 0; + + do { + if (rc_bit(rc, &probs[symbol])) { + symbol = (symbol << 1) + 1; + *dest += 1 << i; + } else { + symbol <<= 1; + } + } while (++i < limit); +} + +/* Decode direct bits (fixed fifty-fifty probability) */ +static inline void XZ_FUNC rc_direct( + struct rc_dec *rc, uint32_t *dest, uint32_t limit) +{ + uint32_t mask; + + do { + rc_normalize(rc); + rc->range >>= 1; + rc->code -= rc->range; + mask = (uint32_t)0 - (rc->code >> 31); + rc->code += rc->range & mask; + *dest = (*dest << 1) + (mask + 1); + } while (--limit > 0); +} + +/******** + * LZMA * + ********/ + +/* Get pointer to literal coder probability array. */ +static uint16_t * XZ_FUNC lzma_literal_probs(struct xz_dec_lzma2 *s) +{ + uint32_t prev_byte = dict_get(&s->dict, 0); + uint32_t low = prev_byte >> (8 - s->lzma.lc); + uint32_t high = (s->dict.pos & s->lzma.literal_pos_mask) << s->lzma.lc; + return s->lzma.literal[low + high]; +} + +/* Decode a literal (one 8-bit byte) */ +static void XZ_FUNC lzma_literal(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + uint32_t symbol; + uint32_t match_byte; + uint32_t match_bit; + uint32_t offset; + uint32_t i; + + probs = lzma_literal_probs(s); + + if (lzma_state_is_literal(s->lzma.state)) { + symbol = rc_bittree(&s->rc, probs, 0x100); + } else { + symbol = 1; + match_byte = dict_get(&s->dict, s->lzma.rep0) << 1; + offset = 0x100; + + do { + match_bit = match_byte & offset; + match_byte <<= 1; + i = offset + match_bit + symbol; + + if (rc_bit(&s->rc, &probs[i])) { + symbol = (symbol << 1) + 1; + offset &= match_bit; + } else { + symbol <<= 1; + offset &= ~match_bit; + } + } while (symbol < 0x100); + } + + dict_put(&s->dict, (uint8_t)symbol); + lzma_state_literal(&s->lzma.state); +} + +/* Decode the length of the match into s->lzma.len. */ +static void XZ_FUNC lzma_len(struct xz_dec_lzma2 *s, struct lzma_len_dec *l, + uint32_t pos_state) +{ + uint16_t *probs; + uint32_t limit; + + if (!rc_bit(&s->rc, &l->choice)) { + probs = l->low[pos_state]; + limit = LEN_LOW_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN; + } else { + if (!rc_bit(&s->rc, &l->choice2)) { + probs = l->mid[pos_state]; + limit = LEN_MID_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS; + } else { + probs = l->high; + limit = LEN_HIGH_SYMBOLS; + s->lzma.len = MATCH_LEN_MIN + LEN_LOW_SYMBOLS + + LEN_MID_SYMBOLS; + } + } + + s->lzma.len += rc_bittree(&s->rc, probs, limit) - limit; +} + +/* Decode a match. The distance will be stored in s->lzma.rep0. */ +static void XZ_FUNC lzma_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint16_t *probs; + uint32_t dist_slot; + uint32_t limit; + + lzma_state_match(&s->lzma.state); + + s->lzma.rep3 = s->lzma.rep2; + s->lzma.rep2 = s->lzma.rep1; + s->lzma.rep1 = s->lzma.rep0; + + lzma_len(s, &s->lzma.match_len_dec, pos_state); + + probs = s->lzma.dist_slot[lzma_get_dist_state(s->lzma.len)]; + dist_slot = rc_bittree(&s->rc, probs, DIST_SLOTS) - DIST_SLOTS; + + if (dist_slot < DIST_MODEL_START) { + s->lzma.rep0 = dist_slot; + } else { + limit = (dist_slot >> 1) - 1; + s->lzma.rep0 = 2 + (dist_slot & 1); + + if (dist_slot < DIST_MODEL_END) { + s->lzma.rep0 <<= limit; + probs = s->lzma.dist_special + s->lzma.rep0 + - dist_slot - 1; + rc_bittree_reverse(&s->rc, probs, + &s->lzma.rep0, limit); + } else { + rc_direct(&s->rc, &s->lzma.rep0, limit - ALIGN_BITS); + s->lzma.rep0 <<= ALIGN_BITS; + rc_bittree_reverse(&s->rc, s->lzma.dist_align, + &s->lzma.rep0, ALIGN_BITS); + } + } +} + +/* + * Decode a repeated match. The distance is one of the four most recently + * seen matches. The distance will be stored in s->lzma.rep0. + */ +static void XZ_FUNC lzma_rep_match(struct xz_dec_lzma2 *s, uint32_t pos_state) +{ + uint32_t tmp; + + if (!rc_bit(&s->rc, &s->lzma.is_rep0[s->lzma.state])) { + if (!rc_bit(&s->rc, &s->lzma.is_rep0_long[ + s->lzma.state][pos_state])) { + lzma_state_short_rep(&s->lzma.state); + s->lzma.len = 1; + return; + } + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep1[s->lzma.state])) { + tmp = s->lzma.rep1; + } else { + if (!rc_bit(&s->rc, &s->lzma.is_rep2[s->lzma.state])) { + tmp = s->lzma.rep2; + } else { + tmp = s->lzma.rep3; + s->lzma.rep3 = s->lzma.rep2; + } + + s->lzma.rep2 = s->lzma.rep1; + } + + s->lzma.rep1 = s->lzma.rep0; + s->lzma.rep0 = tmp; + } + + lzma_state_long_rep(&s->lzma.state); + lzma_len(s, &s->lzma.rep_len_dec, pos_state); +} + +/* LZMA decoder core */ +static bool XZ_FUNC lzma_main(struct xz_dec_lzma2 *s) +{ + uint32_t pos_state; + + /* + * If the dictionary was reached during the previous call, try to + * finish the possibly pending repeat in the dictionary. + */ + if (dict_has_space(&s->dict) && s->lzma.len > 0) + dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0); + + /* + * Decode more LZMA symbols. One iteration may consume up to + * LZMA_IN_REQUIRED - 1 bytes. + */ + while (dict_has_space(&s->dict) && !rc_limit_exceeded(&s->rc)) { + pos_state = s->dict.pos & s->lzma.pos_mask; + + if (!rc_bit(&s->rc, &s->lzma.is_match[ + s->lzma.state][pos_state])) { + lzma_literal(s); + } else { + if (rc_bit(&s->rc, &s->lzma.is_rep[s->lzma.state])) + lzma_rep_match(s, pos_state); + else + lzma_match(s, pos_state); + + if (!dict_repeat(&s->dict, &s->lzma.len, s->lzma.rep0)) + return false; + } + } + + /* + * Having the range decoder always normalized when we are outside + * this function makes it easier to correctly handle end of the chunk. + */ + rc_normalize(&s->rc); + + return true; +} + +/* + * Reset the LZMA decoder and range decoder state. Dictionary is nore reset + * here, because LZMA state may be reset without resetting the dictionary. + */ +static void XZ_FUNC lzma_reset(struct xz_dec_lzma2 *s) +{ + uint16_t *probs; + size_t i; + + s->lzma.state = STATE_LIT_LIT; + s->lzma.rep0 = 0; + s->lzma.rep1 = 0; + s->lzma.rep2 = 0; + s->lzma.rep3 = 0; + + /* + * All probabilities are initialized to the same value. This hack + * makes the code smaller by avoiding a separate loop for each + * probability array. + * + * This could be optimized so that only that part of literal + * probabilities that are actually required. In the common case + * we would write 12 KiB less. + */ + probs = s->lzma.is_match[0]; + for (i = 0; i < PROBS_TOTAL; ++i) + probs[i] = RC_BIT_MODEL_TOTAL / 2; + + rc_reset(&s->rc); +} + +/* + * Decode and validate LZMA properties (lc/lp/pb) and calculate the bit masks + * from the decoded lp and pb values. On success, the LZMA decoder state is + * reset and true is returned. + */ +static bool XZ_FUNC lzma_props(struct xz_dec_lzma2 *s, uint8_t props) +{ + if (props > (4 * 5 + 4) * 9 + 8) + return false; + + s->lzma.pos_mask = 0; + while (props >= 9 * 5) { + props -= 9 * 5; + ++s->lzma.pos_mask; + } + + s->lzma.pos_mask = (1 << s->lzma.pos_mask) - 1; + + s->lzma.literal_pos_mask = 0; + while (props >= 9) { + props -= 9; + ++s->lzma.literal_pos_mask; + } + + s->lzma.lc = props; + + if (s->lzma.lc + s->lzma.literal_pos_mask > 4) + return false; + + s->lzma.literal_pos_mask = (1 << s->lzma.literal_pos_mask) - 1; + + lzma_reset(s); + + return true; +} + +/********* + * LZMA2 * + *********/ + +/* + * The LZMA decoder assumes that if the input limit (s->rc.in_limit) hasn't + * been exceeded, it is safe to read up to LZMA_IN_REQUIRED bytes. This + * wrapper function takes care of making the LZMA decoder's assumption safe. + * + * As long as there is plenty of input left to be decoded in the current LZMA + * chunk, we decode directly from the caller-supplied input buffer until + * there's LZMA_IN_REQUIRED bytes left. Those remaining bytes are copied into + * s->temp.buf, which (hopefully) gets filled on the next call to this + * function. We decode a few bytes from the temporary buffer so that we can + * continue decoding from the caller-supplied input buffer again. + */ +static bool XZ_FUNC lzma2_lzma(struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + size_t in_avail; + uint32_t tmp; + + in_avail = b->in_size - b->in_pos; + if (s->temp.size > 0 || s->lzma2.compressed == 0) { + tmp = 2 * LZMA_IN_REQUIRED - s->temp.size; + if (tmp > s->lzma2.compressed - s->temp.size) + tmp = s->lzma2.compressed - s->temp.size; + if (tmp > in_avail) + tmp = in_avail; + + memcpy(s->temp.buf + s->temp.size, b->in + b->in_pos, tmp); + + if (s->temp.size + tmp == s->lzma2.compressed) { + memzero(s->temp.buf + s->temp.size + tmp, + sizeof(s->temp.buf) + - s->temp.size - tmp); + s->rc.in_limit = s->temp.size + tmp; + } else if (s->temp.size + tmp < LZMA_IN_REQUIRED) { + s->temp.size += tmp; + b->in_pos += tmp; + return true; + } else { + s->rc.in_limit = s->temp.size + tmp - LZMA_IN_REQUIRED; + } + + s->rc.in = s->temp.buf; + s->rc.in_pos = 0; + + if (!lzma_main(s) || s->rc.in_pos > s->temp.size + tmp) + return false; + + s->lzma2.compressed -= s->rc.in_pos; + + if (s->rc.in_pos < s->temp.size) { + s->temp.size -= s->rc.in_pos; + memmove(s->temp.buf, s->temp.buf + s->rc.in_pos, + s->temp.size); + return true; + } + + b->in_pos += s->rc.in_pos - s->temp.size; + s->temp.size = 0; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail >= LZMA_IN_REQUIRED) { + s->rc.in = b->in; + s->rc.in_pos = b->in_pos; + + if (in_avail >= s->lzma2.compressed + LZMA_IN_REQUIRED) + s->rc.in_limit = b->in_pos + s->lzma2.compressed; + else + s->rc.in_limit = b->in_size - LZMA_IN_REQUIRED; + + if (!lzma_main(s)) + return false; + + in_avail = s->rc.in_pos - b->in_pos; + if (in_avail > s->lzma2.compressed) + return false; + + s->lzma2.compressed -= in_avail; + b->in_pos = s->rc.in_pos; + } + + in_avail = b->in_size - b->in_pos; + if (in_avail < LZMA_IN_REQUIRED) { + if (in_avail > s->lzma2.compressed) + in_avail = s->lzma2.compressed; + + memcpy(s->temp.buf, b->in + b->in_pos, in_avail); + s->temp.size = in_avail; + b->in_pos += in_avail; + } + + return true; +} + +/* + * Take care of the LZMA2 control layer, and forward the job of actual LZMA + * decoding or copying of uncompressed chunks to other functions. + */ +XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b) +{ + uint32_t tmp; + + while (b->in_pos < b->in_size || s->lzma2.sequence == SEQ_LZMA_RUN) { + switch (s->lzma2.sequence) { + case SEQ_CONTROL: + /* + * LZMA2 control byte + * + * Exact values: + * 0x00 End marker + * 0x01 Dictionary reset followed by + * an uncompressed chunk + * 0x02 Uncompressed chunk (no dictionary reset) + * + * Highest three bits (s->control & 0xE0): + * 0xE0 Dictionary reset, new properties and state + * reset, followed by LZMA compressed chunk + * 0xC0 New properties and state reset, followed + * by LZMA compressed chunk (no dictionary + * reset) + * 0xA0 State reset using old properties, + * followed by LZMA compressed chunk (no + * dictionary reset) + * 0x80 LZMA chunk (no dictionary or state reset) + * + * For LZMA compressed chunks, the lowest five bits + * (s->control & 1F) are the highest bits of the + * uncompressed size (bits 16-20). + * + * A new LZMA2 stream must begin with a dictionary + * reset. The first LZMA chunk must set new + * properties and reset the LZMA state. + * + * Values that don't match anything described above + * are invalid and we return XZ_DATA_ERROR. + */ + tmp = b->in[b->in_pos++]; + + if (tmp == 0x00) + return XZ_STREAM_END; + + if (tmp >= 0xE0 || tmp == 0x01) { + s->lzma2.need_props = true; + s->lzma2.need_dict_reset = false; + dict_reset(&s->dict, b); + } else if (s->lzma2.need_dict_reset) { + return XZ_DATA_ERROR; + } + + if (tmp >= 0x80) { + s->lzma2.uncompressed = (tmp & 0x1F) << 16; + s->lzma2.sequence = SEQ_UNCOMPRESSED_1; + + if (tmp >= 0xC0) { + /* + * When there are new properties, + * state reset is done at + * SEQ_PROPERTIES. + */ + s->lzma2.need_props = false; + s->lzma2.next_sequence + = SEQ_PROPERTIES; + } else if (s->lzma2.need_props) { + return XZ_DATA_ERROR; + } else { + s->lzma2.next_sequence + = SEQ_LZMA_PREPARE; + if (tmp >= 0xA0) + lzma_reset(s); + } + } else { + if (tmp > 0x02) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_COMPRESSED_0; + s->lzma2.next_sequence = SEQ_COPY; + } + + break; + + case SEQ_UNCOMPRESSED_1: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_UNCOMPRESSED_2; + break; + + case SEQ_UNCOMPRESSED_2: + s->lzma2.uncompressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = SEQ_COMPRESSED_0; + break; + + case SEQ_COMPRESSED_0: + s->lzma2.compressed + = (uint32_t)b->in[b->in_pos++] << 8; + s->lzma2.sequence = SEQ_COMPRESSED_1; + break; + + case SEQ_COMPRESSED_1: + s->lzma2.compressed + += (uint32_t)b->in[b->in_pos++] + 1; + s->lzma2.sequence = s->lzma2.next_sequence; + break; + + case SEQ_PROPERTIES: + if (!lzma_props(s, b->in[b->in_pos++])) + return XZ_DATA_ERROR; + + s->lzma2.sequence = SEQ_LZMA_PREPARE; + + case SEQ_LZMA_PREPARE: + if (s->lzma2.compressed < RC_INIT_BYTES) + return XZ_DATA_ERROR; + + if (!rc_read_init(&s->rc, b)) + return XZ_OK; + + s->lzma2.compressed -= RC_INIT_BYTES; + s->lzma2.sequence = SEQ_LZMA_RUN; + + case SEQ_LZMA_RUN: + /* + * Set dictionary limit to indicate how much we want + * to be encoded at maximum. Decode new data into the + * dictionary. Flush the new data from dictionary to + * b->out. Check if we finished decoding this chunk. + * In case the dictionary got full but we didn't fill + * the output buffer yet, we may run this loop + * multiple times without changing s->lzma2.sequence. + */ + dict_limit(&s->dict, min_t(size_t, + b->out_size - b->out_pos, + s->lzma2.uncompressed)); + if (!lzma2_lzma(s, b)) + return XZ_DATA_ERROR; + + s->lzma2.uncompressed -= dict_flush(&s->dict, b); + + if (s->lzma2.uncompressed == 0) { + if (s->lzma2.compressed > 0 || s->lzma.len > 0 + || !rc_is_finished(&s->rc)) + return XZ_DATA_ERROR; + + rc_reset(&s->rc); + s->lzma2.sequence = SEQ_CONTROL; + } else if (b->out_pos == b->out_size + || (b->in_pos == b->in_size + && s->temp.size + < s->lzma2.compressed)) { + return XZ_OK; + } + + break; + + case SEQ_COPY: + dict_uncompressed(&s->dict, b, &s->lzma2.compressed); + if (s->lzma2.compressed > 0) + return XZ_OK; + + s->lzma2.sequence = SEQ_CONTROL; + break; + } + } + + return XZ_OK; +} + +XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( + enum xz_mode mode, uint32_t dict_max) +{ + struct xz_dec_lzma2 *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->dict.mode = mode; + s->dict.size_max = dict_max; + + if (DEC_IS_PREALLOC(mode)) { + s->dict.buf = vmalloc(dict_max); + if (s->dict.buf == NULL) { + kfree(s); + return NULL; + } + } else if (DEC_IS_DYNALLOC(mode)) { + s->dict.buf = NULL; + s->dict.allocated = 0; + } + + return s; +} + +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props) +{ + /* This limits dictionary size to 3 GiB to keep parsing simpler. */ + if (props > 39) + return XZ_OPTIONS_ERROR; + + s->dict.size = 2 + (props & 1); + s->dict.size <<= (props >> 1) + 11; + + if (DEC_IS_MULTI(s->dict.mode)) { + if (s->dict.size > s->dict.size_max) + return XZ_MEMLIMIT_ERROR; + + s->dict.end = s->dict.size; + + if (DEC_IS_DYNALLOC(s->dict.mode)) { + if (s->dict.allocated < s->dict.size) { + vfree(s->dict.buf); + s->dict.buf = vmalloc(s->dict.size); + if (s->dict.buf == NULL) { + s->dict.allocated = 0; + return XZ_MEM_ERROR; + } + } + } + } + + s->lzma.len = 0; + + s->lzma2.sequence = SEQ_CONTROL; + s->lzma2.need_dict_reset = true; + + s->temp.size = 0; + + return XZ_OK; +} + +XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s) +{ + if (DEC_IS_MULTI(s->dict.mode)) + vfree(s->dict.buf); + + kfree(s); +} diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_dec_stream.c b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_stream.c new file mode 100644 index 000000000..31158b4e8 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_dec_stream.c @@ -0,0 +1,820 @@ +/* + * .xz Stream decoder + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#include "xz_private.h" +#include "xz_stream.h" + +/* Hash used to validate the Index field */ +struct xz_dec_hash { + vli_type unpadded; + vli_type uncompressed; + uint32_t crc32; +}; + +struct xz_dec { + /* Position in dec_main() */ + enum { + SEQ_STREAM_HEADER, + SEQ_BLOCK_START, + SEQ_BLOCK_HEADER, + SEQ_BLOCK_UNCOMPRESS, + SEQ_BLOCK_PADDING, + SEQ_BLOCK_CHECK, + SEQ_INDEX, + SEQ_INDEX_PADDING, + SEQ_INDEX_CRC32, + SEQ_STREAM_FOOTER + } sequence; + + /* Position in variable-length integers and Check fields */ + uint32_t pos; + + /* Variable-length integer decoded by dec_vli() */ + vli_type vli; + + /* Saved in_pos and out_pos */ + size_t in_start; + size_t out_start; + + /* CRC32 value in Block or Index */ + uint32_t crc32; + + /* Type of the integrity check calculated from uncompressed data */ + enum xz_check check_type; + + /* Operation mode */ + enum xz_mode mode; + + /* + * True if the next call to xz_dec_run() is allowed to return + * XZ_BUF_ERROR. + */ + bool allow_buf_error; + + /* Information stored in Block Header */ + struct { + /* + * Value stored in the Compressed Size field, or + * VLI_UNKNOWN if Compressed Size is not present. + */ + vli_type compressed; + + /* + * Value stored in the Uncompressed Size field, or + * VLI_UNKNOWN if Uncompressed Size is not present. + */ + vli_type uncompressed; + + /* Size of the Block Header field */ + uint32_t size; + } block_header; + + /* Information collected when decoding Blocks */ + struct { + /* Observed compressed size of the current Block */ + vli_type compressed; + + /* Observed uncompressed size of the current Block */ + vli_type uncompressed; + + /* Number of Blocks decoded so far */ + vli_type count; + + /* + * Hash calculated from the Block sizes. This is used to + * validate the Index field. + */ + struct xz_dec_hash hash; + } block; + + /* Variables needed when verifying the Index field */ + struct { + /* Position in dec_index() */ + enum { + SEQ_INDEX_COUNT, + SEQ_INDEX_UNPADDED, + SEQ_INDEX_UNCOMPRESSED + } sequence; + + /* Size of the Index in bytes */ + vli_type size; + + /* Number of Records (matches block.count in valid files) */ + vli_type count; + + /* + * Hash calculated from the Records (matches block.hash in + * valid files). + */ + struct xz_dec_hash hash; + } index; + + /* + * Temporary buffer needed to hold Stream Header, Block Header, + * and Stream Footer. The Block Header is the biggest (1 KiB) + * so we reserve space according to that. buf[] has to be aligned + * to a multiple of four bytes; the size_t variables before it + * should guarantee this. + */ + struct { + size_t pos; + size_t size; + uint8_t buf[1024]; + } temp; + + struct xz_dec_lzma2 *lzma2; + +#ifdef XZ_DEC_BCJ + struct xz_dec_bcj *bcj; + bool bcj_active; +#endif +}; + +#ifdef XZ_DEC_ANY_CHECK +/* Sizes of the Check field with different Check IDs */ +static const uint8_t check_sizes[16] = { + 0, + 4, 4, 4, + 8, 8, 8, + 16, 16, 16, + 32, 32, 32, + 64, 64, 64 +}; +#endif + +/* + * Fill s->temp by copying data starting from b->in[b->in_pos]. Caller + * must have set s->temp.pos to indicate how much data we are supposed + * to copy into s->temp.buf. Return true once s->temp.pos has reached + * s->temp.size. + */ +static bool XZ_FUNC fill_temp(struct xz_dec *s, struct xz_buf *b) +{ + size_t copy_size = min_t(size_t, + b->in_size - b->in_pos, s->temp.size - s->temp.pos); + + memcpy(s->temp.buf + s->temp.pos, b->in + b->in_pos, copy_size); + b->in_pos += copy_size; + s->temp.pos += copy_size; + + if (s->temp.pos == s->temp.size) { + s->temp.pos = 0; + return true; + } + + return false; +} + +/* Decode a variable-length integer (little-endian base-128 encoding) */ +static enum xz_ret XZ_FUNC dec_vli(struct xz_dec *s, + const uint8_t *in, size_t *in_pos, size_t in_size) +{ + uint8_t byte; + + if (s->pos == 0) + s->vli = 0; + + while (*in_pos < in_size) { + byte = in[*in_pos]; + ++*in_pos; + + s->vli |= (vli_type)(byte & 0x7F) << s->pos; + + if ((byte & 0x80) == 0) { + /* Don't allow non-minimal encodings. */ + if (byte == 0 && s->pos != 0) + return XZ_DATA_ERROR; + + s->pos = 0; + return XZ_STREAM_END; + } + + s->pos += 7; + if (s->pos == 7 * VLI_BYTES_MAX) + return XZ_DATA_ERROR; + } + + return XZ_OK; +} + +/* + * Decode the Compressed Data field from a Block. Update and validate + * the observed compressed and uncompressed sizes of the Block so that + * they don't exceed the values possibly stored in the Block Header + * (validation assumes that no integer overflow occurs, since vli_type + * is normally uint64_t). Update the CRC32 if presence of the CRC32 + * field was indicated in Stream Header. + * + * Once the decoding is finished, validate that the observed sizes match + * the sizes possibly stored in the Block Header. Update the hash and + * Block count, which are later used to validate the Index field. + */ +static enum xz_ret XZ_FUNC dec_block(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + s->in_start = b->in_pos; + s->out_start = b->out_pos; + +#ifdef XZ_DEC_BCJ + if (s->bcj_active) + ret = xz_dec_bcj_run(s->bcj, s->lzma2, b); + else +#endif + ret = xz_dec_lzma2_run(s->lzma2, b); + + s->block.compressed += b->in_pos - s->in_start; + s->block.uncompressed += b->out_pos - s->out_start; + + /* + * There is no need to separately check for VLI_UNKNOWN, since + * the observed sizes are always smaller than VLI_UNKNOWN. + */ + if (s->block.compressed > s->block_header.compressed + || s->block.uncompressed + > s->block_header.uncompressed) + return XZ_DATA_ERROR; + + if (s->check_type == XZ_CHECK_CRC32) + s->crc32 = xz_crc32(b->out + s->out_start, + b->out_pos - s->out_start, s->crc32); + + if (ret == XZ_STREAM_END) { + if (s->block_header.compressed != VLI_UNKNOWN + && s->block_header.compressed + != s->block.compressed) + return XZ_DATA_ERROR; + + if (s->block_header.uncompressed != VLI_UNKNOWN + && s->block_header.uncompressed + != s->block.uncompressed) + return XZ_DATA_ERROR; + + s->block.hash.unpadded += s->block_header.size + + s->block.compressed; + +#ifdef XZ_DEC_ANY_CHECK + s->block.hash.unpadded += check_sizes[s->check_type]; +#else + if (s->check_type == XZ_CHECK_CRC32) + s->block.hash.unpadded += 4; +#endif + + s->block.hash.uncompressed += s->block.uncompressed; + s->block.hash.crc32 = xz_crc32( + (const uint8_t *)&s->block.hash, + sizeof(s->block.hash), s->block.hash.crc32); + + ++s->block.count; + } + + return ret; +} + +/* Update the Index size and the CRC32 value. */ +static void XZ_FUNC index_update(struct xz_dec *s, const struct xz_buf *b) +{ + size_t in_used = b->in_pos - s->in_start; + s->index.size += in_used; + s->crc32 = xz_crc32(b->in + s->in_start, in_used, s->crc32); +} + +/* + * Decode the Number of Records, Unpadded Size, and Uncompressed Size + * fields from the Index field. That is, Index Padding and CRC32 are not + * decoded by this function. + * + * This can return XZ_OK (more input needed), XZ_STREAM_END (everything + * successfully decoded), or XZ_DATA_ERROR (input is corrupt). + */ +static enum xz_ret XZ_FUNC dec_index(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + do { + ret = dec_vli(s, b->in, &b->in_pos, b->in_size); + if (ret != XZ_STREAM_END) { + index_update(s, b); + return ret; + } + + switch (s->index.sequence) { + case SEQ_INDEX_COUNT: + s->index.count = s->vli; + + /* + * Validate that the Number of Records field + * indicates the same number of Records as + * there were Blocks in the Stream. + */ + if (s->index.count != s->block.count) + return XZ_DATA_ERROR; + + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + + case SEQ_INDEX_UNPADDED: + s->index.hash.unpadded += s->vli; + s->index.sequence = SEQ_INDEX_UNCOMPRESSED; + break; + + case SEQ_INDEX_UNCOMPRESSED: + s->index.hash.uncompressed += s->vli; + s->index.hash.crc32 = xz_crc32( + (const uint8_t *)&s->index.hash, + sizeof(s->index.hash), + s->index.hash.crc32); + --s->index.count; + s->index.sequence = SEQ_INDEX_UNPADDED; + break; + } + } while (s->index.count > 0); + + return XZ_STREAM_END; +} + +/* + * Validate that the next four input bytes match the value of s->crc32. + * s->pos must be zero when starting to validate the first byte. + */ +static enum xz_ret XZ_FUNC crc32_validate(struct xz_dec *s, struct xz_buf *b) +{ + do { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (((s->crc32 >> s->pos) & 0xFF) != b->in[b->in_pos++]) + return XZ_DATA_ERROR; + + s->pos += 8; + } while (s->pos < 32); + + s->crc32 = 0; + s->pos = 0; + + return XZ_STREAM_END; +} + +#ifdef XZ_DEC_ANY_CHECK +/* + * Skip over the Check field when the Check ID is not supported. + * Returns true once the whole Check field has been skipped over. + */ +static bool XZ_FUNC check_skip(struct xz_dec *s, struct xz_buf *b) +{ + while (s->pos < check_sizes[s->check_type]) { + if (b->in_pos == b->in_size) + return false; + + ++b->in_pos; + ++s->pos; + } + + s->pos = 0; + + return true; +} +#endif + +/* Decode the Stream Header field (the first 12 bytes of the .xz Stream). */ +static enum xz_ret XZ_FUNC dec_stream_header(struct xz_dec *s) +{ + if (!memeq(s->temp.buf, HEADER_MAGIC, HEADER_MAGIC_SIZE)) + return XZ_FORMAT_ERROR; + + if (xz_crc32(s->temp.buf + HEADER_MAGIC_SIZE, 2, 0) + != get_le32(s->temp.buf + HEADER_MAGIC_SIZE + 2)) + return XZ_DATA_ERROR; + + if (s->temp.buf[HEADER_MAGIC_SIZE] != 0) + return XZ_OPTIONS_ERROR; + + /* + * Of integrity checks, we support only none (Check ID = 0) and + * CRC32 (Check ID = 1). However, if XZ_DEC_ANY_CHECK is defined, + * we will accept other check types too, but then the check won't + * be verified and a warning (XZ_UNSUPPORTED_CHECK) will be given. + */ + s->check_type = s->temp.buf[HEADER_MAGIC_SIZE + 1]; + +#ifdef XZ_DEC_ANY_CHECK + if (s->check_type > XZ_CHECK_MAX) + return XZ_OPTIONS_ERROR; + + if (s->check_type > XZ_CHECK_CRC32) + return XZ_UNSUPPORTED_CHECK; +#else + if (s->check_type > XZ_CHECK_CRC32) + return XZ_OPTIONS_ERROR; +#endif + + return XZ_OK; +} + +/* Decode the Stream Footer field (the last 12 bytes of the .xz Stream) */ +static enum xz_ret XZ_FUNC dec_stream_footer(struct xz_dec *s) +{ + if (!memeq(s->temp.buf + 10, FOOTER_MAGIC, FOOTER_MAGIC_SIZE)) + return XZ_DATA_ERROR; + + if (xz_crc32(s->temp.buf + 4, 6, 0) != get_le32(s->temp.buf)) + return XZ_DATA_ERROR; + + /* + * Validate Backward Size. Note that we never added the size of the + * Index CRC32 field to s->index.size, thus we use s->index.size / 4 + * instead of s->index.size / 4 - 1. + */ + if ((s->index.size >> 2) != get_le32(s->temp.buf + 4)) + return XZ_DATA_ERROR; + + if (s->temp.buf[8] != 0 || s->temp.buf[9] != s->check_type) + return XZ_DATA_ERROR; + + /* + * Use XZ_STREAM_END instead of XZ_OK to be more convenient + * for the caller. + */ + return XZ_STREAM_END; +} + +/* Decode the Block Header and initialize the filter chain. */ +static enum xz_ret XZ_FUNC dec_block_header(struct xz_dec *s) +{ + enum xz_ret ret; + + /* + * Validate the CRC32. We know that the temp buffer is at least + * eight bytes so this is safe. + */ + s->temp.size -= 4; + if (xz_crc32(s->temp.buf, s->temp.size, 0) + != get_le32(s->temp.buf + s->temp.size)) + return XZ_DATA_ERROR; + + s->temp.pos = 2; + + /* + * Catch unsupported Block Flags. We support only one or two filters + * in the chain, so we catch that with the same test. + */ +#ifdef XZ_DEC_BCJ + if (s->temp.buf[1] & 0x3E) +#else + if (s->temp.buf[1] & 0x3F) +#endif + return XZ_OPTIONS_ERROR; + + /* Compressed Size */ + if (s->temp.buf[1] & 0x40) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.compressed = s->vli; + } else { + s->block_header.compressed = VLI_UNKNOWN; + } + + /* Uncompressed Size */ + if (s->temp.buf[1] & 0x80) { + if (dec_vli(s, s->temp.buf, &s->temp.pos, s->temp.size) + != XZ_STREAM_END) + return XZ_DATA_ERROR; + + s->block_header.uncompressed = s->vli; + } else { + s->block_header.uncompressed = VLI_UNKNOWN; + } + +#ifdef XZ_DEC_BCJ + /* If there are two filters, the first one must be a BCJ filter. */ + s->bcj_active = s->temp.buf[1] & 0x01; + if (s->bcj_active) { + if (s->temp.size - s->temp.pos < 2) + return XZ_OPTIONS_ERROR; + + ret = xz_dec_bcj_reset(s->bcj, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* + * We don't support custom start offset, + * so Size of Properties must be zero. + */ + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + } +#endif + + /* Valid Filter Flags always take at least two bytes. */ + if (s->temp.size - s->temp.pos < 2) + return XZ_DATA_ERROR; + + /* Filter ID = LZMA2 */ + if (s->temp.buf[s->temp.pos++] != 0x21) + return XZ_OPTIONS_ERROR; + + /* Size of Properties = 1-byte Filter Properties */ + if (s->temp.buf[s->temp.pos++] != 0x01) + return XZ_OPTIONS_ERROR; + + /* Filter Properties contains LZMA2 dictionary size. */ + if (s->temp.size - s->temp.pos < 1) + return XZ_DATA_ERROR; + + ret = xz_dec_lzma2_reset(s->lzma2, s->temp.buf[s->temp.pos++]); + if (ret != XZ_OK) + return ret; + + /* The rest must be Header Padding. */ + while (s->temp.pos < s->temp.size) + if (s->temp.buf[s->temp.pos++] != 0x00) + return XZ_OPTIONS_ERROR; + + s->temp.pos = 0; + s->block.compressed = 0; + s->block.uncompressed = 0; + + return XZ_OK; +} + +static NOINLINE enum xz_ret XZ_FUNC dec_main(struct xz_dec *s, struct xz_buf *b) +{ + enum xz_ret ret; + + /* + * Store the start position for the case when we are in the middle + * of the Index field. + */ + s->in_start = b->in_pos; + + while (true) { + switch (s->sequence) { + case SEQ_STREAM_HEADER: + /* + * Stream Header is copied to s->temp, and then + * decoded from there. This way if the caller + * gives us only little input at a time, we can + * still keep the Stream Header decoding code + * simple. Similar approach is used in many places + * in this file. + */ + if (!fill_temp(s, b)) + return XZ_OK; + + /* + * If dec_stream_header() returns + * XZ_UNSUPPORTED_CHECK, it is still possible + * to continue decoding if working in multi-call + * mode. Thus, update s->sequence before calling + * dec_stream_header(). + */ + s->sequence = SEQ_BLOCK_START; + + ret = dec_stream_header(s); + if (ret != XZ_OK) + return ret; + + case SEQ_BLOCK_START: + /* We need one byte of input to continue. */ + if (b->in_pos == b->in_size) + return XZ_OK; + + /* See if this is the beginning of the Index field. */ + if (b->in[b->in_pos] == 0) { + s->in_start = b->in_pos++; + s->sequence = SEQ_INDEX; + break; + } + + /* + * Calculate the size of the Block Header and + * prepare to decode it. + */ + s->block_header.size + = ((uint32_t)b->in[b->in_pos] + 1) * 4; + + s->temp.size = s->block_header.size; + s->temp.pos = 0; + s->sequence = SEQ_BLOCK_HEADER; + + case SEQ_BLOCK_HEADER: + if (!fill_temp(s, b)) + return XZ_OK; + + ret = dec_block_header(s); + if (ret != XZ_OK) + return ret; + + s->sequence = SEQ_BLOCK_UNCOMPRESS; + + case SEQ_BLOCK_UNCOMPRESS: + ret = dec_block(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_BLOCK_PADDING; + + case SEQ_BLOCK_PADDING: + /* + * Size of Compressed Data + Block Padding + * must be a multiple of four. We don't need + * s->block.compressed for anything else + * anymore, so we use it here to test the size + * of the Block Padding field. + */ + while (s->block.compressed & 3) { + if (b->in_pos == b->in_size) + return XZ_OK; + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + + ++s->block.compressed; + } + + s->sequence = SEQ_BLOCK_CHECK; + + case SEQ_BLOCK_CHECK: + if (s->check_type == XZ_CHECK_CRC32) { + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + } +#ifdef XZ_DEC_ANY_CHECK + else if (!check_skip(s, b)) { + return XZ_OK; + } +#endif + + s->sequence = SEQ_BLOCK_START; + break; + + case SEQ_INDEX: + ret = dec_index(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->sequence = SEQ_INDEX_PADDING; + + case SEQ_INDEX_PADDING: + while ((s->index.size + (b->in_pos - s->in_start)) + & 3) { + if (b->in_pos == b->in_size) { + index_update(s, b); + return XZ_OK; + } + + if (b->in[b->in_pos++] != 0) + return XZ_DATA_ERROR; + } + + /* Finish the CRC32 value and Index size. */ + index_update(s, b); + + /* Compare the hashes to validate the Index field. */ + if (!memeq(&s->block.hash, &s->index.hash, + sizeof(s->block.hash))) + return XZ_DATA_ERROR; + + s->sequence = SEQ_INDEX_CRC32; + + case SEQ_INDEX_CRC32: + ret = crc32_validate(s, b); + if (ret != XZ_STREAM_END) + return ret; + + s->temp.size = STREAM_HEADER_SIZE; + s->sequence = SEQ_STREAM_FOOTER; + + case SEQ_STREAM_FOOTER: + if (!fill_temp(s, b)) + return XZ_OK; + + return dec_stream_footer(s); + } + } + + /* Never reached */ +} + +/* + * xz_dec_run() is a wrapper for dec_main() to handle some special cases in + * multi-call and single-call decoding. + * + * In multi-call mode, we must return XZ_BUF_ERROR when it seems clear that we + * are not going to make any progress anymore. This is to prevent the caller + * from calling us infinitely when the input file is truncated or otherwise + * corrupt. Since zlib-style API allows that the caller fills the input buffer + * only when the decoder doesn't produce any new output, we have to be careful + * to avoid returning XZ_BUF_ERROR too easily: XZ_BUF_ERROR is returned only + * after the second consecutive call to xz_dec_run() that makes no progress. + * + * In single-call mode, if we couldn't decode everything and no error + * occurred, either the input is truncated or the output buffer is too small. + * Since we know that the last input byte never produces any output, we know + * that if all the input was consumed and decoding wasn't finished, the file + * must be corrupt. Otherwise the output buffer has to be too small or the + * file is corrupt in a way that decoding it produces too big output. + * + * If single-call decoding fails, we reset b->in_pos and b->out_pos back to + * their original values. This is because with some filter chains there won't + * be any valid uncompressed data in the output buffer unless the decoding + * actually succeeds (that's the price to pay of using the output buffer as + * the workspace). + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_run(struct xz_dec *s, struct xz_buf *b) +{ + size_t in_start; + size_t out_start; + enum xz_ret ret; + + if (DEC_IS_SINGLE(s->mode)) + xz_dec_reset(s); + + in_start = b->in_pos; + out_start = b->out_pos; + ret = dec_main(s, b); + + if (DEC_IS_SINGLE(s->mode)) { + if (ret == XZ_OK) + ret = b->in_pos == b->in_size + ? XZ_DATA_ERROR : XZ_BUF_ERROR; + + if (ret != XZ_STREAM_END) { + b->in_pos = in_start; + b->out_pos = out_start; + } + } else if (ret == XZ_OK && in_start == b->in_pos + && out_start == b->out_pos) { + if (s->allow_buf_error) + ret = XZ_BUF_ERROR; + + s->allow_buf_error = true; + } else { + s->allow_buf_error = false; + } + + return ret; +} + +XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( + enum xz_mode mode, uint32_t dict_max) +{ + struct xz_dec *s = kmalloc(sizeof(*s), GFP_KERNEL); + if (s == NULL) + return NULL; + + s->mode = mode; + +#ifdef XZ_DEC_BCJ + s->bcj = xz_dec_bcj_create(DEC_IS_SINGLE(mode)); + if (s->bcj == NULL) + goto error_bcj; +#endif + + s->lzma2 = xz_dec_lzma2_create(mode, dict_max); + if (s->lzma2 == NULL) + goto error_lzma2; + + xz_dec_reset(s); + return s; + +error_lzma2: +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +error_bcj: +#endif + kfree(s); + return NULL; +} + +XZ_EXTERN void XZ_FUNC xz_dec_reset(struct xz_dec *s) +{ + s->sequence = SEQ_STREAM_HEADER; + s->allow_buf_error = false; + s->pos = 0; + s->crc32 = 0; + memzero(&s->block, sizeof(s->block)); + memzero(&s->index, sizeof(s->index)); + s->temp.pos = 0; + s->temp.size = STREAM_HEADER_SIZE; +} + +XZ_EXTERN void XZ_FUNC xz_dec_end(struct xz_dec *s) +{ + if (s != NULL) { + xz_dec_lzma2_end(s->lzma2); +#ifdef XZ_DEC_BCJ + xz_dec_bcj_end(s->bcj); +#endif + kfree(s); + } +} diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_lzma2.h b/busybox-1_37_0/archival/libarchive/unxz/xz_lzma2.h new file mode 100644 index 000000000..47f21afbc --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_lzma2.h @@ -0,0 +1,204 @@ +/* + * LZMA2 definitions + * + * Authors: Lasse Collin + * Igor Pavlov + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_LZMA2_H +#define XZ_LZMA2_H + +/* Range coder constants */ +#define RC_SHIFT_BITS 8 +#define RC_TOP_BITS 24 +#define RC_TOP_VALUE (1 << RC_TOP_BITS) +#define RC_BIT_MODEL_TOTAL_BITS 11 +#define RC_BIT_MODEL_TOTAL (1 << RC_BIT_MODEL_TOTAL_BITS) +#define RC_MOVE_BITS 5 + +/* + * Maximum number of position states. A position state is the lowest pb + * number of bits of the current uncompressed offset. In some places there + * are different sets of probabilities for different position states. + */ +#define POS_STATES_MAX (1 << 4) + +/* + * This enum is used to track which LZMA symbols have occurred most recently + * and in which order. This information is used to predict the next symbol. + * + * Symbols: + * - Literal: One 8-bit byte + * - Match: Repeat a chunk of data at some distance + * - Long repeat: Multi-byte match at a recently seen distance + * - Short repeat: One-byte repeat at a recently seen distance + * + * The symbol names are in from STATE_oldest_older_previous. REP means + * either short or long repeated match, and NONLIT means any non-literal. + */ +enum lzma_state { + STATE_LIT_LIT, + STATE_MATCH_LIT_LIT, + STATE_REP_LIT_LIT, + STATE_SHORTREP_LIT_LIT, + STATE_MATCH_LIT, + STATE_REP_LIT, + STATE_SHORTREP_LIT, + STATE_LIT_MATCH, + STATE_LIT_LONGREP, + STATE_LIT_SHORTREP, + STATE_NONLIT_MATCH, + STATE_NONLIT_REP +}; + +/* Total number of states */ +#define STATES 12 + +/* The lowest 7 states indicate that the previous state was a literal. */ +#define LIT_STATES 7 + +/* Indicate that the latest symbol was a literal. */ +static inline void XZ_FUNC lzma_state_literal(enum lzma_state *state) +{ + if (*state <= STATE_SHORTREP_LIT_LIT) + *state = STATE_LIT_LIT; + else if (*state <= STATE_LIT_SHORTREP) + *state -= 3; + else + *state -= 6; +} + +/* Indicate that the latest symbol was a match. */ +static inline void XZ_FUNC lzma_state_match(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_MATCH : STATE_NONLIT_MATCH; +} + +/* Indicate that the latest state was a long repeated match. */ +static inline void XZ_FUNC lzma_state_long_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_LONGREP : STATE_NONLIT_REP; +} + +/* Indicate that the latest symbol was a short match. */ +static inline void XZ_FUNC lzma_state_short_rep(enum lzma_state *state) +{ + *state = *state < LIT_STATES ? STATE_LIT_SHORTREP : STATE_NONLIT_REP; +} + +/* Test if the previous symbol was a literal. */ +static inline bool XZ_FUNC lzma_state_is_literal(enum lzma_state state) +{ + return state < LIT_STATES; +} + +/* Each literal coder is divided in three sections: + * - 0x001-0x0FF: Without match byte + * - 0x101-0x1FF: With match byte; match bit is 0 + * - 0x201-0x2FF: With match byte; match bit is 1 + * + * Match byte is used when the previous LZMA symbol was something else than + * a literal (that is, it was some kind of match). + */ +#define LITERAL_CODER_SIZE 0x300 + +/* Maximum number of literal coders */ +#define LITERAL_CODERS_MAX (1 << 4) + +/* Minimum length of a match is two bytes. */ +#define MATCH_LEN_MIN 2 + +/* Match length is encoded with 4, 5, or 10 bits. + * + * Length Bits + * 2-9 4 = Choice=0 + 3 bits + * 10-17 5 = Choice=1 + Choice2=0 + 3 bits + * 18-273 10 = Choice=1 + Choice2=1 + 8 bits + */ +#define LEN_LOW_BITS 3 +#define LEN_LOW_SYMBOLS (1 << LEN_LOW_BITS) +#define LEN_MID_BITS 3 +#define LEN_MID_SYMBOLS (1 << LEN_MID_BITS) +#define LEN_HIGH_BITS 8 +#define LEN_HIGH_SYMBOLS (1 << LEN_HIGH_BITS) +#define LEN_SYMBOLS (LEN_LOW_SYMBOLS + LEN_MID_SYMBOLS + LEN_HIGH_SYMBOLS) + +/* + * Maximum length of a match is 273 which is a result of the encoding + * described above. + */ +#define MATCH_LEN_MAX (MATCH_LEN_MIN + LEN_SYMBOLS - 1) + +/* + * Different sets of probabilities are used for match distances that have + * very short match length: Lengths of 2, 3, and 4 bytes have a separate + * set of probabilities for each length. The matches with longer length + * use a shared set of probabilities. + */ +#define DIST_STATES 4 + +/* + * Get the index of the appropriate probability array for decoding + * the distance slot. + */ +static inline uint32_t XZ_FUNC lzma_get_dist_state(uint32_t len) +{ + return len < DIST_STATES + MATCH_LEN_MIN + ? len - MATCH_LEN_MIN : DIST_STATES - 1; +} + +/* + * The highest two bits of a 32-bit match distance are encoded using six bits. + * This six-bit value is called a distance slot. This way encoding a 32-bit + * value takes 6-36 bits, larger values taking more bits. + */ +#define DIST_SLOT_BITS 6 +#define DIST_SLOTS (1 << DIST_SLOT_BITS) + +/* Match distances up to 127 are fully encoded using probabilities. Since + * the highest two bits (distance slot) are always encoded using six bits, + * the distances 0-3 don't need any additional bits to encode, since the + * distance slot itself is the same as the actual distance. DIST_MODEL_START + * indicates the first distance slot where at least one additional bit is + * needed. + */ +#define DIST_MODEL_START 4 + +/* + * Match distances greater than 127 are encoded in three pieces: + * - distance slot: the highest two bits + * - direct bits: 2-26 bits below the highest two bits + * - alignment bits: four lowest bits + * + * Direct bits don't use any probabilities. + * + * The distance slot value of 14 is for distances 128-191. + */ +#define DIST_MODEL_END 14 + +/* Distance slots that indicate a distance <= 127. */ +#define FULL_DISTANCES_BITS (DIST_MODEL_END / 2) +#define FULL_DISTANCES (1 << FULL_DISTANCES_BITS) + +/* + * For match distances greater than 127, only the highest two bits and the + * lowest four bits (alignment) is encoded using probabilities. + */ +#define ALIGN_BITS 4 +#define ALIGN_SIZE (1 << ALIGN_BITS) +#define ALIGN_MASK (ALIGN_SIZE - 1) + +/* Total number of all probability variables */ +#define PROBS_TOTAL (1846 + LITERAL_CODERS_MAX * LITERAL_CODER_SIZE) + +/* + * LZMA remembers the four most recent match distances. Reusing these + * distances tends to take less space than re-encoding the actual + * distance value. + */ +#define REPS 4 + +#endif diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_private.h b/busybox-1_37_0/archival/libarchive/unxz/xz_private.h new file mode 100644 index 000000000..145649a83 --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_private.h @@ -0,0 +1,159 @@ +/* + * Private includes and definitions + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_PRIVATE_H +#define XZ_PRIVATE_H + +#ifdef __KERNEL__ + /* XZ_PREBOOT may be defined only via decompress_unxz.c. */ +# ifndef XZ_PREBOOT +# include +# include +# include +# define memeq(a, b, size) (memcmp(a, b, size) == 0) +# define memzero(buf, size) memset(buf, 0, size) +# endif +# include +# include +# define get_le32(p) le32_to_cpup((const uint32_t *)(p)) + /* XZ_IGNORE_KCONFIG may be defined only via decompress_unxz.c. */ +# ifndef XZ_IGNORE_KCONFIG +# ifdef CONFIG_XZ_DEC_X86 +# define XZ_DEC_X86 +# endif +# ifdef CONFIG_XZ_DEC_POWERPC +# define XZ_DEC_POWERPC +# endif +# ifdef CONFIG_XZ_DEC_IA64 +# define XZ_DEC_IA64 +# endif +# ifdef CONFIG_XZ_DEC_ARM +# define XZ_DEC_ARM +# endif +# ifdef CONFIG_XZ_DEC_ARMTHUMB +# define XZ_DEC_ARMTHUMB +# endif +# ifdef CONFIG_XZ_DEC_SPARC +# define XZ_DEC_SPARC +# endif +# endif +# include +#else + /* + * For userspace builds, use a separate header to define the required + * macros and functions. This makes it easier to adapt the code into + * different environments and avoids clutter in the Linux kernel tree. + */ +# include "xz_config.h" +#endif + +/* If no specific decoding mode is requested, enable support for all modes. */ +#if !defined(XZ_DEC_SINGLE) && !defined(XZ_DEC_PREALLOC) \ + && !defined(XZ_DEC_DYNALLOC) +# define XZ_DEC_SINGLE +# define XZ_DEC_PREALLOC +# define XZ_DEC_DYNALLOC +#endif + +/* + * The DEC_IS_foo(mode) macros are used in "if" statements. If only some + * of the supported modes are enabled, these macros will evaluate to true or + * false at compile time and thus allow the compiler to omit unneeded code. + */ +#ifdef XZ_DEC_SINGLE +# define DEC_IS_SINGLE(mode) ((mode) == XZ_SINGLE) +#else +# define DEC_IS_SINGLE(mode) (false) +#endif + +#ifdef XZ_DEC_PREALLOC +# define DEC_IS_PREALLOC(mode) ((mode) == XZ_PREALLOC) +#else +# define DEC_IS_PREALLOC(mode) (false) +#endif + +#ifdef XZ_DEC_DYNALLOC +# define DEC_IS_DYNALLOC(mode) ((mode) == XZ_DYNALLOC) +#else +# define DEC_IS_DYNALLOC(mode) (false) +#endif + +#if !defined(XZ_DEC_SINGLE) +# define DEC_IS_MULTI(mode) (true) +#elif defined(XZ_DEC_PREALLOC) || defined(XZ_DEC_DYNALLOC) +# define DEC_IS_MULTI(mode) ((mode) != XZ_SINGLE) +#else +# define DEC_IS_MULTI(mode) (false) +#endif + +/* + * If any of the BCJ filter decoders are wanted, define XZ_DEC_BCJ. + * XZ_DEC_BCJ is used to enable generic support for BCJ decoders. + */ +#ifndef XZ_DEC_BCJ +# if defined(XZ_DEC_X86) || defined(XZ_DEC_POWERPC) \ + || defined(XZ_DEC_IA64) || defined(XZ_DEC_ARM) \ + || defined(XZ_DEC_ARM) || defined(XZ_DEC_ARMTHUMB) \ + || defined(XZ_DEC_SPARC) +# define XZ_DEC_BCJ +# endif +#endif + +/* + * Allocate memory for LZMA2 decoder. xz_dec_lzma2_reset() must be used + * before calling xz_dec_lzma2_run(). + */ +XZ_EXTERN struct xz_dec_lzma2 * XZ_FUNC xz_dec_lzma2_create( + enum xz_mode mode, uint32_t dict_max); + +/* + * Decode the LZMA2 properties (one byte) and reset the decoder. Return + * XZ_OK on success, XZ_MEMLIMIT_ERROR if the preallocated dictionary is not + * big enough, and XZ_OPTIONS_ERROR if props indicates something that this + * decoder doesn't support. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_reset( + struct xz_dec_lzma2 *s, uint8_t props); + +/* Decode raw LZMA2 stream from b->in to b->out. */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_lzma2_run( + struct xz_dec_lzma2 *s, struct xz_buf *b); + +/* Free the memory allocated for the LZMA2 decoder. */ +XZ_EXTERN void XZ_FUNC xz_dec_lzma2_end(struct xz_dec_lzma2 *s); + +#ifdef XZ_DEC_BCJ +/* + * Allocate memory for BCJ decoders. xz_dec_bcj_reset() must be used before + * calling xz_dec_bcj_run(). + */ +XZ_EXTERN struct xz_dec_bcj * XZ_FUNC xz_dec_bcj_create(bool single_call); + +/* + * Decode the Filter ID of a BCJ filter. This implementation doesn't + * support custom start offsets, so no decoding of Filter Properties + * is needed. Returns XZ_OK if the given Filter ID is supported. + * Otherwise XZ_OPTIONS_ERROR is returned. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_reset( + struct xz_dec_bcj *s, uint8_t id); + +/* + * Decode raw BCJ + LZMA2 stream. This must be used only if there actually is + * a BCJ filter in the chain. If the chain has only LZMA2, xz_dec_lzma2_run() + * must be called directly. + */ +XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, + struct xz_dec_lzma2 *lzma2, struct xz_buf *b); + +/* Free the memory allocated for the BCJ filters. */ +#define xz_dec_bcj_end(s) kfree(s) +#endif + +#endif diff --git a/busybox-1_37_0/archival/libarchive/unxz/xz_stream.h b/busybox-1_37_0/archival/libarchive/unxz/xz_stream.h new file mode 100644 index 000000000..45056e42c --- /dev/null +++ b/busybox-1_37_0/archival/libarchive/unxz/xz_stream.h @@ -0,0 +1,62 @@ +/* + * Definitions for handling the .xz file format + * + * Author: Lasse Collin + * + * This file has been put into the public domain. + * You can do whatever you want with this file. + */ + +#ifndef XZ_STREAM_H +#define XZ_STREAM_H + +#if defined(__KERNEL__) && !XZ_INTERNAL_CRC32 +# include +# undef crc32 +# define xz_crc32(buf, size, crc) \ + (~crc32_le(~(uint32_t)(crc), buf, size)) +#endif + +/* + * See the .xz file format specification at + * http://tukaani.org/xz/xz-file-format.txt + * to understand the container format. + */ + +#define STREAM_HEADER_SIZE 12 + +#define HEADER_MAGIC "\375""7zXZ" +#define HEADER_MAGIC_SIZE 6 + +#define FOOTER_MAGIC "YZ" +#define FOOTER_MAGIC_SIZE 2 + +/* + * Variable-length integer can hold a 63-bit unsigned integer or a special + * value indicating that the value is unknown. + * + * Experimental: vli_type can be defined to uint32_t to save a few bytes + * in code size (no effect on speed). Doing so limits the uncompressed and + * compressed size of the file to less than 256 MiB and may also weaken + * error detection slightly. + */ +typedef uint64_t vli_type; + +#define VLI_MAX ((vli_type)-1 / 2) +#define VLI_UNKNOWN ((vli_type)-1) + +/* Maximum encoded size of a VLI */ +#define VLI_BYTES_MAX (sizeof(vli_type) * 8 / 7) + +/* Integrity Check types */ +enum xz_check { + XZ_CHECK_NONE = 0, + XZ_CHECK_CRC32 = 1, + XZ_CHECK_CRC64 = 4, + XZ_CHECK_SHA256 = 10 +}; + +/* Maximum possible Check ID */ +#define XZ_CHECK_MAX 15 + +#endif diff --git a/busybox-1_37_0/archival/lzop.c b/busybox-1_37_0/archival/lzop.c new file mode 100644 index 000000000..bdcc6d548 --- /dev/null +++ b/busybox-1_37_0/archival/lzop.c @@ -0,0 +1,1145 @@ +/* + This file is part of the lzop file compressor. + + Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer + All Rights Reserved. + + Markus F.X.J. Oberhumer + http://www.oberhumer.com/opensource/lzop/ + + lzop and the LZO library are free software; you can redistribute them + and/or modify them under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of + the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; see the file COPYING. + If not, write to the Free Software Foundation, Inc., + 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + + "Minimalized" for busybox by Alain Knaff +*/ +//config:config LZOP +//config: bool "lzop (13 kb)" +//config: default y +//config: help +//config: Lzop compression/decompresion. +//config: +//config:config UNLZOP +//config: bool "unlzop (13 kb)" +//config: default n # INCOMPAT: upstream lzop does not provide such tool +//config: help +//config: Lzop decompresion. +//config: +//config:config LZOPCAT +//config: bool "lzopcat (13 kb)" +//config: default n # INCOMPAT: upstream lzop does not provide such tool +//config: help +//config: Alias to "lzop -dc". +//config: +//config:config LZOP_COMPR_HIGH +//config: bool "lzop compression levels 7,8,9 (not very useful)" +//config: default n +//config: depends on LZOP || UNLZOP || LZOPCAT +//config: help +//config: High levels (7,8,9) of lzop compression. These levels +//config: are actually slower than gzip at equivalent compression ratios +//config: and take up 3.2K of code. + +//applet:IF_LZOP(APPLET(lzop, BB_DIR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_UNLZOP( APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop)) +//applet:IF_LZOPCAT(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat)) + +//kbuild:lib-$(CONFIG_LZOP) += lzop.o +//kbuild:lib-$(CONFIG_UNLZOP) += lzop.o +//kbuild:lib-$(CONFIG_LZOPCAT) += lzop.o + +//usage:#define lzop_trivial_usage +//usage: "[-cfUvd123456789CF] [FILE]..." +//usage:#define lzop_full_usage "\n\n" +//usage: " -1..9 Compression level" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -U Delete input files" +///////: "\n -k Keep input files" (default, so why bother documenting?) +//usage: "\n -v Verbose" +//usage: "\n -F Don't store or verify checksum" +//usage: "\n -C Also write checksum of compressed block" +//usage: +//usage:#define lzopcat_trivial_usage +//usage: "[-vF] [FILE]..." +//usage:#define lzopcat_full_usage "\n\n" +//usage: " -v Verbose" +//usage: "\n -F Don't verify checksum" +//usage: +//usage:#define unlzop_trivial_usage +//usage: "[-cfUvF] [FILE]..." +//usage:#define unlzop_full_usage "\n\n" +//usage: " -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -U Delete input files" +///////: "\n -k Keep input files" (default, so why bother documenting?) +//usage: "\n -t Test integrity" +//usage: "\n -v Verbose" +//usage: "\n -F Don't verify checksum" + +#include "libbb.h" +#include "common_bufsiz.h" +#include "bb_archive.h" +#include "liblzo_interface.h" + +/* lzo-2.03/src/lzo_ptr.h */ +#define pd(a,b) ((unsigned)((a)-(b))) + +#define lzo_version() LZO_VERSION +#define lzo_sizeof_dict_t (sizeof(uint8_t*)) + +/* lzo-2.03/include/lzo/lzo1x.h */ +#define LZO1X_1_MEM_COMPRESS (16384 * lzo_sizeof_dict_t) +#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t) +#define LZO1X_999_MEM_COMPRESS (14 * 16384 * sizeof(short)) + +/* lzo-2.03/src/lzo1x_oo.c */ +#define NO_LIT UINT_MAX + +/**********************************************************************/ +static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off) +{ + ip[0] = m_pos[0]; + if (off == 1) + ip[1] = m_pos[0]; + else + ip[1] = m_pos[1]; +} + +static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off) +{ + ip[0] = m_pos[0]; + if (off == 1) { + ip[2] = ip[1] = m_pos[0]; + } + else if (off == 2) { + ip[1] = m_pos[1]; + ip[2] = m_pos[0]; + } + else { + ip[1] = m_pos[1]; + ip[2] = m_pos[2]; + } +} + +/**********************************************************************/ +// optimize a block of data. +/**********************************************************************/ +#define TEST_IP (ip < ip_end) +#define TEST_OP (op <= op_end) + +static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, + uint8_t *out, unsigned *out_len /*, void* wrkmem */) +{ + uint8_t* op; + uint8_t* ip; + unsigned t; + uint8_t* m_pos; + uint8_t* const ip_end = in + in_len; + uint8_t* const op_end = out + *out_len; + uint8_t* litp = NULL; + unsigned lit = 0; + unsigned next_lit = NO_LIT; + unsigned nl; + unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0; + +// LZO_UNUSED(wrkmem); + + *out_len = 0; + + op = out; + ip = in; + + if (*ip > 17) { + t = *ip++ - 17; + if (t < 4) + goto match_next; + goto first_literal_run; + } + + while (TEST_IP && TEST_OP) { + t = *ip++; + if (t >= 16) + goto match; + /* a literal run */ + litp = ip - 1; + if (t == 0) { + t = 15; + while (*ip == 0) + t += 255, ip++; + t += *ip++; + } + lit = t + 3; + /* copy literals */ + copy_literal_run: + *op++ = *ip++; + *op++ = *ip++; + *op++ = *ip++; + first_literal_run: + do *op++ = *ip++; while (--t > 0); + + t = *ip++; + + if (t >= 16) + goto match; +#if defined(LZO1X) + m_pos = op - 1 - 0x800; +#elif defined(LZO1Y) + m_pos = op - 1 - 0x400; +#endif + m_pos -= t >> 2; + m_pos -= *ip++ << 2; + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; + lit = 0; + goto match_done; + + + /* handle matches */ + do { + if (t < 16) { /* a M1 match */ + m_pos = op - 1; + m_pos -= t >> 2; + m_pos -= *ip++ << 2; + + if (litp == NULL) + goto copy_m1; + + nl = ip[-2] & 3; + /* test if a match follows */ + if (nl == 0 && lit == 1 && ip[0] >= 16) { + next_lit = nl; + /* adjust length of previous short run */ + lit += 2; + *litp = (unsigned char)((*litp & ~3) | lit); + /* copy over the 2 literals that replace the match */ + copy2(ip-2, m_pos, pd(op, m_pos)); + o_m1_a++; + } + /* test if a literal run follows */ + else + if (nl == 0 + && ip[0] < 16 + && ip[0] != 0 + && (lit + 2 + ip[0] < 16) + ) { + t = *ip++; + /* remove short run */ + *litp &= ~3; + /* copy over the 2 literals that replace the match */ + copy2(ip-3+1, m_pos, pd(op, m_pos)); + /* move literals 1 byte ahead */ + litp += 2; + if (lit > 0) + memmove(litp+1, litp, lit); + /* insert new length of long literal run */ + lit += 2 + t + 3; + *litp = (unsigned char)(lit - 3); + + o_m1_b++; + *op++ = *m_pos++; + *op++ = *m_pos++; + goto copy_literal_run; + } + copy_m1: + *op++ = *m_pos++; + *op++ = *m_pos++; + } else { + match: + if (t >= 64) { /* a M2 match */ + m_pos = op - 1; +#if defined(LZO1X) + m_pos -= (t >> 2) & 7; + m_pos -= *ip++ << 3; + t = (t >> 5) - 1; +#elif defined(LZO1Y) + m_pos -= (t >> 2) & 3; + m_pos -= *ip++ << 2; + t = (t >> 4) - 3; +#endif + if (litp == NULL) + goto copy_m; + + nl = ip[-2] & 3; + /* test if in beetween two long literal runs */ + if (t == 1 && lit > 3 && nl == 0 + && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16) + ) { + t = *ip++; + /* copy over the 3 literals that replace the match */ + copy3(ip-1-2, m_pos, pd(op, m_pos)); + /* set new length of previous literal run */ + lit += 3 + t + 3; + *litp = (unsigned char)(lit - 3); + o_m2++; + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; + goto copy_literal_run; + } + } else { + if (t >= 32) { /* a M3 match */ + t &= 31; + if (t == 0) { + t = 31; + while (*ip == 0) + t += 255, ip++; + t += *ip++; + } + m_pos = op - 1; + m_pos -= *ip++ >> 2; + m_pos -= *ip++ << 6; + } else { /* a M4 match */ + m_pos = op; + m_pos -= (t & 8) << 11; + t &= 7; + if (t == 0) { + t = 7; + while (*ip == 0) + t += 255, ip++; + t += *ip++; + } + m_pos -= *ip++ >> 2; + m_pos -= *ip++ << 6; + if (m_pos == op) + goto eof_found; + m_pos -= 0x4000; + } + if (litp == NULL) + goto copy_m; + + nl = ip[-2] & 3; + /* test if in beetween two matches */ + if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) { + next_lit = nl; + /* make a previous short run */ + lit += 3; + *litp = (unsigned char)((*litp & ~3) | lit); + /* copy over the 3 literals that replace the match */ + copy3(ip-3, m_pos, pd(op, m_pos)); + o_m3_a++; + } + /* test if a literal run follows */ + else if (t == 1 && lit <= 3 && nl == 0 + && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16) + ) { + t = *ip++; + /* remove short run */ + *litp &= ~3; + /* copy over the 3 literals that replace the match */ + copy3(ip-4+1, m_pos, pd(op, m_pos)); + /* move literals 1 byte ahead */ + litp += 2; + if (lit > 0) + memmove(litp+1,litp,lit); + /* insert new length of long literal run */ + lit += 3 + t + 3; + *litp = (unsigned char)(lit - 3); + + o_m3_b++; + *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; + goto copy_literal_run; + } + } + copy_m: + *op++ = *m_pos++; + *op++ = *m_pos++; + do *op++ = *m_pos++; while (--t > 0); + } + + match_done: + if (next_lit == NO_LIT) { + t = ip[-2] & 3; + lit = t; + litp = ip - 2; + } + else + t = next_lit; + next_lit = NO_LIT; + if (t == 0) + break; + /* copy literals */ + match_next: + do *op++ = *ip++; while (--t > 0); + t = *ip++; + } while (TEST_IP && TEST_OP); + } + + /* no EOF code was found */ + *out_len = pd(op, out); + return LZO_E_EOF_NOT_FOUND; + + eof_found: +// LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2); +// LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b); + *out_len = pd(op, out); + return (ip == ip_end ? LZO_E_OK : + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); +} + +/**********************************************************************/ +#define F_OS F_OS_UNIX +#define F_CS F_CS_NATIVE + +/**********************************************************************/ +#define ADLER32_INIT_VALUE 1 +#define CRC32_INIT_VALUE 0 + +/**********************************************************************/ +enum { + M_LZO1X_1 = 1, + M_LZO1X_1_15 = 2, + M_LZO1X_999 = 3, +}; + +/**********************************************************************/ +/* header flags */ +#define F_ADLER32_D 0x00000001L +#define F_ADLER32_C 0x00000002L +#define F_H_EXTRA_FIELD 0x00000040L +#define F_H_GMTDIFF 0x00000080L +#define F_CRC32_D 0x00000100L +#define F_CRC32_C 0x00000200L +#define F_H_FILTER 0x00000800L +#define F_H_CRC32 0x00001000L +#define F_MASK 0x00003FFFL + +/* operating system & file system that created the file [mostly unused] */ +#define F_OS_UNIX 0x03000000L +#define F_OS_SHIFT 24 +#define F_OS_MASK 0xff000000L + +/* character set for file name encoding [mostly unused] */ +#define F_CS_NATIVE 0x00000000L +#define F_CS_SHIFT 20 +#define F_CS_MASK 0x00f00000L + +/* these bits must be zero */ +#define F_RESERVED ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL) + +typedef struct chksum_t { + uint32_t f_adler32; + uint32_t f_crc32; +} chksum_t; + +typedef struct header_t { + /* used to have auxiliary fields here */ + + /* Starting from here, the layout and endianness + * are exactly in on-disk format. + */ + uint16_t version_be16; + uint16_t lib_version_be16; + uint16_t version_needed_to_extract_be16; + uint8_t method; + uint8_t level; + uint32_t flags32; /* be32 on disk, but we keep this field in native order */ + uint32_t mode_be32; + uint32_t mtime_be32; + uint32_t gmtdiff_be32; + char len_and_name[1+255+1]; +} header_t; + +struct globals { + /*const uint32_t *lzo_crc32_table;*/ + chksum_t chksum; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +//#define G (*ptr_to_globals) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /*SET_PTR_TO_GLOBALS(xzalloc(sizeof(G)));*/ \ +} while (0) + + +/**********************************************************************/ +#define LZOP_VERSION 0x1010 +//#define LZOP_VERSION_STRING "1.01" +//#define LZOP_VERSION_DATE "Apr 27th 2003" + +// lzop wants to be weird: +// unlike all other compressosrs, its -k "keep" option is the default, +// and -U is used to delete the source. We will invert the bit after getopt(). +#define OPTION_STRING "cfUvqdt123456789CFk" + +/* Note: must be kept in sync with archival/bbunzip.c */ +enum { + OPT_STDOUT = (1 << 0), + OPT_FORCE = (1 << 1), + OPT_KEEP = (1 << 2), + OPT_VERBOSE = (1 << 3), + OPT_QUIET = (1 << 4), + OPT_DECOMPRESS = (1 << 5), + OPT_TEST = (1 << 6), + OPT_1 = (1 << 7), + OPT_2 = (1 << 8), + OPT_3 = (1 << 9), + OPT_4 = (1 << 10), + OPT_5 = (1 << 11), + OPT_6 = (1 << 12), + OPT_7 = (1 << 13), + OPT_8 = (1 << 14), + OPT_9 = (1 << 15), + OPT_C = (1 << 16), + OPT_F = (1 << 17), + OPT_k = (1 << 18), + OPT_789 = OPT_7 | OPT_8 | OPT_9 +}; + +/**********************************************************************/ +// adler32 checksum +// adapted from free code by Mark Adler +// see http://www.zlib.org/ +/**********************************************************************/ +static FAST_FUNC uint32_t +lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) +{ + enum { + LZO_BASE = 65521, /* largest prime smaller than 65536 */ + /* NMAX is the largest n such that + * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + LZO_NMAX = 5552, + }; + uint32_t s1 = adler & 0xffff; + uint32_t s2 = (adler >> 16) & 0xffff; + unsigned k; + + if (buf == NULL) + return 1; + + while (len > 0) { + k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX; + len -= k; + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k > 0); + s1 %= LZO_BASE; + s2 %= LZO_BASE; + } + return (s2 << 16) | s1; +} + +static FAST_FUNC uint32_t +lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) +{ + //if (buf == NULL) - impossible + // return 0; + + return ~crc32_block_endian0(~c, buf, len, global_crc32_table); +} + +/**********************************************************************/ +static void init_chksum(void) +{ + G.chksum.f_adler32 = ADLER32_INIT_VALUE; + G.chksum.f_crc32 = CRC32_INIT_VALUE; +} + +static void add_bytes_to_chksum(const void* buf, int cnt) +{ + /* We need to handle the two checksums at once, because at the + * beginning of the header, we don't know yet which one we'll + * eventually need */ + G.chksum.f_adler32 = lzo_adler32(G.chksum.f_adler32, (const uint8_t*)buf, cnt); + G.chksum.f_crc32 = lzo_crc32(G.chksum.f_crc32, (const uint8_t*)buf, cnt); +} + +static uint32_t chksum_getresult(uint32_t h_flags32) +{ + return (h_flags32 & F_H_CRC32) ? G.chksum.f_crc32 : G.chksum.f_adler32; +} + +/**********************************************************************/ +static uint32_t read32(void) +{ + uint32_t v; + xread(0, &v, 4); + return ntohl(v); +} +static void f_read(void* buf, int cnt) +{ + xread(0, buf, cnt); + add_bytes_to_chksum(buf, cnt); +} +//static int f_read8(void) +//{ +// uint8_t v; +// f_read(&v, 1); +// return v; +//} +//static unsigned f_read16(void) +//{ +// uint16_t v; +// f_read(&v, 2); +// return ntohs(v); +//} +static uint32_t f_read32(void) +{ + uint32_t v; + f_read(&v, 4); + return ntohl(v); +} + +static void write32(uint32_t v) +{ + v = htonl(v); + xwrite(1, &v, 4); +} +static void f_write(const void* buf, int cnt) +{ + xwrite(1, buf, cnt); + add_bytes_to_chksum(buf, cnt); +} +//static void f_write8(uint8_t v) +//{ +// f_write(&v, 1); +//} +//static void f_write16(uint16_t v) +//{ +// v = htons(v); +// f_write(&v, 2); +//} +//static void f_write32(uint32_t v) +//{ +// v = htonl(v); +// f_write(&v, 4); +//} + +/**********************************************************************/ +#define LZO_BLOCK_SIZE (256 * 1024l) +#define MAX_BLOCK_SIZE (64 * 1024l * 1024l) /* DO NOT CHANGE */ + +/* LZO may expand uncompressible data by a small amount */ +#define MAX_COMPRESSED_SIZE(x) ((x) + (x) / 16 + 64 + 3) + +/**********************************************************************/ +// compress a file +/**********************************************************************/ +static NOINLINE int lzo_compress(const header_t *h) +{ + unsigned block_size = LZO_BLOCK_SIZE; + int r = 0; /* LZO_E_OK */ + uint8_t *const b1 = xzalloc(block_size); + uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size)); + uint32_t d_adler32 = ADLER32_INIT_VALUE; + uint32_t d_crc32 = CRC32_INIT_VALUE; + uint8_t *wrk_mem = NULL; + + /* Only these methods are possible, see lzo_set_method(): + * -1: M_LZO1X_1_15 + * -2..6: M_LZO1X_1 + * -7..9: M_LZO1X_999 if ENABLE_LZOP_COMPR_HIGH + */ + if (h->method == M_LZO1X_1) + wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS); + else /* check only if it's not the only possibility */ + IF_LZOP_COMPR_HIGH(if (h->method == M_LZO1X_1_15)) + wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS); +#if ENABLE_LZOP_COMPR_HIGH + else /* must be h->method == M_LZO1X_999 */ + wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS); +#endif + + for (;;) { + unsigned src_len, dst_len; + int l; + uint32_t wordbuf[6]; + uint32_t *wordptr = wordbuf; + + /* read a block */ + l = full_read(0, b1, block_size); + src_len = (l > 0 ? l : 0); + + /* write uncompressed block size */ + /* exit if last block */ + if (src_len == 0) { + write32(0); + break; + } + *wordptr++ = htonl(src_len); + + /* compute checksum of uncompressed block */ + if (h->flags32 & F_ADLER32_D) + d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len); + if (h->flags32 & F_CRC32_D) + d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len); + + /* compress */ + if (h->method == M_LZO1X_1) + r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem); + else IF_LZOP_COMPR_HIGH(if (h->method == M_LZO1X_1_15)) + r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem); +#if ENABLE_LZOP_COMPR_HIGH + else /* must be h->method == M_LZO1X_999 */ + r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len, + wrk_mem, h->level); +#endif + if (r != 0) /* not LZO_E_OK */ + bb_error_msg_and_die("%s: %s", "internal error", "compression"); + + /* write compressed block size */ + if (dst_len < src_len) { + /* optimize */ + if (h->method == M_LZO1X_999) { + unsigned new_len = src_len; + r = lzo1x_optimize(b2, dst_len, b1, &new_len /*, NULL*/); + if (r != 0 /*LZO_E_OK*/ || new_len != src_len) + bb_error_msg_and_die("%s: %s", "internal error", "optimization"); + } + *wordptr++ = htonl(dst_len); + } else { + /* data actually expanded => store data uncompressed */ + *wordptr++ = htonl(src_len); + } + + /* write checksum of uncompressed block */ + if (h->flags32 & F_ADLER32_D) + *wordptr++ = htonl(d_adler32); + if (h->flags32 & F_CRC32_D) + *wordptr++ = htonl(d_crc32); + + if (dst_len < src_len) { + /* write checksum of compressed block */ + if (h->flags32 & F_ADLER32_C) + *wordptr++ = htonl(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len)); + if (h->flags32 & F_CRC32_C) + *wordptr++ = htonl(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); + } + xwrite(1, wordbuf, ((char*)wordptr) - ((char*)wordbuf)); + if (dst_len < src_len) { + /* write compressed block data */ + xwrite(1, b2, dst_len); + } else { + /* write uncompressed block data */ + xwrite(1, b1, src_len); + } + // /* if full_read() was nevertheless "short", it was EOF */ + // if (src_len < block_size) + // break; + } + + free(wrk_mem); + free(b1); + free(b2); + return 1; +} + +static FAST_FUNC void lzo_check( + uint32_t init, + uint8_t* buf, unsigned len, + uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned), + uint32_t ref) +{ + /* This function, by having the same order of parameters + * as fn, and by being marked FAST_FUNC (same as fn), + * saves a dozen bytes of code. + */ + uint32_t c = fn(init, buf, len); + if (c != ref) + bb_simple_error_msg_and_die("checksum error"); +} + +/**********************************************************************/ +// decompress a file +/**********************************************************************/ +// used to have "const header_t *h" parameter, but since it uses +// only flags32 field, changed to receive only that. +static NOINLINE int lzo_decompress(uint32_t h_flags32) +{ + unsigned block_size = LZO_BLOCK_SIZE; + int r; + uint32_t src_len, dst_len; + uint32_t c_adler32 = ADLER32_INIT_VALUE; + uint32_t d_adler32 = ADLER32_INIT_VALUE; + uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE; + uint8_t *b1; + uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size); + uint8_t *b2 = NULL; + + for (;;) { + uint8_t *dst; + + /* read uncompressed block size */ + dst_len = read32(); + + /* exit if last block */ + if (dst_len == 0) + break; + + /* error if split file */ + if (dst_len == 0xffffffffL) + /* should not happen - not yet implemented */ + bb_simple_error_msg_and_die("this file is a split lzop file"); + + if (dst_len > MAX_BLOCK_SIZE) + bb_simple_error_msg_and_die("corrupted data"); + + /* read compressed block size */ + src_len = read32(); + if (src_len <= 0 || src_len > dst_len) + bb_simple_error_msg_and_die("corrupted data"); + + if (dst_len > block_size) { + if (b2) { + free(b2); + b2 = NULL; + } + block_size = dst_len; + mcs_block_size = MAX_COMPRESSED_SIZE(block_size); + } + + /* read checksum of uncompressed block */ + if (h_flags32 & F_ADLER32_D) + d_adler32 = read32(); + if (h_flags32 & F_CRC32_D) + d_crc32 = read32(); + + /* read checksum of compressed block */ + if (src_len < dst_len) { + if (h_flags32 & F_ADLER32_C) + c_adler32 = read32(); + if (h_flags32 & F_CRC32_C) + c_crc32 = read32(); + } + + if (b2 == NULL) + b2 = xzalloc(mcs_block_size); + /* read the block into the end of our buffer */ + b1 = b2 + mcs_block_size - src_len; + xread(0, b1, src_len); + + if (src_len < dst_len) { + unsigned d = dst_len; + + if (!(option_mask32 & OPT_F)) { + /* verify checksum of compressed block */ + if (h_flags32 & F_ADLER32_C) + lzo_check(ADLER32_INIT_VALUE, + b1, src_len, + lzo_adler32, c_adler32); + if (h_flags32 & F_CRC32_C) + lzo_check(CRC32_INIT_VALUE, + b1, src_len, + lzo_crc32, c_crc32); + } + + /* decompress */ +// if (option_mask32 & OPT_F) +// r = lzo1x_decompress(b1, src_len, b2, &d /*, NULL*/); +// else + r = lzo1x_decompress_safe(b1, src_len, b2, &d /*, NULL*/); + + if (r != 0 /*LZO_E_OK*/ || dst_len != d) { + bb_simple_error_msg_and_die("corrupted data"); + } + dst = b2; + } else { + /* "stored" block => no decompression */ + dst = b1; + } + + if (!(option_mask32 & OPT_F)) { + /* verify checksum of uncompressed block */ + if (h_flags32 & F_ADLER32_D) + lzo_check(ADLER32_INIT_VALUE, + dst, dst_len, + lzo_adler32, d_adler32); + if (h_flags32 & F_CRC32_D) + lzo_check(CRC32_INIT_VALUE, + dst, dst_len, + lzo_crc32, d_crc32); + } + + /* write uncompressed block data */ + xwrite(1, dst, dst_len); + } + + free(b2); + return 1; +} + +/**********************************************************************/ +// lzop file signature (shamelessly borrowed from PNG) +/**********************************************************************/ +/* + * The first nine bytes of a lzop file always contain the following values: + * + * 0 1 2 3 4 5 6 7 8 + * --- --- --- --- --- --- --- --- --- + * (hex) 89 4c 5a 4f 00 0d 0a 1a 0a + * (decimal) 137 76 90 79 0 13 10 26 10 + * (C notation - ASCII) \211 L Z O \0 \r \n \032 \n + */ + +/* (vda) comparison with lzop v1.02rc1 ("lzop -1 len_and_name+1 + 0; /* 0 is strlen(h->len_and_name+1) */ + /* Store length byte */ + /*h->len_and_name[0] = end - (h->len_and_name+1); - zero already */ + + f_write(&h->version_be16, end - (char*)&h->version_be16); + + h->flags32 = htonl(h->flags32); /* native endianness for lzo_compress() */ + + write32(chksum_getresult(h->flags32)); +} + +static int read_header(header_t *h) +{ + int l; + uint32_t checksum; + /* As it stands now, only h->flags32 is used by our caller. + * Therefore we don't store many fields in h->FIELD. + */ + unsigned h_version; + unsigned h_version_needed_to_extract; + + init_chksum(); + + /* We don't support versions < 0.94, since 0.94 + * came only 2 months after 0.90: + * 0.90 (10 Aug 1997): First public release of lzop + * 0.94 (15 Oct 1997): Header format change + */ + + /* Read up to and including name length byte */ + f_read(&h->version_be16, ((char*)&h->len_and_name[1]) - ((char*)&h->version_be16)); + + h_version = htons(h->version_be16); + if (h_version < 0x0940) + return 3; + h_version_needed_to_extract = htons(h->version_needed_to_extract_be16); + if (h_version_needed_to_extract > LZOP_VERSION) + return 16; + if (h_version_needed_to_extract < 0x0940) + return 3; + + if (h->method <= 0) + return 14; + + /* former lzo_get_method(h): */ + if (h->method == M_LZO1X_1) { + if (h->level == 0) + h->level = 3; + } else if (h->method == M_LZO1X_1_15) { + if (h->level == 0) + h->level = 1; + } else if (h->method == M_LZO1X_999) { + if (h->level == 0) + h->level = 9; + } else + return -1; /* not a LZO method */ + /* check compression level */ + if (h->level < 1 || h->level > 9) + return 15; + + h->flags32 = ntohl(h->flags32); + if (h->flags32 & F_H_FILTER) + return 16; /* filter not supported */ + /* check reserved flags */ + if (h->flags32 & F_RESERVED) + return -13; + + l = h->len_and_name[0]; + if (l > 0) + /* UNUSED */ f_read(h->len_and_name+1, l); + /* UNUSED h->len_and_name[1+l] = 0; */ + + checksum = chksum_getresult(h->flags32); + if (read32() != checksum) + return 2; + + /* skip extra field [not used yet] */ + if (h->flags32 & F_H_EXTRA_FIELD) { + uint32_t extra_field_len; + uint32_t extra_field_checksum; + uint32_t k; + char dummy; + + /* note: the checksum also covers the length */ + init_chksum(); + extra_field_len = f_read32(); + for (k = 0; k < extra_field_len; k++) + f_read(&dummy, 1); + checksum = chksum_getresult(h->flags32); + extra_field_checksum = read32(); + if (extra_field_checksum != checksum) + return 3; + } + + return 0; +} + +/**********************************************************************/ +// compress +/**********************************************************************/ +static void lzo_set_method(header_t *h) +{ + smallint level; + + /* levels 2..6 or none (defaults to level 3) */ + h->method = M_LZO1X_1; + level = 5; /* levels 2-6 are actually the same */ + + if (option_mask32 & OPT_1) { + h->method = M_LZO1X_1_15; + level = 1; + } + if (option_mask32 & OPT_789) { +#if ENABLE_LZOP_COMPR_HIGH + h->method = M_LZO1X_999; + level = 9; + if (option_mask32 & OPT_7) + level = 7; + else if (option_mask32 & OPT_8) + level = 8; +#else + bb_simple_error_msg_and_die("high compression not compiled in"); +#endif + } + + h->level = level; +} + +static int do_lzo_compress(void) +{ + header_t header; + +#define h (&header) + memset(h, 0, sizeof(*h)); + + lzo_set_method(h); + + h->version_be16 = htons(LZOP_VERSION & 0xffff); + h->version_needed_to_extract_be16 = htons(0x0940); + h->lib_version_be16 = htons(lzo_version() & 0xffff); + + h->flags32 = htonl((F_OS & F_OS_MASK) | (F_CS & F_CS_MASK)); + + if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) { + h->flags32 |= htonl(F_ADLER32_D); + if (option_mask32 & OPT_C) + h->flags32 |= htonl(F_ADLER32_C); + } + + /* write_header() also converts h->flags32 to native endianness */ + write_header(h); + + return lzo_compress(h); +#undef h +} + +/**********************************************************************/ +// decompress +/**********************************************************************/ +static int do_lzo_decompress(void) +{ + int r; + header_t header; + + check_magic(); + r = read_header(&header); + if (r != 0) + bb_error_msg_and_die("header_error %d", r); + return lzo_decompress(header.flags32); +} + +static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_ext UNUSED_PARAM) +{ + if (option_mask32 & OPT_DECOMPRESS) { + char *extension = strrchr(filename, '.'); + if (!extension || strcmp(extension + 1, "lzo") != 0) + return xasprintf("%s.out", filename); + *extension = '\0'; + return filename; + } + return xasprintf("%s.lzo", filename); +} + +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_state_t *xstate UNUSED_PARAM) +{ + if (option_mask32 & OPT_DECOMPRESS) + return do_lzo_decompress(); + return do_lzo_compress(); +} + +int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int lzop_main(int argc UNUSED_PARAM, char **argv) +{ + INIT_G(); + + getopt32(argv, OPTION_STRING); + argv += optind; + /* -U is "anti -k", invert bit for bbunpack(): */ + option_mask32 ^= OPT_KEEP; + /* -k disables -U (if any): */ + /* opt_complementary "k-U"? - nope, only handles -Uk, not -kU */ + if (option_mask32 & OPT_k) + option_mask32 |= OPT_KEEP; + + /* lzopcat? */ + if (ENABLE_LZOPCAT && applet_name[4] == 'c') + option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); + /* unlzop? */ + if (ENABLE_UNLZOP && applet_name[4] == 'o') + option_mask32 |= OPT_DECOMPRESS; + + global_crc32_new_table_le(); + return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); +} diff --git a/busybox-1_37_0/archival/rpm.c b/busybox-1_37_0/archival/rpm.c new file mode 100644 index 000000000..af8db99a6 --- /dev/null +++ b/busybox-1_37_0/archival/rpm.c @@ -0,0 +1,561 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rpm applet for busybox + * + * Copyright (C) 2001,2002 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RPM +//config: bool "rpm (32 kb)" +//config: default y +//config: help +//config: Mini RPM applet - queries and extracts RPM packages. + +//applet:IF_RPM(APPLET(rpm, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_RPM) += rpm.o + +#include "libbb.h" +#include "common_bufsiz.h" +#include "bb_archive.h" +#include "rpm.h" + +#define RPM_CHAR_TYPE 1 +#define RPM_INT8_TYPE 2 +#define RPM_INT16_TYPE 3 +#define RPM_INT32_TYPE 4 +/* #define RPM_INT64_TYPE 5 ---- These aren't supported (yet) */ +#define RPM_STRING_TYPE 6 +#define RPM_BIN_TYPE 7 +#define RPM_STRING_ARRAY_TYPE 8 +#define RPM_I18NSTRING_TYPE 9 + +#define TAG_NAME 1000 +#define TAG_VERSION 1001 +#define TAG_RELEASE 1002 +#define TAG_SUMMARY 1004 +#define TAG_DESCRIPTION 1005 +#define TAG_BUILDTIME 1006 +#define TAG_BUILDHOST 1007 +#define TAG_SIZE 1009 +#define TAG_VENDOR 1011 +#define TAG_LICENSE 1014 +#define TAG_PACKAGER 1015 +#define TAG_GROUP 1016 +#define TAG_URL 1020 +#define TAG_PREIN 1023 +#define TAG_POSTIN 1024 +#define TAG_FILEFLAGS 1037 +#define TAG_FILEUSERNAME 1039 +#define TAG_FILEGROUPNAME 1040 +#define TAG_SOURCERPM 1044 +#define TAG_PREINPROG 1085 +#define TAG_POSTINPROG 1086 +#define TAG_PREFIXS 1098 +#define TAG_DIRINDEXES 1116 +#define TAG_BASENAMES 1117 +#define TAG_DIRNAMES 1118 +#define TAG_PAYLOADCOMPRESSOR 1125 + + +#define RPMFILE_CONFIG (1 << 0) +#define RPMFILE_DOC (1 << 1) + +enum rpm_functions_e { + rpm_query = 1, + rpm_install = 2, + rpm_query_info = 4, + rpm_query_package = 8, + rpm_query_list = 16, + rpm_query_list_doc = 32, + rpm_query_list_config = 64 +}; + +typedef struct { + uint32_t tag; /* 4 byte tag */ + uint32_t type; /* 4 byte type */ + uint32_t offset; /* 4 byte offset */ + uint32_t count; /* 4 byte count */ +} rpm_index; + +struct globals { + void *map; + rpm_index *mytags; + int tagcount; + unsigned mapsize; + IF_VARIABLE_ARCH_PAGESIZE(unsigned pagesize;) +#define G_pagesize cached_pagesize(G.pagesize) +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { setup_common_bufsiz(); } while (0) + +static int rpm_gettags(const char *filename) +{ + rpm_index *tags; + int fd; + unsigned pass, idx; + unsigned storepos; + + if (!filename) { /* rpm2cpio w/o filename? */ + filename = bb_msg_standard_output; + fd = 0; + } else { + fd = xopen(filename, O_RDONLY); + } + + storepos = xlseek(fd, 96, SEEK_CUR); /* Seek past the unused lead */ + G.tagcount = 0; + tags = NULL; + idx = 0; + /* 1st pass is the signature headers, 2nd is the main stuff */ + for (pass = 0; pass < 2; pass++) { + struct rpm_header header; + unsigned cnt; + + xread(fd, &header, sizeof(header)); + if (header.magic_and_ver != htonl(RPM_HEADER_MAGICnVER)) + bb_error_msg_and_die("invalid RPM header magic in '%s'", filename); + header.size = ntohl(header.size); + cnt = ntohl(header.entries); + storepos += sizeof(header) + cnt * 16; + + G.tagcount += cnt; + tags = xrealloc(tags, sizeof(tags[0]) * G.tagcount); + xread(fd, &tags[idx], sizeof(tags[0]) * cnt); + while (cnt--) { + rpm_index *tag = &tags[idx]; + tag->tag = ntohl(tag->tag); + tag->type = ntohl(tag->type); + tag->count = ntohl(tag->count); + tag->offset = storepos + ntohl(tag->offset); + if (pass == 0) + tag->tag -= 743; + idx++; + } + /* Skip padding to 8 byte boundary after reading signature headers */ + if (pass == 0) + while (header.size & 7) + header.size++; + /* Seek past store */ + storepos = xlseek(fd, header.size, SEEK_CUR); + } + G.mytags = tags; + + /* Map the store */ + storepos = (storepos + G_pagesize) & -(int)G_pagesize; + /* remember size for munmap */ + G.mapsize = storepos; + /* some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ + G.map = mmap_read(fd, storepos); + if (G.map == MAP_FAILED) + bb_perror_msg_and_die("mmap '%s'", filename); + + return fd; +} + +static int bsearch_rpmtag(const void *key, const void *item) +{ + int *tag = (int *)key; + rpm_index *tmp = (rpm_index *) item; + return (*tag - tmp->tag); +} + +static char *rpm_getstr(int tag, int itemindex) +{ + rpm_index *found; + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); + if (!found || itemindex >= found->count) + return NULL; + if (found->type == RPM_STRING_TYPE + || found->type == RPM_I18NSTRING_TYPE + || found->type == RPM_STRING_ARRAY_TYPE + ) { + int n; + char *tmpstr = (char *) G.map + found->offset; + for (n = 0; n < itemindex; n++) + tmpstr = tmpstr + strlen(tmpstr) + 1; + return tmpstr; + } + return NULL; +} +static char *rpm_getstr0(int tag) +{ + return rpm_getstr(tag, 0); +} + +#if ENABLE_RPM + +static int rpm_getint(int tag, int itemindex) +{ + rpm_index *found; + char *tmpint; + + /* gcc throws warnings here when sizeof(void*)!=sizeof(int) ... + * it's ok to ignore it because tag won't be used as a pointer */ + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); + if (!found || itemindex >= found->count) + return -1; + + tmpint = (char *) G.map + found->offset; + if (found->type == RPM_INT32_TYPE) { + tmpint += itemindex*4; + return ntohl(*(int32_t*)tmpint); + } + if (found->type == RPM_INT16_TYPE) { + tmpint += itemindex*2; + return ntohs(*(int16_t*)tmpint); + } + if (found->type == RPM_INT8_TYPE) { + tmpint += itemindex; + return *(int8_t*)tmpint; + } + return -1; +} + +static int rpm_getcount(int tag) +{ + rpm_index *found; + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(G.mytags[0]), bsearch_rpmtag); + if (!found) + return 0; + return found->count; +} + +static void fileaction_dobackup(char *filename, int fileref) +{ + struct stat oldfile; + int stat_res; + char *newname; + if (rpm_getint(TAG_FILEFLAGS, fileref) & RPMFILE_CONFIG) { + /* Only need to backup config files */ + stat_res = lstat(filename, &oldfile); + if (stat_res == 0 && S_ISREG(oldfile.st_mode)) { + /* File already exists - really should check MD5's etc to see if different */ + newname = xasprintf("%s.rpmorig", filename); + copy_file(filename, newname, FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS); + remove_file(filename, FILEUTILS_RECUR | FILEUTILS_FORCE); + free(newname); + } + } +} + +static void fileaction_setowngrp(char *filename, int fileref) +{ + /* real rpm warns: "user foo does not exist - using " */ + struct passwd *pw = getpwnam(rpm_getstr(TAG_FILEUSERNAME, fileref)); + int uid = pw ? pw->pw_uid : getuid(); /* or euid? */ + struct group *gr = getgrnam(rpm_getstr(TAG_FILEGROUPNAME, fileref)); + int gid = gr ? gr->gr_gid : getgid(); + chown(filename, uid, gid); +} + +static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)) +{ + int count = 0; + while (rpm_getstr(filetag, count)) { + char* filename = xasprintf("%s%s", + rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, count)), + rpm_getstr(TAG_BASENAMES, count)); + fileaction(filename, count++); + free(filename); + } +} + +#if 0 //DEBUG +static void print_all_tags(void) +{ + unsigned i = 0; + while (i < G.tagcount) { + rpm_index *tag = &G.mytags[i]; + if (tag->type == RPM_STRING_TYPE + || tag->type == RPM_I18NSTRING_TYPE + || tag->type == RPM_STRING_ARRAY_TYPE + ) { + unsigned n; + char *str = (char *) G.map + tag->offset; + + printf("tag[%u] %08x type %08x offset %08x count %d '%s'\n", + i, tag->tag, tag->type, tag->offset, tag->count, str + ); + for (n = 1; n < tag->count; n++) { + str += strlen(str) + 1; + printf("\t'%s'\n", str); + } + } + i++; + } +} +#else +#define print_all_tags() ((void)0) +#endif + +static void extract_cpio(int fd, const char *source_rpm) +{ + archive_handle_t *archive_handle; + + if (source_rpm != NULL) { + /* Binary rpm (it was built from some SRPM), install to root */ + xchdir("/"); + } /* else: SRPM, install to current dir */ + + /* Initialize */ + archive_handle = init_handle(); + archive_handle->seek = seek_by_read; + archive_handle->action_data = data_extract_all; +#if 0 /* For testing (rpm -i only lists the files in internal cpio): */ + archive_handle->action_header = header_list; + archive_handle->action_data = data_skip; +#endif + archive_handle->ah_flags = ARCHIVE_RESTORE_DATE | ARCHIVE_CREATE_LEADING_DIRS + /* compat: overwrite existing files. + * try "rpm -i foo.src.rpm" few times in a row - + * standard rpm will not complain. + */ + | ARCHIVE_REPLACE_VIA_RENAME; + archive_handle->src_fd = fd; + /*archive_handle->offset = 0; - init_handle() did it */ + + setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); + while (get_header_cpio(archive_handle) == EXIT_SUCCESS) + continue; +} + +//usage:#define rpm_trivial_usage +//usage: "-i PACKAGE.rpm; rpm -qp[ildc] PACKAGE.rpm" +//usage:#define rpm_full_usage "\n\n" +//usage: "Manipulate RPM packages\n" +//usage: "\nCommands:" +//usage: "\n -i Install package" +//usage: "\n -qp Query package" +//usage: "\n -qpi Show information" +//usage: "\n -qpl List contents" +//usage: "\n -qpd List documents" +//usage: "\n -qpc List config files" + +/* RPM version 4.13.0.1: + * Unlike -q, -i seems to imply -p: -i, -ip and -pi work the same. + * OTOH, with -q order is important: "-piq FILE.rpm" works as -qp, not -qpi + * (IOW: shows only package name, not package info). + * "-iq ARG" works as -q: treats ARG as package name, not a file. + * + * "man rpm" on -l option and options implying it: + * -l, --list List files in package. + * -c, --configfiles List only configuration files (implies -l). + * -d, --docfiles List only documentation files (implies -l). + * -L, --licensefiles List only license files (implies -l). + * --dump Dump file information as follows (implies -l): + * path size mtime digest mode owner group isconfig isdoc rdev symlink + * -s, --state Display the states of files in the package (implies -l). + * The state of each file is one of normal, not installed, or replaced. + * + * Looks like we can switch to getopt32 here: in practice, people + * do place -q first if they intend to use it (misinterpreting "-piq" wouldn't matter). + */ +int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rpm_main(int argc, char **argv) +{ + int opt, func = 0; + + INIT_G(); + INIT_PAGESIZE(G.pagesize); + + while ((opt = getopt(argc, argv, "iqpldc")) != -1) { + switch (opt) { + case 'i': /* First arg: Install mode, with q: Information */ + if (!func) func = rpm_install; + else func |= rpm_query_info; + break; + case 'q': /* First arg: Query mode */ + if (func) bb_show_usage(); + func = rpm_query; + break; + case 'p': /* Query a package (IOW: .rpm file, we are not querying RPMDB) */ + func |= rpm_query_package; + break; + case 'l': /* List files in a package */ + func |= rpm_query_list; + break; + case 'd': /* List doc files in a package (implies -l) */ + func |= rpm_query_list; + func |= rpm_query_list_doc; + break; + case 'c': /* List config files in a package (implies -l) */ + func |= rpm_query_list; + func |= rpm_query_list_config; + break; + default: + bb_show_usage(); + } + } + argv += optind; + //argc -= optind; + if (!argv[0]) { + bb_show_usage(); + } + + for (;;) { + int rpm_fd; + const char *source_rpm; + + rpm_fd = rpm_gettags(*argv); + print_all_tags(); + + source_rpm = rpm_getstr0(TAG_SOURCERPM); + + if (func & rpm_install) { + /* -i (and not -qi) */ + + /* Backup any config files */ + loop_through_files(TAG_BASENAMES, fileaction_dobackup); + /* Extact the archive */ + extract_cpio(rpm_fd, source_rpm); + /* Set the correct file uid/gid's */ + loop_through_files(TAG_BASENAMES, fileaction_setowngrp); + } + else + if ((func & (rpm_query|rpm_query_package)) == (rpm_query|rpm_query_package)) { + /* -qp */ + + if (!(func & (rpm_query_info|rpm_query_list))) { + /* If just a straight query, just give package name */ + printf("%s-%s-%s\n", rpm_getstr0(TAG_NAME), rpm_getstr0(TAG_VERSION), rpm_getstr0(TAG_RELEASE)); + } + if (func & rpm_query_info) { + /* Do the nice printout */ + time_t bdate_time; + struct tm *bdate_ptm; + char bdatestring[50]; + const char *p; + + printf("%-12s: %s\n", "Name" , rpm_getstr0(TAG_NAME)); + /* TODO compat: add "Epoch" here */ + printf("%-12s: %s\n", "Version" , rpm_getstr0(TAG_VERSION)); + printf("%-12s: %s\n", "Release" , rpm_getstr0(TAG_RELEASE)); + /* add "Architecture" */ + /* printf("%-12s: %s\n", "Install Date", "(not installed)"); - we don't know */ + printf("%-12s: %s\n", "Group" , rpm_getstr0(TAG_GROUP)); + printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); + printf("%-12s: %s\n", "License" , rpm_getstr0(TAG_LICENSE)); + /* add "Signature" */ + printf("%-12s: %s\n", "Source RPM" , source_rpm ? source_rpm : "(none)"); + bdate_time = rpm_getint(TAG_BUILDTIME, 0); + bdate_ptm = localtime(&bdate_time); + strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); + printf("%-12s: %s\n", "Build Date" , bdatestring); + printf("%-12s: %s\n", "Build Host" , rpm_getstr0(TAG_BUILDHOST)); + p = rpm_getstr0(TAG_PREFIXS); + printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); + /* add "Packager" */ + p = rpm_getstr0(TAG_VENDOR); + if (p) /* rpm 4.13.0.1 does not show "(none)" for Vendor: */ + printf("%-12s: %s\n", "Vendor" , p); + p = rpm_getstr0(TAG_URL); + if (p) /* rpm 4.13.0.1 does not show "(none)"/"(null)" for URL: */ + printf("%-12s: %s\n", "URL" , p); + printf("%-12s: %s\n", "Summary" , rpm_getstr0(TAG_SUMMARY)); + printf("Description :\n%s\n", rpm_getstr0(TAG_DESCRIPTION)); + } + if (func & rpm_query_list) { + int count, it, flags; + count = rpm_getcount(TAG_BASENAMES); + for (it = 0; it < count; it++) { + flags = rpm_getint(TAG_FILEFLAGS, it); + switch (func & (rpm_query_list_doc|rpm_query_list_config)) { + case rpm_query_list_doc: + if (!(flags & RPMFILE_DOC)) continue; + break; + case rpm_query_list_config: + if (!(flags & RPMFILE_CONFIG)) continue; + break; + case rpm_query_list_doc|rpm_query_list_config: + if (!(flags & (RPMFILE_CONFIG|RPMFILE_DOC))) continue; + break; + } + printf("%s%s\n", + rpm_getstr(TAG_DIRNAMES, rpm_getint(TAG_DIRINDEXES, it)), + rpm_getstr(TAG_BASENAMES, it)); + } + } + } else { + /* Unsupported (help text shows what we support) */ + bb_show_usage(); + } + if (!*++argv) + break; + munmap(G.map, G.mapsize); + free(G.mytags); + close(rpm_fd); + } + + return 0; +} + +#endif /* RPM */ + +/* + * Mini rpm2cpio implementation for busybox + * + * Copyright (C) 2001 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RPM2CPIO +//config: bool "rpm2cpio (21 kb)" +//config: default y +//config: help +//config: Converts a RPM file into a CPIO archive. + +//applet:IF_RPM2CPIO(APPLET(rpm2cpio, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_RPM2CPIO) += rpm.o + +//usage:#define rpm2cpio_trivial_usage +//usage: "PACKAGE.rpm" +//usage:#define rpm2cpio_full_usage "\n\n" +//usage: "Output a cpio archive of the rpm file" + +#if ENABLE_RPM2CPIO + +/* No getopt required */ +int rpm2cpio_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) +{ + const char *str; + int rpm_fd; + + INIT_G(); + INIT_PAGESIZE(G.pagesize); + + rpm_fd = rpm_gettags(argv[1]); + + //if (SEAMLESS_COMPRESSION) - we do this at the end instead. + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); + + if (ENABLE_FEATURE_SEAMLESS_LZMA + && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL + && strcmp(str, "lzma") == 0 + ) { + // lzma compression can't be detected + // set up decompressor without detection + setup_lzma_on_fd(rpm_fd); + } else { + setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); + } + + if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) + bb_simple_error_msg_and_die("error unpacking"); + + if (ENABLE_FEATURE_CLEAN_UP) { + close(rpm_fd); + } + + if (SEAMLESS_COMPRESSION) { + check_errors_in_children(0); + return bb_got_signal; + } + return EXIT_SUCCESS; +} + +#endif /* RPM2CPIO */ diff --git a/busybox-1_37_0/archival/rpm.h b/busybox-1_37_0/archival/rpm.h new file mode 100644 index 000000000..afe2b550c --- /dev/null +++ b/busybox-1_37_0/archival/rpm.h @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * RPM structs and consts + * + * Copyright (C) 2001 by Laurence Anderson + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* RPM file starts with this struct: */ +struct rpm_lead { + uint32_t magic; + uint8_t major, minor; + uint16_t type; + uint16_t archnum; + char name[66]; + uint16_t osnum; + uint16_t signature_type; + char reserved[16]; +}; +struct BUG_rpm_lead { + char bug[sizeof(struct rpm_lead) == 96 ? 1 : -1]; +}; +#define RPM_LEAD_MAGIC 0xedabeedb +#define RPM_LEAD_MAGIC_STR "\355\253\356\333" + +/* Then follows the header: */ +struct rpm_header { + uint32_t magic_and_ver; /* 3 byte magic: 0x8e 0xad 0xe8; 1 byte version: 0x01 */ + uint32_t reserved; /* 4 bytes reserved */ + uint32_t entries; /* Number of entries in header (4 bytes) */ + uint32_t size; /* Size of store (4 bytes) */ +}; +struct BUG_rpm_header { + char bug[sizeof(struct rpm_header) == 16 ? 1 : -1]; +}; +#define RPM_HEADER_MAGICnVER 0x8eade801 +#define RPM_HEADER_MAGIC_STR "\216\255\350" diff --git a/busybox-1_37_0/archival/tar.c b/busybox-1_37_0/archival/tar.c new file mode 100644 index 000000000..d6ca6c1e0 --- /dev/null +++ b/busybox-1_37_0/archival/tar.c @@ -0,0 +1,1286 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tar implementation for busybox + * + * Modified to use common extraction code used by ar, cpio, dpkg-deb, dpkg + * by Glenn McGrath + * + * Note, that as of BusyBox-0.43, tar has been completely rewritten from the + * ground up. It still has remnants of the old code lying about, but it is + * very different now (i.e., cleaner, less global variables, etc.) + * + * Copyright (C) 1999-2004 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 GPL has been granted. + * + * Based in part on the tar implementation from busybox-0.28 + * Copyright (C) 1995 Bruce Perens + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config TAR +//config: bool "tar (39 kb)" +//config: default y +//config: help +//config: tar is an archiving program. It's commonly used with gzip to +//config: create compressed archives. It's probably the most widely used +//config: UNIX archive program. +//config: +//config:config FEATURE_TAR_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on TAR && LONG_OPTS +//config: +//config:config FEATURE_TAR_CREATE +//config: bool "Enable -c (archive creation)" +//config: default y +//config: depends on TAR +//config: +//config:config FEATURE_TAR_AUTODETECT +//config: bool "Autodetect compressed tarballs" +//config: default y +//config: depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ) +//config: help +//config: With this option tar can automatically detect compressed +//config: tarballs. Currently it works only on files (not pipes etc). +//config: +//config:config FEATURE_TAR_FROM +//config: bool "Enable -X (exclude from) and -T (include from) options" +//config: default y +//config: depends on TAR +//config: help +//config: If you enable this option you'll be able to specify +//config: a list of files to include or exclude from an archive. +//config: +//config:config FEATURE_TAR_OLDGNU_COMPATIBILITY +//config: bool "Support old tar header format" +//config: default y +//config: depends on TAR || DPKG +//config: help +//config: This option is required to unpack archives created in +//config: the old GNU format; help to kill this old format by +//config: repacking your ancient archives with the new format. +//config: +//config:config FEATURE_TAR_OLDSUN_COMPATIBILITY +//config: bool "Enable untarring of tarballs with checksums produced by buggy Sun tar" +//config: default y +//config: depends on TAR || DPKG +//config: help +//config: This option is required to unpack archives created by some old +//config: version of Sun's tar (it was calculating checksum using signed +//config: arithmetic). It is said to be fixed in newer Sun tar, but "old" +//config: tarballs still exist. +//config: +//config:config FEATURE_TAR_GNU_EXTENSIONS +//config: bool "Support GNU tar extensions (long filenames)" +//config: default y +//config: depends on TAR || DPKG +//config: +//config:config FEATURE_TAR_TO_COMMAND +//config: bool "Support writing to an external program (--to-command)" +//config: default y +//config: depends on TAR && FEATURE_TAR_LONG_OPTIONS +//config: help +//config: If you enable this option you'll be able to instruct tar to send +//config: the contents of each extracted file to the standard input of an +//config: external program. +//config: +//config:config FEATURE_TAR_UNAME_GNAME +//config: bool "Enable use of user and group names" +//config: default y +//config: depends on TAR +//config: help +//config: Enable use of user and group names in tar. This affects contents +//config: listings (-t) and preserving permissions when unpacking (-p). +//config: +200 bytes. +//config: +//config:config FEATURE_TAR_NOPRESERVE_TIME +//config: bool "Enable -m (do not preserve time) GNU option" +//config: default y +//config: depends on TAR +//config: +//config:config FEATURE_TAR_SELINUX +//config: bool "Support extracting SELinux labels" +//config: default n +//config: depends on TAR && SELINUX +//config: help +//config: With this option busybox supports restoring SELinux labels +//config: when extracting files from tar archives. + +//applet:IF_TAR(APPLET(tar, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TAR) += tar.o + +#include +#include "libbb.h" +#include "common_bufsiz.h" +#include "bb_archive.h" +/* FIXME: Stop using this non-standard feature */ +#ifndef FNM_LEADING_DIR +# define FNM_LEADING_DIR 0 +#endif + +#if 0 +# define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) +#else +# define DBG(...) ((void)0) +#endif +#define DBG_OPTION_PARSING 0 + + +#define block_buf bb_common_bufsiz1 +#define INIT_G() do { setup_common_bufsiz(); } while (0) + + +#if ENABLE_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 { + struct 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) */ +} HardLinkInfo; + +/* Some info to be carried along when creating a new tarball */ +typedef struct TarBallInfo { + int tarFd; /* Open-for-write file descriptor + * for the tarball */ + int verboseFlag; /* Whether to print extra stuff or not */ +# if ENABLE_FEATURE_TAR_FROM + const llist_t *excludeList; /* List of files to not include */ +# endif + HardLinkInfo *hlInfoHead; /* Hard Link Tracking Information */ + HardLinkInfo *hlInfo; /* Hard Link Info for the current file */ +//TODO: save only st_dev + st_ino + struct stat tarFileStatBuf; /* 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 */ +} TarBallInfo; + +/* A nice enum with all the possible tar file content types */ +enum { + 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 */ +}; + +/* Might be faster (and bigger) if the dev/ino were stored in numeric order;) */ +static void addHardLinkInfo(HardLinkInfo **hlInfoHeadPtr, + struct stat *statbuf, + const char *fileName) +{ + /* Note: hlInfoHeadPtr can never be NULL! */ + HardLinkInfo *hlInfo; + + hlInfo = xmalloc(sizeof(HardLinkInfo) + strlen(fileName)); + hlInfo->next = *hlInfoHeadPtr; + *hlInfoHeadPtr = hlInfo; + hlInfo->dev = statbuf->st_dev; + hlInfo->ino = statbuf->st_ino; +// hlInfo->linkCount = statbuf->st_nlink; + strcpy(hlInfo->name, fileName); +} + +static void freeHardLinkInfo(HardLinkInfo **hlInfoHeadPtr) +{ + HardLinkInfo *hlInfo; + HardLinkInfo *hlInfoNext; + + if (hlInfoHeadPtr) { + hlInfo = *hlInfoHeadPtr; + while (hlInfo) { + hlInfoNext = hlInfo->next; + free(hlInfo); + hlInfo = hlInfoNext; + } + *hlInfoHeadPtr = NULL; + } +} + +/* Might be faster (and bigger) if the dev/ino were stored in numeric order ;) */ +static HardLinkInfo *findHardLinkInfo(HardLinkInfo *hlInfo, struct stat *statbuf) +{ + while (hlInfo) { + if (statbuf->st_ino == hlInfo->ino + && statbuf->st_dev == hlInfo->dev + ) { + DBG("found hardlink:'%s'", hlInfo->name); + break; + } + hlInfo = hlInfo->next; + } + return hlInfo; +} + +/* Put an octal string into the specified buffer. + * The number is zero padded and possibly NUL terminated. + * Stores low-order bits only if whole value does not fit. */ +static void putOctal(char *cp, int len, off_t value) +{ + char tempBuffer[sizeof(off_t)*3 + 1]; + char *tempString = tempBuffer; + int width; + + width = sprintf(tempBuffer, "%0*"OFF_FMT"o", len, value); + tempString += (width - len); + + /* If string has leading zeroes, we can drop one */ + /* and field will have trailing '\0' */ + /* (increases chances of compat with other tars) */ + if (tempString[0] == '0') + tempString++; + + /* Copy the string to the field */ + memcpy(cp, tempString, len); +} +#define PUT_OCTAL(a, b) putOctal((a), sizeof(a), (b)) + +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS +static void writeLongname(int fd, int type, const char *name, int dir) +{ + struct prefilled { + 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 */ + }; + struct tar_header_t header; + int size; + + memset(&header, 0, sizeof(header)); + header.typeflag = type; + strcpy(header.name, "././@LongLink"); + /* This sets mode/uid/gid/mtime to "00...00" strings */ + memset((char*)&header + offsetof(struct tar_header_t, mode), /* make gcc-9.x happy */ + '0', sizeof(struct prefilled)); + header.mode [sizeof(header.mode ) - 1] = '\0'; + header.uid [sizeof(header.uid ) - 1] = '\0'; + header.gid [sizeof(header.gid ) - 1] = '\0'; + /* header.size is filled by '0' now, will be corrected below */ + header.mtime[sizeof(header.mtime) - 1] = '\0'; + + dir = !!dir; /* normalize: 0/1 */ + size = strlen(name) + 1 + dir; /* GNU tar uses strlen+1 */ + /* + dir: account for possible '/' */ + + PUT_OCTAL(header.size, size); + chksum_and_xwrite_tar_header(fd, &header); + + /* Write filename[/] and pad the block. */ + /* dir=0: writes 'name', pads */ + /* dir=1: writes 'name', writes '/', pads */ + dir *= 2; + xwrite(fd, name, size - dir); + xwrite(fd, "/", dir); + size = (-size) & (TAR_BLOCK_SIZE-1); + memset(&header, 0, size); + xwrite(fd, &header, size); +} +# endif + +/* Write out a tar header for the specified file/directory/whatever */ +static int writeTarHeader(struct TarBallInfo *tbInfo, + const char *header_name, const char *fileName, struct stat *statbuf) +{ + struct tar_header_t header; + + memset(&header, 0, sizeof(header)); + + strncpy(header.name, header_name, sizeof(header.name)); + + /* POSIX says to mask mode with 07777. */ + PUT_OCTAL(header.mode, statbuf->st_mode & 07777); + PUT_OCTAL(header.uid, statbuf->st_uid); + PUT_OCTAL(header.gid, statbuf->st_gid); + memset(header.size, '0', sizeof(header.size)-1); /* Regular file size is handled later */ + /* users report that files with negative st_mtime cause trouble, so: */ + PUT_OCTAL(header.mtime, statbuf->st_mtime >= 0 ? statbuf->st_mtime : 0); + + /* Enter the user and group names */ + safe_strncpy(header.uname, get_cached_username(statbuf->st_uid), sizeof(header.uname)); + safe_strncpy(header.gname, get_cached_groupname(statbuf->st_gid), sizeof(header.gname)); + + if (tbInfo->hlInfo) { + /* This is a hard link */ + header.typeflag = LNKTYPE; + strncpy(header.linkname, tbInfo->hlInfo->name, + sizeof(header.linkname)); +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + /* Write out long linkname if needed */ + if (header.linkname[sizeof(header.linkname)-1]) + writeLongname(tbInfo->tarFd, GNULONGLINK, + tbInfo->hlInfo->name, 0); +# endif + } else if (S_ISLNK(statbuf->st_mode)) { + char *lpath = xmalloc_readlink_or_warn(fileName); + if (!lpath) + return FALSE; + header.typeflag = SYMTYPE; + strncpy(header.linkname, lpath, sizeof(header.linkname)); +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + /* Write out long linkname if needed */ + if (header.linkname[sizeof(header.linkname)-1]) + writeLongname(tbInfo->tarFd, GNULONGLINK, lpath, 0); +# else + /* If it is larger than 100 bytes, bail out */ + if (header.linkname[sizeof(header.linkname)-1]) { + free(lpath); + bb_simple_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); + return FALSE; + } +# endif + free(lpath); + } else if (S_ISDIR(statbuf->st_mode)) { + header.typeflag = DIRTYPE; + /* Append '/' only if there is a space for it */ + if (!header.name[sizeof(header.name)-1]) + header.name[strlen(header.name)] = '/'; + } else if (S_ISCHR(statbuf->st_mode)) { + header.typeflag = CHRTYPE; + PUT_OCTAL(header.devmajor, major(statbuf->st_rdev)); + PUT_OCTAL(header.devminor, minor(statbuf->st_rdev)); + } else if (S_ISBLK(statbuf->st_mode)) { + header.typeflag = BLKTYPE; + PUT_OCTAL(header.devmajor, major(statbuf->st_rdev)); + PUT_OCTAL(header.devminor, minor(statbuf->st_rdev)); + } else if (S_ISFIFO(statbuf->st_mode)) { + header.typeflag = FIFOTYPE; + } else if (S_ISREG(statbuf->st_mode)) { + /* header.size field is 12 bytes long */ + /* Does octal-encoded size fit? */ + uoff_t filesize = statbuf->st_size; + if (sizeof(filesize) <= 4 + || filesize <= (uoff_t)0777777777777LL + ) { + PUT_OCTAL(header.size, filesize); + } + /* Does base256-encoded size fit? + * It always does unless off_t is wider than 64 bits. + */ + else if (ENABLE_FEATURE_TAR_GNU_EXTENSIONS +# if ULLONG_MAX > 0xffffffffffffffffLL /* 2^64-1 */ + && (filesize <= 0x3fffffffffffffffffffffffLL) +# endif + ) { + /* GNU tar uses "base-256 encoding" for very large numbers. + * Encoding is binary, with highest bit always set as a marker + * and sign in next-highest bit: + * 80 00 .. 00 - zero + * bf ff .. ff - largest positive number + * ff ff .. ff - minus 1 + * c0 00 .. 00 - smallest negative number + */ + char *p8 = header.size + sizeof(header.size); + do { + *--p8 = (uint8_t)filesize; + filesize >>= 8; + } while (p8 != header.size); + *p8 |= 0x80; + } else { + bb_error_msg_and_die("can't store file '%s' " + "of size %"OFF_FMT"u, aborting", + fileName, statbuf->st_size); + } + header.typeflag = REGTYPE; + } else { + bb_error_msg("%s: unknown file type", fileName); + return FALSE; + } + +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + /* Write out long name if needed */ + /* (we, like GNU tar, output long linkname *before* long name) */ + if (header.name[sizeof(header.name)-1]) + writeLongname(tbInfo->tarFd, GNULONGNAME, + header_name, S_ISDIR(statbuf->st_mode)); +# endif + + chksum_and_xwrite_tar_header(tbInfo->tarFd, &header); + + /* Now do the verbose thing (or not) */ + if (tbInfo->verboseFlag) { + FILE *vbFd = stdout; + + /* If archive goes to stdout, verbose goes to stderr */ + if (tbInfo->tarFd == STDOUT_FILENO) + vbFd = stderr; + /* GNU "tar cvvf" prints "extended" listing a-la "ls -l" */ + /* We don't have such excesses here: for us "v" == "vv" */ + /* '/' is probably a GNUism */ + fprintf(vbFd, "%s%s\n", header_name, + S_ISDIR(statbuf->st_mode) ? "/" : ""); + } + + return TRUE; +} + +# if ENABLE_FEATURE_TAR_FROM +static int exclude_file(const llist_t *excluded_files, const char *file) +{ + while (excluded_files) { + if (excluded_files->data[0] == '/') { + if (fnmatch(excluded_files->data, 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->data, p, + FNM_PATHNAME | FNM_LEADING_DIR) == 0 + ) { + return 1; + } + } + } + excluded_files = excluded_files->link; + } + + return 0; +} +# else +# define exclude_file(excluded_files, file) 0 +# endif + +static int FAST_FUNC writeFileToTarball(struct recursive_state *state, + const char *fileName, + struct stat *statbuf) +{ + struct TarBallInfo *tbInfo = (struct TarBallInfo *) state->userData; + const char *header_name; + int inputFileFd = -1; + + DBG("writeFileToTarball('%s')", fileName); + + /* Strip leading '/' and such (must be before memorizing hardlink's name) */ + header_name = strip_unsafe_prefix(fileName); + + if (header_name[0] == '\0') + return TRUE; + + if (exclude_file(tbInfo->excludeList, header_name)) + return SKIP; /* "do not recurse on this directory", no error message printed */ + + /* It is against the rules to archive a socket */ + if (S_ISSOCK(statbuf->st_mode)) { + bb_error_msg("%s: socket ignored", fileName); + return TRUE; + } + + /* + * Check to see if we are dealing with a hard link. + * If so - + * Treat the first occurrence of a given dev/inode as a file while + * treating any additional occurrences as hard links. This is done + * by adding the file information to the HardLinkInfo linked list. + */ + tbInfo->hlInfo = NULL; + if (!S_ISDIR(statbuf->st_mode) && statbuf->st_nlink > 1) { + DBG("'%s': st_nlink > 1", header_name); + tbInfo->hlInfo = findHardLinkInfo(tbInfo->hlInfoHead, statbuf); + if (tbInfo->hlInfo == NULL) { + DBG("'%s': addHardLinkInfo", header_name); + addHardLinkInfo(&tbInfo->hlInfoHead, statbuf, header_name); + } + } + + /* 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->tarFileStatBuf.st_dev == statbuf->st_dev + && tbInfo->tarFileStatBuf.st_ino == statbuf->st_ino + ) { + bb_error_msg("%s: file is the archive; skipping", fileName); + return TRUE; + } + +# if !ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (strlen(header_name) >= NAME_SIZE) { + bb_simple_error_msg("names longer than "NAME_SIZE_STR" chars not supported"); + return TRUE; + } +# endif + + /* Is this a regular file? */ + if (tbInfo->hlInfo == NULL && S_ISREG(statbuf->st_mode)) { + /* open the file we want to archive, and make sure all is well */ + inputFileFd = open_or_warn(fileName, O_RDONLY); + if (inputFileFd < 0) { + return FALSE; /* make recursive_action() return FALSE */ + } + } + + /* Add an entry to the tarball */ + if (writeTarHeader(tbInfo, header_name, fileName, statbuf) == FALSE) { + return FALSE; /* make recursive_action() return FALSE */ + } + + /* If it was a regular file, write out the body */ + if (inputFileFd >= 0) { + size_t readSize; + /* Write the file to the archive. */ + /* We record size into header first, */ + /* and then write out file. If file shrinks in between, */ + /* tar will be corrupted. So we don't allow for that. */ + /* NB: GNU tar 1.16 warns and pads with zeroes */ + /* or even seeks back and updates header */ + bb_copyfd_exact_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); + ////off_t readSize; + ////readSize = bb_copyfd_size(inputFileFd, tbInfo->tarFd, statbuf->st_size); + ////if (readSize != statbuf->st_size && readSize >= 0) { + //// bb_error_msg_and_die("short read from %s, aborting", fileName); + ////} + + /* Check that file did not grow in between? */ + /* if (safe_read(inputFileFd, 1) == 1) warn but continue? */ + + close(inputFileFd); + + /* Pad the file up to the tar block size */ + /* (a few tricks here in the name of code size) */ + readSize = (-(int)statbuf->st_size) & (TAR_BLOCK_SIZE-1); + memset(block_buf, 0, readSize); + xwrite(tbInfo->tarFd, block_buf, readSize); + } + + return TRUE; +} + +# if SEAMLESS_COMPRESSION +/* Don't inline: vfork scares gcc and pessimizes code */ +static void NOINLINE vfork_compressor(int tar_fd, const char *gzip) +{ + // On Linux, vfork never unpauses parent early, although standard + // allows for that. Do we want to waste bytes checking for it? +# define WAIT_FOR_CHILD 0 + volatile int vfork_exec_errno = 0; + struct fd_pair data; +# if WAIT_FOR_CHILD + struct fd_pair status; + xpiped_pair(status); +# endif + xpiped_pair(data); + + signal(SIGPIPE, SIG_IGN); /* we only want EPIPE on errors */ + + if (xvfork() == 0) { + /* child */ + int tfd; + /* NB: close _first_, then move fds! */ + close(data.wr); +# if WAIT_FOR_CHILD + close(status.rd); + /* status.wr will close only on exec - + * parent waits for this close to happen */ + fcntl(status.wr, F_SETFD, FD_CLOEXEC); +# endif + /* copy it: parent's tar_fd variable must not change */ + tfd = tar_fd; + if (tfd == 0) { + /* Output tar fd may be zero. + * xmove_fd(data.rd, 0) would destroy it. + * Reproducer: + * exec 0>&- + * exec 1>&- + * tar czf Z.tar.gz FILE + * Swapping move_fd's order wouldn't work: + * data.rd is 1 and _it_ would be destroyed. + */ + tfd = dup(tfd); + } + xmove_fd(data.rd, 0); + xmove_fd(tfd, 1); + + /* exec gzip/bzip2/... program */ + //BB_EXECLP(gzip, gzip, "-f", (char *)0); - WRONG for "xz", + // if xz is an enabled applet, it'll be a version which + // can only decompress. We do need to execute external + // program, not applet. + execlp(gzip, gzip, "-f", (char *)0); + + vfork_exec_errno = errno; + _exit_FAILURE(); + } + + /* parent */ + xmove_fd(data.wr, tar_fd); + close(data.rd); +# if WAIT_FOR_CHILD + close(status.wr); + while (1) { + /* Wait until child execs (or fails to) */ + char buf; + int n = full_read(status.rd, &buf, 1); + if (n < 0 /* && errno == EAGAIN */) + continue; /* try it again */ + } + close(status.rd); +# endif + if (vfork_exec_errno) { + errno = vfork_exec_errno; + bb_perror_msg_and_die("can't execute '%s'", gzip); + } +} +# endif /* SEAMLESS_COMPRESSION */ + + +# if !SEAMLESS_COMPRESSION +/* Do not pass gzip flag to writeTarFile() */ +#define writeTarFile(tbInfo, recurseFlags, filelist, gzip) \ + writeTarFile(tbInfo, recurseFlags, filelist) +# endif +/* gcc 4.2.1 inlines it, making code bigger */ +static NOINLINE int writeTarFile( + struct TarBallInfo *tbInfo, + int recurseFlags, + const llist_t *filelist, + const char *gzip) +{ + int errorFlag = FALSE; + + /*tbInfo->hlInfoHead = NULL; - already is */ + + /* Store the stat info for the tarball's file, so + * can avoid including the tarball into itself.... */ + xfstat(tbInfo->tarFd, &tbInfo->tarFileStatBuf, "can't stat tar file"); + +# if SEAMLESS_COMPRESSION + if (gzip) + vfork_compressor(tbInfo->tarFd, gzip); +# endif + + /* Read the directory/files and iterate over them one at a time */ + while (filelist) { + if (!recursive_action(filelist->data, recurseFlags, + writeFileToTarball, writeFileToTarball, tbInfo) + ) { + errorFlag = TRUE; + } + filelist = filelist->link; + } + /* Write two empty blocks to the end of the archive */ + memset(block_buf, 0, 2*TAR_BLOCK_SIZE); + xwrite(tbInfo->tarFd, block_buf, 2*TAR_BLOCK_SIZE); + + /* 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 */ + + /* Close so the child process (if any) will exit */ + close(tbInfo->tarFd); + + /* Hang up the tools, close up shop, head home */ + if (ENABLE_FEATURE_CLEAN_UP) + freeHardLinkInfo(&tbInfo->hlInfoHead); + + if (errorFlag) + bb_simple_error_msg("error exit delayed from previous errors"); + +# if SEAMLESS_COMPRESSION + if (gzip) { + int status; + if (safe_waitpid(-1, &status, 0) == -1) + bb_simple_perror_msg("waitpid"); + else if (!WIFEXITED(status) || WEXITSTATUS(status)) + /* gzip was killed or has exited with nonzero! */ + errorFlag = TRUE; + } +# endif + return errorFlag; +} + +#endif /* FEATURE_TAR_CREATE */ + +#if ENABLE_FEATURE_TAR_FROM +static llist_t *append_file_list_to_list(llist_t *list) +{ + llist_t *newlist = NULL; + + while (list) { + FILE *src_stream; + char *line; + + src_stream = xfopen_stdin(llist_pop(&list)); + while ((line = xmalloc_fgetline(src_stream)) != NULL) { + /* kill trailing '/' unless the string is just "/" */ + char *cp = last_char_is(line, '/'); + if (cp > line) + *cp = '\0'; + llist_add_to_end(&newlist, line); + } + fclose(src_stream); + } + return newlist; +} +#endif + +//usage:#define tar_trivial_usage +//usage: IF_FEATURE_TAR_CREATE("c|") "x|t [-" +//usage: IF_FEATURE_SEAMLESS_Z("Z") +//usage: IF_FEATURE_SEAMLESS_GZ("z") +//usage: IF_FEATURE_SEAMLESS_XZ("J") +//usage: IF_FEATURE_SEAMLESS_BZ2("j") +//usage: "a" +//usage: IF_FEATURE_TAR_CREATE("h") +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") +//usage: "vokO] " +//usage: "[-f TARFILE] [-C DIR] " +//usage: IF_FEATURE_TAR_FROM("[-T FILE] [-X FILE] "IF_FEATURE_TAR_LONG_OPTIONS("[LONGOPT]... ")) +//usage: "[FILE]..." +//usage:#define tar_full_usage "\n\n" +//usage: IF_FEATURE_TAR_CREATE("Create, extract, ") +//usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") +//usage: "or list files from a tar file" +//usage: "\n" +//usage: IF_FEATURE_TAR_CREATE( +//usage: "\n c Create" +//usage: ) +//usage: "\n x Extract" +//usage: "\n t List" +//usage: "\n -f FILE Name of TARFILE ('-' for stdin/out)" +//usage: "\n -C DIR Change to DIR before operation" +//usage: "\n -v Verbose" +//usage: "\n -O Extract to stdout" +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME( +//usage: "\n -m Don't restore mtime" +//usage: ) +//usage: "\n -o Don't restore user:group" +///////:-p - accepted but ignored, restores mode (aliases in GNU tar: --preserve-permissions, --same-permissions) +//usage: "\n -k Don't replace existing files" +//usage: IF_FEATURE_SEAMLESS_Z( +//usage: "\n -Z (De)compress using compress" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_GZ( +//usage: "\n -z (De)compress using gzip" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_XZ( +//usage: "\n -J (De)compress using xz" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_BZ2( +//usage: "\n -j (De)compress using bzip2" +//usage: ) +//usage: IF_FEATURE_SEAMLESS_LZMA( +//usage: IF_FEATURE_TAR_LONG_OPTIONS( +//usage: "\n --lzma (De)compress using lzma" +//usage: ) +//usage: ) +//usage: "\n -a (De)compress based on extension" +//usage: IF_FEATURE_TAR_CREATE( +//usage: "\n -h Follow symlinks" +//usage: ) +//usage: IF_FEATURE_TAR_FROM( +//usage: "\n -T FILE File with names to include" +//usage: "\n -X FILE File with glob patterns to exclude" +//usage: IF_FEATURE_TAR_LONG_OPTIONS( +//usage: "\n --exclude PATTERN Glob pattern to exclude" +//usage: ) +//usage: ) +//usage: IF_FEATURE_TAR_LONG_OPTIONS( +//usage: "\n --overwrite Replace existing files" +//usage: "\n --strip-components NUM NUM of leading components to strip" +//usage: "\n --no-recursion Don't descend in directories" +//usage: "\n --numeric-owner Use numeric user:group" +//usage: "\n --no-same-permissions Don't restore access permissions" +//usage: IF_FEATURE_TAR_TO_COMMAND( +//usage: "\n --to-command COMMAND Pipe files to COMMAND" +//usage: ) +//usage: ) +//usage: +//usage:#define tar_example_usage +//usage: "$ zcat /tmp/tarball.tar.gz | tar -xf -\n" +//usage: "$ tar -cf /tmp/tarball.tar /usr/local\n" + +enum { + OPTBIT_KEEP_OLD = 8, + IF_FEATURE_TAR_CREATE( OPTBIT_CREATE ,) + IF_FEATURE_TAR_CREATE( OPTBIT_DEREFERENCE ,) + IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2 ,) + IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) + IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) + IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,) + IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,) + IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit + OPTBIT_AUTOCOMPRESS_BY_EXT, + IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + OPTBIT_STRIP_COMPONENTS, + IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA ,) + OPTBIT_NORECURSION, + IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) + OPTBIT_NUMERIC_OWNER, + OPTBIT_NOPRESERVE_PERM, + OPTBIT_OVERWRITE, +#endif + OPT_TEST = 1 << 0, // t + OPT_EXTRACT = 1 << 1, // x + OPT_BASEDIR = 1 << 2, // C + OPT_TARNAME = 1 << 3, // f + OPT_2STDOUT = 1 << 4, // O + OPT_NOPRESERVE_OWNER = 1 << 5, // o == no-same-owner + OPT_P = 1 << 6, // p + OPT_VERBOSE = 1 << 7, // v + OPT_KEEP_OLD = 1 << 8, // k + OPT_CREATE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_CREATE )) + 0, // c + OPT_DEREFERENCE = IF_FEATURE_TAR_CREATE( (1 << OPTBIT_DEREFERENCE )) + 0, // h + OPT_BZIP2 = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2 )) + 0, // j + OPT_INCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_INCLUDE_FROM)) + 0, // T + OPT_EXCLUDE_FROM = IF_FEATURE_TAR_FROM( (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X + OPT_GZIP = IF_FEATURE_SEAMLESS_GZ( (1 << OPTBIT_GZIP )) + 0, // z + OPT_XZ = IF_FEATURE_SEAMLESS_XZ( (1 << OPTBIT_XZ )) + 0, // J + OPT_COMPRESS = IF_FEATURE_SEAMLESS_Z( (1 << OPTBIT_COMPRESS )) + 0, // Z + OPT_AUTOCOMPRESS_BY_EXT = 1 << OPTBIT_AUTOCOMPRESS_BY_EXT, // a + OPT_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m + OPT_STRIP_COMPONENTS = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_STRIP_COMPONENTS)) + 0, // strip-components + OPT_LZMA = IF_FEATURE_TAR_LONG_OPTIONS(IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA))) + 0, // lzma + OPT_NORECURSION = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NORECURSION )) + 0, // no-recursion + OPT_2COMMAND = IF_FEATURE_TAR_TO_COMMAND( (1 << OPTBIT_2COMMAND )) + 0, // to-command + OPT_NUMERIC_OWNER = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NUMERIC_OWNER )) + 0, // numeric-owner + OPT_NOPRESERVE_PERM = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_NOPRESERVE_PERM)) + 0, // no-same-permissions + OPT_OVERWRITE = IF_FEATURE_TAR_LONG_OPTIONS((1 << OPTBIT_OVERWRITE )) + 0, // overwrite + + OPT_ANY_COMPRESS = (OPT_BZIP2 | OPT_LZMA | OPT_GZIP | OPT_XZ | OPT_COMPRESS), +}; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS +static const char tar_longopts[] ALIGN1 = + "list\0" No_argument "t" + "extract\0" No_argument "x" + "directory\0" Required_argument "C" + "file\0" Required_argument "f" + "to-stdout\0" No_argument "O" + /* do not restore owner */ + /* Note: GNU tar handles 'o' as no-same-owner only on extract, + * on create, 'o' is --old-archive. We do not support --old-archive. */ + "no-same-owner\0" No_argument "o" + "same-permissions\0" No_argument "p" + "verbose\0" No_argument "v" + "keep-old\0" No_argument "k" +# if ENABLE_FEATURE_TAR_CREATE + "create\0" No_argument "c" + "dereference\0" No_argument "h" +# endif +# if ENABLE_FEATURE_SEAMLESS_BZ2 + "bzip2\0" No_argument "j" +# endif +# if ENABLE_FEATURE_TAR_FROM + "files-from\0" Required_argument "T" + "exclude-from\0" Required_argument "X" +# endif +# if ENABLE_FEATURE_SEAMLESS_GZ + "gzip\0" No_argument "z" +# endif +# if ENABLE_FEATURE_SEAMLESS_XZ + "xz\0" No_argument "J" +# endif +# if ENABLE_FEATURE_SEAMLESS_Z + "compress\0" No_argument "Z" +# endif + "auto-compress\0" No_argument "a" +# if ENABLE_FEATURE_TAR_NOPRESERVE_TIME + "touch\0" No_argument "m" +# endif + "strip-components\0" Required_argument "\xf8" +# if ENABLE_FEATURE_SEAMLESS_LZMA + "lzma\0" No_argument "\xf9" +# endif + "no-recursion\0" No_argument "\xfa" +# if ENABLE_FEATURE_TAR_TO_COMMAND + "to-command\0" Required_argument "\xfb" +# endif + /* use numeric uid/gid from tar header, not textual */ + "numeric-owner\0" No_argument "\xfc" + /* do not restore mode */ + "no-same-permissions\0" No_argument "\xfd" + /* on unpack, open with O_TRUNC and !O_EXCL */ + "overwrite\0" No_argument "\xfe" + /* --exclude takes next bit position in option mask, */ + /* therefore we have to put it _after_ --no-same-permissions */ +# if ENABLE_FEATURE_TAR_FROM + "exclude\0" Required_argument "\xff" +# endif + ; +# define GETOPT32 getopt32long +# define LONGOPTS ,tar_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS +#endif + +int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tar_main(int argc UNUSED_PARAM, char **argv) +{ + archive_handle_t *tar_handle; + char *base_dir = NULL; + const char *tar_filename = "-"; + unsigned opt; + int verboseFlag = 0; +#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM + llist_t *excludes = NULL; +#endif + INIT_G(); + + /* Initialise default values */ + tar_handle = init_handle(); + tar_handle->ah_flags = ARCHIVE_CREATE_LEADING_DIRS + | ARCHIVE_RESTORE_DATE + | ARCHIVE_UNLINK_OLD; + + /* Apparently only root's tar preserves perms (see bug 3844) */ + if (getuid() != 0) + tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; + +#if ENABLE_DESKTOP + /* Lie to buildroot when it starts asking stupid questions. */ + if (argv[1] && strcmp(argv[1], "--version") == 0) { + // Output of 'tar --version' examples: + // tar (GNU tar) 1.15.1 + // tar (GNU tar) 1.25 + // bsdtar 2.8.3 - libarchive 2.8.3 + puts("tar (busybox) " BB_VER); + return 0; + } +#endif + if (argv[1] && argv[1][0] != '-' && argv[1][0] != '\0') { + /* Compat: + * 1st argument without dash handles options with parameters + * differently from dashed one: it takes *next argv[i]* + * as parameter even if there are more chars in 1st argument: + * "tar fx TARFILE" - "x" is not taken as f's param + * but is interpreted as -x option + * "tar -xf TARFILE" - dashed equivalent of the above + * "tar -fx ..." - "x" is taken as f's param + * getopt32 wouldn't handle 1st command correctly. + * Unfortunately, people do use such commands. + * We massage argv[1] to work around it by moving 'f' + * to the end of the string. + * More contrived "tar fCx TARFILE DIR" still fails, + * but such commands are much less likely to be used. + */ + char *f = strchr(argv[1], 'f'); + if (f) { + while (f[1] != '\0') { + *f = f[1]; + f++; + } + *f = 'f'; + } + /* Prepend '-' to the first argument */ + argv[1] = xasprintf("-%s", argv[1]); + } + opt = GETOPT32(argv, "^" + "txC:f:Oopvk" + IF_FEATURE_TAR_CREATE( "ch" ) + IF_FEATURE_SEAMLESS_BZ2( "j" ) + IF_FEATURE_TAR_FROM( "T:*X:*") + IF_FEATURE_SEAMLESS_GZ( "z" ) + IF_FEATURE_SEAMLESS_XZ( "J" ) + IF_FEATURE_SEAMLESS_Z( "Z" ) + "a" + IF_FEATURE_TAR_NOPRESERVE_TIME("m") + IF_FEATURE_TAR_LONG_OPTIONS("\xf8:") // --strip-components + "\0" + "tt:vv:" // count -t,-v +#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM + "\xff::" // --exclude=PATTERN is a list +#endif + IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd + IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive + IF_NOT_FEATURE_TAR_CREATE("t--x:x--t") // mutually exclusive +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + ":\xf8+" // --strip-components=NUM +#endif + LONGOPTS + , &base_dir // -C dir + , &tar_filename // -f filename + IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T + IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X +#if ENABLE_FEATURE_TAR_LONG_OPTIONS + , &tar_handle->tar__strip_components // --strip-components +#endif + IF_FEATURE_TAR_TO_COMMAND(, &(tar_handle->tar__to_command)) // --to-command +#if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM + , &excludes // --exclude +#endif + , &verboseFlag // combined count for -t and -v + , &verboseFlag // combined count for -t and -v + ); +#if DBG_OPTION_PARSING + bb_error_msg("opt: 0x%08x", opt); +# define showopt(o) bb_error_msg("opt & %s(%x):\t%x", #o, o, opt & o); + showopt(OPT_TEST ); + showopt(OPT_EXTRACT ); + showopt(OPT_BASEDIR ); + showopt(OPT_TARNAME ); + showopt(OPT_2STDOUT ); + showopt(OPT_NOPRESERVE_OWNER); + showopt(OPT_P ); + showopt(OPT_VERBOSE ); + showopt(OPT_KEEP_OLD ); + showopt(OPT_CREATE ); + showopt(OPT_DEREFERENCE ); + showopt(OPT_BZIP2 ); + showopt(OPT_INCLUDE_FROM ); + showopt(OPT_EXCLUDE_FROM ); + showopt(OPT_GZIP ); + showopt(OPT_XZ ); + showopt(OPT_COMPRESS ); + showopt(OPT_AUTOCOMPRESS_BY_EXT); + showopt(OPT_NOPRESERVE_TIME ); + showopt(OPT_STRIP_COMPONENTS); + showopt(OPT_LZMA ); + showopt(OPT_NORECURSION ); + showopt(OPT_2COMMAND ); + showopt(OPT_NUMERIC_OWNER ); + showopt(OPT_NOPRESERVE_PERM ); + showopt(OPT_OVERWRITE ); + showopt(OPT_ANY_COMPRESS ); + bb_error_msg("base_dir:'%s'", base_dir); + bb_error_msg("tar_filename:'%s'", tar_filename); + bb_error_msg("verboseFlag:%d", verboseFlag); + bb_error_msg("tar_handle->tar__to_command:'%s'", tar_handle->tar__to_command); + bb_error_msg("tar_handle->tar__strip_components:%u", tar_handle->tar__strip_components); + return 0; +# undef showopt +#endif + argv += optind; + + if (verboseFlag) + tar_handle->action_header = header_verbose_list; + if (verboseFlag == 1) + tar_handle->action_header = header_list; + + if (opt & OPT_EXTRACT) + tar_handle->action_data = data_extract_all; + + if (opt & OPT_2STDOUT) + tar_handle->action_data = data_extract_to_stdout; + + if (opt & OPT_2COMMAND) { + putenv((char*)"TAR_FILETYPE=f"); + signal(SIGPIPE, SIG_IGN); + tar_handle->action_data = data_extract_to_command; + IF_FEATURE_TAR_TO_COMMAND(tar_handle->tar__to_command_shell = xstrdup(get_shell_name());) + } + + if (opt & OPT_KEEP_OLD) + tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; + + if (opt & OPT_NUMERIC_OWNER) + tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER; + + if (opt & OPT_NOPRESERVE_OWNER) + tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_OWNER; + + if (opt & OPT_NOPRESERVE_PERM) + tar_handle->ah_flags |= ARCHIVE_DONT_RESTORE_PERM; + + if (opt & OPT_OVERWRITE) { + tar_handle->ah_flags &= ~ARCHIVE_UNLINK_OLD; + tar_handle->ah_flags |= ARCHIVE_O_TRUNC; + } + + if (opt & OPT_NOPRESERVE_TIME) + tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; + +#if ENABLE_FEATURE_TAR_FROM + /* Convert each -X EXCLFILE to list of to-be-rejected glob patterns */ + tar_handle->reject = append_file_list_to_list(tar_handle->reject); +# if ENABLE_FEATURE_TAR_LONG_OPTIONS + /* Append --exclude=GLOBPATTERNs to reject */ + if (excludes) { + llist_t **p2next = &tar_handle->reject; + while (*p2next) + p2next = &((*p2next)->link); + *p2next = excludes; + } +# endif + tar_handle->accept = append_file_list_to_list(tar_handle->accept); +#endif + + /* Setup an array of filenames to work with */ + /* TODO: This is the same as in ar, make a separate function? */ + while (*argv) { + /* kill trailing '/' unless the string is just "/" */ + char *cp = last_char_is(*argv, '/'); + if (cp > *argv) + *cp = '\0'; + llist_add_to_end(&tar_handle->accept, *argv); + argv++; + } + + if (tar_handle->accept || tar_handle->reject) + tar_handle->filter = filter_accept_reject_list; + + /* Open the tar file */ + { + int tar_fd = STDIN_FILENO; + int flags = O_RDONLY; + + if (opt & OPT_CREATE) { + /* Make sure there is at least one file to tar up */ + if (tar_handle->accept == NULL) + bb_simple_error_msg_and_die("empty archive"); + + tar_fd = STDOUT_FILENO; + /* Mimicking GNU tar 1.15.1: */ + flags = O_WRONLY | O_CREAT | O_TRUNC; + } + + if (LONE_DASH(tar_filename)) { + tar_handle->src_fd = tar_fd; + tar_handle->seek = seek_by_read; + } else + if (ENABLE_FEATURE_TAR_AUTODETECT + && ENABLE_FEATURE_SEAMLESS_LZMA + && flags == O_RDONLY + && !(opt & OPT_ANY_COMPRESS) + && is_suffixed_with(tar_filename, ".lzma") + /* We do this only for .lzma files, they have no signature. + * All other compression formats are recognized in + * get_header_tar() when first tar block has invalid format. + * Doing it here for all filenames would falsely trigger + * on e.g. tarball with 1st file named "BZh5". + */ + ) { + tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); + if (tar_handle->src_fd < 0) + bb_perror_msg_and_die("can't open '%s'", tar_filename); + } else { + tar_handle->src_fd = xopen(tar_filename, flags); +#if ENABLE_FEATURE_TAR_CREATE + if ((OPT_GZIP | OPT_BZIP2 | OPT_XZ | OPT_LZMA) != 0 /* at least one is config-enabled */ + && (opt & OPT_AUTOCOMPRESS_BY_EXT) + && flags != O_RDONLY + ) { + if (OPT_GZIP != 0 && is_suffixed_with(tar_filename, "gz")) + opt |= OPT_GZIP; + if (OPT_BZIP2 != 0 && is_suffixed_with(tar_filename, "bz2")) + opt |= OPT_BZIP2; + if (OPT_XZ != 0 && is_suffixed_with(tar_filename, "xz")) + opt |= OPT_XZ; + if (OPT_LZMA != 0 && is_suffixed_with(tar_filename, "lzma")) + opt |= OPT_LZMA; + } +#endif + } + } + + if (base_dir) + xchdir(base_dir); + +#if ENABLE_FEATURE_TAR_CREATE + /* Create an archive */ + if (opt & OPT_CREATE) { + struct TarBallInfo *tbInfo; +# if SEAMLESS_COMPRESSION + const char *zipMode = NULL; + if (opt & OPT_COMPRESS) + zipMode = "compress"; + if (opt & OPT_GZIP) + zipMode = "gzip"; + if (opt & OPT_BZIP2) + zipMode = "bzip2"; + if (opt & OPT_LZMA) + zipMode = "lzma"; + if (opt & OPT_XZ) + zipMode = "xz"; +# endif + tbInfo = xzalloc(sizeof(*tbInfo)); + tbInfo->tarFd = tar_handle->src_fd; + tbInfo->verboseFlag = verboseFlag; +# if ENABLE_FEATURE_TAR_FROM + tbInfo->excludeList = tar_handle->reject; +# endif + /* NB: writeTarFile() closes tar_handle->src_fd */ + return writeTarFile(tbInfo, + (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0) + | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE), + tar_handle->accept, + zipMode); + } +#endif + + if (opt & OPT_ANY_COMPRESS) { + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_state_t *xstate);) + USE_FOR_NOMMU(const char *xformer_prog;) + + if (opt & OPT_COMPRESS) { + USE_FOR_MMU(IF_FEATURE_SEAMLESS_Z(xformer = unpack_Z_stream;)) + USE_FOR_NOMMU(xformer_prog = "uncompress";) + } + if (opt & OPT_GZIP) { + USE_FOR_MMU(IF_FEATURE_SEAMLESS_GZ(xformer = unpack_gz_stream;)) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + } + if (opt & OPT_BZIP2) { + USE_FOR_MMU(IF_FEATURE_SEAMLESS_BZ2(xformer = unpack_bz2_stream;)) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + } + if (opt & OPT_LZMA) { + USE_FOR_MMU(IF_FEATURE_SEAMLESS_LZMA(xformer = unpack_lzma_stream;)) + USE_FOR_NOMMU(xformer_prog = "unlzma";) + } + if (opt & OPT_XZ) { + USE_FOR_MMU(IF_FEATURE_SEAMLESS_XZ(xformer = unpack_xz_stream;)) + USE_FOR_NOMMU(xformer_prog = "unxz";) + } + + fork_transformer_with_sig(tar_handle->src_fd, xformer, xformer_prog); + /* Can't lseek over pipes */ + tar_handle->seek = seek_by_read; + /*tar_handle->offset = 0; - already is */ + } + + /* Zero processed headers (== empty file) is not a valid tarball. + * We (ab)use bb_got_signal as exitcode here, + * because check_errors_in_children() uses _it_ as error indicator. + */ + bb_got_signal = EXIT_FAILURE; + + while (get_header_tar(tar_handle) == EXIT_SUCCESS) + bb_got_signal = EXIT_SUCCESS; /* saw at least one header, good */ + + create_links_from_list(tar_handle->link_placeholders); + + /* Check that every file that should have been extracted was */ + while (tar_handle->accept) { + if (!find_list_entry(tar_handle->reject, tar_handle->accept->data) + && !find_list_entry(tar_handle->passed, tar_handle->accept->data) + ) { + bb_error_msg_and_die("%s: not found in archive", + tar_handle->accept->data); + } + tar_handle->accept = tar_handle->accept->link; + } + if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) + close(tar_handle->src_fd); + + if (SEAMLESS_COMPRESSION || OPT_COMPRESS) { + /* Set bb_got_signal to 1 if a child died with !0 exitcode */ + check_errors_in_children(0); + } + + return bb_got_signal; +} diff --git a/busybox-1_37_0/archival/tar_symlink_attack b/busybox-1_37_0/archival/tar_symlink_attack new file mode 100755 index 000000000..35455f200 --- /dev/null +++ b/busybox-1_37_0/archival/tar_symlink_attack @@ -0,0 +1,16 @@ +#!/bin/sh +# Makes "symlink attack" tarball (needs GNU tar for --append) + +true >anything.txt +tar cvf tar_symlink_attack.tar anything.txt +rm anything.txt + +ln -s /tmp symlink +tar --append -f tar_symlink_attack.tar symlink +rm symlink + +mkdir symlink +echo BUG >symlink/bb_test_evilfile +tar --append -f tar_symlink_attack.tar symlink/bb_test_evilfile +rm symlink/bb_test_evilfile +rmdir symlink diff --git a/busybox-1_37_0/archival/unzip.c b/busybox-1_37_0/archival/unzip.c new file mode 100644 index 000000000..71a302915 --- /dev/null +++ b/busybox-1_37_0/archival/unzip.c @@ -0,0 +1,1088 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini unzip implementation for busybox + * + * Copyright (C) 2004 by Ed Clark + * + * Loosely based on original busybox unzip applet by Laurence Anderson. + * All options and features should work in this version. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* For reference see + * http://www.pkware.com/company/standards/appnote/ + * http://www.info-zip.org/pub/infozip/doc/appnote-iz-latest.zip + * + * TODO + * Zip64 + other methods + */ +//config:config UNZIP +//config: bool "unzip (26 kb)" +//config: default y +//config: help +//config: unzip will list or extract files from a ZIP archive, +//config: commonly found on DOS/WIN systems. The default behavior +//config: (with no options) is to extract the archive into the +//config: current directory. +//config: +//config:config FEATURE_UNZIP_CDF +//config: bool "Read and use Central Directory data" +//config: default y +//config: depends on UNZIP +//config: help +//config: If you know that you only need to deal with simple +//config: ZIP files without deleted/updated files, SFX archives etc, +//config: you can reduce code size by unselecting this option. +//config: To support less trivial ZIPs, say Y. +//config: +//config:config FEATURE_UNZIP_BZIP2 +//config: bool "Support compression method 12 (bzip2)" +//config: default y +//config: depends on FEATURE_UNZIP_CDF && DESKTOP +// FEATURE_UNZIP_CDF is needed, otherwise we can't find start of next file +// DESKTOP is needed to get back uncompressed length +//config: +//config:config FEATURE_UNZIP_LZMA +//config: bool "Support compression method 14 (lzma)" +//config: default y +//config: depends on FEATURE_UNZIP_CDF && DESKTOP +//config: +//config:config FEATURE_UNZIP_XZ +//config: bool "Support compression method 95 (xz)" +//config: default y +//config: depends on FEATURE_UNZIP_CDF && DESKTOP + +//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_UNZIP) += unzip.o + +//usage:#define unzip_trivial_usage +//usage: "[-lnojpqK] FILE[.zip] [FILE]... [-x FILE]... [-d DIR]" +//usage:#define unzip_full_usage "\n\n" +//usage: "Extract FILEs from ZIP archive\n" +//usage: "\n -l List contents (with -q for short form)" +//usage: "\n -n Never overwrite files (default: ask)" +//usage: "\n -o Overwrite" +//usage: "\n -j Do not restore paths" +//usage: "\n -p Write to stdout" +//usage: "\n -t Test" +//usage: "\n -q Quiet" +//usage: "\n -K Do not clear SUID bit" +//usage: "\n -x FILE Exclude FILEs" +//usage: "\n -d DIR Extract into DIR" + +#include "libbb.h" +#include "bb_archive.h" + +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + +enum { +#if BB_BIG_ENDIAN + ZIP_FILEHEADER_MAGIC = 0x504b0304, + ZIP_CDF_MAGIC = 0x504b0102, /* CDF item */ + ZIP_CDE_MAGIC = 0x504b0506, /* End of CDF */ + ZIP64_CDE_MAGIC = 0x504b0606, /* End of Zip64 CDF */ + ZIP_DD_MAGIC = 0x504b0708, +#else + ZIP_FILEHEADER_MAGIC = 0x04034b50, + ZIP_CDF_MAGIC = 0x02014b50, + ZIP_CDE_MAGIC = 0x06054b50, + ZIP64_CDE_MAGIC = 0x06064b50, + ZIP_DD_MAGIC = 0x08074b50, +#endif +}; + +#define ZIP_HEADER_LEN 26 + +typedef union { + uint8_t raw[ZIP_HEADER_LEN]; + struct { + uint16_t version; /* 0-1 */ + uint16_t zip_flags; /* 2-3 */ + uint16_t method; /* 4-5 */ + uint16_t modtime; /* 6-7 */ + uint16_t moddate; /* 8-9 */ + uint32_t crc32 PACKED; /* 10-13 */ + uint32_t cmpsize PACKED; /* 14-17 */ + uint32_t ucmpsize PACKED; /* 18-21 */ + uint16_t filename_len; /* 22-23 */ + uint16_t extra_len; /* 24-25 */ + /* filename follows (not NUL terminated) */ + /* extra field follows */ + /* data follows */ + } fmt PACKED; +} zip_header_t; /* PACKED - gcc 4.2.1 doesn't like it (spews warning) */ + +#define FIX_ENDIANNESS_ZIP(zip) \ +do { if (BB_BIG_ENDIAN) { \ + (zip).fmt.method = SWAP_LE16((zip).fmt.method ); \ + (zip).fmt.modtime = SWAP_LE16((zip).fmt.modtime ); \ + (zip).fmt.moddate = SWAP_LE16((zip).fmt.moddate ); \ + (zip).fmt.crc32 = SWAP_LE32((zip).fmt.crc32 ); \ + (zip).fmt.cmpsize = SWAP_LE32((zip).fmt.cmpsize ); \ + (zip).fmt.ucmpsize = SWAP_LE32((zip).fmt.ucmpsize ); \ + (zip).fmt.filename_len = SWAP_LE16((zip).fmt.filename_len); \ + (zip).fmt.extra_len = SWAP_LE16((zip).fmt.extra_len ); \ +}} while (0) + +#define CDF_HEADER_LEN 42 + +typedef union { + uint8_t raw[CDF_HEADER_LEN]; + struct { + /* uint32_t signature; 50 4b 01 02 */ + uint16_t version_made_by; /* 0-1 */ + uint16_t version_needed; /* 2-3 */ + uint16_t cdf_flags; /* 4-5 */ + uint16_t method; /* 6-7 */ + uint16_t modtime; /* 8-9 */ + uint16_t moddate; /* 10-11 */ + uint32_t crc32; /* 12-15 */ + uint32_t cmpsize; /* 16-19 */ + uint32_t ucmpsize; /* 20-23 */ + uint16_t filename_len; /* 24-25 */ + uint16_t extra_len; /* 26-27 */ + uint16_t file_comment_length; /* 28-29 */ + uint16_t disk_number_start; /* 30-31 */ + uint16_t internal_attributes; /* 32-33 */ + uint32_t external_attributes PACKED; /* 34-37 */ + uint32_t relative_offset_of_local_header PACKED; /* 38-41 */ + /* filename follows (not NUL terminated) */ + /* extra field follows */ + /* file comment follows */ + } fmt PACKED; +} cdf_header_t; + +#define FIX_ENDIANNESS_CDF(cdf) \ +do { if (BB_BIG_ENDIAN) { \ + (cdf).fmt.version_made_by = SWAP_LE16((cdf).fmt.version_made_by); \ + (cdf).fmt.version_needed = SWAP_LE16((cdf).fmt.version_needed ); \ + (cdf).fmt.method = SWAP_LE16((cdf).fmt.method ); \ + (cdf).fmt.modtime = SWAP_LE16((cdf).fmt.modtime ); \ + (cdf).fmt.moddate = SWAP_LE16((cdf).fmt.moddate ); \ + (cdf).fmt.crc32 = SWAP_LE32((cdf).fmt.crc32 ); \ + (cdf).fmt.cmpsize = SWAP_LE32((cdf).fmt.cmpsize ); \ + (cdf).fmt.ucmpsize = SWAP_LE32((cdf).fmt.ucmpsize ); \ + (cdf).fmt.filename_len = SWAP_LE16((cdf).fmt.filename_len ); \ + (cdf).fmt.extra_len = SWAP_LE16((cdf).fmt.extra_len ); \ + (cdf).fmt.file_comment_length = SWAP_LE16((cdf).fmt.file_comment_length); \ + (cdf).fmt.external_attributes = SWAP_LE32((cdf).fmt.external_attributes); \ +}} while (0) + +#define CDE_LEN 16 + +typedef union { + uint8_t raw[CDE_LEN]; + struct { + /* uint32_t signature; 50 4b 05 06 */ + uint16_t this_disk_no; + uint16_t disk_with_cdf_no; + uint16_t cdf_entries_on_this_disk; + uint16_t cdf_entries_total; + uint32_t cdf_size; + uint32_t cdf_offset; + /* uint16_t archive_comment_length; */ + /* archive comment follows */ + } fmt PACKED; +} cde_t; + +#define FIX_ENDIANNESS_CDE(cde) \ +do { if (BB_BIG_ENDIAN) { \ + (cde).fmt.cdf_offset = SWAP_LE32((cde).fmt.cdf_offset); \ +}} while (0) + +struct BUG { + /* Check the offset of the last element, not the length. This leniency + * allows for poor packing, whereby the overall struct may be too long, + * even though the elements are all in the right place. + */ + char BUG_zip_header_must_be_26_bytes[ + offsetof(zip_header_t, fmt.extra_len) + 2 + == ZIP_HEADER_LEN ? 1 : -1]; + char BUG_cdf_header_must_be_42_bytes[ + offsetof(cdf_header_t, fmt.relative_offset_of_local_header) + 4 + == CDF_HEADER_LEN ? 1 : -1]; + char BUG_cde_must_be_16_bytes[ + sizeof(cde_t) == CDE_LEN ? 1 : -1]; +}; + + +enum { zip_fd = 3 }; + + +/* This value means that we failed to find CDF */ +#define BAD_CDF_OFFSET ((uint32_t)0xffffffff) + +#if !ENABLE_FEATURE_UNZIP_CDF + +# define find_cdf_offset() BAD_CDF_OFFSET + +#else +/* Seen in the wild: + * Self-extracting PRO2K3XP_32.exe contains 19078464 byte zip archive, + * where CDE was nearly 48 kbytes before EOF. + * (Surprisingly, it also apparently has *another* CDE structure + * closer to the end, with bogus cdf_offset). + * To make extraction work, bumped PEEK_FROM_END from 16k to 64k. + */ +#define PEEK_FROM_END (64*1024) +/* NB: does not preserve file position! */ +static uint32_t find_cdf_offset(void) +{ + cde_t cde; + unsigned char *buf; + unsigned char *p; + off_t end; + uint32_t found; + + end = lseek(zip_fd, 0, SEEK_END); + if (end == (off_t) -1) + return BAD_CDF_OFFSET; + + end -= PEEK_FROM_END; + if (end < 0) + end = 0; + + dbg("Looking for cdf_offset starting from 0x%"OFF_FMT"x", end); + xlseek(zip_fd, end, SEEK_SET); + buf = xzalloc(PEEK_FROM_END); + full_read(zip_fd, buf, PEEK_FROM_END); + + found = BAD_CDF_OFFSET; + p = buf; + while (p <= buf + PEEK_FROM_END - CDE_LEN - 4) { + if (*p != 'P') { + p++; + continue; + } + if (*++p != 'K') + continue; + if (*++p != 5) + continue; + if (*++p != 6) + continue; + /* we found CDE! */ + memcpy(cde.raw, p + 1, CDE_LEN); + dbg("cde.this_disk_no:%d", cde.fmt.this_disk_no ); + dbg("cde.disk_with_cdf_no:%d", cde.fmt.disk_with_cdf_no ); + dbg("cde.cdf_entries_on_this_disk:%d", cde.fmt.cdf_entries_on_this_disk); + dbg("cde.cdf_entries_total:%d", cde.fmt.cdf_entries_total ); + dbg("cde.cdf_size:%d", cde.fmt.cdf_size ); + dbg("cde.cdf_offset:%x", cde.fmt.cdf_offset ); + FIX_ENDIANNESS_CDE(cde); + /* + * I've seen .ZIP files with seemingly valid CDEs + * where cdf_offset points past EOF - ?? + * This check ignores such CDEs: + */ + if (cde.fmt.cdf_offset < end + (p - buf)) { + found = cde.fmt.cdf_offset; + dbg("Possible cdf_offset:0x%x at 0x%"OFF_FMT"x", + (unsigned)found, end + (p-3 - buf)); + dbg(" cdf_offset+cdf_size:0x%x", + (unsigned)(found + SWAP_LE32(cde.fmt.cdf_size))); + /* + * We do not "break" here because only the last CDE is valid. + * I've seen a .zip archive which contained a .zip file, + * uncompressed, and taking the first CDE was using + * the CDE inside that file! + */ + } + } + free(buf); + dbg("Found cdf_offset:0x%x", (unsigned)found); + return found; +}; + +static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf) +{ + uint32_t magic; + + if (cdf_offset == BAD_CDF_OFFSET) + return cdf_offset; + + dbg("Reading CDF at 0x%x", (unsigned)cdf_offset); + xlseek(zip_fd, cdf_offset, SEEK_SET); + xread(zip_fd, &magic, 4); + /* Central Directory End? Assume CDF has ended. + * (more correct method is to use cde.cdf_entries_total counter) + */ + if (magic == ZIP_CDE_MAGIC) { + dbg("got ZIP_CDE_MAGIC"); + return 0; /* EOF */ + } + if (magic == ZIP64_CDE_MAGIC) { /* seen in .zip with >4GB files */ + dbg("got ZIP64_CDE_MAGIC"); + return 0; /* EOF */ + } + xread(zip_fd, cdf->raw, CDF_HEADER_LEN); + + FIX_ENDIANNESS_CDF(*cdf); + dbg(" magic:%08x filename_len:%u extra_len:%u file_comment_length:%u", + magic, + (unsigned)cdf->fmt.filename_len, + (unsigned)cdf->fmt.extra_len, + (unsigned)cdf->fmt.file_comment_length + ); +//TODO: require that magic == ZIP_CDF_MAGIC? + + cdf_offset += 4 + CDF_HEADER_LEN + + cdf->fmt.filename_len + + cdf->fmt.extra_len + + cdf->fmt.file_comment_length; + + dbg("Next cdf_offset 0x%x", cdf_offset); + return cdf_offset; +}; +#endif + +static void die_if_bad_fnamesize(unsigned sz) +{ + if (sz > 0xfff) /* more than 4k?! no funny business please */ + bb_simple_error_msg_and_die("bad archive"); +} + +static void unzip_skip(off_t skip) +{ + if (skip != 0) + if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1) + bb_copyfd_exact_size(zip_fd, -1, skip); +} + +static void unzip_create_leading_dirs(const char *fn) +{ + /* Create all leading directories */ + char *name = xstrdup(fn); + + /* mode of -1: set mode according to umask */ + if (bb_make_directory(dirname(name), -1, FILEUTILS_RECUR)) { + xfunc_die(); /* bb_make_directory is noisy */ + } + free(name); +} + +#if ENABLE_FEATURE_UNZIP_CDF +static void unzip_extract_symlink(llist_t **symlink_placeholders, + zip_header_t *zip, + const char *dst_fn) +{ + char *target; + + die_if_bad_fnamesize(zip->fmt.ucmpsize); + + if (zip->fmt.method == 0) { + /* Method 0 - stored (not compressed) */ + target = xzalloc(zip->fmt.ucmpsize + 1); + xread(zip_fd, target, zip->fmt.ucmpsize); + } else { +#if 1 + bb_simple_error_msg_and_die("compressed symlink is not supported"); +#else + transformer_state_t xstate; + init_transformer_state(&xstate); + xstate.mem_output_size_max = zip->fmt.ucmpsize; + /* ...unpack... */ + if (!xstate.mem_output_buf) + WTF(); + target = xstate.mem_output_buf; + target = xrealloc(target, xstate.mem_output_size + 1); + target[xstate.mem_output_size] = '\0'; +#endif + } + create_or_remember_link(symlink_placeholders, + target, + dst_fn, + 0); + free(target); +} +#endif + +static void unzip_extract(zip_header_t *zip, int dst_fd) +{ + transformer_state_t xstate; + + if (zip->fmt.method == 0) { + /* Method 0 - stored (not compressed) */ + off_t size = zip->fmt.ucmpsize; + if (size) + bb_copyfd_exact_size(zip_fd, dst_fd, size); + return; + } + + init_transformer_state(&xstate); + xstate.bytes_in = zip->fmt.cmpsize; + xstate.src_fd = zip_fd; + xstate.dst_fd = dst_fd; + if (zip->fmt.method == 8) { + /* Method 8 - inflate */ + if (inflate_unzip(&xstate) < 0) + bb_simple_error_msg_and_die("inflate error"); + /* Validate decompression - crc */ + if (zip->fmt.crc32 != (xstate.crc32 ^ 0xffffffffL)) { + bb_simple_error_msg_and_die("crc error"); + } + } +#if ENABLE_FEATURE_UNZIP_BZIP2 + else if (zip->fmt.method == 12) { + /* Tested. Unpacker reads too much, but we use CDF + * and will seek to the correct beginning of next file. + */ + xstate.bytes_out = unpack_bz2_stream(&xstate); + if (xstate.bytes_out < 0) + bb_simple_error_msg_and_die("inflate error"); + } +#endif +#if ENABLE_FEATURE_UNZIP_LZMA + else if (zip->fmt.method == 14) { + /* Not tested yet */ + xstate.bytes_out = unpack_lzma_stream(&xstate); + if (xstate.bytes_out < 0) + bb_simple_error_msg_and_die("inflate error"); + } +#endif +#if ENABLE_FEATURE_UNZIP_XZ + else if (zip->fmt.method == 95) { + /* Not tested yet */ + xstate.bytes_out = unpack_xz_stream(&xstate); + if (xstate.bytes_out < 0) + bb_simple_error_msg_and_die("inflate error"); + } +#endif + else { + bb_error_msg_and_die("unsupported method %u", zip->fmt.method); + } + + /* Validate decompression - size */ + if (zip->fmt.ucmpsize != 0xffffffff /* seen on files with >4GB uncompressed data */ + && zip->fmt.ucmpsize != xstate.bytes_out + ) { + /* Don't die. Who knows, maybe len calculation + * was botched somewhere. After all, crc matched! */ + bb_simple_error_msg("bad length"); + } +} + +static void my_fgets80(char *buf80) +{ + fflush_all(); + if (!fgets(buf80, 80, stdin)) { + bb_simple_perror_msg_and_die("can't read standard input"); + } +} + +static int get_lstat_mode(const char *dst_fn) +{ + struct stat stat_buf; + if (lstat(dst_fn, &stat_buf) == -1) { + if (errno != ENOENT) { + bb_perror_msg_and_die("can't stat '%s'", + dst_fn + ); + } + /* File does not exist */ + return -1; + } + return stat_buf.st_mode; +} + +int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unzip_main(int argc, char **argv) +{ + enum { + OPT_l = (1 << 0), + OPT_x = (1 << 1), + OPT_j = (1 << 2), + OPT_K = (1 << 3), + }; + unsigned opts; + smallint quiet = 0; + IF_NOT_FEATURE_UNZIP_CDF(const) smallint verbose = 0; + enum { O_PROMPT, O_NEVER, O_ALWAYS }; + smallint overwrite = O_PROMPT; + uint32_t cdf_offset; + unsigned long total_usize; + unsigned long total_size; + unsigned total_entries; + int dst_fd = -1; + char *src_fn = NULL; + char *dst_fn = NULL; + llist_t *zaccept = NULL; + llist_t *zreject = NULL; + char *base_dir = NULL; +#if ENABLE_FEATURE_UNZIP_CDF + llist_t *symlink_placeholders = NULL; +#endif + int i; + char key_buf[80]; /* must match size used by my_fgets80 */ + +/* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP: + * + * # /usr/bin/unzip -qq -v decompress_unlzma.i.zip + * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i + * # /usr/bin/unzip -q -v decompress_unlzma.i.zip + * Length Method Size Ratio Date Time CRC-32 Name + * -------- ------ ------- ----- ---- ---- ------ ---- + * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i + * -------- ------- --- ------- + * 204372 35278 83% 1 file + * # /usr/bin/unzip -v decompress_unlzma.i.zip + * Archive: decompress_unlzma.i.zip + * Length Method Size Ratio Date Time CRC-32 Name + * -------- ------ ------- ----- ---- ---- ------ ---- + * 204372 Defl:N 35278 83% 09-06-09 14:23 0d056252 decompress_unlzma.i + * -------- ------- --- ------- + * 204372 35278 83% 1 file + * # unzip -v decompress_unlzma.i.zip + * Archive: decompress_unlzma.i.zip + * Length Date Time Name + * -------- ---- ---- ---- + * 204372 09-06-09 14:23 decompress_unlzma.i + * -------- ------- + * 204372 1 files + * # /usr/bin/unzip -l -qq decompress_unlzma.i.zip + * 204372 09-06-09 14:23 decompress_unlzma.i + * # /usr/bin/unzip -l -q decompress_unlzma.i.zip + * Length Date Time Name + * -------- ---- ---- ---- + * 204372 09-06-09 14:23 decompress_unlzma.i + * -------- ------- + * 204372 1 file + * # /usr/bin/unzip -l decompress_unlzma.i.zip + * Archive: decompress_unlzma.i.zip + * Length Date Time Name + * -------- ---- ---- ---- + * 204372 09-06-09 14:23 decompress_unlzma.i + * -------- ------- + * 204372 1 file + */ + +//TODO: accept and ignore these? +// -a convert to text files with 't' label, -aa: all files +// -b do not convert to text - bbox: we don't convert anything +// -D skip restoration of timestamps for extracted items - bbox: we don't restore these (yet?) +// -X restore user:group ownership + opts = 0; + /* '-' makes getopt return 1 for non-options */ + while ((i = getopt(argc, argv, "-d:lnotpqxjvK")) != -1) { + switch (i) { + case 'd': /* Extract to base directory */ + base_dir = optarg; + break; + + case 'l': /* List */ + opts |= OPT_l; + break; + + case 'n': /* Never overwrite existing files */ + overwrite = O_NEVER; + break; + + case 'o': /* Always overwrite existing files */ + overwrite = O_ALWAYS; + break; + + case 't': /* Extract files to /dev/null */ + xmove_fd(xopen("/dev/null", O_WRONLY), STDOUT_FILENO); + /*fallthrough*/ + +// NB: -c extract files to stdout/screen (unlike -p, also prints .zip and file names to stdout) + case 'p': /* Extract files to stdout */ + dst_fd = STDOUT_FILENO; + /*fallthrough*/ + + case 'q': /* Be quiet */ + quiet++; + break; + + case 'v': /* Verbose list */ + IF_FEATURE_UNZIP_CDF(verbose++;) + opts |= OPT_l; + break; + + case 'x': + opts |= OPT_x; + break; + + case 'j': + opts |= OPT_j; + break; + + case 'K': + opts |= OPT_K; + break; + + case 1: + if (!src_fn) { + /* The zip file */ + /* +5: space for ".zip" and NUL */ + src_fn = xmalloc(strlen(optarg) + 5); + strcpy(src_fn, optarg); + } else if (!(opts & OPT_x)) { + /* Include files */ + llist_add_to(&zaccept, optarg); + } else { + /* Exclude files */ + llist_add_to(&zreject, optarg); + } + break; + + default: + bb_show_usage(); + } + } + +#ifndef __GLIBC__ + /* + * This code is needed for non-GNU getopt + * which doesn't understand "-" in option string. + * The -x option won't work properly in this case: + * "unzip a.zip q -x w e" will be interpreted as + * "unzip a.zip q w e -x" = "unzip a.zip q w e" + */ + argv += optind; + if (argv[0]) { + /* +5: space for ".zip" and NUL */ + src_fn = xmalloc(strlen(argv[0]) + 5); + strcpy(src_fn, argv[0]); + while (*++argv) + llist_add_to(&zaccept, *argv); + } +#endif + + if (!src_fn) { + bb_show_usage(); + } + + /* Open input file */ + if (LONE_DASH(src_fn)) { + xdup2(STDIN_FILENO, zip_fd); + /* Cannot use prompt mode since zip data is arriving on STDIN */ + if (overwrite == O_PROMPT) + overwrite = O_NEVER; + } else { + static const char extn[][5] ALIGN1 = { ".zip", ".ZIP" }; + char *ext = src_fn + strlen(src_fn); + int src_fd; + + i = 0; + for (;;) { + src_fd = open(src_fn, O_RDONLY); + if (src_fd >= 0) + break; + if (++i > 2) { + *ext = '\0'; + bb_error_msg_and_die("can't open %s[.zip]", + src_fn + ); + } + strcpy(ext, extn[i - 1]); + } + xmove_fd(src_fd, zip_fd); + } + + /* Change dir if necessary */ + if (base_dir) { + /* -p DIR: try to create, errors don't matter. + * UnZip 6.00 does no multi-level mkdir (-p DIR1/DIR2 syntax), + * not using bb_make_directory() here (yet?) + */ + mkdir(base_dir, 0777); + xchdir(base_dir); + } + + if (quiet <= 1) { /* not -qq */ + if (quiet == 0) { + printf("Archive: %s\n", + printable_string(src_fn) + ); + } + if (opts & OPT_l) { + puts(verbose ? + " Length Method Size Cmpr Date Time CRC-32 Name\n" + "-------- ------ ------- ---- ---------- ----- -------- ----" + : + " Length Date Time Name\n" + "--------- ---------- ----- ----" + ); + } + } + +/* Example of an archive with one 0-byte long file named 'z' + * created by Zip 2.31 on Unix: + * 0000 [50 4b]03 04 0a 00 00 00 00 00 42 1a b8 3c 00 00 |PK........B..<..| + * sig........ vneed flags compr mtime mdate crc32> + * 0010 00 00 00 00 00 00 00 00 00 00 01 00 15 00 7a 55 |..............zU| + * >..... csize...... usize...... fnlen exlen fn ex> + * 0020 54 09 00 03 cc d3 f9 4b cc d3 f9 4b 55 78 04 00 |T......K...KUx..| + * >tra_field...................................... + * 0030 00 00 00 00[50 4b]01 02 17 03 0a 00 00 00 00 00 |....PK..........| + * ........... sig........ vmade vneed flags compr + * 0040 42 1a b8 3c 00 00 00 00 00 00 00 00 00 00 00 00 |B..<............| + * mtime mdate crc32...... csize...... usize...... + * 0050 01 00 0d 00 00 00 00 00 00 00 00 00 a4 81 00 00 |................| + * fnlen exlen clen. dnum. iattr eattr...... relofs> (eattr = rw-r--r--) + * 0060 00 00 7a 55 54 05 00 03 cc d3 f9 4b 55 78 00 00 |..zUT......KUx..| + * >..... fn extra_field........................... + * 0070 [50 4b]05 06 00 00 00 00 01 00 01 00 3c 00 00 00 |PK..........<...| + * 0080 34 00 00 00 00 00 |4.....| + */ + total_usize = 0; + total_size = 0; + total_entries = 0; + cdf_offset = find_cdf_offset(); /* try to seek to the end, find CDE and CDF start */ + while (1) { + zip_header_t zip; + mode_t dir_mode = 0777; +#if ENABLE_FEATURE_UNZIP_CDF + mode_t file_mode = 0666; +#endif + + if (!ENABLE_FEATURE_UNZIP_CDF || cdf_offset == BAD_CDF_OFFSET) { + /* Normally happens when input is unseekable. + * + * Valid ZIP file has Central Directory at the end + * with central directory file headers (CDFs). + * After it, there is a Central Directory End structure. + * CDFs identify what files are in the ZIP and where + * they are located. This allows ZIP readers to load + * the list of files without reading the entire ZIP archive. + * ZIP files may be appended to, only files specified in + * the CD are valid. Scanning for local file headers is + * not a correct algorithm. + * + * We try to do the above, and resort to "linear" reading + * of ZIP file only if seek failed or CDE wasn't found. + */ + uint32_t magic; + + /* Check magic number */ + xread(zip_fd, &magic, 4); + /* CDF item? Assume there are no more files, exit */ + if (magic == ZIP_CDF_MAGIC) { + dbg("got ZIP_CDF_MAGIC"); + break; + } + /* Data descriptor? It was a streaming file, go on */ + if (magic == ZIP_DD_MAGIC) { + dbg("got ZIP_DD_MAGIC"); + /* skip over duplicate crc32, cmpsize and ucmpsize */ + unzip_skip(3 * 4); + continue; + } + if (magic != ZIP_FILEHEADER_MAGIC) + bb_error_msg_and_die("invalid zip magic %08X", (int)magic); + dbg("got ZIP_FILEHEADER_MAGIC"); + + xread(zip_fd, zip.raw, ZIP_HEADER_LEN); + FIX_ENDIANNESS_ZIP(zip); + if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) { + bb_error_msg_and_die("zip flag %s is not supported", + "8 (streaming)"); + } + } +#if ENABLE_FEATURE_UNZIP_CDF + else { + /* cdf_offset is valid (and we know the file is seekable) */ + cdf_header_t cdf; + cdf_offset = read_next_cdf(cdf_offset, &cdf); + if (cdf_offset == 0) /* EOF? */ + break; +# if 1 + xlseek(zip_fd, + SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4, + SEEK_SET); + xread(zip_fd, zip.raw, ZIP_HEADER_LEN); + FIX_ENDIANNESS_ZIP(zip); + if (zip.fmt.zip_flags & SWAP_LE16(0x0008)) { + /* 0x0008 - streaming. [u]cmpsize can be reliably gotten + * only from Central Directory. + */ + zip.fmt.crc32 = cdf.fmt.crc32; + zip.fmt.cmpsize = cdf.fmt.cmpsize; + zip.fmt.ucmpsize = cdf.fmt.ucmpsize; + } +// Seen in some zipfiles: central directory 9 byte extra field contains +// a subfield with ID 0x5455 and 5 data bytes, which is a Unix-style UTC mtime. +// Local header version: +// u16 0x5455 ("UT") +// u16 size (1 + 4 * n) +// u8 flags: bit 0:mtime is present, bit 1:atime is present, bit 2:ctime is present +// u32 mtime +// u32 atime +// u32 ctime +// Central header version: +// u16 0x5455 ("UT") +// u16 size (5 (or 1?)) +// u8 flags: bit 0:mtime is present, bit 1:atime is present, bit 2:ctime is present +// u32 mtime (CDF does not store atime/ctime) +# else + /* CDF has the same data as local header, no need to read the latter... + * ...not really. An archive was seen with cdf.extra_len == 6 but + * zip.extra_len == 0. + */ + memcpy(&zip.fmt.version, + &cdf.fmt.version_needed, ZIP_HEADER_LEN); + xlseek(zip_fd, + SWAP_LE32(cdf.fmt.relative_offset_of_local_header) + 4 + ZIP_HEADER_LEN, + SEEK_SET); +# endif + if ((cdf.fmt.version_made_by >> 8) == 3) { + /* This archive is created on Unix */ + file_mode = (cdf.fmt.external_attributes >> 16); + if (!(opts & OPT_K)) + file_mode &= ~(mode_t)(S_ISUID | S_ISGID); + dir_mode = file_mode; + } + } +#endif + + if (zip.fmt.zip_flags & SWAP_LE16(0x0001)) { + /* 0x0001 - encrypted */ + bb_error_msg_and_die("zip flag %s is not supported", + "1 (encryption)"); + } + dbg("File cmpsize:0x%x extra_len:0x%x ucmpsize:0x%x", + (unsigned)zip.fmt.cmpsize, + (unsigned)zip.fmt.extra_len, + (unsigned)zip.fmt.ucmpsize + ); + + /* Read filename */ + free(dst_fn); + die_if_bad_fnamesize(zip.fmt.filename_len); + dst_fn = xzalloc(zip.fmt.filename_len + 1); + xread(zip_fd, dst_fn, zip.fmt.filename_len); + /* Skip extra header bytes */ + unzip_skip(zip.fmt.extra_len); + + /* Guard against "/abspath", "/../" and similar attacks */ +// NB: UnZip 6.00 has option -: to disable this + overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn)); + + /* Filter zip entries */ + if (find_list_entry(zreject, dst_fn) + || (zaccept && !find_list_entry(zaccept, dst_fn)) + ) { /* Skip entry */ + goto skip_cmpsize; + } + + if (opts & OPT_l) { + /* List entry */ + char dtbuf[sizeof("mm-dd-yyyy hh:mm")]; + sprintf(dtbuf, "%02u-%02u-%04u %02u:%02u", + (zip.fmt.moddate >> 5) & 0xf, // mm: 0x01e0 + (zip.fmt.moddate) & 0x1f, // dd: 0x001f + (zip.fmt.moddate >> 9) + 1980, // yy: 0xfe00 + (zip.fmt.modtime >> 11), // hh: 0xf800 + (zip.fmt.modtime >> 5) & 0x3f // mm: 0x07e0 + // seconds/2 not shown, encoded in -- 0x001f + ); + if (!verbose) { + // " Length Date Time Name\n" + // "--------- ---------- ----- ----" + printf( "%9u " "%s " "%s\n", + (unsigned)zip.fmt.ucmpsize, + dtbuf, + printable_string(dst_fn) + ); + } else { + char method6[7]; + unsigned long percents; + + sprintf(method6, "%6u", zip.fmt.method); + if (zip.fmt.method == 0) { + strcpy(method6, "Stored"); + } + if (zip.fmt.method == 8) { + strcpy(method6, "Defl:N"); + /* normal, maximum, fast, superfast */ + IF_DESKTOP(method6[5] = "NXFS"[(zip.fmt.zip_flags >> 1) & 3];) + } + percents = zip.fmt.ucmpsize - zip.fmt.cmpsize; + if ((int32_t)percents < 0) + percents = 0; /* happens if ucmpsize < cmpsize */ + percents = percents * 100; + if (zip.fmt.ucmpsize) + percents /= zip.fmt.ucmpsize; + // " Length Method Size Cmpr Date Time CRC-32 Name\n" + // "-------- ------ ------- ---- ---------- ----- -------- ----" + printf( "%8u %s" "%9u%4u%% " "%s " "%08x " "%s\n", + (unsigned)zip.fmt.ucmpsize, + method6, + (unsigned)zip.fmt.cmpsize, + (unsigned)percents, + dtbuf, + zip.fmt.crc32, + printable_string(dst_fn) + ); + total_size += zip.fmt.cmpsize; + } + total_usize += zip.fmt.ucmpsize; + goto skip_cmpsize; + } + + if (dst_fd == STDOUT_FILENO) { + /* Extracting to STDOUT */ + goto do_extract; + } + + /* Strip paths (after -l: unzip -lj a.zip lists full names) */ + if (opts & OPT_j) + overlapping_strcpy(dst_fn, bb_basename(dst_fn)); + /* Did this strip everything ("DIR/" case)? Then skip */ + if (!dst_fn[0]) + goto skip_cmpsize; + + if (last_char_is(dst_fn, '/')) { + int mode; + + /* Extract directory */ + mode = get_lstat_mode(dst_fn); + if (mode == -1) { /* ENOENT */ + if (!quiet) { + printf(" creating: %s\n", printable_string(dst_fn)); + } + unzip_create_leading_dirs(dst_fn); + if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) { + xfunc_die(); + } + } else { + if (!S_ISDIR(mode)) { + bb_error_msg_and_die("'%s' exists but is not a %s", + printable_string(dst_fn), + "directory" + ); + } + } + goto skip_cmpsize; + } + check_file: + /* Does target file already exist? */ + { + int mode = get_lstat_mode(dst_fn); + if (mode == -1) { + /* ENOENT: does not exist */ + goto do_open_and_extract; + } + if (overwrite == O_NEVER) { + goto skip_cmpsize; + } + if (!S_ISREG(mode)) { + fishy: + bb_error_msg_and_die("'%s' exists but is not a %s", + printable_string(dst_fn), + "regular file" + ); + } + if (overwrite == O_ALWAYS) { + goto do_open_and_extract; + } + printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", + printable_string(dst_fn) + ); + my_fgets80(key_buf); + /* User input could take a long time. Is it still a regular file? */ + mode = get_lstat_mode(dst_fn); + if (!S_ISREG(mode)) + goto fishy; + } + + /* Extract (or skip) it */ + switch (key_buf[0]) { + case 'A': + overwrite = O_ALWAYS; + case 'y': /* Open file and fall into unzip */ + do_open_and_extract: + unzip_create_leading_dirs(dst_fn); +#if ENABLE_FEATURE_UNZIP_CDF + dst_fd = -1; + if (!S_ISLNK(file_mode)) { + dst_fd = xopen3(dst_fn, + O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW, + file_mode); + } +#else + /* O_NOFOLLOW defends against symlink attacks */ + dst_fd = xopen(dst_fn, O_WRONLY | O_CREAT | O_TRUNC | O_NOFOLLOW); +#endif + if (!quiet) { + printf(/* zip.fmt.method == 0 + ? " extracting: %s\n" + : */ " inflating: %s\n", + printable_string(dst_fn) + ); + } + do_extract: +#if ENABLE_FEATURE_UNZIP_CDF + if (S_ISLNK(file_mode)) { + if (dst_fd != STDOUT_FILENO) /* not -p? */ + unzip_extract_symlink(&symlink_placeholders, &zip, dst_fn); + } else +#endif + { + unzip_extract(&zip, dst_fd); + if (dst_fd != STDOUT_FILENO) { + /* closing STDOUT is potentially bad for future business */ + close(dst_fd); + } + } + break; + + case 'N': + overwrite = O_NEVER; + case 'n': /* Skip entry data */ + skip_cmpsize: + unzip_skip(zip.fmt.cmpsize); + break; + + case 'r': + /* Prompt for new name */ + printf("new name: "); + my_fgets80(key_buf); + free(dst_fn); + dst_fn = xstrdup(key_buf); + chomp(dst_fn); + goto check_file; + + default: + printf("error: invalid response [%c]\n", (char)key_buf[0]); + goto check_file; + } + + total_entries++; + } + +#if ENABLE_FEATURE_UNZIP_CDF + create_links_from_list(symlink_placeholders); +#endif + + if ((opts & OPT_l) && quiet <= 1) { + if (!verbose) { + // " Length Date Time Name\n" + // "--------- ---------- ----- ----" + printf( " --------%21s" "-------\n" + "%9lu%21s" "%u files\n", + "", + total_usize, "", total_entries); + } else { + unsigned long percents = total_usize - total_size; + if ((long)percents < 0) + percents = 0; /* happens if usize < size */ + percents = percents * 100; + if (total_usize) + percents /= total_usize; + // " Length Method Size Cmpr Date Time CRC-32 Name\n" + // "-------- ------ ------- ---- ---------- ----- -------- ----" + printf( "-------- ------- ----%28s" "----\n" + "%8lu" "%17lu%4u%%%28s" "%u files\n", + "", + total_usize, total_size, (unsigned)percents, "", + total_entries); + } + } + + return 0; +} diff --git a/busybox-1_37_0/boot-files/initramfs/bin/arch b/busybox-1_37_0/boot-files/initramfs/bin/arch new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/arch @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ash b/busybox-1_37_0/boot-files/initramfs/bin/ash new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ash @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/base32 b/busybox-1_37_0/boot-files/initramfs/bin/base32 new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/base32 @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/base64 b/busybox-1_37_0/boot-files/initramfs/bin/base64 new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/base64 @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/busybox b/busybox-1_37_0/boot-files/initramfs/bin/busybox new file mode 100755 index 000000000..219241cb5 Binary files /dev/null and b/busybox-1_37_0/boot-files/initramfs/bin/busybox differ diff --git a/busybox-1_37_0/boot-files/initramfs/bin/cat b/busybox-1_37_0/boot-files/initramfs/bin/cat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/cat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/chattr b/busybox-1_37_0/boot-files/initramfs/bin/chattr new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/chattr @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/chgrp b/busybox-1_37_0/boot-files/initramfs/bin/chgrp new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/chgrp @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/chmod b/busybox-1_37_0/boot-files/initramfs/bin/chmod new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/chmod @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/chown b/busybox-1_37_0/boot-files/initramfs/bin/chown new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/chown @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/conspy b/busybox-1_37_0/boot-files/initramfs/bin/conspy new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/conspy @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/cp b/busybox-1_37_0/boot-files/initramfs/bin/cp new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/cp @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/cpio b/busybox-1_37_0/boot-files/initramfs/bin/cpio new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/cpio @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/cttyhack b/busybox-1_37_0/boot-files/initramfs/bin/cttyhack new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/cttyhack @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/date b/busybox-1_37_0/boot-files/initramfs/bin/date new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/date @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/dd b/busybox-1_37_0/boot-files/initramfs/bin/dd new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/dd @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/df b/busybox-1_37_0/boot-files/initramfs/bin/df new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/df @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/dmesg b/busybox-1_37_0/boot-files/initramfs/bin/dmesg new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/dmesg @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/dnsdomainname b/busybox-1_37_0/boot-files/initramfs/bin/dnsdomainname new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/dnsdomainname @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/dumpkmap b/busybox-1_37_0/boot-files/initramfs/bin/dumpkmap new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/dumpkmap @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/echo b/busybox-1_37_0/boot-files/initramfs/bin/echo new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/echo @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ed b/busybox-1_37_0/boot-files/initramfs/bin/ed new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ed @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/egrep b/busybox-1_37_0/boot-files/initramfs/bin/egrep new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/egrep @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/false b/busybox-1_37_0/boot-files/initramfs/bin/false new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/false @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/fatattr b/busybox-1_37_0/boot-files/initramfs/bin/fatattr new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/fatattr @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/fdflush b/busybox-1_37_0/boot-files/initramfs/bin/fdflush new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/fdflush @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/fgrep b/busybox-1_37_0/boot-files/initramfs/bin/fgrep new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/fgrep @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/fsync b/busybox-1_37_0/boot-files/initramfs/bin/fsync new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/fsync @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/getopt b/busybox-1_37_0/boot-files/initramfs/bin/getopt new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/getopt @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/grep b/busybox-1_37_0/boot-files/initramfs/bin/grep new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/grep @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/gunzip b/busybox-1_37_0/boot-files/initramfs/bin/gunzip new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/gunzip @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/gzip b/busybox-1_37_0/boot-files/initramfs/bin/gzip new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/gzip @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/hostname b/busybox-1_37_0/boot-files/initramfs/bin/hostname new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/hostname @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/hush b/busybox-1_37_0/boot-files/initramfs/bin/hush new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/hush @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ionice b/busybox-1_37_0/boot-files/initramfs/bin/ionice new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ionice @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/iostat b/busybox-1_37_0/boot-files/initramfs/bin/iostat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/iostat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ipcalc b/busybox-1_37_0/boot-files/initramfs/bin/ipcalc new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ipcalc @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/kbd_mode b/busybox-1_37_0/boot-files/initramfs/bin/kbd_mode new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/kbd_mode @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/kill b/busybox-1_37_0/boot-files/initramfs/bin/kill new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/kill @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/link b/busybox-1_37_0/boot-files/initramfs/bin/link new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/link @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/linux32 b/busybox-1_37_0/boot-files/initramfs/bin/linux32 new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/linux32 @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/linux64 b/busybox-1_37_0/boot-files/initramfs/bin/linux64 new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/linux64 @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ln b/busybox-1_37_0/boot-files/initramfs/bin/ln new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ln @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/login b/busybox-1_37_0/boot-files/initramfs/bin/login new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/login @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ls b/busybox-1_37_0/boot-files/initramfs/bin/ls new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ls @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/lsattr b/busybox-1_37_0/boot-files/initramfs/bin/lsattr new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/lsattr @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/lzop b/busybox-1_37_0/boot-files/initramfs/bin/lzop new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/lzop @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/makemime b/busybox-1_37_0/boot-files/initramfs/bin/makemime new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/makemime @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mkdir b/busybox-1_37_0/boot-files/initramfs/bin/mkdir new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mkdir @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mknod b/busybox-1_37_0/boot-files/initramfs/bin/mknod new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mknod @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mktemp b/busybox-1_37_0/boot-files/initramfs/bin/mktemp new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mktemp @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/more b/busybox-1_37_0/boot-files/initramfs/bin/more new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/more @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mount b/busybox-1_37_0/boot-files/initramfs/bin/mount new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mount @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mountpoint b/busybox-1_37_0/boot-files/initramfs/bin/mountpoint new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mountpoint @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mpstat b/busybox-1_37_0/boot-files/initramfs/bin/mpstat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mpstat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mt b/busybox-1_37_0/boot-files/initramfs/bin/mt new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mt @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/mv b/busybox-1_37_0/boot-files/initramfs/bin/mv new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/mv @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/netstat b/busybox-1_37_0/boot-files/initramfs/bin/netstat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/netstat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/nice b/busybox-1_37_0/boot-files/initramfs/bin/nice new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/nice @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/pidof b/busybox-1_37_0/boot-files/initramfs/bin/pidof new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/pidof @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ping b/busybox-1_37_0/boot-files/initramfs/bin/ping new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ping @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ping6 b/busybox-1_37_0/boot-files/initramfs/bin/ping6 new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ping6 @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/pipe_progress b/busybox-1_37_0/boot-files/initramfs/bin/pipe_progress new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/pipe_progress @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/printenv b/busybox-1_37_0/boot-files/initramfs/bin/printenv new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/printenv @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/ps b/busybox-1_37_0/boot-files/initramfs/bin/ps new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/ps @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/pwd b/busybox-1_37_0/boot-files/initramfs/bin/pwd new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/pwd @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/reformime b/busybox-1_37_0/boot-files/initramfs/bin/reformime new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/reformime @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/resume b/busybox-1_37_0/boot-files/initramfs/bin/resume new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/resume @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/rev b/busybox-1_37_0/boot-files/initramfs/bin/rev new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/rev @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/rm b/busybox-1_37_0/boot-files/initramfs/bin/rm new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/rm @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/rmdir b/busybox-1_37_0/boot-files/initramfs/bin/rmdir new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/rmdir @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/rpm b/busybox-1_37_0/boot-files/initramfs/bin/rpm new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/rpm @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/run-parts b/busybox-1_37_0/boot-files/initramfs/bin/run-parts new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/run-parts @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/scriptreplay b/busybox-1_37_0/boot-files/initramfs/bin/scriptreplay new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/scriptreplay @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/sed b/busybox-1_37_0/boot-files/initramfs/bin/sed new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/sed @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/setarch b/busybox-1_37_0/boot-files/initramfs/bin/setarch new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/setarch @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/setpriv b/busybox-1_37_0/boot-files/initramfs/bin/setpriv new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/setpriv @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/setserial b/busybox-1_37_0/boot-files/initramfs/bin/setserial new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/setserial @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/sh b/busybox-1_37_0/boot-files/initramfs/bin/sh new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/sh @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/sleep b/busybox-1_37_0/boot-files/initramfs/bin/sleep new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/sleep @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/stat b/busybox-1_37_0/boot-files/initramfs/bin/stat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/stat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/stty b/busybox-1_37_0/boot-files/initramfs/bin/stty new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/stty @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/su b/busybox-1_37_0/boot-files/initramfs/bin/su new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/su @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/sync b/busybox-1_37_0/boot-files/initramfs/bin/sync new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/sync @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/tar b/busybox-1_37_0/boot-files/initramfs/bin/tar new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/tar @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/touch b/busybox-1_37_0/boot-files/initramfs/bin/touch new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/touch @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/true b/busybox-1_37_0/boot-files/initramfs/bin/true new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/true @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/umount b/busybox-1_37_0/boot-files/initramfs/bin/umount new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/umount @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/uname b/busybox-1_37_0/boot-files/initramfs/bin/uname new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/uname @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/usleep b/busybox-1_37_0/boot-files/initramfs/bin/usleep new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/usleep @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/vi b/busybox-1_37_0/boot-files/initramfs/bin/vi new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/vi @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/watch b/busybox-1_37_0/boot-files/initramfs/bin/watch new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/watch @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/bin/zcat b/busybox-1_37_0/boot-files/initramfs/bin/zcat new file mode 120000 index 000000000..c3fa81028 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/bin/zcat @@ -0,0 +1 @@ +busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/linuxrc b/busybox-1_37_0/boot-files/initramfs/linuxrc new file mode 120000 index 000000000..f9f73421a --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/linuxrc @@ -0,0 +1 @@ +bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/acpid b/busybox-1_37_0/boot-files/initramfs/sbin/acpid new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/acpid @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/adjtimex b/busybox-1_37_0/boot-files/initramfs/sbin/adjtimex new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/adjtimex @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/arp b/busybox-1_37_0/boot-files/initramfs/sbin/arp new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/arp @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/blkid b/busybox-1_37_0/boot-files/initramfs/sbin/blkid new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/blkid @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/blockdev b/busybox-1_37_0/boot-files/initramfs/sbin/blockdev new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/blockdev @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/bootchartd b/busybox-1_37_0/boot-files/initramfs/sbin/bootchartd new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/bootchartd @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/depmod b/busybox-1_37_0/boot-files/initramfs/sbin/depmod new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/depmod @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/devmem b/busybox-1_37_0/boot-files/initramfs/sbin/devmem new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/devmem @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/fbsplash b/busybox-1_37_0/boot-files/initramfs/sbin/fbsplash new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/fbsplash @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/fdisk b/busybox-1_37_0/boot-files/initramfs/sbin/fdisk new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/fdisk @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/findfs b/busybox-1_37_0/boot-files/initramfs/sbin/findfs new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/findfs @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/freeramdisk b/busybox-1_37_0/boot-files/initramfs/sbin/freeramdisk new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/freeramdisk @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/fsck b/busybox-1_37_0/boot-files/initramfs/sbin/fsck new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/fsck @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/fsck.minix b/busybox-1_37_0/boot-files/initramfs/sbin/fsck.minix new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/fsck.minix @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/fstrim b/busybox-1_37_0/boot-files/initramfs/sbin/fstrim new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/fstrim @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/getty b/busybox-1_37_0/boot-files/initramfs/sbin/getty new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/getty @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/halt b/busybox-1_37_0/boot-files/initramfs/sbin/halt new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/halt @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/hdparm b/busybox-1_37_0/boot-files/initramfs/sbin/hdparm new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/hdparm @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/hwclock b/busybox-1_37_0/boot-files/initramfs/sbin/hwclock new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/hwclock @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ifconfig b/busybox-1_37_0/boot-files/initramfs/sbin/ifconfig new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ifconfig @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ifdown b/busybox-1_37_0/boot-files/initramfs/sbin/ifdown new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ifdown @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ifenslave b/busybox-1_37_0/boot-files/initramfs/sbin/ifenslave new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ifenslave @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ifup b/busybox-1_37_0/boot-files/initramfs/sbin/ifup new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ifup @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/init b/busybox-1_37_0/boot-files/initramfs/sbin/init new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/init @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/insmod b/busybox-1_37_0/boot-files/initramfs/sbin/insmod new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/insmod @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ip b/busybox-1_37_0/boot-files/initramfs/sbin/ip new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ip @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ipaddr b/busybox-1_37_0/boot-files/initramfs/sbin/ipaddr new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ipaddr @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/iplink b/busybox-1_37_0/boot-files/initramfs/sbin/iplink new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/iplink @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/ipneigh b/busybox-1_37_0/boot-files/initramfs/sbin/ipneigh new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/ipneigh @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/iproute b/busybox-1_37_0/boot-files/initramfs/sbin/iproute new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/iproute @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/iprule b/busybox-1_37_0/boot-files/initramfs/sbin/iprule new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/iprule @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/iptunnel b/busybox-1_37_0/boot-files/initramfs/sbin/iptunnel new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/iptunnel @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/klogd b/busybox-1_37_0/boot-files/initramfs/sbin/klogd new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/klogd @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/loadkmap b/busybox-1_37_0/boot-files/initramfs/sbin/loadkmap new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/loadkmap @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/logread b/busybox-1_37_0/boot-files/initramfs/sbin/logread new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/logread @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/losetup b/busybox-1_37_0/boot-files/initramfs/sbin/losetup new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/losetup @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/lsmod b/busybox-1_37_0/boot-files/initramfs/sbin/lsmod new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/lsmod @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/makedevs b/busybox-1_37_0/boot-files/initramfs/sbin/makedevs new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/makedevs @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mdev b/busybox-1_37_0/boot-files/initramfs/sbin/mdev new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mdev @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mkdosfs b/busybox-1_37_0/boot-files/initramfs/sbin/mkdosfs new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mkdosfs @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mke2fs b/busybox-1_37_0/boot-files/initramfs/sbin/mke2fs new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mke2fs @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.ext2 b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.ext2 new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.ext2 @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.minix b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.minix new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.minix @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.vfat b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.vfat new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mkfs.vfat @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/mkswap b/busybox-1_37_0/boot-files/initramfs/sbin/mkswap new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/mkswap @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/modinfo b/busybox-1_37_0/boot-files/initramfs/sbin/modinfo new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/modinfo @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/modprobe b/busybox-1_37_0/boot-files/initramfs/sbin/modprobe new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/modprobe @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/nameif b/busybox-1_37_0/boot-files/initramfs/sbin/nameif new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/nameif @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/pivot_root b/busybox-1_37_0/boot-files/initramfs/sbin/pivot_root new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/pivot_root @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/poweroff b/busybox-1_37_0/boot-files/initramfs/sbin/poweroff new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/poweroff @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/raidautorun b/busybox-1_37_0/boot-files/initramfs/sbin/raidautorun new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/raidautorun @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/reboot b/busybox-1_37_0/boot-files/initramfs/sbin/reboot new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/reboot @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/rmmod b/busybox-1_37_0/boot-files/initramfs/sbin/rmmod new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/rmmod @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/route b/busybox-1_37_0/boot-files/initramfs/sbin/route new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/route @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/run-init b/busybox-1_37_0/boot-files/initramfs/sbin/run-init new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/run-init @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/runlevel b/busybox-1_37_0/boot-files/initramfs/sbin/runlevel new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/runlevel @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/setconsole b/busybox-1_37_0/boot-files/initramfs/sbin/setconsole new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/setconsole @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/slattach b/busybox-1_37_0/boot-files/initramfs/sbin/slattach new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/slattach @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/start-stop-daemon b/busybox-1_37_0/boot-files/initramfs/sbin/start-stop-daemon new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/start-stop-daemon @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/sulogin b/busybox-1_37_0/boot-files/initramfs/sbin/sulogin new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/sulogin @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/swapoff b/busybox-1_37_0/boot-files/initramfs/sbin/swapoff new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/swapoff @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/swapon b/busybox-1_37_0/boot-files/initramfs/sbin/swapon new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/swapon @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/switch_root b/busybox-1_37_0/boot-files/initramfs/sbin/switch_root new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/switch_root @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/sysctl b/busybox-1_37_0/boot-files/initramfs/sbin/sysctl new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/sysctl @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/syslogd b/busybox-1_37_0/boot-files/initramfs/sbin/syslogd new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/syslogd @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/tc b/busybox-1_37_0/boot-files/initramfs/sbin/tc new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/tc @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/tunctl b/busybox-1_37_0/boot-files/initramfs/sbin/tunctl new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/tunctl @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/udhcpc b/busybox-1_37_0/boot-files/initramfs/sbin/udhcpc new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/udhcpc @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/uevent b/busybox-1_37_0/boot-files/initramfs/sbin/uevent new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/uevent @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/vconfig b/busybox-1_37_0/boot-files/initramfs/sbin/vconfig new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/vconfig @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/watchdog b/busybox-1_37_0/boot-files/initramfs/sbin/watchdog new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/watchdog @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/sbin/zcip b/busybox-1_37_0/boot-files/initramfs/sbin/zcip new file mode 120000 index 000000000..71259713e --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/sbin/zcip @@ -0,0 +1 @@ +../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/[ b/busybox-1_37_0/boot-files/initramfs/usr/bin/[ new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/[ @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/[[ b/busybox-1_37_0/boot-files/initramfs/usr/bin/[[ new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/[[ @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ascii b/busybox-1_37_0/boot-files/initramfs/usr/bin/ascii new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ascii @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/awk b/busybox-1_37_0/boot-files/initramfs/usr/bin/awk new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/awk @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/basename b/busybox-1_37_0/boot-files/initramfs/usr/bin/basename new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/basename @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/bc b/busybox-1_37_0/boot-files/initramfs/usr/bin/bc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/bc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/beep b/busybox-1_37_0/boot-files/initramfs/usr/bin/beep new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/beep @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/blkdiscard b/busybox-1_37_0/boot-files/initramfs/usr/bin/blkdiscard new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/blkdiscard @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/bunzip2 b/busybox-1_37_0/boot-files/initramfs/usr/bin/bunzip2 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/bunzip2 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/bzcat b/busybox-1_37_0/boot-files/initramfs/usr/bin/bzcat new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/bzcat @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/bzip2 b/busybox-1_37_0/boot-files/initramfs/usr/bin/bzip2 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/bzip2 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/cal b/busybox-1_37_0/boot-files/initramfs/usr/bin/cal new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/cal @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/chpst b/busybox-1_37_0/boot-files/initramfs/usr/bin/chpst new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/chpst @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/chrt b/busybox-1_37_0/boot-files/initramfs/usr/bin/chrt new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/chrt @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/chvt b/busybox-1_37_0/boot-files/initramfs/usr/bin/chvt new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/chvt @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/cksum b/busybox-1_37_0/boot-files/initramfs/usr/bin/cksum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/cksum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/clear b/busybox-1_37_0/boot-files/initramfs/usr/bin/clear new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/clear @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/cmp b/busybox-1_37_0/boot-files/initramfs/usr/bin/cmp new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/cmp @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/comm b/busybox-1_37_0/boot-files/initramfs/usr/bin/comm new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/comm @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/crc32 b/busybox-1_37_0/boot-files/initramfs/usr/bin/crc32 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/crc32 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/crontab b/busybox-1_37_0/boot-files/initramfs/usr/bin/crontab new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/crontab @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/cryptpw b/busybox-1_37_0/boot-files/initramfs/usr/bin/cryptpw new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/cryptpw @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/cut b/busybox-1_37_0/boot-files/initramfs/usr/bin/cut new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/cut @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dc b/busybox-1_37_0/boot-files/initramfs/usr/bin/dc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/deallocvt b/busybox-1_37_0/boot-files/initramfs/usr/bin/deallocvt new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/deallocvt @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/diff b/busybox-1_37_0/boot-files/initramfs/usr/bin/diff new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/diff @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dirname b/busybox-1_37_0/boot-files/initramfs/usr/bin/dirname new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dirname @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dos2unix b/busybox-1_37_0/boot-files/initramfs/usr/bin/dos2unix new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dos2unix @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg b/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg-deb b/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg-deb new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dpkg-deb @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/du b/busybox-1_37_0/boot-files/initramfs/usr/bin/du new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/du @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/dumpleases b/busybox-1_37_0/boot-files/initramfs/usr/bin/dumpleases new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/dumpleases @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/eject b/busybox-1_37_0/boot-files/initramfs/usr/bin/eject new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/eject @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/env b/busybox-1_37_0/boot-files/initramfs/usr/bin/env new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/env @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/envdir b/busybox-1_37_0/boot-files/initramfs/usr/bin/envdir new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/envdir @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/envuidgid b/busybox-1_37_0/boot-files/initramfs/usr/bin/envuidgid new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/envuidgid @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/expand b/busybox-1_37_0/boot-files/initramfs/usr/bin/expand new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/expand @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/expr b/busybox-1_37_0/boot-files/initramfs/usr/bin/expr new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/expr @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/factor b/busybox-1_37_0/boot-files/initramfs/usr/bin/factor new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/factor @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/fallocate b/busybox-1_37_0/boot-files/initramfs/usr/bin/fallocate new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/fallocate @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/fgconsole b/busybox-1_37_0/boot-files/initramfs/usr/bin/fgconsole new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/fgconsole @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/find b/busybox-1_37_0/boot-files/initramfs/usr/bin/find new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/find @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/flock b/busybox-1_37_0/boot-files/initramfs/usr/bin/flock new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/flock @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/fold b/busybox-1_37_0/boot-files/initramfs/usr/bin/fold new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/fold @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/free b/busybox-1_37_0/boot-files/initramfs/usr/bin/free new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/free @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpget b/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpget new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpget @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpput b/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpput new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ftpput @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/fuser b/busybox-1_37_0/boot-files/initramfs/usr/bin/fuser new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/fuser @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/getfattr b/busybox-1_37_0/boot-files/initramfs/usr/bin/getfattr new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/getfattr @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/groups b/busybox-1_37_0/boot-files/initramfs/usr/bin/groups new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/groups @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/hd b/busybox-1_37_0/boot-files/initramfs/usr/bin/hd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/hd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/head b/busybox-1_37_0/boot-files/initramfs/usr/bin/head new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/head @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/hexdump b/busybox-1_37_0/boot-files/initramfs/usr/bin/hexdump new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/hexdump @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/hexedit b/busybox-1_37_0/boot-files/initramfs/usr/bin/hexedit new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/hexedit @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/hostid b/busybox-1_37_0/boot-files/initramfs/usr/bin/hostid new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/hostid @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/id b/busybox-1_37_0/boot-files/initramfs/usr/bin/id new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/id @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/install b/busybox-1_37_0/boot-files/initramfs/usr/bin/install new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/install @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcrm b/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcrm new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcrm @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcs b/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcs new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ipcs @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/killall b/busybox-1_37_0/boot-files/initramfs/usr/bin/killall new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/killall @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/last b/busybox-1_37_0/boot-files/initramfs/usr/bin/last new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/last @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/less b/busybox-1_37_0/boot-files/initramfs/usr/bin/less new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/less @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/logger b/busybox-1_37_0/boot-files/initramfs/usr/bin/logger new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/logger @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/logname b/busybox-1_37_0/boot-files/initramfs/usr/bin/logname new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/logname @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lpq b/busybox-1_37_0/boot-files/initramfs/usr/bin/lpq new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lpq @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lpr b/busybox-1_37_0/boot-files/initramfs/usr/bin/lpr new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lpr @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lsof b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsof new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsof @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lspci b/busybox-1_37_0/boot-files/initramfs/usr/bin/lspci new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lspci @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lsscsi b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsscsi new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsscsi @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lsusb b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsusb new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lsusb @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lzcat b/busybox-1_37_0/boot-files/initramfs/usr/bin/lzcat new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lzcat @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/lzma b/busybox-1_37_0/boot-files/initramfs/usr/bin/lzma new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/lzma @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/man b/busybox-1_37_0/boot-files/initramfs/usr/bin/man new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/man @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/md5sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/md5sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/md5sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/mesg b/busybox-1_37_0/boot-files/initramfs/usr/bin/mesg new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/mesg @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/microcom b/busybox-1_37_0/boot-files/initramfs/usr/bin/microcom new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/microcom @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/mkfifo b/busybox-1_37_0/boot-files/initramfs/usr/bin/mkfifo new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/mkfifo @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/mkpasswd b/busybox-1_37_0/boot-files/initramfs/usr/bin/mkpasswd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/mkpasswd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nc b/busybox-1_37_0/boot-files/initramfs/usr/bin/nc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nl b/busybox-1_37_0/boot-files/initramfs/usr/bin/nl new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nl @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nmeter b/busybox-1_37_0/boot-files/initramfs/usr/bin/nmeter new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nmeter @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nohup b/busybox-1_37_0/boot-files/initramfs/usr/bin/nohup new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nohup @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nproc b/busybox-1_37_0/boot-files/initramfs/usr/bin/nproc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nproc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nsenter b/busybox-1_37_0/boot-files/initramfs/usr/bin/nsenter new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nsenter @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/nslookup b/busybox-1_37_0/boot-files/initramfs/usr/bin/nslookup new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/nslookup @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/od b/busybox-1_37_0/boot-files/initramfs/usr/bin/od new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/od @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/openvt b/busybox-1_37_0/boot-files/initramfs/usr/bin/openvt new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/openvt @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/passwd b/busybox-1_37_0/boot-files/initramfs/usr/bin/passwd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/passwd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/paste b/busybox-1_37_0/boot-files/initramfs/usr/bin/paste new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/paste @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/patch b/busybox-1_37_0/boot-files/initramfs/usr/bin/patch new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/patch @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pgrep b/busybox-1_37_0/boot-files/initramfs/usr/bin/pgrep new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pgrep @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pkill b/busybox-1_37_0/boot-files/initramfs/usr/bin/pkill new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pkill @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pmap b/busybox-1_37_0/boot-files/initramfs/usr/bin/pmap new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pmap @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/printf b/busybox-1_37_0/boot-files/initramfs/usr/bin/printf new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/printf @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pscan b/busybox-1_37_0/boot-files/initramfs/usr/bin/pscan new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pscan @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pstree b/busybox-1_37_0/boot-files/initramfs/usr/bin/pstree new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pstree @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/pwdx b/busybox-1_37_0/boot-files/initramfs/usr/bin/pwdx new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/pwdx @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/readlink b/busybox-1_37_0/boot-files/initramfs/usr/bin/readlink new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/readlink @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/realpath b/busybox-1_37_0/boot-files/initramfs/usr/bin/realpath new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/realpath @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/renice b/busybox-1_37_0/boot-files/initramfs/usr/bin/renice new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/renice @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/reset b/busybox-1_37_0/boot-files/initramfs/usr/bin/reset new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/reset @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/resize b/busybox-1_37_0/boot-files/initramfs/usr/bin/resize new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/resize @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/rpm2cpio b/busybox-1_37_0/boot-files/initramfs/usr/bin/rpm2cpio new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/rpm2cpio @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/runsv b/busybox-1_37_0/boot-files/initramfs/usr/bin/runsv new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/runsv @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/runsvdir b/busybox-1_37_0/boot-files/initramfs/usr/bin/runsvdir new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/runsvdir @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/rx b/busybox-1_37_0/boot-files/initramfs/usr/bin/rx new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/rx @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/script b/busybox-1_37_0/boot-files/initramfs/usr/bin/script new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/script @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/seq b/busybox-1_37_0/boot-files/initramfs/usr/bin/seq new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/seq @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/setfattr b/busybox-1_37_0/boot-files/initramfs/usr/bin/setfattr new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/setfattr @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/setkeycodes b/busybox-1_37_0/boot-files/initramfs/usr/bin/setkeycodes new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/setkeycodes @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/setsid b/busybox-1_37_0/boot-files/initramfs/usr/bin/setsid new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/setsid @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/setuidgid b/busybox-1_37_0/boot-files/initramfs/usr/bin/setuidgid new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/setuidgid @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sha1sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha1sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha1sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sha256sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha256sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha256sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sha3sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha3sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha3sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sha512sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha512sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sha512sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/showkey b/busybox-1_37_0/boot-files/initramfs/usr/bin/showkey new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/showkey @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/shred b/busybox-1_37_0/boot-files/initramfs/usr/bin/shred new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/shred @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/shuf b/busybox-1_37_0/boot-files/initramfs/usr/bin/shuf new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/shuf @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/smemcap b/busybox-1_37_0/boot-files/initramfs/usr/bin/smemcap new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/smemcap @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/softlimit b/busybox-1_37_0/boot-files/initramfs/usr/bin/softlimit new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/softlimit @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sort b/busybox-1_37_0/boot-files/initramfs/usr/bin/sort new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sort @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/split b/busybox-1_37_0/boot-files/initramfs/usr/bin/split new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/split @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ssl_client b/busybox-1_37_0/boot-files/initramfs/usr/bin/ssl_client new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ssl_client @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/strings b/busybox-1_37_0/boot-files/initramfs/usr/bin/strings new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/strings @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sum b/busybox-1_37_0/boot-files/initramfs/usr/bin/sum new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sum @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/sv b/busybox-1_37_0/boot-files/initramfs/usr/bin/sv new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/sv @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/svc b/busybox-1_37_0/boot-files/initramfs/usr/bin/svc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/svc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/svok b/busybox-1_37_0/boot-files/initramfs/usr/bin/svok new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/svok @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tac b/busybox-1_37_0/boot-files/initramfs/usr/bin/tac new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tac @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tail b/busybox-1_37_0/boot-files/initramfs/usr/bin/tail new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tail @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/taskset b/busybox-1_37_0/boot-files/initramfs/usr/bin/taskset new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/taskset @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tcpsvd b/busybox-1_37_0/boot-files/initramfs/usr/bin/tcpsvd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tcpsvd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tee b/busybox-1_37_0/boot-files/initramfs/usr/bin/tee new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tee @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/telnet b/busybox-1_37_0/boot-files/initramfs/usr/bin/telnet new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/telnet @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/test b/busybox-1_37_0/boot-files/initramfs/usr/bin/test new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/test @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tftp b/busybox-1_37_0/boot-files/initramfs/usr/bin/tftp new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tftp @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/time b/busybox-1_37_0/boot-files/initramfs/usr/bin/time new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/time @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/timeout b/busybox-1_37_0/boot-files/initramfs/usr/bin/timeout new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/timeout @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/top b/busybox-1_37_0/boot-files/initramfs/usr/bin/top new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/top @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tr b/busybox-1_37_0/boot-files/initramfs/usr/bin/tr new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tr @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute b/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute6 b/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute6 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/traceroute6 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tree b/busybox-1_37_0/boot-files/initramfs/usr/bin/tree new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tree @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/truncate b/busybox-1_37_0/boot-files/initramfs/usr/bin/truncate new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/truncate @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ts b/busybox-1_37_0/boot-files/initramfs/usr/bin/ts new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ts @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tsort b/busybox-1_37_0/boot-files/initramfs/usr/bin/tsort new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tsort @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/tty b/busybox-1_37_0/boot-files/initramfs/usr/bin/tty new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/tty @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/ttysize b/busybox-1_37_0/boot-files/initramfs/usr/bin/ttysize new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/ttysize @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/udhcpc6 b/busybox-1_37_0/boot-files/initramfs/usr/bin/udhcpc6 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/udhcpc6 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/udpsvd b/busybox-1_37_0/boot-files/initramfs/usr/bin/udpsvd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/udpsvd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unexpand b/busybox-1_37_0/boot-files/initramfs/usr/bin/unexpand new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unexpand @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/uniq b/busybox-1_37_0/boot-files/initramfs/usr/bin/uniq new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/uniq @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unix2dos b/busybox-1_37_0/boot-files/initramfs/usr/bin/unix2dos new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unix2dos @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unlink b/busybox-1_37_0/boot-files/initramfs/usr/bin/unlink new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unlink @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unlzma b/busybox-1_37_0/boot-files/initramfs/usr/bin/unlzma new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unlzma @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unshare b/busybox-1_37_0/boot-files/initramfs/usr/bin/unshare new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unshare @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unxz b/busybox-1_37_0/boot-files/initramfs/usr/bin/unxz new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unxz @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/unzip b/busybox-1_37_0/boot-files/initramfs/usr/bin/unzip new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/unzip @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/uptime b/busybox-1_37_0/boot-files/initramfs/usr/bin/uptime new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/uptime @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/users b/busybox-1_37_0/boot-files/initramfs/usr/bin/users new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/users @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/uudecode b/busybox-1_37_0/boot-files/initramfs/usr/bin/uudecode new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/uudecode @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/uuencode b/busybox-1_37_0/boot-files/initramfs/usr/bin/uuencode new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/uuencode @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/vlock b/busybox-1_37_0/boot-files/initramfs/usr/bin/vlock new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/vlock @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/volname b/busybox-1_37_0/boot-files/initramfs/usr/bin/volname new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/volname @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/w b/busybox-1_37_0/boot-files/initramfs/usr/bin/w new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/w @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/wall b/busybox-1_37_0/boot-files/initramfs/usr/bin/wall new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/wall @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/wc b/busybox-1_37_0/boot-files/initramfs/usr/bin/wc new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/wc @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/wget b/busybox-1_37_0/boot-files/initramfs/usr/bin/wget new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/wget @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/which b/busybox-1_37_0/boot-files/initramfs/usr/bin/which new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/which @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/who b/busybox-1_37_0/boot-files/initramfs/usr/bin/who new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/who @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/whoami b/busybox-1_37_0/boot-files/initramfs/usr/bin/whoami new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/whoami @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/whois b/busybox-1_37_0/boot-files/initramfs/usr/bin/whois new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/whois @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/xargs b/busybox-1_37_0/boot-files/initramfs/usr/bin/xargs new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/xargs @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/xxd b/busybox-1_37_0/boot-files/initramfs/usr/bin/xxd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/xxd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/xz b/busybox-1_37_0/boot-files/initramfs/usr/bin/xz new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/xz @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/xzcat b/busybox-1_37_0/boot-files/initramfs/usr/bin/xzcat new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/xzcat @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/bin/yes b/busybox-1_37_0/boot-files/initramfs/usr/bin/yes new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/bin/yes @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/add-shell b/busybox-1_37_0/boot-files/initramfs/usr/sbin/add-shell new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/add-shell @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/addgroup b/busybox-1_37_0/boot-files/initramfs/usr/sbin/addgroup new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/addgroup @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/adduser b/busybox-1_37_0/boot-files/initramfs/usr/sbin/adduser new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/adduser @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/arping b/busybox-1_37_0/boot-files/initramfs/usr/sbin/arping new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/arping @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/brctl b/busybox-1_37_0/boot-files/initramfs/usr/sbin/brctl new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/brctl @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/chat b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chat new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chat @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/chpasswd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chpasswd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chpasswd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/chroot b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chroot new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/chroot @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/crond b/busybox-1_37_0/boot-files/initramfs/usr/sbin/crond new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/crond @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/delgroup b/busybox-1_37_0/boot-files/initramfs/usr/sbin/delgroup new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/delgroup @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/deluser b/busybox-1_37_0/boot-files/initramfs/usr/sbin/deluser new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/deluser @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/dhcprelay b/busybox-1_37_0/boot-files/initramfs/usr/sbin/dhcprelay new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/dhcprelay @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/dnsd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/dnsd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/dnsd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ether-wake b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ether-wake new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ether-wake @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/fakeidentd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fakeidentd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fakeidentd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/fbset b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fbset new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fbset @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/fdformat b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fdformat new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fdformat @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/fsfreeze b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fsfreeze new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/fsfreeze @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ftpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ftpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ftpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/httpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/httpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/httpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdetect b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdetect new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdetect @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdump b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdump new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cdump @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cget b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cget new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cget @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cset b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cset new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2cset @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2ctransfer b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2ctransfer new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/i2ctransfer @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ifplugd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ifplugd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ifplugd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/inetd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/inetd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/inetd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/killall5 b/busybox-1_37_0/boot-files/initramfs/usr/sbin/killall5 new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/killall5 @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/loadfont b/busybox-1_37_0/boot-files/initramfs/usr/sbin/loadfont new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/loadfont @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/lpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/lpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/lpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/mim b/busybox-1_37_0/boot-files/initramfs/usr/sbin/mim new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/mim @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/nanddump b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nanddump new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nanddump @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/nandwrite b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nandwrite new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nandwrite @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/nbd-client b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nbd-client new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nbd-client @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/nologin b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nologin new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/nologin @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ntpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ntpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ntpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/partprobe b/busybox-1_37_0/boot-files/initramfs/usr/sbin/partprobe new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/partprobe @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/popmaildir b/busybox-1_37_0/boot-files/initramfs/usr/sbin/popmaildir new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/popmaildir @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/powertop b/busybox-1_37_0/boot-files/initramfs/usr/sbin/powertop new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/powertop @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdate b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdate new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdate @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdev b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdev new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rdev @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/readahead b/busybox-1_37_0/boot-files/initramfs/usr/sbin/readahead new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/readahead @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/readprofile b/busybox-1_37_0/boot-files/initramfs/usr/sbin/readprofile new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/readprofile @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/remove-shell b/busybox-1_37_0/boot-files/initramfs/usr/sbin/remove-shell new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/remove-shell @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/rtcwake b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rtcwake new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/rtcwake @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/seedrng b/busybox-1_37_0/boot-files/initramfs/usr/sbin/seedrng new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/seedrng @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/sendmail b/busybox-1_37_0/boot-files/initramfs/usr/sbin/sendmail new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/sendmail @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/setfont b/busybox-1_37_0/boot-files/initramfs/usr/sbin/setfont new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/setfont @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/setlogcons b/busybox-1_37_0/boot-files/initramfs/usr/sbin/setlogcons new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/setlogcons @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/svlogd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/svlogd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/svlogd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/telnetd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/telnetd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/telnetd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/tftpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/tftpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/tftpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiattach b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiattach new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiattach @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubidetach b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubidetach new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubidetach @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubimkvol b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubimkvol new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubimkvol @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirename b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirename new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirename @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirmvol b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirmvol new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirmvol @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirsvol b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirsvol new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubirsvol @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiupdatevol b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiupdatevol new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/ubiupdatevol @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/boot-files/initramfs/usr/sbin/udhcpd b/busybox-1_37_0/boot-files/initramfs/usr/sbin/udhcpd new file mode 120000 index 000000000..f948f1a72 --- /dev/null +++ b/busybox-1_37_0/boot-files/initramfs/usr/sbin/udhcpd @@ -0,0 +1 @@ +../../bin/busybox \ No newline at end of file diff --git a/busybox-1_37_0/busybox_ldscript.README.txt b/busybox-1_37_0/busybox_ldscript.README.txt new file mode 100644 index 000000000..1625a970a --- /dev/null +++ b/busybox-1_37_0/busybox_ldscript.README.txt @@ -0,0 +1,47 @@ +/* Add SORT_BY_ALIGNMENT to linker script (found in busybox_unstripped.out): +## .rodata : { *(.rodata SORT_BY_ALIGNMENT(.rodata.*) .gnu.linkonce.r.*) } +## .data : { *(.data SORT_BY_ALIGNMENT(.data.*) .gnu.linkonce.d.*) } +## .bss : { *(.bss SORT_BY_ALIGNMENT(.bss.*) .gnu.linkonce.b.*) } +## This will eliminate most of the padding (~3kb). +## Hmm, "ld --sort-section alignment" should do it too. +## +## There is a ld hack which is meant to decrease disk usage +## at the cost of more RAM usage (??!!) in standard ld script: +## . = ALIGN (0x1000) - ((0x1000 - .) & (0x1000 - 1)); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000); +## Replace it with: +## . = ALIGN (0x1000); . = DATA_SEGMENT_ALIGN (0x1000, 0x1000); +## to unconditionally align .data to the next page boundary, +## instead of "next page, plus current offset in this page" +*/ + +/* To reduce the number of VMAs each bbox process has, +## move *(.bss SORT_BY_ALIGNMENT(.bss.*) ...) +## part from .bss : {...} block to .data : { ... } block. +## (This usually increases .data section by only one page). +## Result: +## +## text data bss dec hex filename +## 1050792 560 7580 1058932 102874 busybox.bss +## 1050792 8149 0 1058941 10287d busybox.nobss +## +## $ exec busybox.bss pmap $$ +## 0000000008048000 1028K r-xp /path/to/busybox.bss +## 0000000008149000 8K rw-p /path/to/busybox.bss +## 000000000814b000 4K rw-p [ anon ] <---- this VMA is eliminated +## 00000000085f5000 4K ---p [heap] +## 00000000085f6000 4K rw-p [heap] +## 00000000f7778000 8K rw-p [ anon ] +## 00000000f777a000 12K r--p [vvar] +## 00000000f777d000 8K r-xp [vdso] +## 00000000ff7e9000 132K rw-p [stack] +## +## $ exec busybox.nobss pmap $$ +## 0000000008048000 1028K r-xp /path/to/busybox.nobss +## 0000000008149000 12K rw-p /path/to/busybox.nobss +## 00000000086f0000 4K ---p [heap] +## 00000000086f1000 4K rw-p [heap] +## 00000000f7783000 8K rw-p [ anon ] +## 00000000f7785000 12K r--p [vvar] +## 00000000f7788000 8K r-xp [vdso] +## 00000000ffac0000 132K rw-p [stack] +*/ diff --git a/busybox-1_37_0/configs/TEST_nommu_defconfig b/busybox-1_37_0/configs/TEST_nommu_defconfig new file mode 100644 index 000000000..fa3e96326 --- /dev/null +++ b/busybox-1_37_0/configs/TEST_nommu_defconfig @@ -0,0 +1,913 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.16.0 +# Wed Jan 27 21:01:26 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +CONFIG_EXTRA_COMPAT=y +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_UNICODE_SUPPORT is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_PIDFILE=y +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +CONFIG_SELINUX=y +CONFIG_FEATURE_PREFER_APPLETS=y +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +CONFIG_NOMMU=y +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +CONFIG_FEATURE_ETC_NETWORKS=y +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +CONFIG_FEATURE_EDITING_VI=y +CONFIG_FEATURE_EDITING_HISTORY=15 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_TAB_COMPLETION=y +CONFIG_FEATURE_USERNAME_COMPLETION=y +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +CONFIG_FEATURE_EDITING_ASK_TERMINAL=y +CONFIG_FEATURE_NON_POSIX_CP=y +CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y +CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_MONOTONIC_SYSCALL=y +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_GUNZIP=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAL=y +CONFIG_CAT=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_FEATURE_ENV_LONG_OPTIONS=y +CONFIG_EXPAND=y +CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHO=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +CONFIG_KBD_MODE=y +CONFIG_LOADFONT=y +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y +CONFIG_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +CONFIG_FEATURE_FIND_CONTEXT=y +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +CONFIG_FEATURE_KILL_REMOVED=y +CONFIG_FEATURE_KILL_DELAY=1 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_MESG=y + +# +# Login/Password Management Utilities +# +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +CONFIG_FEATURE_CHECK_NAMES=y +CONFIG_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_DELUSER=y +CONFIG_GETTY=y +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +CONFIG_LOGIN=y +# CONFIG_PAM is not set +CONFIG_LOGIN_SCRIPTS=y +CONFIG_FEATURE_NOLOGIN=y +CONFIG_FEATURE_SECURETTY=y +CONFIG_PASSWD=y +CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +CONFIG_CRYPTPW=y +CONFIG_CHPASSWD=y +CONFIG_SU=y +CONFIG_FEATURE_SU_SYSLOG=y +CONFIG_FEATURE_SU_CHECKS_SHELLS=y +CONFIG_SULOGIN=y +CONFIG_VLOCK=y + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y + +# +# Linux Module Utilities +# +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +CONFIG_FEATURE_AIX_LABEL=y +CONFIG_FEATURE_SGI_LABEL=y +CONFIG_FEATURE_SUN_LABEL=y +CONFIG_FEATURE_OSF_LABEL=y +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FREERAMDISK=y +CONFIG_FSCK_MINIX=y +CONFIG_MKFS_EXT2=y +CONFIG_MKFS_MINIX=y + +# +# Minix filesystem support +# +CONFIG_FEATURE_MINIX2=y +CONFIG_MKFS_REISER=y +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y +CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y +CONFIG_IPCRM=y +CONFIG_IPCS=y +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +CONFIG_FEATURE_MDEV_RENAME=y +CONFIG_FEATURE_MDEV_RENAME_REGEXP=y +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +CONFIG_VOLUMEID=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y +CONFIG_MOUNT=y +CONFIG_FEATURE_MOUNT_FAKE=y +CONFIG_FEATURE_MOUNT_VERBOSE=y +CONFIG_FEATURE_MOUNT_HELPERS=y +CONFIG_FEATURE_MOUNT_LABEL=y +CONFIG_FEATURE_MOUNT_NFS=y +CONFIG_FEATURE_MOUNT_CIFS=y +CONFIG_FEATURE_MOUNT_FLAGS=y +CONFIG_FEATURE_MOUNT_FSTAB=y +CONFIG_PIVOT_ROOT=y +CONFIG_RDATE=y +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +CONFIG_SETARCH=y +CONFIG_SWAPONOFF=y +CONFIG_FEATURE_SWAPON_PRI=y +CONFIG_SWITCH_ROOT=y +CONFIG_UMOUNT=y +CONFIG_FEATURE_UMOUNT_ALL=y + +# +# Common options for mount/umount +# +CONFIG_FEATURE_MOUNT_LOOP=y +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Miscellaneous Utilities +# +CONFIG_ADJTIMEX=y +CONFIG_BBCONFIG=y +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +CONFIG_FEATURE_CHAT_TTY_HIFI=y +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +CONFIG_EJECT=y +CONFIG_FEATURE_EJECT_SCSI=y +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +CONFIG_IONICE=y +CONFIG_INOTIFYD=y +CONFIG_LAST=y +CONFIG_FEATURE_LAST_SMALL=y +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +CONFIG_MICROCOM=y +CONFIG_MOUNTPOINT=y +CONFIG_MT=y +CONFIG_RAIDAUTORUN=y +CONFIG_READAHEAD=y +CONFIG_RUNLEVEL=y +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +CONFIG_TASKSET=y +CONFIG_FEATURE_TASKSET_FANCY=y +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WALL=y +CONFIG_WATCHDOG=y + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +CONFIG_FEATURE_UNIX_LOCAL=y +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +CONFIG_VERBOSE_RESOLUTION_ERRORS=y +CONFIG_ARP=y +CONFIG_ARPING=y +CONFIG_BRCTL=y +CONFIG_FEATURE_BRCTL_FANCY=y +CONFIG_FEATURE_BRCTL_SHOW=y +CONFIG_DNSD=y +CONFIG_ETHER_WAKE=y +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +CONFIG_FEATURE_IFCONFIG_SLIP=y +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +CONFIG_IFENSLAVE=y +CONFIG_IFPLUGD=y +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +CONFIG_FEATURE_IFUPDOWN_IPV6=y +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y +CONFIG_INETD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y +CONFIG_FEATURE_INETD_RPC=y +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_LINK_CAN=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +CONFIG_FEATURE_IP_RARE_PROTOCOLS=y +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +CONFIG_NAMEIF=y +CONFIG_FEATURE_NAMEIF_EXTENDED=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +CONFIG_NSLOOKUP=y +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_PSCAN=y +CONFIG_ROUTE=y +CONFIG_SLATTACH=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +CONFIG_TFTP_DEBUG=y +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_ZCIP=y +CONFIG_TCPSVD=y +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +CONFIG_UDPSVD=y + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_FREE=y +CONFIG_FUSER=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_NMETER=y +CONFIG_PGREP=y +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +CONFIG_PKILL=y +CONFIG_PS=y +CONFIG_FEATURE_PS_WIDE=y +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS=y +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_UPTIME=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +CONFIG_FEATURE_RUNSVDIR_LOG=y +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y + +# +# SELinux Utilities +# +CONFIG_CHCON=y +CONFIG_FEATURE_CHCON_LONG_OPTIONS=y +CONFIG_GETENFORCE=y +CONFIG_GETSEBOOL=y +CONFIG_LOAD_POLICY=y +CONFIG_MATCHPATHCON=y +CONFIG_RESTORECON=y +CONFIG_RUNCON=y +CONFIG_FEATURE_RUNCON_LONG_OPTIONS=y +CONFIG_SELINUXENABLED=y +CONFIG_SETENFORCE=y +CONFIG_SETFILES=y +CONFIG_FEATURE_SETFILES_CHECK_OPTION=y +CONFIG_SETSEBOOL=y +CONFIG_SESTATUS=y + +# +# Shells +# +# CONFIG_FEATURE_SH_IS_ASH is not set +CONFIG_FEATURE_SH_IS_HUSH=y +# CONFIG_FEATURE_SH_IS_NONE is not set +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_HELP=y +CONFIG_HUSH_INTERACTIVE=y +CONFIG_HUSH_JOB=y +CONFIG_HUSH_TICK=y +CONFIG_HUSH_IF=y +CONFIG_HUSH_LOOPS=y +CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +CONFIG_FEATURE_SH_STANDALONE=y +CONFIG_FEATURE_SH_NOFORK=y +CONFIG_CTTYHACK=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_SYSLOGD_DUP=y +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +CONFIG_KLOGD=y +CONFIG_LOGGER=y diff --git a/busybox-1_37_0/configs/TEST_noprintf_defconfig b/busybox-1_37_0/configs/TEST_noprintf_defconfig new file mode 100644 index 000000000..9b378fd55 --- /dev/null +++ b/busybox-1_37_0/configs/TEST_noprintf_defconfig @@ -0,0 +1,920 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.17.0.git +# Mon Jun 7 13:37:55 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +CONFIG_EXTRA_COMPAT=y +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +# CONFIG_FEATURE_COMPRESS_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=65535 +CONFIG_UNICODE_COMBINING_WCHARS=y +CONFIG_UNICODE_WIDE_WCHARS=y +CONFIG_UNICODE_BIDI_SUPPORT=y +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +CONFIG_UNICODE_PRESERVE_BROKEN=y +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +CONFIG_FEATURE_PIDFILE=y +# CONFIG_FEATURE_SUID is not set +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +# CONFIG_FEATURE_SYSLOG is not set + +# +# Build Options +# +CONFIG_STATIC=y +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="i486-linux-uclibc-" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +CONFIG_WERROR=y +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +CONFIG_FEATURE_EDITING_VI=y +CONFIG_FEATURE_EDITING_HISTORY=15 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_TAB_COMPLETION=y +CONFIG_FEATURE_USERNAME_COMPLETION=y +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +CONFIG_FEATURE_EDITING_ASK_TERMINAL=y +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=64 +CONFIG_MONOTONIC_SYSCALL=y +# CONFIG_IOCTL_HEX2STR_ERROR is not set +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +# CONFIG_AR is not set +# CONFIG_FEATURE_AR_LONG_FILENAMES is not set +# CONFIG_FEATURE_AR_CREATE is not set +# CONFIG_BUNZIP2 is not set +# CONFIG_BZIP2 is not set +# CONFIG_CPIO is not set +# CONFIG_FEATURE_CPIO_O is not set +# CONFIG_FEATURE_CPIO_P is not set +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +# CONFIG_GUNZIP is not set +# CONFIG_GZIP is not set +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +# CONFIG_LZOP is not set +# CONFIG_LZOP_COMPR_HIGH is not set +# CONFIG_RPM2CPIO is not set +# CONFIG_RPM is not set +# CONFIG_TAR is not set +# CONFIG_FEATURE_TAR_CREATE is not set +# CONFIG_FEATURE_TAR_AUTODETECT is not set +# CONFIG_FEATURE_TAR_FROM is not set +# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set +# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set +# CONFIG_FEATURE_TAR_GNU_EXTENSIONS is not set +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_FEATURE_TAR_UNAME_GNAME is not set +# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +# CONFIG_FEATURE_TAR_SELINUX is not set +# CONFIG_UNCOMPRESS is not set +# CONFIG_UNLZMA is not set +# CONFIG_FEATURE_LZMA_FAST is not set +# CONFIG_LZMA is not set +# CONFIG_UNXZ is not set +# CONFIG_XZ is not set +# CONFIG_UNZIP is not set + +# +# Coreutils +# +CONFIG_BASENAME=y +# CONFIG_CAT is not set +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_TEST is not set +# CONFIG_FEATURE_TEST_64 is not set +# CONFIG_TR is not set +# CONFIG_FEATURE_TR_CLASSES is not set +# CONFIG_FEATURE_TR_EQUIV is not set +# CONFIG_CAL is not set +# CONFIG_CATV is not set +# CONFIG_CHGRP is not set +# CONFIG_CHMOD is not set +# CONFIG_CHOWN is not set +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +# CONFIG_CHROOT is not set +# CONFIG_CKSUM is not set +# CONFIG_COMM is not set +# CONFIG_CP is not set +# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +# CONFIG_CUT is not set +# CONFIG_DD is not set +# CONFIG_FEATURE_DD_SIGNAL_HANDLING is not set +# CONFIG_FEATURE_DD_THIRD_STATUS_LINE is not set +# CONFIG_FEATURE_DD_IBS_OBS is not set +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +# CONFIG_DIRNAME is not set +# CONFIG_DOS2UNIX is not set +# CONFIG_UNIX2DOS is not set +# CONFIG_DU is not set +# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set +# CONFIG_ECHO is not set +# CONFIG_FEATURE_FANCY_ECHO is not set +# CONFIG_ENV is not set +# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set +# CONFIG_EXPAND is not set +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +# CONFIG_EXPR is not set +# CONFIG_EXPR_MATH_SUPPORT_64 is not set +CONFIG_FALSE=y +# CONFIG_FOLD is not set +# CONFIG_FSYNC is not set +# CONFIG_HEAD is not set +# CONFIG_FEATURE_FANCY_HEAD is not set +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_INSTALL is not set +# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +# CONFIG_LN is not set +# CONFIG_LOGNAME is not set +# CONFIG_LS is not set +# CONFIG_FEATURE_LS_FILETYPES is not set +# CONFIG_FEATURE_LS_FOLLOWLINKS is not set +# CONFIG_FEATURE_LS_RECURSIVE is not set +# CONFIG_FEATURE_LS_SORTFILES is not set +# CONFIG_FEATURE_LS_TIMESTAMPS is not set +# CONFIG_FEATURE_LS_USERNAME is not set +# CONFIG_FEATURE_LS_COLOR is not set +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +# CONFIG_MD5SUM is not set +# CONFIG_MKDIR is not set +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set +# CONFIG_MKFIFO is not set +# CONFIG_MKNOD is not set +# CONFIG_MV is not set +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set +# CONFIG_NICE is not set +# CONFIG_NOHUP is not set +# CONFIG_OD is not set +# CONFIG_PRINTENV is not set +# CONFIG_PRINTF is not set +# CONFIG_PWD is not set +# CONFIG_READLINK is not set +# CONFIG_FEATURE_READLINK_FOLLOW is not set +# CONFIG_REALPATH is not set +# CONFIG_RM is not set +# CONFIG_RMDIR is not set +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +# CONFIG_SEQ is not set +# CONFIG_SHA1SUM is not set +# CONFIG_SHA256SUM is not set +# CONFIG_SHA512SUM is not set +# CONFIG_SLEEP is not set +# CONFIG_FEATURE_FANCY_SLEEP is not set +# CONFIG_FEATURE_FLOAT_SLEEP is not set +# CONFIG_SORT is not set +# CONFIG_FEATURE_SORT_BIG is not set +# CONFIG_SPLIT is not set +# CONFIG_FEATURE_SPLIT_FANCY is not set +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +# CONFIG_STTY is not set +# CONFIG_SUM is not set +# CONFIG_SYNC is not set +# CONFIG_TAC is not set +# CONFIG_TAIL is not set +# CONFIG_FEATURE_FANCY_TAIL is not set +# CONFIG_TEE is not set +# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set +# CONFIG_TOUCH is not set +CONFIG_TRUE=y +# CONFIG_TTY is not set +# CONFIG_UNAME is not set +# CONFIG_UNEXPAND is not set +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +# CONFIG_UNIQ is not set +# CONFIG_USLEEP is not set +# CONFIG_UUDECODE is not set +# CONFIG_UUENCODE is not set +# CONFIG_WC is not set +# CONFIG_FEATURE_WC_LARGE is not set +# CONFIG_WHO is not set +# CONFIG_WHOAMI is not set +# CONFIG_YES is not set +# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set +# CONFIG_FEATURE_HUMAN_READABLE is not set +# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set + +# +# Console Utilities +# +# CONFIG_CHVT is not set +# CONFIG_FGCONSOLE is not set +# CONFIG_CLEAR is not set +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +# CONFIG_RESET is not set +# CONFIG_RESIZE is not set +# CONFIG_FEATURE_RESIZE_PRINT is not set +# CONFIG_SETCONSOLE is not set +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +# CONFIG_SETKEYCODES is not set +# CONFIG_SETLOGCONS is not set +# CONFIG_SHOWKEY is not set +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +# CONFIG_MKTEMP is not set +CONFIG_PIPE_PROGRESS=y +# CONFIG_RUN_PARTS is not set +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +# CONFIG_FEATURE_RUN_PARTS_FANCY is not set +# CONFIG_START_STOP_DAEMON is not set +# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +# CONFIG_WHICH is not set + +# +# Editors +# +# CONFIG_AWK is not set +# CONFIG_FEATURE_AWK_LIBM is not set +# CONFIG_CMP is not set +# CONFIG_DIFF is not set +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +# CONFIG_FEATURE_DIFF_DIR is not set +# CONFIG_ED is not set +# CONFIG_PATCH is not set +# CONFIG_SED is not set +# CONFIG_VI is not set +CONFIG_FEATURE_VI_MAX_LEN=0 +# CONFIG_FEATURE_VI_8BIT is not set +# CONFIG_FEATURE_VI_COLON is not set +# CONFIG_FEATURE_VI_YANKMARK is not set +# CONFIG_FEATURE_VI_SEARCH is not set +# CONFIG_FEATURE_VI_USE_SIGNALS is not set +# CONFIG_FEATURE_VI_DOT_CMD is not set +# CONFIG_FEATURE_VI_READONLY is not set +# CONFIG_FEATURE_VI_SETOPTS is not set +# CONFIG_FEATURE_VI_SET is not set +# CONFIG_FEATURE_VI_WIN_RESIZE is not set +# CONFIG_FEATURE_VI_ASK_TERMINAL is not set +# CONFIG_FEATURE_ALLOW_EXEC is not set + +# +# Finding Utilities +# +# CONFIG_FIND is not set +# CONFIG_FEATURE_FIND_PRINT0 is not set +# CONFIG_FEATURE_FIND_MTIME is not set +# CONFIG_FEATURE_FIND_MMIN is not set +# CONFIG_FEATURE_FIND_PERM is not set +# CONFIG_FEATURE_FIND_TYPE is not set +# CONFIG_FEATURE_FIND_XDEV is not set +# CONFIG_FEATURE_FIND_MAXDEPTH is not set +# CONFIG_FEATURE_FIND_NEWER is not set +# CONFIG_FEATURE_FIND_INUM is not set +# CONFIG_FEATURE_FIND_EXEC is not set +# CONFIG_FEATURE_FIND_USER is not set +# CONFIG_FEATURE_FIND_GROUP is not set +# CONFIG_FEATURE_FIND_NOT is not set +# CONFIG_FEATURE_FIND_DEPTH is not set +# CONFIG_FEATURE_FIND_PAREN is not set +# CONFIG_FEATURE_FIND_SIZE is not set +# CONFIG_FEATURE_FIND_PRUNE is not set +# CONFIG_FEATURE_FIND_DELETE is not set +# CONFIG_FEATURE_FIND_PATH is not set +# CONFIG_FEATURE_FIND_REGEX is not set +# CONFIG_FEATURE_FIND_CONTEXT is not set +# CONFIG_FEATURE_FIND_LINKS is not set +# CONFIG_GREP is not set +# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_CONTEXT is not set +# CONFIG_XARGS is not set +# CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION is not set +# CONFIG_FEATURE_XARGS_SUPPORT_QUOTES is not set +# CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT is not set +# CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM is not set + +# +# Init Utilities +# +# CONFIG_INIT is not set +# CONFIG_FEATURE_USE_INITTAB is not set +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +# CONFIG_FEATURE_INIT_SCTTY is not set +# CONFIG_FEATURE_INIT_SYSLOG is not set +# CONFIG_FEATURE_INIT_QUIET is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +# CONFIG_LINUXRC is not set +# CONFIG_HALT is not set +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +# CONFIG_MESG is not set +# CONFIG_BOOTCHARTD is not set + +# +# Login/Password Management Utilities +# +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_DELUSER is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_PAM is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +# CONFIG_CHATTR is not set +# CONFIG_FSCK is not set +# CONFIG_LSATTR is not set +# CONFIG_TUNE2FS is not set + +# +# Linux Module Utilities +# +# CONFIG_MODINFO is not set +# CONFIG_MODPROBE_SMALL is not set +# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set +# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +# CONFIG_BLKID is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set +# CONFIG_FBSET is not set +# CONFIG_FEATURE_FBSET_FANCY is not set +# CONFIG_FEATURE_FBSET_READMODE is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +# CONFIG_FEATURE_FDISK_WRITABLE is not set +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_FDISK_ADVANCED is not set +# CONFIG_FINDFS is not set +# CONFIG_FLOCK is not set +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +# CONFIG_GETOPT is not set +# CONFIG_FEATURE_GETOPT_LONG is not set +# CONFIG_HEXDUMP is not set +# CONFIG_FEATURE_HEXDUMP_REVERSE is not set +# CONFIG_HD is not set +# CONFIG_HWCLOCK is not set +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +# CONFIG_LOSETUP is not set +# CONFIG_LSPCI is not set +# CONFIG_LSUSB is not set +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +# CONFIG_MKSWAP is not set +# CONFIG_FEATURE_MKSWAP_UUID is not set +# CONFIG_MORE is not set +CONFIG_VOLUMEID=y +# CONFIG_FEATURE_VOLUMEID_EXT is not set +# CONFIG_FEATURE_VOLUMEID_BTRFS is not set +# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +# CONFIG_FEATURE_VOLUMEID_FAT is not set +# CONFIG_FEATURE_VOLUMEID_HFS is not set +# CONFIG_FEATURE_VOLUMEID_JFS is not set +# CONFIG_FEATURE_VOLUMEID_XFS is not set +# CONFIG_FEATURE_VOLUMEID_NTFS is not set +# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set +# CONFIG_FEATURE_VOLUMEID_UDF is not set +# CONFIG_FEATURE_VOLUMEID_LUKS is not set +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set +# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set +# CONFIG_FEATURE_VOLUMEID_ROMFS is not set +# CONFIG_FEATURE_VOLUMEID_SYSV is not set +# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set +# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_RDEV is not set +# CONFIG_READPROFILE is not set +# CONFIG_RTCWAKE is not set +# CONFIG_SCRIPT is not set +# CONFIG_SCRIPTREPLAY is not set +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +# CONFIG_SWITCH_ROOT is not set +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +CONFIG_BBCONFIG=y +# CONFIG_BEEP is not set +CONFIG_FEATURE_BEEP_FREQ=0 +CONFIG_FEATURE_BEEP_LENGTH_MS=0 +# CONFIG_CHAT is not set +# CONFIG_FEATURE_CHAT_NOFAIL is not set +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set +# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set +# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set +# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set +# CONFIG_FEATURE_CHAT_CLR_ABORT is not set +# CONFIG_CHRT is not set +# CONFIG_CROND is not set +# CONFIG_FEATURE_CROND_D is not set +# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_DIR="" +# CONFIG_CRONTAB is not set +# CONFIG_DC is not set +# CONFIG_FEATURE_DC_LIBM is not set +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +# CONFIG_DEVMEM is not set +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +# CONFIG_FBSPLASH is not set +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +# CONFIG_INOTIFYD is not set +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +# CONFIG_LESS is not set +CONFIG_FEATURE_LESS_MAXLINES=0 +# CONFIG_FEATURE_LESS_BRACKETS is not set +# CONFIG_FEATURE_LESS_FLAGS is not set +# CONFIG_FEATURE_LESS_MARKS is not set +# CONFIG_FEATURE_LESS_REGEXP is not set +# CONFIG_FEATURE_LESS_WINCH is not set +# CONFIG_FEATURE_LESS_DASHCMD is not set +# CONFIG_FEATURE_LESS_LINENUMS is not set +# CONFIG_HDPARM is not set +# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set +# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set +# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +# CONFIG_FEATURE_MAKEDEVS_TABLE is not set +# CONFIG_MAN is not set +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +# CONFIG_RAIDAUTORUN is not set +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +# CONFIG_RX is not set +# CONFIG_SETSID is not set +# CONFIG_STRINGS is not set +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +# CONFIG_TIME is not set +# CONFIG_TIMEOUT is not set +# CONFIG_TTYSIZE is not set +# CONFIG_VOLNAME is not set +# CONFIG_WALL is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +# CONFIG_ARP is not set +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +# CONFIG_DNSD is not set +# CONFIG_ETHER_WAKE is not set +# CONFIG_FAKEIDENTD is not set +# CONFIG_FTPD is not set +# CONFIG_FEATURE_FTP_WRITE is not set +# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set +# CONFIG_FTPGET is not set +# CONFIG_FTPPUT is not set +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +# CONFIG_HTTPD is not set +# CONFIG_FEATURE_HTTPD_RANGES is not set +# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set +# CONFIG_FEATURE_HTTPD_SETUID is not set +# CONFIG_FEATURE_HTTPD_BASIC_AUTH is not set +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +# CONFIG_FEATURE_HTTPD_CGI is not set +# CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR is not set +# CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV is not set +# CONFIG_FEATURE_HTTPD_ENCODE_URL_STR is not set +# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set +# CONFIG_FEATURE_HTTPD_PROXY is not set +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +# CONFIG_IFUPDOWN is not set +CONFIG_IFUPDOWN_IFSTATE_PATH="" +# CONFIG_FEATURE_IFUPDOWN_IP is not set +# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +# CONFIG_IP is not set +# CONFIG_FEATURE_IP_ADDRESS is not set +# CONFIG_FEATURE_IP_LINK is not set +# CONFIG_FEATURE_IP_ROUTE is not set +# CONFIG_FEATURE_IP_TUNNEL is not set +# CONFIG_FEATURE_IP_RULE is not set +# CONFIG_FEATURE_IP_SHORT_FORMS is not set +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_IPRULE is not set +# CONFIG_IPCALC is not set +# CONFIG_FEATURE_IPCALC_FANCY is not set +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +# CONFIG_NC is not set +# CONFIG_NC_SERVER is not set +# CONFIG_NC_EXTRA is not set +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set +# CONFIG_FEATURE_NETSTAT_PRG is not set +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +# CONFIG_PSCAN is not set +# CONFIG_ROUTE is not set +# CONFIG_SLATTACH is not set +# CONFIG_TCPSVD is not set +# CONFIG_TELNET is not set +# CONFIG_FEATURE_TELNET_TTYPE is not set +# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +# CONFIG_TELNETD is not set +# CONFIG_FEATURE_TELNETD_STANDALONE is not set +# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set +# CONFIG_TFTP is not set +# CONFIG_TFTPD is not set +# CONFIG_FEATURE_TFTP_GET is not set +# CONFIG_FEATURE_TFTP_PUT is not set +# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set +# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +# CONFIG_TFTP_DEBUG is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +# CONFIG_TUNCTL is not set +# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" +# CONFIG_UDHCPC is not set +# CONFIG_FEATURE_UDHCPC_ARPING is not set +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=0 +# CONFIG_FEATURE_UDHCP_RFC3397 is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" +# CONFIG_UDPSVD is not set +# CONFIG_VCONFIG is not set +# CONFIG_WGET is not set +# CONFIG_FEATURE_WGET_STATUSBAR is not set +# CONFIG_FEATURE_WGET_AUTHENTICATION is not set +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +# CONFIG_LPD is not set +# CONFIG_LPR is not set +# CONFIG_LPQ is not set + +# +# Mail Utilities +# +# CONFIG_MAKEMIME is not set +CONFIG_FEATURE_MIME_CHARSET="" +# CONFIG_POPMAILDIR is not set +# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set +# CONFIG_REFORMIME is not set +# CONFIG_FEATURE_REFORMIME_COMPAT is not set +# CONFIG_SENDMAIL is not set + +# +# Process Utilities +# +# CONFIG_FREE is not set +# CONFIG_FUSER is not set +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_NMETER is not set +# CONFIG_PGREP is not set +# CONFIG_PIDOF is not set +# CONFIG_FEATURE_PIDOF_SINGLE is not set +# CONFIG_FEATURE_PIDOF_OMIT is not set +# CONFIG_PKILL is not set +# CONFIG_PS is not set +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +# CONFIG_RENICE is not set +# CONFIG_BB_SYSCTL is not set +# CONFIG_TOP is not set +# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set +# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set +# CONFIG_FEATURE_TOP_SMP_CPU is not set +# CONFIG_FEATURE_TOP_DECIMALS is not set +# CONFIG_FEATURE_TOP_SMP_PROCESS is not set +# CONFIG_FEATURE_TOPMEM is not set +# CONFIG_FEATURE_SHOW_THREADS is not set +# CONFIG_UPTIME is not set +# CONFIG_WATCH is not set + +# +# Runit Utilities +# +# CONFIG_RUNSV is not set +# CONFIG_RUNSVDIR is not set +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +# CONFIG_SV is not set +CONFIG_SV_DEFAULT_SERVICE_DIR="" +# CONFIG_SVLOGD is not set +# CONFIG_CHPST is not set +# CONFIG_SETUIDGID is not set +# CONFIG_ENVUIDGID is not set +# CONFIG_ENVDIR is not set +# CONFIG_SOFTLIMIT is not set +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_FEATURE_SH_IS_ASH is not set +# CONFIG_FEATURE_SH_IS_HUSH is not set +CONFIG_FEATURE_SH_IS_NONE=y +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +# CONFIG_SH_MATH_SUPPORT is not set +# CONFIG_SH_MATH_SUPPORT_64 is not set +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_CTTYHACK is not set + +# +# System Logging Utilities +# +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +# CONFIG_KLOGD is not set +# CONFIG_LOGGER is not set diff --git a/busybox-1_37_0/configs/TEST_rh9_defconfig b/busybox-1_37_0/configs/TEST_rh9_defconfig new file mode 100644 index 000000000..4ac62b9da --- /dev/null +++ b/busybox-1_37_0/configs/TEST_rh9_defconfig @@ -0,0 +1,927 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.17.0.git +# Fri Apr 16 22:25:22 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +CONFIG_LOCALE_SUPPORT=y +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_UTMP=y +CONFIG_FEATURE_WTMP=y +CONFIG_FEATURE_PIDFILE=y +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options +# +# CONFIG_INSTALL_NO_USR is not set +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=15 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_MONOTONIC_SYSCALL is not set +CONFIG_IOCTL_HEX2STR_ERROR=y +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GUNZIP=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAL=y +CONFIG_CAT=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_FEATURE_ENV_LONG_OPTIONS=y +CONFIG_EXPAND=y +CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHO=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +CONFIG_KBD_MODE=y +CONFIG_LOADFONT=y +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y +CONFIG_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y + +# +# Common options for loadfont and setfont +# +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_MESG=y + +# +# Login/Password Management Utilities +# +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_DELUSER=y +CONFIG_GETTY=y +CONFIG_LOGIN=y +# CONFIG_PAM is not set +CONFIG_LOGIN_SCRIPTS=y +CONFIG_FEATURE_NOLOGIN=y +CONFIG_FEATURE_SECURETTY=y +CONFIG_PASSWD=y +CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +CONFIG_CRYPTPW=y +CONFIG_CHPASSWD=y +CONFIG_SU=y +CONFIG_FEATURE_SU_SYSLOG=y +CONFIG_FEATURE_SU_CHECKS_SHELLS=y +CONFIG_SULOGIN=y +CONFIG_VLOCK=y + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y + +# +# Linux Module Utilities +# +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +# CONFIG_FLOCK is not set +CONFIG_FREERAMDISK=y +CONFIG_FSCK_MINIX=y +# CONFIG_MKFS_EXT2 is not set +CONFIG_MKFS_MINIX=y + +# +# Minix filesystem support +# +CONFIG_FEATURE_MINIX2=y +# CONFIG_MKFS_REISER is not set +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y +CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y +CONFIG_IPCRM=y +CONFIG_IPCS=y +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +CONFIG_FEATURE_MDEV_RENAME=y +CONFIG_FEATURE_MDEV_RENAME_REGEXP=y +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +CONFIG_VOLUMEID=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y +CONFIG_MOUNT=y +CONFIG_FEATURE_MOUNT_FAKE=y +CONFIG_FEATURE_MOUNT_VERBOSE=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +CONFIG_FEATURE_MOUNT_LABEL=y +CONFIG_FEATURE_MOUNT_NFS=y +CONFIG_FEATURE_MOUNT_CIFS=y +CONFIG_FEATURE_MOUNT_FLAGS=y +CONFIG_FEATURE_MOUNT_FSTAB=y +CONFIG_PIVOT_ROOT=y +CONFIG_RDATE=y +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +CONFIG_SETARCH=y +CONFIG_SWAPONOFF=y +CONFIG_FEATURE_SWAPON_PRI=y +CONFIG_SWITCH_ROOT=y +CONFIG_UMOUNT=y +CONFIG_FEATURE_UMOUNT_ALL=y + +# +# Common options for mount/umount +# +CONFIG_FEATURE_MOUNT_LOOP=y +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set + +# +# Miscellaneous Utilities +# +CONFIG_ADJTIMEX=y +# CONFIG_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +CONFIG_EJECT=y +CONFIG_FEATURE_EJECT_SCSI=y +CONFIG_FBSPLASH=y +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +# CONFIG_INOTIFYD is not set +CONFIG_LAST=y +# CONFIG_FEATURE_LAST_SMALL is not set +CONFIG_FEATURE_LAST_FANCY=y +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +CONFIG_MICROCOM=y +CONFIG_MOUNTPOINT=y +CONFIG_MT=y +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +CONFIG_RUNLEVEL=y +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WALL=y +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +# CONFIG_FEATURE_UNIX_LOCAL is not set +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +CONFIG_ARPING=y +CONFIG_BRCTL=y +CONFIG_FEATURE_BRCTL_FANCY=y +CONFIG_FEATURE_BRCTL_SHOW=y +CONFIG_DNSD=y +CONFIG_ETHER_WAKE=y +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +CONFIG_FEATURE_IFCONFIG_SLIP=y +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE is not set +CONFIG_IFPLUGD=y +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +CONFIG_FEATURE_IFUPDOWN_IPV6=y +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_INETD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y +CONFIG_FEATURE_INETD_RPC=y +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +CONFIG_NAMEIF=y +CONFIG_FEATURE_NAMEIF_EXTENDED=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +CONFIG_NSLOOKUP=y +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_PSCAN=y +CONFIG_ROUTE=y +CONFIG_SLATTACH=y +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_TIMEOUT=y +CONFIG_ZCIP=y + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_FREE=y +CONFIG_FUSER=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_NMETER=y +CONFIG_PGREP=y +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +CONFIG_PKILL=y +CONFIG_PS=y +CONFIG_FEATURE_PS_WIDE=y +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_UPTIME=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +CONFIG_ASH=y +CONFIG_ASH_BASH_COMPAT=y +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_ECHO=y +CONFIG_ASH_PRINTF=y +CONFIG_ASH_TEST=y +CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y +CONFIG_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_HELP=y +CONFIG_HUSH_INTERACTIVE=y +CONFIG_HUSH_JOB=y +CONFIG_HUSH_TICK=y +CONFIG_HUSH_IF=y +CONFIG_HUSH_LOOPS=y +CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_CTTYHACK=y + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_SYSLOGD_DUP=y +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +CONFIG_KLOGD=y +CONFIG_LOGGER=y diff --git a/busybox-1_37_0/configs/android2_defconfig b/busybox-1_37_0/configs/android2_defconfig new file mode 100644 index 000000000..d4b8f1616 --- /dev/null +++ b/busybox-1_37_0/configs/android2_defconfig @@ -0,0 +1,981 @@ +# Run "make android2_defconfig", then "make". +# +# Tested with the standalone toolchain from ndk r6: +# android-ndk-r6/build/tools/make-standalone-toolchain.sh --platform=android-8 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +# CONFIG_SHOW_USAGE is not set +# CONFIG_FEATURE_VERBOSE_USAGE is not set +# CONFIG_FEATURE_COMPRESS_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_INSTALL_NO_USR is not set +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_UNICODE_SUPPORT is not set +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=0 +CONFIG_LAST_SUPPORTED_WCHAR=0 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +# CONFIG_FEATURE_RTMINMAX is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=0 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_FEATURE_NON_POSIX_CP is not set +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set +# CONFIG_MONOTONIC_SYSCALL is not set +# CONFIG_IOCTL_HEX2STR_ERROR is not set +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_GUNZIP=y +CONFIG_GZIP=y +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_FEATURE_TAR_TO_COMMAND is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_CUT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +# CONFIG_ENV is not set +# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set +CONFIG_EXPAND=y +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +# CONFIG_EXPR is not set +# CONFIG_EXPR_MATH_SUPPORT_64 is not set +CONFIG_FALSE=y +CONFIG_FOLD=y +# CONFIG_FSYNC is not set +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +# CONFIG_HOSTID is not set +CONFIG_INSTALL=y +# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +# CONFIG_FEATURE_LS_COLOR is not set +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +# CONFIG_TTY is not set +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +CONFIG_UNIQ=y +# CONFIG_USLEEP is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +# CONFIG_WHO is not set +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_PATCH=y +# CONFIG_VI is not set +CONFIG_FEATURE_VI_MAX_LEN=0 +# CONFIG_FEATURE_VI_8BIT is not set +# CONFIG_FEATURE_VI_COLON is not set +# CONFIG_FEATURE_VI_YANKMARK is not set +# CONFIG_FEATURE_VI_SEARCH is not set +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +# CONFIG_FEATURE_VI_USE_SIGNALS is not set +# CONFIG_FEATURE_VI_DOT_CMD is not set +# CONFIG_FEATURE_VI_READONLY is not set +# CONFIG_FEATURE_VI_SETOPTS is not set +# CONFIG_FEATURE_VI_SET is not set +# CONFIG_FEATURE_VI_WIN_RESIZE is not set +# CONFIG_FEATURE_VI_ASK_TERMINAL is not set +# CONFIG_AWK is not set +# CONFIG_FEATURE_AWK_LIBM is not set +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +# CONFIG_ED is not set +# CONFIG_SED is not set +# CONFIG_FEATURE_ALLOW_EXEC is not set + +# +# Finding Utilities +# +# CONFIG_FIND is not set +# CONFIG_FEATURE_FIND_PRINT0 is not set +# CONFIG_FEATURE_FIND_MTIME is not set +# CONFIG_FEATURE_FIND_MMIN is not set +# CONFIG_FEATURE_FIND_PERM is not set +# CONFIG_FEATURE_FIND_TYPE is not set +# CONFIG_FEATURE_FIND_XDEV is not set +# CONFIG_FEATURE_FIND_MAXDEPTH is not set +# CONFIG_FEATURE_FIND_NEWER is not set +# CONFIG_FEATURE_FIND_INUM is not set +# CONFIG_FEATURE_FIND_EXEC is not set +# CONFIG_FEATURE_FIND_USER is not set +# CONFIG_FEATURE_FIND_GROUP is not set +# CONFIG_FEATURE_FIND_NOT is not set +# CONFIG_FEATURE_FIND_DEPTH is not set +# CONFIG_FEATURE_FIND_PAREN is not set +# CONFIG_FEATURE_FIND_SIZE is not set +# CONFIG_FEATURE_FIND_PRUNE is not set +# CONFIG_FEATURE_FIND_DELETE is not set +# CONFIG_FEATURE_FIND_PATH is not set +# CONFIG_FEATURE_FIND_REGEX is not set +# CONFIG_FEATURE_FIND_CONTEXT is not set +# CONFIG_FEATURE_FIND_LINKS is not set +# CONFIG_GREP is not set +# CONFIG_FEATURE_GREP_EGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_FGREP_ALIAS is not set +# CONFIG_FEATURE_GREP_CONTEXT is not set +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +# CONFIG_BOOTCHARTD is not set +# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set +# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_PAM is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLOCKDEV=y +CONFIG_REV=y +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +# CONFIG_HWCLOCK is not set +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +# CONFIG_SWITCH_ROOT is not set +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +# CONFIG_NANDWRITE is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +# CONFIG_CROND is not set +# CONFIG_FEATURE_CROND_D is not set +# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_DIR="" +# CONFIG_CRONTAB is not set +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +CONFIG_INOTIFYD=y +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +# CONFIG_LESS is not set +CONFIG_FEATURE_LESS_MAXLINES=0 +# CONFIG_FEATURE_LESS_BRACKETS is not set +# CONFIG_FEATURE_LESS_FLAGS is not set +# CONFIG_FEATURE_LESS_MARKS is not set +# CONFIG_FEATURE_LESS_REGEXP is not set +# CONFIG_FEATURE_LESS_WINCH is not set +# CONFIG_FEATURE_LESS_DASHCMD is not set +# CONFIG_FEATURE_LESS_LINENUMS is not set +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +# CONFIG_WALL is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +CONFIG_WHOIS=y +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +CONFIG_PSCAN=y +CONFIG_ROUTE=y +# CONFIG_SLATTACH is not set +CONFIG_TCPSVD=y +# CONFIG_TELNET is not set +# CONFIG_FEATURE_TELNET_TTYPE is not set +# CONFIG_FEATURE_TELNET_AUTOLOGIN is not set +# CONFIG_TELNETD is not set +# CONFIG_FEATURE_TELNETD_STANDALONE is not set +# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set +# CONFIG_TFTP is not set +# CONFIG_TFTPD is not set +# CONFIG_FEATURE_TFTP_GET is not set +# CONFIG_FEATURE_TFTP_PUT is not set +# CONFIG_FEATURE_TFTP_BLOCKSIZE is not set +# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +# CONFIG_TFTP_DEBUG is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +# CONFIG_UDPSVD is not set +# CONFIG_VCONFIG is not set +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_PGREP is not set +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +# CONFIG_PKILL is not set +# CONFIG_PS is not set +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +# CONFIG_UPTIME is not set +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_FEATURE_SH_IS_ASH is not set +# CONFIG_FEATURE_SH_IS_HUSH is not set +CONFIG_FEATURE_SH_IS_NONE=y +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +# CONFIG_SH_MATH_SUPPORT is not set +# CONFIG_SH_MATH_SUPPORT_64 is not set +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set + +# +# System Logging Utilities +# +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +CONFIG_KLOGD=y +CONFIG_FEATURE_KLOGD_KLOGCTL=y +# CONFIG_LOGGER is not set diff --git a/busybox-1_37_0/configs/android_502_defconfig b/busybox-1_37_0/configs/android_502_defconfig new file mode 100644 index 000000000..104e70f23 --- /dev/null +++ b/busybox-1_37_0/configs/android_502_defconfig @@ -0,0 +1,1126 @@ +## This config was successfully used to build busybox on +## Samsung SM-T700 tablet +## Android 5.0.2 +## gcc/toolchain from https://termux.com/ +## binutils 2.26.20160125 +## gcc 4.9.3 +## bionic ANDROID_API 21 +## +## Static build did not work (static libraries not installed?): +## # CONFIG_STATIC is not set +## syslog() requires an additional library: +## CONFIG_EXTRA_LDLIBS="log" +## Bionic's botched off_t: +## # CONFIG_LFS is not set +## +## Incompatible password database API: +## # CONFIG_FEATURE_SHADOWPASSWDS is not set +## # CONFIG_USE_BB_PWD_GRP is not set +## # CONFIG_USE_BB_SHADOW is not set +## # CONFIG_ADDUSER is not set +## # CONFIG_ADDGROUP is not set +## # CONFIG_DELUSER is not set +## # CONFIG_DELGROUP is not set +## +## No utmp/wtmp: +## # CONFIG_FEATURE_UTMP is not set +## # CONFIG_FEATURE_WTMP is not set +## # CONFIG_WHO is not set +## # CONFIG_LAST is not set +## # CONFIG_USERS is not set +## # CONFIG_WALL is not set +## +## Assorted header problems: +## # CONFIG_HOSTID is not set +## # CONFIG_FEATURE_SYNC_FANCY is not set - syncfs() +## # CONFIG_LOGNAME is not set - getlogin_r() +## # CONFIG_LOADFONT is not set +## # CONFIG_SETFONT is not set +## # CONFIG_MDEV is not set +## # CONFIG_FSCK_MINIX is not set +## # CONFIG_MKFS_MINIX is not set +## # CONFIG_IPCRM is not set +## # CONFIG_IPCS is not set +## # CONFIG_SWAPONOFF is not set +## # CONFIG_CONSPY is not set +## # CONFIG_NANDWRITE is not set +## # CONFIG_NANDDUMP is not set +## # CONFIG_RFKILL is not set +## # CONFIG_UBIATTACH is not set +## # CONFIG_UBIDETACH is not set +## # CONFIG_UBIMKVOL is not set +## # CONFIG_UBIRMVOL is not set +## # CONFIG_UBIRSVOL is not set +## # CONFIG_UBIUPDATEVOL is not set +## # CONFIG_FEATURE_EJECT_SCSI is not set - scsi headers +## # CONFIG_ARP is not set +## # CONFIG_ARPING is not set +## # CONFIG_ETHER_WAKE is not set +## # CONFIG_IFCONFIG is not set +## # CONFIG_IFENSLAVE is not set +## # CONFIG_NSLOOKUP is not set +## # CONFIG_ROUTE is not set +## # CONFIG_ZCIP is not set +## # CONFIG_HUSH is not set - glob.h +## # CONFIG_KLOGD is not set +## # CONFIG_LOGGER is not set +## # CONFIG_LOGREAD is not set +## # CONFIG_SYSLOGD is not set +##----------------------------------------------- + +# +# Automatically generated make config: don't edit +# Busybox version: 1.25.0.git +# Mon Mar 14 20:43:42 2016 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_INSTALL_NO_USR is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_PAM is not set +CONFIG_FEATURE_USE_SENDFILE=y +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +CONFIG_FEATURE_PIDFILE=y +CONFIG_PID_FILE_PATH="/var/run" +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_SYSROOT="" +CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="log" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_DEBUG_SANITIZE is not set +# CONFIG_UNIT_TEST is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +CONFIG_FEATURE_RTMINMAX=y +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_SHA3_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=255 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +CONFIG_FEATURE_REVERSE_SEARCH=y +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +CONFIG_FEATURE_SKIP_ROOTFS=y +CONFIG_MONOTONIC_SYSCALL=y +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +# CONFIG_FEATURE_SEAMLESS_Z is not set +# CONFIG_AR is not set +# CONFIG_FEATURE_AR_LONG_FILENAMES is not set +# CONFIG_FEATURE_AR_CREATE is not set +# CONFIG_UNCOMPRESS is not set +CONFIG_GUNZIP=y +CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y +CONFIG_BUNZIP2=y +CONFIG_UNLZMA=y +# CONFIG_FEATURE_LZMA_FAST is not set +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_GZIP_FAST=0 +# CONFIG_FEATURE_GZIP_LEVELS is not set +CONFIG_LZOP=y +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM=y +CONFIG_RPM2CPIO=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_FEATURE_DATE_NANO is not set +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_FEATURE_DD_STATUS=y +# CONFIG_HOSTID is not set +CONFIG_ID=y +CONFIG_GROUPS=y +CONFIG_SHUF=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y +CONFIG_FEATURE_STAT_FILESYSTEM=y +CONFIG_SYNC=y +# CONFIG_FEATURE_SYNC_FANCY is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUNCATE=y +CONFIG_UNLINK=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_FEATURE_ENV_LONG_OPTIONS=y +CONFIG_EXPAND=y +CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SHA3SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNAME_OSNAME="GNU/Linux" +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options +# +CONFIG_FEATURE_VERBOSE=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +CONFIG_KBD_MODE=y +# CONFIG_LOADFONT is not set +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=y +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_VI_UNDO=y +CONFIG_FEATURE_VI_UNDO_QUEUE=y +CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_EXEC_PLUS=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y +CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y + +# +# Init Utilities +# +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_FEATURE_INIT_MODIFY_CMDLINE=y +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_LAST_ID=0 +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +CONFIG_CHPASSWD=y +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des" +CONFIG_CRYPTPW=y +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +CONFIG_GETTY=y +CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +CONFIG_LOGIN_SCRIPTS=y +CONFIG_FEATURE_NOLOGIN=y +CONFIG_FEATURE_SECURETTY=y +CONFIG_PASSWD=y +CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +CONFIG_SU=y +CONFIG_FEATURE_SU_SYSLOG=y +CONFIG_FEATURE_SU_CHECKS_SHELLS=y +CONFIG_SULOGIN=y +CONFIG_VLOCK=y + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y +# CONFIG_TUNE2FS is not set + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLKDISCARD=y +CONFIG_BLOCKDEV=y +CONFIG_FATATTR=y +CONFIG_FSTRIM=y +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +CONFIG_MOUNT=y +CONFIG_FEATURE_MOUNT_FAKE=y +CONFIG_FEATURE_MOUNT_VERBOSE=y +# CONFIG_FEATURE_MOUNT_HELPERS is not set +CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_NFS is not set +CONFIG_FEATURE_MOUNT_CIFS=y +CONFIG_FEATURE_MOUNT_FLAGS=y +CONFIG_FEATURE_MOUNT_FSTAB=y +CONFIG_FEATURE_MOUNT_OTHERTAB=y +CONFIG_REV=y +CONFIG_SETARCH=y +CONFIG_UEVENT=y +CONFIG_ACPID=y +CONFIG_FEATURE_ACPID_COMPAT=y +CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +# CONFIG_FSCK_MINIX is not set +CONFIG_MKFS_EXT2=y +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +CONFIG_MKFS_VFAT=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +CONFIG_PIVOT_ROOT=y +CONFIG_RDATE=y +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_DISCARD is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +CONFIG_SWITCH_ROOT=y +CONFIG_UMOUNT=y +CONFIG_FEATURE_UMOUNT_ALL=y + +# +# Common options for mount/umount +# +CONFIG_FEATURE_MOUNT_LOOP=y +CONFIG_FEATURE_MOUNT_LOOP_CREATE=y +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_BCACHE=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_EXFAT=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_F2FS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_NILFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_XFS=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_I2CGET=y +CONFIG_I2CSET=y +CONFIG_I2CDUMP=y +CONFIG_I2CDETECT=y +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_TRUNCATE=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +# CONFIG_NANDWRITE is not set +# CONFIG_NANDDUMP is not set +# CONFIG_RFKILL is not set +CONFIG_SETSERIAL=y +CONFIG_TASKSET=y +CONFIG_FEATURE_TASKSET_FANCY=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_WALL is not set +CONFIG_ADJTIMEX=y +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +CONFIG_EJECT=y +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FBSPLASH=y +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +CONFIG_IONICE=y +# CONFIG_INOTIFYD is not set +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +CONFIG_MICROCOM=y +CONFIG_MOUNTPOINT=y +# CONFIG_MT is not set +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +# CONFIG_RUNLEVEL is not set +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WATCHDOG=y + +# +# Networking Utilities +# +CONFIG_NAMEIF=y +CONFIG_FEATURE_NAMEIF_EXTENDED=y +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +CONFIG_PING6=y +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_TIMEOUT=y +CONFIG_FEATURE_WGET_OPENSSL=y +CONFIG_FEATURE_WGET_SSL_HELPER=y +CONFIG_WHOIS=y +CONFIG_FEATURE_IPV6=y +# CONFIG_FEATURE_UNIX_LOCAL is not set +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +# CONFIG_ARP is not set +# CONFIG_ARPING is not set +CONFIG_BRCTL=y +CONFIG_FEATURE_BRCTL_FANCY=y +CONFIG_FEATURE_BRCTL_SHOW=y +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FEATURE_FTP_AUTHENTICATION=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFENSLAVE is not set +CONFIG_IFPLUGD=y +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +CONFIG_FEATURE_IFUPDOWN_IPV6=y +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_INETD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y +# CONFIG_FEATURE_INETD_RPC is not set +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_ROUTE_DIR="/etc/iproute2" +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_NEIGH=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPNEIGH=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_FEATURE_NTPD_CONF=y +CONFIG_PSCAN=y +# CONFIG_ROUTE is not set +CONFIG_SLATTACH=y +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +CONFIG_TRACEROUTE6=y +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set +CONFIG_UDHCPD=y +CONFIG_DHCPRELAY=y +CONFIG_DUMPLEASES=y +CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY=y +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_LSOF=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +CONFIG_FREE=y +CONFIG_FUSER=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_PGREP=y +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +CONFIG_PKILL=y +CONFIG_PS=y +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +CONFIG_ASH=y +CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_IDLE_TIMEOUT is not set +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_ECHO=y +CONFIG_ASH_PRINTF=y +CONFIG_ASH_TEST=y +CONFIG_ASH_HELP=y +CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_FEATURE_SH_HISTFILESIZE=y + +# +# System Logging Utilities +# +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set +# CONFIG_LOGGER is not set +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_FEATURE_KMSG_SYSLOG is not set diff --git a/busybox-1_37_0/configs/android_defconfig b/busybox-1_37_0/configs/android_defconfig new file mode 100644 index 000000000..92a66048a --- /dev/null +++ b/busybox-1_37_0/configs/android_defconfig @@ -0,0 +1,1013 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.20.0.git +# Sun Nov 6 07:51:38 2011 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +# CONFIG_SHOW_USAGE is not set +# CONFIG_FEATURE_VERBOSE_USAGE is not set +# CONFIG_FEATURE_COMPRESS_USAGE is not set +# CONFIG_FEATURE_INSTALLER is not set +# CONFIG_INSTALL_NO_USR is not set +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_UNICODE_SUPPORT is not set +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=0 +CONFIG_LAST_SUPPORTED_WCHAR=0 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_LONG_OPTS is not set +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +# CONFIG_FEATURE_SUID is not set +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-eabi-" +# +# Removed: +# warning flags: +# -Wno-multichar -W -Wall -Wno-unused -Winit-self -Wpointer-arith +# -Werror=return-type -Werror=non-virtual-dtor -Werror=address +# -Werror=sequence-point -Wstrict-aliasing=2 -Wno-undef -Wno-shadow +# bbox already adds these: +# -ffunction-sections -fomit-frame-pointer +# enabled implicitly by -Os: +# -frerun-cse-after-loop +# should be not needed, or even increases code size: +# -finline-functions -fno-inline-functions-called-once -finline-limit=64 +# -fstack-protector -fno-strict-aliasing -fno-exceptions -funwind-tables +# -fmessage-length=0 (only affects error message format) +# todo: do we need these? - +# -fno-short-enums +# -fgcse-after-reload +# -frename-registers +CONFIG_EXTRA_CFLAGS="-I$A/system/core/include -I$A/bionic/libc/arch-arm/include -I$A/bionic/libc/include -I$A/bionic/libc/kernel/common -I$A/bionic/libc/kernel/arch-arm -I$A/bionic/libm/include -I$A/bionic/libm/include/arch/arm -include $A/system/core/include/arch/linux-arm/AndroidConfig.h -I$A/system/core/include/arch/linux-arm/ -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +# CONFIG_FEATURE_RTMINMAX is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=0 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_FEATURE_NON_POSIX_CP is not set +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set +# CONFIG_MONOTONIC_SYSCALL is not set +# CONFIG_IOCTL_HEX2STR_ERROR is not set +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_GUNZIP=y +CONFIG_GZIP=y +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_FEATURE_TAR_TO_COMMAND is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_CUT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set +CONFIG_EXPAND=y +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_INSTALL=y +# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +# CONFIG_FEATURE_LS_COLOR is not set +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +# CONFIG_TTY is not set +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_PATCH=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +# CONFIG_PAM is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLOCKDEV=y +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +CONFIG_FEATURE_MDEV_RENAME=y +CONFIG_FEATURE_MDEV_RENAME_REGEXP=y +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_REV=y +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +CONFIG_FEATURE_BLKID_TYPE=y +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +CONFIG_SWITCH_ROOT=y +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_XFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +# CONFIG_NANDWRITE is not set +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +CONFIG_INOTIFYD=y +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +# CONFIG_WALL is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +# CONFIG_PING6 is not set +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_USE_SENDFILE=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +CONFIG_PSCAN=y +CONFIG_ROUTE=y +# CONFIG_SLATTACH is not set +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE6 is not set +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +CONFIG_FREE=y +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_PGREP is not set +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +# CONFIG_PKILL is not set +CONFIG_PS=y +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_FEATURE_SH_IS_ASH is not set +# CONFIG_FEATURE_SH_IS_HUSH is not set +CONFIG_FEATURE_SH_IS_NONE=y +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +# CONFIG_SH_MATH_SUPPORT is not set +# CONFIG_SH_MATH_SUPPORT_64 is not set +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set + +# +# System Logging Utilities +# +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +CONFIG_KLOGD=y +CONFIG_FEATURE_KLOGD_KLOGCTL=y +# CONFIG_LOGGER is not set diff --git a/busybox-1_37_0/configs/android_ndk_defconfig b/busybox-1_37_0/configs/android_ndk_defconfig new file mode 100644 index 000000000..425593454 --- /dev/null +++ b/busybox-1_37_0/configs/android_ndk_defconfig @@ -0,0 +1,1042 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.24.0.git +# Fri Sep 18 20:39:29 2015 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +CONFIG_INSTALL_NO_USR=y +# CONFIG_LOCALE_SUPPORT is not set +# CONFIG_UNICODE_SUPPORT is not set +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=0 +CONFIG_LAST_SUPPORTED_WCHAR=0 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_PAM is not set +CONFIG_FEATURE_USE_SENDFILE=y +CONFIG_LONG_OPTS=y +# CONFIG_FEATURE_DEVPTS is not set +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_PIDFILE is not set +CONFIG_PID_FILE_PATH="" +# CONFIG_FEATURE_SUID is not set +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +# CONFIG_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" +CONFIG_SYSROOT="/opt/android-ndk/platforms/android-9/arch-arm" +CONFIG_EXTRA_CFLAGS="-DANDROID -D__ANDROID__ -DSK_RELEASE -nostdlib -march=armv7-a -msoft-float -mfloat-abi=softfp -mfpu=neon -mthumb -mthumb-interwork -fpic -fno-short-enums -fgcse-after-reload -frename-registers -fuse-ld=bfd" +CONFIG_EXTRA_LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined ${SYSROOT}/usr/lib/crtbegin_dynamic.o ${SYSROOT}/usr/lib/crtend_android.o" +CONFIG_EXTRA_LDLIBS="dl m c gcc" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_UNIT_TEST is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +# CONFIG_FEATURE_RTMINMAX is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_SHA3_SMALL=1 +# CONFIG_FEATURE_FAST_TOP is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=0 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +# CONFIG_FEATURE_REVERSE_SEARCH is not set +# CONFIG_FEATURE_TAB_COMPLETION is not set +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_FEATURE_NON_POSIX_CP is not set +CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_FEATURE_SKIP_ROOTFS is not set +# CONFIG_MONOTONIC_SYSCALL is not set +# CONFIG_IOCTL_HEX2STR_ERROR is not set +# CONFIG_FEATURE_HWIB is not set + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_UNCOMPRESS=y +CONFIG_GUNZIP=y +CONFIG_BUNZIP2=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_DPKG=y +CONFIG_DPKG_DEB=y +CONFIG_GZIP=y +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 +# CONFIG_FEATURE_GZIP_LEVELS is not set +CONFIG_LZOP=y +CONFIG_LZOP_COMPR_HIGH=y +CONFIG_RPM=y +CONFIG_RPM2CPIO=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +# CONFIG_FEATURE_TAR_LONG_OPTIONS is not set +# CONFIG_FEATURE_TAR_TO_COMMAND is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_FEATURE_DD_STATUS=y +# CONFIG_HOSTID is not set +# CONFIG_ID is not set +# CONFIG_GROUPS is not set +CONFIG_SHUF=y +CONFIG_SYNC=y +# CONFIG_FEATURE_SYNC_FANCY is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUNCATE=y +CONFIG_UNLINK=y +CONFIG_BASE64=y +# CONFIG_WHO is not set +# CONFIG_USERS is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +# CONFIG_FEATURE_CP_LONG_OPTIONS is not set +CONFIG_CUT=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +# CONFIG_FEATURE_ENV_LONG_OPTIONS is not set +CONFIG_EXPAND=y +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_INSTALL=y +# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +CONFIG_LN=y +# CONFIG_LOGNAME is not set +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +# CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MV=y +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SHA3SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TRUE=y +# CONFIG_TTY is not set +CONFIG_UNAME=y +CONFIG_UNAME_OSNAME="GNU/Linux" +CONFIG_UNEXPAND=y +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options +# +CONFIG_FEATURE_VERBOSE=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +CONFIG_CHVT=y +CONFIG_FGCONSOLE=y +CONFIG_CLEAR=y +CONFIG_DEALLOCVT=y +CONFIG_DUMPKMAP=y +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +CONFIG_LOADKMAP=y +CONFIG_OPENVT=y +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +CONFIG_SETCONSOLE=y +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +CONFIG_SETKEYCODES=y +CONFIG_SETLOGCONS=y +CONFIG_SHOWKEY=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y +CONFIG_CMP=y +CONFIG_DIFF=y +# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_VI_UNDO=y +CONFIG_FEATURE_VI_UNDO_QUEUE=y +CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_EXEC_PLUS=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y +CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y + +# +# Init Utilities +# +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_HALT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_INIT_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_LINUXRC=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_FEATURE_SHADOWPASSWDS is not set +# CONFIG_USE_BB_PWD_GRP is not set +# CONFIG_USE_BB_SHADOW is not set +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_LAST_ID=0 +CONFIG_FIRST_SYSTEM_ID=0 +CONFIG_LAST_SYSTEM_ID=0 +# CONFIG_ADDGROUP is not set +# CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS is not set +# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set +# CONFIG_DELUSER is not set +# CONFIG_DELGROUP is not set +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="" +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y + +# +# Linux Module Utilities +# +CONFIG_MODINFO=y +CONFIG_MODPROBE_SMALL=y +CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y +CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +CONFIG_DEFAULT_MODULES_DIR="/system/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" + +# +# Linux System Utilities +# +CONFIG_BLOCKDEV=y +CONFIG_FATATTR=y +CONFIG_FSTRIM=y +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_FEATURE_MOUNT_OTHERTAB is not set +CONFIG_REV=y +CONFIG_UEVENT=y +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKID=y +CONFIG_FEATURE_BLKID_TYPE=y +CONFIG_DMESG=y +CONFIG_FEATURE_DMESG_PRETTY=y +CONFIG_FBSET=y +CONFIG_FEATURE_FBSET_FANCY=y +CONFIG_FEATURE_FBSET_READMODE=y +CONFIG_FDFLUSH=y +CONFIG_FDFORMAT=y +CONFIG_FDISK=y +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +CONFIG_FEATURE_FDISK_WRITABLE=y +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +CONFIG_FEATURE_FDISK_ADVANCED=y +CONFIG_FINDFS=y +CONFIG_FLOCK=y +CONFIG_FREERAMDISK=y +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_FEATURE_HEXDUMP_REVERSE=y +CONFIG_HD=y +CONFIG_HWCLOCK=y +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +CONFIG_LOSETUP=y +CONFIG_LSPCI=y +CONFIG_LSUSB=y +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_DISCARD is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +CONFIG_SWITCH_ROOT=y +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_BTRFS=y +CONFIG_FEATURE_VOLUMEID_CRAMFS=y +CONFIG_FEATURE_VOLUMEID_EXFAT=y +CONFIG_FEATURE_VOLUMEID_EXT=y +CONFIG_FEATURE_VOLUMEID_F2FS=y +CONFIG_FEATURE_VOLUMEID_FAT=y +CONFIG_FEATURE_VOLUMEID_HFS=y +CONFIG_FEATURE_VOLUMEID_ISO9660=y +CONFIG_FEATURE_VOLUMEID_JFS=y +CONFIG_FEATURE_VOLUMEID_LINUXRAID=y +CONFIG_FEATURE_VOLUMEID_LINUXSWAP=y +CONFIG_FEATURE_VOLUMEID_LUKS=y +CONFIG_FEATURE_VOLUMEID_NILFS=y +CONFIG_FEATURE_VOLUMEID_NTFS=y +CONFIG_FEATURE_VOLUMEID_OCFS2=y +CONFIG_FEATURE_VOLUMEID_REISERFS=y +CONFIG_FEATURE_VOLUMEID_ROMFS=y +CONFIG_FEATURE_VOLUMEID_SQUASHFS=y +CONFIG_FEATURE_VOLUMEID_SYSV=y +CONFIG_FEATURE_VOLUMEID_UDF=y +CONFIG_FEATURE_VOLUMEID_XFS=y + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_I2CGET=y +CONFIG_I2CSET=y +CONFIG_I2CDUMP=y +CONFIG_I2CDETECT=y +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_TRUNCATE=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +# CONFIG_NANDWRITE is not set +CONFIG_NANDDUMP=y +# CONFIG_RFKILL is not set +CONFIG_SETSERIAL=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +# CONFIG_WALL is not set +# CONFIG_ADJTIMEX is not set +CONFIG_BBCONFIG=y +CONFIG_FEATURE_COMPRESS_BBCONFIG=y +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +CONFIG_CHRT=y +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FBSPLASH=y +CONFIG_FLASHCP=y +CONFIG_FLASH_LOCK=y +CONFIG_FLASH_UNLOCK=y +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +CONFIG_INOTIFYD=y +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_HDPARM=y +CONFIG_FEATURE_HDPARM_GET_IDENTITY=y +CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET=y +CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF=y +CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA=y +CONFIG_MAKEDEVS=y +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +CONFIG_FEATURE_MAKEDEVS_TABLE=y +CONFIG_MAN=y +# CONFIG_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +CONFIG_RAIDAUTORUN=y +# CONFIG_READAHEAD is not set +# CONFIG_RUNLEVEL is not set +CONFIG_RX=y +CONFIG_SETSID=y +CONFIG_STRINGS=y +CONFIG_TIME=y +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +CONFIG_PING=y +# CONFIG_PING6 is not set +CONFIG_FEATURE_FANCY_PING=y +CONFIG_WHOIS=y +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +CONFIG_ARP=y +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FEATURE_FTP_AUTHENTICATION=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set +# CONFIG_HOSTNAME is not set +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +# CONFIG_FEATURE_HTTPD_AUTH_MD5 is not set +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_IFCONFIG=y +CONFIG_FEATURE_IFCONFIG_STATUS=y +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ=y +CONFIG_FEATURE_IFCONFIG_HW=y +CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS=y +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +CONFIG_IFUPDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" +CONFIG_FEATURE_IFUPDOWN_IP=y +CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN=y +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +CONFIG_FEATURE_IFUPDOWN_MAPPING=y +CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP=y +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +CONFIG_IP=y +CONFIG_FEATURE_IP_ADDRESS=y +CONFIG_FEATURE_IP_LINK=y +CONFIG_FEATURE_IP_ROUTE=y +CONFIG_FEATURE_IP_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPADDR=y +CONFIG_IPLINK=y +CONFIG_IPROUTE=y +CONFIG_IPTUNNEL=y +CONFIG_IPRULE=y +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +# CONFIG_FEATURE_IPCALC_LONG_OPTIONS is not set +CONFIG_NETSTAT=y +CONFIG_FEATURE_NETSTAT_WIDE=y +CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +# CONFIG_FEATURE_NTPD_CONF is not set +CONFIG_PSCAN=y +CONFIG_ROUTE=y +# CONFIG_SLATTACH is not set +CONFIG_TCPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TRACEROUTE=y +# CONFIG_TRACEROUTE6 is not set +CONFIG_FEATURE_TRACEROUTE_VERBOSE=y +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +CONFIG_DHCPD_LEASES_FILE="" +CONFIG_UDHCPC=y +CONFIG_FEATURE_UDHCPC_ARPING=y +CONFIG_FEATURE_UDHCPC_SANITIZEOPT=y +CONFIG_FEATURE_UDHCP_PORT=y +CONFIG_UDHCP_DEBUG=9 +CONFIG_FEATURE_UDHCP_RFC3397=y +CONFIG_FEATURE_UDHCP_8021Q=y +CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" +CONFIG_UDPSVD=y +CONFIG_VCONFIG=y +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_MAKEMIME=y +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_LSOF=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +CONFIG_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +CONFIG_FREE=y +CONFIG_FUSER=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set +# CONFIG_KILLALL5 is not set +# CONFIG_PGREP is not set +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +# CONFIG_PKILL is not set +CONFIG_PS=y +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +CONFIG_FEATURE_PS_TIME=y +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +CONFIG_FEATURE_SHOW_THREADS=y +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVLOGD=y +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +# CONFIG_ASH is not set +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_HELP is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +CONFIG_CTTYHACK=y +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_FEATURE_SH_IS_ASH is not set +# CONFIG_FEATURE_SH_IS_HUSH is not set +CONFIG_FEATURE_SH_IS_NONE=y +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +# CONFIG_SH_MATH_SUPPORT is not set +# CONFIG_SH_MATH_SUPPORT_64 is not set +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +# CONFIG_FEATURE_SH_HISTFILESIZE is not set + +# +# System Logging Utilities +# +# CONFIG_SYSLOGD is not set +# CONFIG_FEATURE_ROTATE_LOGFILE is not set +# CONFIG_FEATURE_REMOTE_LOG is not set +# CONFIG_FEATURE_SYSLOGD_DUP is not set +# CONFIG_FEATURE_SYSLOGD_CFG is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=0 +# CONFIG_FEATURE_IPC_SYSLOG is not set +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=0 +# CONFIG_LOGREAD is not set +# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set +# CONFIG_FEATURE_KMSG_SYSLOG is not set +CONFIG_KLOGD=y +CONFIG_FEATURE_KLOGD_KLOGCTL=y +# CONFIG_LOGGER is not set diff --git a/busybox-1_37_0/configs/cygwin_defconfig b/busybox-1_37_0/configs/cygwin_defconfig new file mode 100644 index 000000000..61e2c2463 --- /dev/null +++ b/busybox-1_37_0/configs/cygwin_defconfig @@ -0,0 +1,1222 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.37.0.git +# Mon Oct 9 11:08:46 2023 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Settings +# +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_FEDORA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +CONFIG_LONG_OPTS=y +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_LFS=y +CONFIG_TIME64=y +# CONFIG_PAM is not set +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_UTMP is not set +# CONFIG_FEATURE_WTMP is not set +CONFIG_FEATURE_PIDFILE=y +CONFIG_PID_FILE_PATH="/var/run" +CONFIG_BUSYBOX=y +CONFIG_FEATURE_SHOW_SCRIPT=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_INSTALL_NO_USR is not set +CONFIG_FEATURE_SUID=y +# CONFIG_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_CLEAN_UP is not set +CONFIG_FEATURE_SYSLOG_INFO=y +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_LIBBUSYBOX_STATIC is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_SYSROOT="" +CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" +# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_STACK_OPTIMIZATION_386=y +CONFIG_STATIC_LIBGCC=y + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_DEBUG_SANITIZE is not set +# CONFIG_UNIT_TEST is not set +# CONFIG_WERROR is not set +# CONFIG_WARN_SIMPLE_MSG is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Library Tuning +# +# CONFIG_FEATURE_USE_BSS_TAIL is not set +CONFIG_FLOAT_DURATION=y +CONFIG_FEATURE_RTMINMAX=y +CONFIG_FEATURE_RTMINMAX_USE_LIBC_DEFINITIONS=y +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_SHA1_SMALL=3 +CONFIG_SHA1_HWACCEL=y +CONFIG_SHA256_HWACCEL=y +CONFIG_SHA3_SMALL=1 +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_USE_SENDFILE=y +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_MONOTONIC_SYSCALL is not set +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=255 +CONFIG_FEATURE_EDITING_SAVEHISTORY=y +# CONFIG_FEATURE_EDITING_SAVE_ON_EXIT is not set +CONFIG_FEATURE_REVERSE_SEARCH=y +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +CONFIG_FEATURE_EDITING_FANCY_PROMPT=y +CONFIG_FEATURE_EDITING_WINCH=y +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +# CONFIG_LOCALE_SUPPORT is not set +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=65533 +CONFIG_LAST_SUPPORTED_WCHAR=0 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +# CONFIG_LOOP_CONFIGURE is not set +# CONFIG_NO_LOOP_CONFIGURE is not set +CONFIG_TRY_LOOP_CONFIGURE=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +# CONFIG_FEATURE_SEAMLESS_Z is not set +# CONFIG_AR is not set +# CONFIG_FEATURE_AR_LONG_FILENAMES is not set +# CONFIG_FEATURE_AR_CREATE is not set +# CONFIG_UNCOMPRESS is not set +CONFIG_GUNZIP=y +CONFIG_ZCAT=y +CONFIG_FEATURE_GUNZIP_LONG_OPTIONS=y +CONFIG_BUNZIP2=y +CONFIG_BZCAT=y +CONFIG_UNLZMA=y +CONFIG_LZCAT=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZCAT=y +CONFIG_XZ=y +CONFIG_BZIP2=y +CONFIG_BZIP2_SMALL=8 +CONFIG_FEATURE_BZIP2_DECOMPRESS=y +CONFIG_CPIO=y +CONFIG_FEATURE_CPIO_O=y +CONFIG_FEATURE_CPIO_P=y +CONFIG_FEATURE_CPIO_IGNORE_DEVNO=y +CONFIG_FEATURE_CPIO_RENUMBER_INODES=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_GZIP_FAST=0 +# CONFIG_FEATURE_GZIP_LEVELS is not set +CONFIG_FEATURE_GZIP_DECOMPRESS=y +CONFIG_LZOP=y +# CONFIG_UNLZOP is not set +# CONFIG_LZOPCAT is not set +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM=y +CONFIG_RPM2CPIO=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +CONFIG_FEATURE_TAR_UNAME_GNAME=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNZIP=y +CONFIG_FEATURE_UNZIP_CDF=y +CONFIG_FEATURE_UNZIP_BZIP2=y +CONFIG_FEATURE_UNZIP_LZMA=y +CONFIG_FEATURE_UNZIP_XZ=y +CONFIG_FEATURE_LZMA_FAST=y + +# +# Coreutils +# +CONFIG_FEATURE_VERBOSE=y + +# +# Common options for date and touch +# +CONFIG_FEATURE_TIMEZONE=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y +CONFIG_BASENAME=y +CONFIG_CAT=y +CONFIG_FEATURE_CATN=y +CONFIG_FEATURE_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_CRC32=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_FEATURE_CP_REFLINK=y +CONFIG_CUT=y +CONFIG_FEATURE_CUT_REGEX=y +CONFIG_DATE=y +CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_FEATURE_DATE_NANO is not set +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +CONFIG_FEATURE_DD_STATUS=y +CONFIG_DF=y +CONFIG_FEATURE_DF_FANCY=y +CONFIG_FEATURE_SKIP_ROOTFS=y +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +# CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K is not set +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_EXPAND=y +CONFIG_UNEXPAND=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FACTOR=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_GROUPS=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LINK=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_WIDTH=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SHA3SUM=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y +CONFIG_MKDIR=y +CONFIG_MKFIFO=y +CONFIG_MKNOD=y +CONFIG_MKTEMP=y +CONFIG_MV=y +CONFIG_NICE=y +CONFIG_NL=y +CONFIG_NOHUP=y +CONFIG_NPROC=y +CONFIG_OD=y +CONFIG_PASTE=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +CONFIG_SEQ=y +CONFIG_SHRED=y +CONFIG_SHUF=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +# CONFIG_FEATURE_SORT_OPTIMIZE_MEMORY is not set +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +# CONFIG_FEATURE_STAT_FILESYSTEM is not set +CONFIG_STTY=y +CONFIG_SUM=y +CONFIG_SYNC=y +CONFIG_FEATURE_SYNC_FANCY=y +CONFIG_FSYNC=y +CONFIG_TAC=y +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TEST=y +CONFIG_TEST1=y +CONFIG_TEST2=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TIMEOUT=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_TRUE=y +CONFIG_TRUNCATE=y +CONFIG_TSORT=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNAME_OSNAME="GNU/Linux" +CONFIG_BB_ARCH=y +CONFIG_UNIQ=y +CONFIG_UNLINK=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_BASE32=y +CONFIG_BASE64=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +# CONFIG_WHO is not set +# CONFIG_W is not set +# CONFIG_USERS is not set +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +CONFIG_CLEAR=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_FGCONSOLE is not set +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +# CONFIG_SETCONSOLE is not set +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETKEYCODES is not set +# CONFIG_SETLOGCONS is not set +# CONFIG_SHOWKEY is not set + +# +# Debian Utilities +# +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +CONFIG_START_STOP_DAEMON=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_WHICH=y + +# +# klibc-utils +# +# CONFIG_MINIPS is not set +# CONFIG_NUKE is not set +CONFIG_RESUME=y +CONFIG_RUN_INIT=y + +# +# Editors +# +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_FEATURE_AWK_GNU_EXTENSIONS=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_PATCH=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=4096 +# CONFIG_FEATURE_VI_8BIT is not set +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_COLON_EXPAND=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +# CONFIG_FEATURE_VI_REGEX_SEARCH is not set +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_VI_UNDO=y +CONFIG_FEATURE_VI_UNDO_QUEUE=y +CONFIG_FEATURE_VI_UNDO_QUEUE_MAX=256 +CONFIG_FEATURE_VI_VERBOSE_STATUS=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_ATIME=y +CONFIG_FEATURE_FIND_CTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_AMIN=y +CONFIG_FEATURE_FIND_CMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_EXECUTABLE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_SAMEFILE=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_EXEC_PLUS=y +CONFIG_FEATURE_FIND_EXEC_OK=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_QUIT=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_EMPTY=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_EGREP=y +CONFIG_FGREP=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y +CONFIG_FEATURE_XARGS_SUPPORT_REPL_STR=y +CONFIG_FEATURE_XARGS_SUPPORT_PARALLEL=y +CONFIG_FEATURE_XARGS_SUPPORT_ARGS_FILE=y + +# +# Init Utilities +# +# CONFIG_BOOTCHARTD is not set +# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set +# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set +# CONFIG_HALT is not set +CONFIG_POWEROFF=y +CONFIG_REBOOT=y +CONFIG_FEATURE_WAIT_FOR_INIT=y +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +# CONFIG_INIT is not set +# CONFIG_LINUXRC is not set +# CONFIG_FEATURE_USE_INITTAB is not set +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +# CONFIG_FEATURE_INIT_SCTTY is not set +# CONFIG_FEATURE_INIT_SYSLOG is not set +# CONFIG_FEATURE_INIT_QUIET is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +CONFIG_INIT_TERMINAL_TYPE="" +# CONFIG_FEATURE_INIT_MODIFY_CMDLINE is not set + +# +# Login/Password Management Utilities +# +CONFIG_FEATURE_SHADOWPASSWDS=y +CONFIG_USE_BB_PWD_GRP=y +CONFIG_USE_BB_SHADOW=y +CONFIG_USE_BB_CRYPT=y +CONFIG_USE_BB_CRYPT_SHA=y +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +CONFIG_ADDUSER=y +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_LAST_ID=60000 +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_CHPASSWD=y +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des" +CONFIG_CRYPTPW=y +CONFIG_MKPASSWD=y +CONFIG_DELUSER=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +# CONFIG_GETTY is not set +CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set +CONFIG_LOGIN_SCRIPTS=y +CONFIG_FEATURE_NOLOGIN=y +CONFIG_FEATURE_SECURETTY=y +CONFIG_PASSWD=y +CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +CONFIG_SU=y +CONFIG_FEATURE_SU_SYSLOG=y +CONFIG_FEATURE_SU_CHECKS_SHELLS=y +# CONFIG_FEATURE_SU_BLANK_PW_NEEDS_SECURE_TTY is not set +CONFIG_SULOGIN=y +CONFIG_VLOCK=y + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +# CONFIG_LSATTR is not set +# CONFIG_TUNE2FS is not set + +# +# Linux Module Utilities +# +# CONFIG_MODPROBE_SMALL is not set +# CONFIG_DEPMOD is not set +# CONFIG_INSMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODINFO is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_RMMOD is not set + +# +# Options common to multiple modutils +# +# CONFIG_FEATURE_CMDLINE_MODULE_OPTIONS is not set +# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" + +# +# Linux System Utilities +# +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +CONFIG_BLKDISCARD=y +# CONFIG_BLKID is not set +# CONFIG_FEATURE_BLKID_TYPE is not set +# CONFIG_BLOCKDEV is not set +CONFIG_CAL=y +CONFIG_CHRT=y +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +CONFIG_FALLOCATE=y +CONFIG_FATATTR=y +# CONFIG_FBSET is not set +# CONFIG_FEATURE_FBSET_FANCY is not set +# CONFIG_FEATURE_FBSET_READMODE is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set +# CONFIG_FEATURE_FDISK_WRITABLE is not set +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +# CONFIG_FEATURE_FDISK_ADVANCED is not set +# CONFIG_FINDFS is not set +CONFIG_FLOCK=y +# CONFIG_FDFLUSH is not set +# CONFIG_FREERAMDISK is not set +CONFIG_FSCK_MINIX=y +CONFIG_FSFREEZE=y +CONFIG_FSTRIM=y +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +CONFIG_HD=y +CONFIG_XXD=y +# CONFIG_HWCLOCK is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IONICE is not set +CONFIG_IPCRM=y +# CONFIG_IPCS is not set +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_FANCY is not set +# CONFIG_LOSETUP is not set +# CONFIG_LSPCI is not set +# CONFIG_LSUSB is not set +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +# CONFIG_FEATURE_MDEV_DAEMON is not set +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y +CONFIG_MKE2FS=y +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +CONFIG_FEATURE_MINIX2=y +# CONFIG_MKFS_REISER is not set +CONFIG_MKDOSFS=y +# CONFIG_MKFS_VFAT is not set +CONFIG_MKSWAP=y +CONFIG_FEATURE_MKSWAP_UUID=y +CONFIG_MORE=y +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_FEATURE_MOUNT_OTHERTAB is not set +# CONFIG_MOUNTPOINT is not set +CONFIG_NOLOGIN=y +# CONFIG_NOLOGIN_DEPENDENCIES is not set +CONFIG_NSENTER=y +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +CONFIG_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RENICE=y +CONFIG_REV=y +# CONFIG_RTCWAKE is not set +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +CONFIG_LINUX32=y +CONFIG_LINUX64=y +CONFIG_SETPRIV=y +CONFIG_FEATURE_SETPRIV_DUMP=y +CONFIG_FEATURE_SETPRIV_CAPABILITIES=y +CONFIG_FEATURE_SETPRIV_CAPABILITY_NAMES=y +CONFIG_SETSID=y +CONFIG_SWAPON=y +CONFIG_FEATURE_SWAPON_DISCARD=y +# CONFIG_FEATURE_SWAPON_PRI is not set +CONFIG_SWAPOFF=y +CONFIG_FEATURE_SWAPONOFF_LABEL=y +# CONFIG_SWITCH_ROOT is not set +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +# CONFIG_FEATURE_TASKSET_CPULIST is not set +CONFIG_UEVENT=y +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +CONFIG_UNSHARE=y +# CONFIG_WALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_VOLUMEID=y + +# +# Filesystem/Volume identification +# +CONFIG_FEATURE_VOLUMEID_BCACHE=y +# CONFIG_FEATURE_VOLUMEID_BTRFS is not set +# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set +CONFIG_FEATURE_VOLUMEID_EROFS=y +CONFIG_FEATURE_VOLUMEID_EXFAT=y +# CONFIG_FEATURE_VOLUMEID_EXT is not set +CONFIG_FEATURE_VOLUMEID_F2FS=y +# CONFIG_FEATURE_VOLUMEID_FAT is not set +# CONFIG_FEATURE_VOLUMEID_HFS is not set +# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set +# CONFIG_FEATURE_VOLUMEID_JFS is not set +# CONFIG_FEATURE_VOLUMEID_LFS is not set +# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set +# CONFIG_FEATURE_VOLUMEID_LUKS is not set +CONFIG_FEATURE_VOLUMEID_MINIX=y +CONFIG_FEATURE_VOLUMEID_NILFS=y +# CONFIG_FEATURE_VOLUMEID_NTFS is not set +# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set +# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +# CONFIG_FEATURE_VOLUMEID_ROMFS is not set +# CONFIG_FEATURE_VOLUMEID_SQUASHFS is not set +# CONFIG_FEATURE_VOLUMEID_SYSV is not set +CONFIG_FEATURE_VOLUMEID_UBIFS=y +# CONFIG_FEATURE_VOLUMEID_UDF is not set +# CONFIG_FEATURE_VOLUMEID_XFS is not set + +# +# Miscellaneous Utilities +# +# CONFIG_ADJTIMEX is not set +CONFIG_ASCII=y +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BC=y +CONFIG_DC=y +CONFIG_FEATURE_DC_BIG=y +# CONFIG_FEATURE_DC_LIBM is not set +CONFIG_FEATURE_BC_INTERACTIVE=y +CONFIG_FEATURE_BC_LONG_OPTIONS=y +# CONFIG_BEEP is not set +CONFIG_FEATURE_BEEP_FREQ=0 +CONFIG_FEATURE_BEEP_LENGTH_MS=0 +CONFIG_CHAT=y +CONFIG_FEATURE_CHAT_NOFAIL=y +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +CONFIG_FEATURE_CHAT_IMPLICIT_CR=y +CONFIG_FEATURE_CHAT_SWALLOW_OPTS=y +CONFIG_FEATURE_CHAT_SEND_ESCAPES=y +CONFIG_FEATURE_CHAT_VAR_ABORT_LEN=y +CONFIG_FEATURE_CHAT_CLR_ABORT=y +# CONFIG_CONSPY is not set +CONFIG_CROND=y +CONFIG_FEATURE_CROND_D=y +CONFIG_FEATURE_CROND_CALL_SENDMAIL=y +CONFIG_FEATURE_CROND_SPECIAL_TIMES=y +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +CONFIG_DEVMEM=y +# CONFIG_FBSPLASH is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASHCP is not set +CONFIG_GETFATTR=y +# CONFIG_HDPARM is not set +# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set +# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set +# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set +CONFIG_HEXEDIT=y +CONFIG_I2CGET=y +CONFIG_I2CSET=y +CONFIG_I2CDUMP=y +CONFIG_I2CDETECT=y +CONFIG_I2CTRANSFER=y +# CONFIG_INOTIFYD is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_TRUNCATE=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +CONFIG_FEATURE_LESS_WINCH=y +CONFIG_FEATURE_LESS_ASK_TERMINAL=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=y +CONFIG_FEATURE_LESS_RAW=y +CONFIG_FEATURE_LESS_ENV=y +CONFIG_LSSCSI=y +# CONFIG_MAKEDEVS is not set +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +# CONFIG_FEATURE_MAKEDEVS_TABLE is not set +CONFIG_MAN=y +# CONFIG_MICROCOM is not set +CONFIG_MIM=y +CONFIG_MT=y +# CONFIG_NANDWRITE is not set +# CONFIG_NANDDUMP is not set +CONFIG_PARTPROBE=y +# CONFIG_RAIDAUTORUN is not set +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +# CONFIG_RX is not set +CONFIG_SEEDRNG=y +CONFIG_SETFATTR=y +# CONFIG_SETSERIAL is not set +CONFIG_STRINGS=y +CONFIG_TIME=y +CONFIG_TREE=y +CONFIG_TS=y +CONFIG_TTYSIZE=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_UBIMKVOL is not set +# CONFIG_UBIRMVOL is not set +# CONFIG_UBIRSVOL is not set +# CONFIG_UBIUPDATEVOL is not set +CONFIG_UBIRENAME=y +CONFIG_VOLNAME=y +# CONFIG_WATCHDOG is not set +# CONFIG_FEATURE_WATCHDOG_OPEN_TWICE is not set + +# +# Networking Utilities +# +CONFIG_FEATURE_IPV6=y +# CONFIG_FEATURE_UNIX_LOCAL is not set +CONFIG_FEATURE_PREFER_IPV4_ADDRESS=y +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +# CONFIG_FEATURE_ETC_NETWORKS is not set +# CONFIG_FEATURE_ETC_SERVICES is not set +CONFIG_FEATURE_HWIB=y +# CONFIG_FEATURE_TLS_SHA1 is not set +# CONFIG_ARP is not set +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FTPD=y +CONFIG_FEATURE_FTPD_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FEATURE_FTPD_AUTHENTICATION=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_DNSDOMAINNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_PORT_DEFAULT=80 +CONFIG_FEATURE_HTTPD_RANGES=y +CONFIG_FEATURE_HTTPD_SETUID=y +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +CONFIG_FEATURE_HTTPD_ETAG=y +CONFIG_FEATURE_HTTPD_LAST_MODIFIED=y +CONFIG_FEATURE_HTTPD_DATE=y +CONFIG_FEATURE_HTTPD_ACL_IP=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +CONFIG_IFUP=y +CONFIG_IFDOWN=y +CONFIG_IFUPDOWN_IFSTATE_PATH="" +# CONFIG_FEATURE_IFUPDOWN_IP is not set +# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +CONFIG_INETD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME=y +CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN=y +# CONFIG_FEATURE_INETD_RPC is not set +# CONFIG_IP is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_IPRULE is not set +CONFIG_IPNEIGH=y +# CONFIG_FEATURE_IP_ADDRESS is not set +# CONFIG_FEATURE_IP_LINK is not set +# CONFIG_FEATURE_IP_ROUTE is not set +CONFIG_FEATURE_IP_ROUTE_DIR="" +# CONFIG_FEATURE_IP_TUNNEL is not set +# CONFIG_FEATURE_IP_RULE is not set +CONFIG_FEATURE_IP_NEIGH=y +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FAKEIDENTD=y +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +# CONFIG_NBDCLIENT is not set +CONFIG_NC=y +# CONFIG_NETCAT is not set +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y +# CONFIG_NC_110_COMPAT is not set +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set +# CONFIG_FEATURE_NETSTAT_PRG is not set +# CONFIG_NSLOOKUP is not set +# CONFIG_FEATURE_NSLOOKUP_BIG is not set +# CONFIG_FEATURE_NSLOOKUP_LONG_OPTIONS is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +# CONFIG_FEATURE_NTPD_CONF is not set +# CONFIG_FEATURE_NTP_AUTH is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +CONFIG_PSCAN=y +# CONFIG_ROUTE is not set +# CONFIG_SLATTACH is not set +CONFIG_SSL_CLIENT=y +CONFIG_TC=y +CONFIG_FEATURE_TC_INGRESS=y +CONFIG_TCPSVD=y +CONFIG_UDPSVD=y +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_FEATURE_TELNET_WIDTH=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_PORT_DEFAULT=23 +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +CONFIG_FEATURE_TFTP_HPA_COMPAT=y +CONFIG_TFTPD=y +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +# CONFIG_TFTP_DEBUG is not set +CONFIG_TLS=y +# CONFIG_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +# CONFIG_TUNCTL is not set +# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_VCONFIG is not set +CONFIG_WGET=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_FTP=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_TIMEOUT=y +CONFIG_FEATURE_WGET_HTTPS=y +CONFIG_FEATURE_WGET_OPENSSL=y +CONFIG_WHOIS=y +# CONFIG_ZCIP is not set +# CONFIG_UDHCPD is not set +# CONFIG_FEATURE_UDHCPD_BOOTP is not set +# CONFIG_FEATURE_UDHCPD_BASE_IP_ON_MAC is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" +# CONFIG_DUMPLEASES is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_UDHCPC is not set +# CONFIG_FEATURE_UDHCPC_ARPING is not set +# CONFIG_FEATURE_UDHCPC_SANITIZEOPT is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="" +CONFIG_UDHCPC6_DEFAULT_SCRIPT="/usr/share/udhcpc/default6.script" +CONFIG_UDHCPC6=y +CONFIG_FEATURE_UDHCPC6_RFC3646=y +CONFIG_FEATURE_UDHCPC6_RFC4704=y +CONFIG_FEATURE_UDHCPC6_RFC4833=y +CONFIG_FEATURE_UDHCPC6_RFC5970=y + +# +# Common options for DHCP applets +# +CONFIG_UDHCPC_DEFAULT_INTERFACE="eth0" +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=0 +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 +# CONFIG_FEATURE_UDHCP_RFC3397 is not set +# CONFIG_FEATURE_UDHCP_8021Q is not set +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" + +# +# Print Utilities +# +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +CONFIG_FEATURE_MIME_CHARSET="us-ascii" +CONFIG_MAKEMIME=y +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +CONFIG_SENDMAIL=y + +# +# Process Utilities +# +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_SHOW_THREADS is not set +# CONFIG_FREE is not set +CONFIG_FUSER=y +CONFIG_IOSTAT=y +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +CONFIG_LSOF=y +CONFIG_MPSTAT=y +CONFIG_NMETER=y +CONFIG_PGREP=y +CONFIG_PKILL=y +CONFIG_PIDOF=y +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y +# CONFIG_PMAP is not set +# CONFIG_POWERTOP is not set +# CONFIG_FEATURE_POWERTOP_INTERACTIVE is not set +CONFIG_PS=y +# CONFIG_FEATURE_PS_WIDE is not set +# CONFIG_FEATURE_PS_LONG is not set +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_BB_SYSCTL=y +CONFIG_TOP=y +CONFIG_FEATURE_TOP_INTERACTIVE=y +CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE=y +CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS=y +CONFIG_FEATURE_TOP_SMP_CPU=y +CONFIG_FEATURE_TOP_DECIMALS=y +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y +# CONFIG_UPTIME is not set +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set +CONFIG_WATCH=y + +# +# Runit Utilities +# +CONFIG_CHPST=y +CONFIG_SETUIDGID=y +CONFIG_ENVUIDGID=y +CONFIG_ENVDIR=y +CONFIG_SOFTLIMIT=y +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +CONFIG_SV=y +CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" +CONFIG_SVC=y +CONFIG_SVOK=y +CONFIG_SVLOGD=y +# CONFIG_CHCON is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RUNCON is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SESTATUS is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_RESTORECON is not set +# CONFIG_SETSEBOOL is not set + +# +# Shells +# +CONFIG_SH_IS_ASH=y +# CONFIG_SH_IS_HUSH is not set +# CONFIG_SH_IS_NONE is not set +# CONFIG_BASH_IS_ASH is not set +# CONFIG_BASH_IS_HUSH is not set +CONFIG_BASH_IS_NONE=y +CONFIG_SHELL_ASH=y +CONFIG_ASH=y +CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +CONFIG_ASH_INTERNAL_GLOB=y +CONFIG_ASH_BASH_COMPAT=y +# CONFIG_ASH_BASH_SOURCE_CURDIR is not set +CONFIG_ASH_BASH_NOT_FOUND_HOOK=y +CONFIG_ASH_JOB_CONTROL=y +CONFIG_ASH_ALIAS=y +CONFIG_ASH_RANDOM_SUPPORT=y +CONFIG_ASH_EXPAND_PRMT=y +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_MAIL is not set +CONFIG_ASH_ECHO=y +CONFIG_ASH_PRINTF=y +CONFIG_ASH_TEST=y +CONFIG_ASH_HELP=y +CONFIG_ASH_GETOPTS=y +CONFIG_ASH_CMDCMD=y +# CONFIG_CTTYHACK is not set +CONFIG_HUSH=y +CONFIG_SHELL_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_BRACE_EXPANSION=y +# CONFIG_HUSH_BASH_SOURCE_CURDIR is not set +CONFIG_HUSH_LINENO_VAR=y +CONFIG_HUSH_INTERACTIVE=y +CONFIG_HUSH_SAVEHISTORY=y +CONFIG_HUSH_JOB=y +CONFIG_HUSH_TICK=y +CONFIG_HUSH_IF=y +CONFIG_HUSH_LOOPS=y +CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y +CONFIG_HUSH_LOCAL=y +CONFIG_HUSH_RANDOM_SUPPORT=y +CONFIG_HUSH_MODE_X=y +CONFIG_HUSH_ECHO=y +CONFIG_HUSH_PRINTF=y +CONFIG_HUSH_TEST=y +CONFIG_HUSH_HELP=y +CONFIG_HUSH_EXPORT=y +CONFIG_HUSH_EXPORT_N=y +CONFIG_HUSH_READONLY=y +CONFIG_HUSH_KILL=y +CONFIG_HUSH_WAIT=y +CONFIG_HUSH_COMMAND=y +CONFIG_HUSH_TRAP=y +CONFIG_HUSH_TYPE=y +CONFIG_HUSH_TIMES=y +CONFIG_HUSH_READ=y +CONFIG_HUSH_SET=y +CONFIG_HUSH_UNSET=y +CONFIG_HUSH_ULIMIT=y +CONFIG_HUSH_UMASK=y +CONFIG_HUSH_GETOPTS=y +# CONFIG_HUSH_MEMLEAK is not set + +# +# Options common to all shells +# +CONFIG_FEATURE_SH_MATH=y +CONFIG_FEATURE_SH_MATH_64=y +CONFIG_FEATURE_SH_MATH_BASE=y +CONFIG_FEATURE_SH_EXTRA_QUIET=y +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set +CONFIG_FEATURE_SH_READ_FRAC=y +CONFIG_FEATURE_SH_HISTFILESIZE=y +CONFIG_FEATURE_SH_EMBEDDED_SCRIPTS=y + +# +# System Logging Utilities +# +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set +CONFIG_LOGGER=y +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_SYSLOGD_DUP=y +CONFIG_FEATURE_SYSLOGD_CFG=y +# CONFIG_FEATURE_SYSLOGD_PRECISE_TIMESTAMPS is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_FEATURE_KMSG_SYSLOG=y diff --git a/busybox-1_37_0/configs/freebsd_defconfig b/busybox-1_37_0/configs/freebsd_defconfig new file mode 100644 index 000000000..6cbd54895 --- /dev/null +++ b/busybox-1_37_0/configs/freebsd_defconfig @@ -0,0 +1,958 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.18.1 +# Tue Dec 21 19:47:40 2010 +# +CONFIG_HAVE_DOT_CONFIG=y + +# +# Busybox Settings +# + +# +# General Configuration +# +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set +CONFIG_INCLUDE_SUSv2=y +CONFIG_USE_PORTABLE_CODE=y +CONFIG_FEATURE_BUFFERS_USE_MALLOC=y +# CONFIG_FEATURE_BUFFERS_GO_ON_STACK is not set +# CONFIG_FEATURE_BUFFERS_GO_IN_BSS is not set +CONFIG_SHOW_USAGE=y +CONFIG_FEATURE_VERBOSE_USAGE=y +CONFIG_FEATURE_COMPRESS_USAGE=y +CONFIG_FEATURE_INSTALLER=y +# CONFIG_INSTALL_NO_USR is not set +CONFIG_LOCALE_SUPPORT=y +CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_USING_LOCALE is not set +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set +CONFIG_SUBST_WCHAR=63 +CONFIG_LAST_SUPPORTED_WCHAR=767 +# CONFIG_UNICODE_COMBINING_WCHARS is not set +# CONFIG_UNICODE_WIDE_WCHARS is not set +# CONFIG_UNICODE_BIDI_SUPPORT is not set +# CONFIG_UNICODE_NEUTRAL_TABLE is not set +# CONFIG_UNICODE_PRESERVE_BROKEN is not set +CONFIG_LONG_OPTS=y +CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_CLEAN_UP is not set +# CONFIG_FEATURE_WTMP is not set +# CONFIG_FEATURE_UTMP is not set +CONFIG_FEATURE_PIDFILE=y +CONFIG_FEATURE_SUID=y +CONFIG_FEATURE_SUID_CONFIG=y +CONFIG_FEATURE_SUID_CONFIG_QUIET=y +# CONFIG_SELINUX is not set +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" +CONFIG_FEATURE_SYSLOG=y + +# +# Build Options +# +# CONFIG_STATIC is not set +# CONFIG_PIE is not set +# CONFIG_NOMMU is not set +# CONFIG_BUILD_LIBBUSYBOX is not set +# CONFIG_FEATURE_INDIVIDUAL is not set +# CONFIG_FEATURE_SHARED_BUSYBOX is not set +CONFIG_LFS=y +CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" + +# +# Debugging Options +# +# CONFIG_DEBUG is not set +# CONFIG_DEBUG_PESSIMIZE is not set +# CONFIG_WERROR is not set +CONFIG_NO_DEBUG_LIB=y +# CONFIG_DMALLOC is not set +# CONFIG_EFENCE is not set + +# +# Installation Options ("make install" behavior) +# +CONFIG_INSTALL_APPLET_SYMLINKS=y +# CONFIG_INSTALL_APPLET_HARDLINKS is not set +# CONFIG_INSTALL_APPLET_SCRIPT_WRAPPERS is not set +# CONFIG_INSTALL_APPLET_DONT is not set +# CONFIG_INSTALL_SH_APPLET_SYMLINK is not set +# CONFIG_INSTALL_SH_APPLET_HARDLINK is not set +# CONFIG_INSTALL_SH_APPLET_SCRIPT_WRAPPER is not set +CONFIG_PREFIX="./_install" + +# +# Busybox Library Tuning +# +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_EDITING=y +CONFIG_FEATURE_EDITING_MAX_LEN=1024 +# CONFIG_FEATURE_EDITING_VI is not set +CONFIG_FEATURE_EDITING_HISTORY=30 +# CONFIG_FEATURE_EDITING_SAVEHISTORY is not set +CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_USERNAME_COMPLETION is not set +# CONFIG_FEATURE_EDITING_FANCY_PROMPT is not set +# CONFIG_FEATURE_EDITING_ASK_TERMINAL is not set +CONFIG_FEATURE_NON_POSIX_CP=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set +CONFIG_FEATURE_COPYBUF_KB=4 +# CONFIG_MONOTONIC_SYSCALL is not set +CONFIG_IOCTL_HEX2STR_ERROR=y +CONFIG_FEATURE_HWIB=y + +# +# Applets +# + +# +# Archival Utilities +# +CONFIG_FEATURE_SEAMLESS_XZ=y +CONFIG_FEATURE_SEAMLESS_LZMA=y +CONFIG_FEATURE_SEAMLESS_BZ2=y +CONFIG_FEATURE_SEAMLESS_GZ=y +CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_AR=y +CONFIG_FEATURE_AR_LONG_FILENAMES=y +CONFIG_FEATURE_AR_CREATE=y +CONFIG_BUNZIP2=y +CONFIG_BZIP2=y +CONFIG_CPIO=y +# CONFIG_FEATURE_CPIO_O is not set +# CONFIG_FEATURE_CPIO_P is not set +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set +CONFIG_GUNZIP=y +CONFIG_GZIP=y +CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +CONFIG_LZOP=y +# CONFIG_LZOP_COMPR_HIGH is not set +CONFIG_RPM2CPIO=y +CONFIG_RPM=y +CONFIG_TAR=y +CONFIG_FEATURE_TAR_CREATE=y +CONFIG_FEATURE_TAR_AUTODETECT=y +CONFIG_FEATURE_TAR_FROM=y +CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y +CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y +CONFIG_FEATURE_TAR_LONG_OPTIONS=y +CONFIG_FEATURE_TAR_TO_COMMAND=y +# CONFIG_FEATURE_TAR_UNAME_GNAME is not set +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y + +# +# Coreutils +# +CONFIG_BASENAME=y +CONFIG_CAT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set +# CONFIG_FEATURE_DATE_NANO is not set +# CONFIG_FEATURE_DATE_COMPAT is not set +CONFIG_TEST=y +CONFIG_FEATURE_TEST_64=y +CONFIG_TR=y +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +# CONFIG_BASE64 is not set +CONFIG_CAL=y +CONFIG_CATV=y +CONFIG_CHGRP=y +CONFIG_CHMOD=y +CONFIG_CHOWN=y +CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y +CONFIG_CHROOT=y +CONFIG_CKSUM=y +CONFIG_COMM=y +CONFIG_CP=y +CONFIG_FEATURE_CP_LONG_OPTIONS=y +CONFIG_CUT=y +CONFIG_DD=y +CONFIG_FEATURE_DD_SIGNAL_HANDLING=y +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set +CONFIG_DIRNAME=y +CONFIG_DOS2UNIX=y +CONFIG_UNIX2DOS=y +CONFIG_DU=y +CONFIG_FEATURE_DU_DEFAULT_BLOCKSIZE_1K=y +CONFIG_ECHO=y +CONFIG_FEATURE_FANCY_ECHO=y +CONFIG_ENV=y +CONFIG_FEATURE_ENV_LONG_OPTIONS=y +CONFIG_EXPAND=y +CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +CONFIG_EXPR=y +CONFIG_EXPR_MATH_SUPPORT_64=y +CONFIG_FALSE=y +CONFIG_FOLD=y +CONFIG_FSYNC=y +CONFIG_HEAD=y +CONFIG_FEATURE_FANCY_HEAD=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y +CONFIG_LENGTH=y +CONFIG_LN=y +CONFIG_LOGNAME=y +CONFIG_LS=y +CONFIG_FEATURE_LS_FILETYPES=y +CONFIG_FEATURE_LS_FOLLOWLINKS=y +CONFIG_FEATURE_LS_RECURSIVE=y +CONFIG_FEATURE_LS_SORTFILES=y +CONFIG_FEATURE_LS_TIMESTAMPS=y +CONFIG_FEATURE_LS_USERNAME=y +CONFIG_FEATURE_LS_COLOR=y +CONFIG_FEATURE_LS_COLOR_IS_DEFAULT=y +CONFIG_MD5SUM=y +CONFIG_MKDIR=y +CONFIG_FEATURE_MKDIR_LONG_OPTIONS=y +CONFIG_MKFIFO=y +# CONFIG_MKNOD is not set +CONFIG_MV=y +CONFIG_FEATURE_MV_LONG_OPTIONS=y +CONFIG_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y +CONFIG_PRINTF=y +CONFIG_PWD=y +CONFIG_READLINK=y +CONFIG_FEATURE_READLINK_FOLLOW=y +CONFIG_REALPATH=y +CONFIG_RM=y +CONFIG_RMDIR=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y +CONFIG_SHA256SUM=y +CONFIG_SHA512SUM=y +CONFIG_SLEEP=y +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y +CONFIG_SORT=y +CONFIG_FEATURE_SORT_BIG=y +CONFIG_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +# CONFIG_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set +# CONFIG_STTY is not set +CONFIG_SUM=y +CONFIG_SYNC=y +# CONFIG_TAC is not set +CONFIG_TAIL=y +CONFIG_FEATURE_FANCY_TAIL=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +CONFIG_TOUCH=y +CONFIG_TRUE=y +CONFIG_TTY=y +CONFIG_UNAME=y +CONFIG_UNEXPAND=y +CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +CONFIG_UNIQ=y +CONFIG_USLEEP=y +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y +CONFIG_WC=y +CONFIG_FEATURE_WC_LARGE=y +# CONFIG_WHO is not set +CONFIG_WHOAMI=y +CONFIG_YES=y + +# +# Common options for cp and mv +# +CONFIG_FEATURE_PRESERVE_HARDLINKS=y + +# +# Common options for df, du, ls +# +CONFIG_FEATURE_HUMAN_READABLE=y + +# +# Common options for md5sum, sha1sum, sha256sum, sha512sum +# +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y + +# +# Console Utilities +# +# CONFIG_CHVT is not set +# CONFIG_FGCONSOLE is not set +CONFIG_CLEAR=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set +CONFIG_RESET=y +CONFIG_RESIZE=y +CONFIG_FEATURE_RESIZE_PRINT=y +# CONFIG_SETCONSOLE is not set +# CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +# CONFIG_SETFONT is not set +# CONFIG_FEATURE_SETFONT_TEXTUAL_MAP is not set +CONFIG_DEFAULT_SETFONT_DIR="" +# CONFIG_SETKEYCODES is not set +# CONFIG_SETLOGCONS is not set +# CONFIG_SHOWKEY is not set +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set + +# +# Debian Utilities +# +CONFIG_MKTEMP=y +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y +CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y +CONFIG_FEATURE_RUN_PARTS_FANCY=y +# CONFIG_START_STOP_DAEMON is not set +# CONFIG_FEATURE_START_STOP_DAEMON_FANCY is not set +# CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS is not set +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_PATCH=y +CONFIG_AWK=y +CONFIG_FEATURE_AWK_LIBM=y +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y +CONFIG_VI=y +CONFIG_FEATURE_VI_MAX_LEN=1024 +CONFIG_FEATURE_VI_8BIT=y +CONFIG_FEATURE_VI_COLON=y +CONFIG_FEATURE_VI_YANKMARK=y +CONFIG_FEATURE_VI_SEARCH=y +CONFIG_FEATURE_VI_USE_SIGNALS=y +CONFIG_FEATURE_VI_DOT_CMD=y +CONFIG_FEATURE_VI_READONLY=y +CONFIG_FEATURE_VI_SETOPTS=y +CONFIG_FEATURE_VI_SET=y +CONFIG_FEATURE_VI_WIN_RESIZE=y +CONFIG_FEATURE_VI_ASK_TERMINAL=y +CONFIG_FEATURE_ALLOW_EXEC=y + +# +# Finding Utilities +# +CONFIG_FIND=y +CONFIG_FEATURE_FIND_PRINT0=y +CONFIG_FEATURE_FIND_MTIME=y +CONFIG_FEATURE_FIND_MMIN=y +CONFIG_FEATURE_FIND_PERM=y +CONFIG_FEATURE_FIND_TYPE=y +CONFIG_FEATURE_FIND_XDEV=y +CONFIG_FEATURE_FIND_MAXDEPTH=y +CONFIG_FEATURE_FIND_NEWER=y +CONFIG_FEATURE_FIND_INUM=y +CONFIG_FEATURE_FIND_EXEC=y +CONFIG_FEATURE_FIND_USER=y +CONFIG_FEATURE_FIND_GROUP=y +CONFIG_FEATURE_FIND_NOT=y +CONFIG_FEATURE_FIND_DEPTH=y +CONFIG_FEATURE_FIND_PAREN=y +CONFIG_FEATURE_FIND_SIZE=y +CONFIG_FEATURE_FIND_PRUNE=y +CONFIG_FEATURE_FIND_DELETE=y +CONFIG_FEATURE_FIND_PATH=y +CONFIG_FEATURE_FIND_REGEX=y +# CONFIG_FEATURE_FIND_CONTEXT is not set +CONFIG_FEATURE_FIND_LINKS=y +CONFIG_GREP=y +CONFIG_FEATURE_GREP_EGREP_ALIAS=y +CONFIG_FEATURE_GREP_FGREP_ALIAS=y +CONFIG_FEATURE_GREP_CONTEXT=y +CONFIG_XARGS=y +CONFIG_FEATURE_XARGS_SUPPORT_CONFIRMATION=y +CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y +CONFIG_FEATURE_XARGS_SUPPORT_TERMOPT=y +CONFIG_FEATURE_XARGS_SUPPORT_ZERO_TERM=y + +# +# Init Utilities +# +# CONFIG_BOOTCHARTD is not set +# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set +# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set +# CONFIG_HALT is not set +# CONFIG_FEATURE_CALL_TELINIT is not set +CONFIG_TELINIT_PATH="" +# CONFIG_INIT is not set +# CONFIG_FEATURE_USE_INITTAB is not set +# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_FEATURE_KILL_DELAY=0 +# CONFIG_FEATURE_INIT_SCTTY is not set +# CONFIG_FEATURE_INIT_SYSLOG is not set +# CONFIG_FEATURE_INIT_QUIET is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +# CONFIG_LINUXRC is not set +CONFIG_INIT_TERMINAL_TYPE="" +# CONFIG_MESG is not set + +# +# Login/Password Management Utilities +# +# CONFIG_ADD_SHELL is not set +# CONFIG_REMOVE_SHELL is not set +# CONFIG_FEATURE_SHADOWPASSWDS is not set +CONFIG_USE_BB_PWD_GRP=y +# CONFIG_USE_BB_SHADOW is not set +# CONFIG_USE_BB_CRYPT is not set +# CONFIG_USE_BB_CRYPT_SHA is not set +# CONFIG_ADDUSER is not set +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +# CONFIG_FEATURE_CHECK_NAMES is not set +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 +CONFIG_ADDGROUP=y +CONFIG_FEATURE_ADDGROUP_LONG_OPTIONS=y +CONFIG_FEATURE_ADDUSER_TO_GROUP=y +# CONFIG_DELUSER is not set +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +# CONFIG_GETTY is not set +# CONFIG_LOGIN is not set +# CONFIG_PAM is not set +# CONFIG_LOGIN_SCRIPTS is not set +# CONFIG_FEATURE_NOLOGIN is not set +# CONFIG_FEATURE_SECURETTY is not set +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +# CONFIG_CRYPTPW is not set +# CONFIG_CHPASSWD is not set +# CONFIG_SU is not set +# CONFIG_FEATURE_SU_SYSLOG is not set +# CONFIG_FEATURE_SU_CHECKS_SHELLS is not set +# CONFIG_SULOGIN is not set +# CONFIG_VLOCK is not set + +# +# Linux Ext2 FS Progs +# +CONFIG_CHATTR=y +# CONFIG_FSCK is not set +# CONFIG_LSATTR is not set +# CONFIG_TUNE2FS is not set +# CONFIG_MODINFO is not set +# CONFIG_MODPROBE_SMALL is not set +# CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE is not set +# CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED is not set +# CONFIG_INSMOD is not set +# CONFIG_RMMOD is not set +# CONFIG_LSMOD is not set +# CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT is not set +# CONFIG_MODPROBE is not set +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set +# CONFIG_FEATURE_2_4_MODULES is not set +# CONFIG_FEATURE_INSMOD_TRY_MMAP is not set +# CONFIG_FEATURE_INSMOD_VERSION_CHECKING is not set +# CONFIG_FEATURE_INSMOD_KSYMOOPS_SYMBOLS is not set +# CONFIG_FEATURE_INSMOD_LOADINKMEM is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP is not set +# CONFIG_FEATURE_INSMOD_LOAD_MAP_FULL is not set +# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set +# CONFIG_FEATURE_MODUTILS_ALIAS is not set +# CONFIG_FEATURE_MODUTILS_SYMBOLS is not set +CONFIG_DEFAULT_MODULES_DIR="" +CONFIG_DEFAULT_DEPMOD_FILE="" + +# +# Linux System Utilities +# +# CONFIG_BLOCKDEV is not set +CONFIG_REV=y +# CONFIG_ACPID is not set +# CONFIG_FEATURE_ACPID_COMPAT is not set +# CONFIG_BLKID is not set +# CONFIG_DMESG is not set +# CONFIG_FEATURE_DMESG_PRETTY is not set +# CONFIG_FBSET is not set +# CONFIG_FEATURE_FBSET_FANCY is not set +# CONFIG_FEATURE_FBSET_READMODE is not set +# CONFIG_FDFLUSH is not set +# CONFIG_FDFORMAT is not set +# CONFIG_FDISK is not set +CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +# CONFIG_FEATURE_FDISK_WRITABLE is not set +# CONFIG_FEATURE_AIX_LABEL is not set +# CONFIG_FEATURE_SGI_LABEL is not set +# CONFIG_FEATURE_SUN_LABEL is not set +# CONFIG_FEATURE_OSF_LABEL is not set +# CONFIG_FEATURE_GPT_LABEL is not set +# CONFIG_FEATURE_FDISK_ADVANCED is not set +# CONFIG_FINDFS is not set +CONFIG_FLOCK=y +# CONFIG_FREERAMDISK is not set +# CONFIG_FSCK_MINIX is not set +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set +# CONFIG_MKFS_REISER is not set +# CONFIG_MKFS_VFAT is not set +CONFIG_GETOPT=y +CONFIG_FEATURE_GETOPT_LONG=y +CONFIG_HEXDUMP=y +# CONFIG_FEATURE_HEXDUMP_REVERSE is not set +CONFIG_HD=y +# CONFIG_HWCLOCK is not set +# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set +# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set +# CONFIG_IPCRM is not set +# CONFIG_IPCS is not set +# CONFIG_LOSETUP is not set +CONFIG_LSPCI=y +CONFIG_LSUSB=y +# CONFIG_MDEV is not set +# CONFIG_FEATURE_MDEV_CONF is not set +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +# CONFIG_FEATURE_MDEV_EXEC is not set +# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set +# CONFIG_MKSWAP is not set +# CONFIG_FEATURE_MKSWAP_UUID is not set +CONFIG_MORE=y +# CONFIG_MOUNT is not set +# CONFIG_FEATURE_MOUNT_FAKE is not set +# CONFIG_FEATURE_MOUNT_VERBOSE is not set +# CONFIG_FEATURE_MOUNT_HELPERS is not set +# CONFIG_FEATURE_MOUNT_LABEL is not set +# CONFIG_FEATURE_MOUNT_NFS is not set +# CONFIG_FEATURE_MOUNT_CIFS is not set +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set +# CONFIG_RDATE is not set +# CONFIG_RDEV is not set +CONFIG_READPROFILE=y +# CONFIG_RTCWAKE is not set +# CONFIG_SCRIPT is not set +CONFIG_SCRIPTREPLAY=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF is not set +# CONFIG_FEATURE_SWAPON_PRI is not set +# CONFIG_SWITCH_ROOT is not set +# CONFIG_UMOUNT is not set +# CONFIG_FEATURE_UMOUNT_ALL is not set +# CONFIG_FEATURE_MOUNT_LOOP is not set +# CONFIG_FEATURE_MOUNT_LOOP_CREATE is not set +# CONFIG_FEATURE_MTAB_SUPPORT is not set +# CONFIG_VOLUMEID is not set +# CONFIG_FEATURE_VOLUMEID_EXT is not set +# CONFIG_FEATURE_VOLUMEID_BTRFS is not set +# CONFIG_FEATURE_VOLUMEID_REISERFS is not set +# CONFIG_FEATURE_VOLUMEID_FAT is not set +# CONFIG_FEATURE_VOLUMEID_HFS is not set +# CONFIG_FEATURE_VOLUMEID_JFS is not set +# CONFIG_FEATURE_VOLUMEID_XFS is not set +# CONFIG_FEATURE_VOLUMEID_NTFS is not set +# CONFIG_FEATURE_VOLUMEID_ISO9660 is not set +# CONFIG_FEATURE_VOLUMEID_UDF is not set +# CONFIG_FEATURE_VOLUMEID_LUKS is not set +# CONFIG_FEATURE_VOLUMEID_LINUXSWAP is not set +# CONFIG_FEATURE_VOLUMEID_CRAMFS is not set +# CONFIG_FEATURE_VOLUMEID_ROMFS is not set +# CONFIG_FEATURE_VOLUMEID_SYSV is not set +# CONFIG_FEATURE_VOLUMEID_OCFS2 is not set +# CONFIG_FEATURE_VOLUMEID_LINUXRAID is not set + +# +# Miscellaneous Utilities +# +# CONFIG_CONSPY is not set +# CONFIG_NANDWRITE is not set +# CONFIG_NANDDUMP is not set +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set +# CONFIG_ADJTIMEX is not set +# CONFIG_BBCONFIG is not set +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +# CONFIG_BEEP is not set +CONFIG_FEATURE_BEEP_FREQ=0 +CONFIG_FEATURE_BEEP_LENGTH_MS=0 +# CONFIG_CHAT is not set +# CONFIG_FEATURE_CHAT_NOFAIL is not set +# CONFIG_FEATURE_CHAT_TTY_HIFI is not set +# CONFIG_FEATURE_CHAT_IMPLICIT_CR is not set +# CONFIG_FEATURE_CHAT_SWALLOW_OPTS is not set +# CONFIG_FEATURE_CHAT_SEND_ESCAPES is not set +# CONFIG_FEATURE_CHAT_VAR_ABORT_LEN is not set +# CONFIG_FEATURE_CHAT_CLR_ABORT is not set +CONFIG_CHRT=y +# CONFIG_CROND is not set +# CONFIG_FEATURE_CROND_D is not set +# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set +CONFIG_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y +CONFIG_DC=y +CONFIG_FEATURE_DC_LIBM=y +# CONFIG_DEVFSD is not set +# CONFIG_DEVFSD_MODLOAD is not set +# CONFIG_DEVFSD_FG_NP is not set +# CONFIG_DEVFSD_VERBOSE is not set +# CONFIG_FEATURE_DEVFS is not set +# CONFIG_DEVMEM is not set +# CONFIG_EJECT is not set +# CONFIG_FEATURE_EJECT_SCSI is not set +# CONFIG_FBSPLASH is not set +# CONFIG_FLASHCP is not set +# CONFIG_FLASH_LOCK is not set +# CONFIG_FLASH_UNLOCK is not set +# CONFIG_FLASH_ERASEALL is not set +# CONFIG_IONICE is not set +# CONFIG_INOTIFYD is not set +# CONFIG_LAST is not set +# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_FEATURE_LAST_FANCY is not set +CONFIG_LESS=y +CONFIG_FEATURE_LESS_MAXLINES=9999999 +CONFIG_FEATURE_LESS_BRACKETS=y +CONFIG_FEATURE_LESS_FLAGS=y +CONFIG_FEATURE_LESS_MARKS=y +CONFIG_FEATURE_LESS_REGEXP=y +# CONFIG_FEATURE_LESS_WINCH is not set +# CONFIG_FEATURE_LESS_DASHCMD is not set +# CONFIG_FEATURE_LESS_LINENUMS is not set +# CONFIG_HDPARM is not set +# CONFIG_FEATURE_HDPARM_GET_IDENTITY is not set +# CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_DRIVE_RESET is not set +# CONFIG_FEATURE_HDPARM_HDIO_TRISTATE_HWIF is not set +# CONFIG_FEATURE_HDPARM_HDIO_GETSET_DMA is not set +# CONFIG_MAKEDEVS is not set +# CONFIG_FEATURE_MAKEDEVS_LEAF is not set +# CONFIG_FEATURE_MAKEDEVS_TABLE is not set +# CONFIG_MAN is not set +CONFIG_MICROCOM=y +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set +# CONFIG_RAIDAUTORUN is not set +# CONFIG_READAHEAD is not set +# CONFIG_RFKILL is not set +# CONFIG_RUNLEVEL is not set +# CONFIG_RX is not set +CONFIG_SETSID=y +CONFIG_STRINGS=y +# CONFIG_TASKSET is not set +# CONFIG_FEATURE_TASKSET_FANCY is not set +# CONFIG_TIME is not set +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +# CONFIG_WALL is not set +# CONFIG_WATCHDOG is not set + +# +# Networking Utilities +# +# CONFIG_NBDCLIENT is not set +CONFIG_NC=y +# CONFIG_NC_SERVER is not set +# CONFIG_NC_EXTRA is not set +# CONFIG_NC_110_COMPAT is not set +# CONFIG_FEATURE_IPV6 is not set +# CONFIG_FEATURE_UNIX_LOCAL is not set +# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set +# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +# CONFIG_ARP is not set +# CONFIG_ARPING is not set +# CONFIG_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set +CONFIG_DNSD=y +# CONFIG_ETHER_WAKE is not set +CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y +CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST=y +CONFIG_FTPGET=y +CONFIG_FTPPUT=y +CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y +CONFIG_HOSTNAME=y +CONFIG_HTTPD=y +CONFIG_FEATURE_HTTPD_RANGES=y +# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set +# CONFIG_FEATURE_HTTPD_SETUID is not set +CONFIG_FEATURE_HTTPD_BASIC_AUTH=y +CONFIG_FEATURE_HTTPD_AUTH_MD5=y +CONFIG_FEATURE_HTTPD_CGI=y +CONFIG_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR=y +CONFIG_FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV=y +CONFIG_FEATURE_HTTPD_ENCODE_URL_STR=y +CONFIG_FEATURE_HTTPD_ERROR_PAGES=y +CONFIG_FEATURE_HTTPD_PROXY=y +CONFIG_FEATURE_HTTPD_GZIP=y +# CONFIG_IFCONFIG is not set +# CONFIG_FEATURE_IFCONFIG_STATUS is not set +# CONFIG_FEATURE_IFCONFIG_SLIP is not set +# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set +# CONFIG_FEATURE_IFCONFIG_HW is not set +# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set +# CONFIG_IFENSLAVE is not set +# CONFIG_IFPLUGD is not set +# CONFIG_IFUPDOWN is not set +CONFIG_IFUPDOWN_IFSTATE_PATH="" +# CONFIG_FEATURE_IFUPDOWN_IP is not set +# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set +# CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN is not set +# CONFIG_FEATURE_IFUPDOWN_IPV4 is not set +# CONFIG_FEATURE_IFUPDOWN_IPV6 is not set +# CONFIG_FEATURE_IFUPDOWN_MAPPING is not set +# CONFIG_FEATURE_IFUPDOWN_EXTERNAL_DHCP is not set +# CONFIG_INETD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_ECHO is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DISCARD is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_TIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_DAYTIME is not set +# CONFIG_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN is not set +# CONFIG_FEATURE_INETD_RPC is not set +# CONFIG_IP is not set +# CONFIG_FEATURE_IP_ADDRESS is not set +# CONFIG_FEATURE_IP_LINK is not set +# CONFIG_FEATURE_IP_ROUTE is not set +# CONFIG_FEATURE_IP_TUNNEL is not set +# CONFIG_FEATURE_IP_RULE is not set +# CONFIG_FEATURE_IP_SHORT_FORMS is not set +# CONFIG_FEATURE_IP_RARE_PROTOCOLS is not set +# CONFIG_IPADDR is not set +# CONFIG_IPLINK is not set +# CONFIG_IPROUTE is not set +# CONFIG_IPTUNNEL is not set +# CONFIG_IPRULE is not set +CONFIG_IPCALC=y +CONFIG_FEATURE_IPCALC_FANCY=y +CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y +# CONFIG_NAMEIF is not set +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +# CONFIG_NETSTAT is not set +# CONFIG_FEATURE_NETSTAT_WIDE is not set +# CONFIG_FEATURE_NETSTAT_PRG is not set +# CONFIG_NSLOOKUP is not set +# CONFIG_NTPD is not set +# CONFIG_FEATURE_NTPD_SERVER is not set +# CONFIG_PING is not set +# CONFIG_PING6 is not set +# CONFIG_FEATURE_FANCY_PING is not set +CONFIG_PSCAN=y +# CONFIG_ROUTE is not set +# CONFIG_SLATTACH is not set +# CONFIG_TCPSVD is not set +CONFIG_TELNET=y +CONFIG_FEATURE_TELNET_TTYPE=y +CONFIG_FEATURE_TELNET_AUTOLOGIN=y +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y +CONFIG_TFTP=y +CONFIG_TFTPD=y + +# +# Common options for tftp/tftpd +# +CONFIG_FEATURE_TFTP_GET=y +CONFIG_FEATURE_TFTP_PUT=y +CONFIG_FEATURE_TFTP_BLOCKSIZE=y +CONFIG_FEATURE_TFTP_PROGRESS_BAR=y +# CONFIG_TFTP_DEBUG is not set +# CONFIG_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +# CONFIG_TUNCTL is not set +# CONFIG_FEATURE_TUNCTL_UG is not set +# CONFIG_UDHCPD is not set +# CONFIG_DHCPRELAY is not set +# CONFIG_DUMPLEASES is not set +# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" +# CONFIG_UDHCPC is not set +# CONFIG_FEATURE_UDHCPC_ARPING is not set +# CONFIG_FEATURE_UDHCP_PORT is not set +CONFIG_UDHCP_DEBUG=0 +# CONFIG_FEATURE_UDHCP_RFC3397 is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" +# CONFIG_UDPSVD is not set +# CONFIG_VCONFIG is not set +CONFIG_WGET=y +CONFIG_FEATURE_WGET_STATUSBAR=y +CONFIG_FEATURE_WGET_AUTHENTICATION=y +CONFIG_FEATURE_WGET_LONG_OPTIONS=y +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set + +# +# Print Utilities +# +# CONFIG_LPD is not set +CONFIG_LPR=y +CONFIG_LPQ=y + +# +# Mail Utilities +# +# CONFIG_MAKEMIME is not set +CONFIG_FEATURE_MIME_CHARSET="" +# CONFIG_POPMAILDIR is not set +# CONFIG_FEATURE_POPMAILDIR_DELIVERY is not set +# CONFIG_REFORMIME is not set +# CONFIG_FEATURE_REFORMIME_COMPAT is not set +# CONFIG_SENDMAIL is not set + +# +# Process Utilities +# +CONFIG_IOSTAT=y +CONFIG_MPSTAT=y +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set +# CONFIG_FUSER is not set +CONFIG_KILL=y +CONFIG_KILLALL=y +CONFIG_KILLALL5=y +# CONFIG_NMETER is not set +CONFIG_PGREP=y +# CONFIG_PIDOF is not set +# CONFIG_FEATURE_PIDOF_SINGLE is not set +# CONFIG_FEATURE_PIDOF_OMIT is not set +CONFIG_PKILL=y +CONFIG_PS=y +CONFIG_FEATURE_PS_WIDE=y +# CONFIG_FEATURE_PS_TIME is not set +# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set +CONFIG_RENICE=y +CONFIG_BB_SYSCTL=y +# CONFIG_TOP is not set +# CONFIG_FEATURE_TOP_CPU_USAGE_PERCENTAGE is not set +# CONFIG_FEATURE_TOP_CPU_GLOBAL_PERCENTS is not set +# CONFIG_FEATURE_TOP_SMP_CPU is not set +# CONFIG_FEATURE_TOP_DECIMALS is not set +# CONFIG_FEATURE_TOP_SMP_PROCESS is not set +# CONFIG_FEATURE_TOPMEM is not set +CONFIG_FEATURE_SHOW_THREADS=y +# CONFIG_UPTIME is not set +CONFIG_WATCH=y + +# +# Runit Utilities +# +# CONFIG_RUNSV is not set +# CONFIG_RUNSVDIR is not set +# CONFIG_FEATURE_RUNSVDIR_LOG is not set +# CONFIG_SV is not set +CONFIG_SV_DEFAULT_SERVICE_DIR="" +# CONFIG_SVLOGD is not set +# CONFIG_CHPST is not set +# CONFIG_SETUIDGID is not set +# CONFIG_ENVUIDGID is not set +# CONFIG_ENVDIR is not set +# CONFIG_SOFTLIMIT is not set +# CONFIG_CHCON is not set +# CONFIG_FEATURE_CHCON_LONG_OPTIONS is not set +# CONFIG_GETENFORCE is not set +# CONFIG_GETSEBOOL is not set +# CONFIG_LOAD_POLICY is not set +# CONFIG_MATCHPATHCON is not set +# CONFIG_RESTORECON is not set +# CONFIG_RUNCON is not set +# CONFIG_FEATURE_RUNCON_LONG_OPTIONS is not set +# CONFIG_SELINUXENABLED is not set +# CONFIG_SETENFORCE is not set +# CONFIG_SETFILES is not set +# CONFIG_FEATURE_SETFILES_CHECK_OPTION is not set +# CONFIG_SETSEBOOL is not set +# CONFIG_SESTATUS is not set + +# +# Shells +# +CONFIG_ASH=y +# CONFIG_ASH_BASH_COMPAT is not set +# CONFIG_ASH_JOB_CONTROL is not set +# CONFIG_ASH_ALIAS is not set +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_ECHO is not set +# CONFIG_ASH_PRINTF is not set +# CONFIG_ASH_TEST is not set +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set +# CONFIG_ASH_OPTIMIZE_FOR_SIZE is not set +# CONFIG_ASH_RANDOM_SUPPORT is not set +# CONFIG_ASH_EXPAND_PRMT is not set +# CONFIG_CTTYHACK is not set +# CONFIG_HUSH is not set +# CONFIG_HUSH_BASH_COMPAT is not set +# CONFIG_HUSH_BRACE_EXPANSION is not set +# CONFIG_HUSH_HELP is not set +# CONFIG_HUSH_INTERACTIVE is not set +# CONFIG_HUSH_SAVEHISTORY is not set +# CONFIG_HUSH_JOB is not set +# CONFIG_HUSH_TICK is not set +# CONFIG_HUSH_IF is not set +# CONFIG_HUSH_LOOPS is not set +# CONFIG_HUSH_CASE is not set +# CONFIG_HUSH_FUNCTIONS is not set +# CONFIG_HUSH_LOCAL is not set +# CONFIG_HUSH_RANDOM_SUPPORT is not set +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +CONFIG_FEATURE_SH_IS_ASH=y +# CONFIG_FEATURE_SH_IS_HUSH is not set +# CONFIG_FEATURE_SH_IS_NONE is not set +# CONFIG_FEATURE_BASH_IS_ASH is not set +# CONFIG_FEATURE_BASH_IS_HUSH is not set +CONFIG_FEATURE_BASH_IS_NONE=y +CONFIG_SH_MATH_SUPPORT=y +CONFIG_SH_MATH_SUPPORT_64=y +# CONFIG_FEATURE_SH_EXTRA_QUIET is not set +# CONFIG_FEATURE_SH_STANDALONE is not set +# CONFIG_FEATURE_SH_NOFORK is not set + +# +# System Logging Utilities +# +CONFIG_SYSLOGD=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +CONFIG_FEATURE_REMOTE_LOG=y +# CONFIG_FEATURE_SYSLOGD_DUP is not set +CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 +CONFIG_FEATURE_IPC_SYSLOG=y +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 +CONFIG_LOGREAD=y +CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING=y +# CONFIG_KLOGD is not set +# CONFIG_FEATURE_KLOGD_KLOGCTL is not set +CONFIG_LOGGER=y diff --git a/busybox-1_37_0/console-tools/Config.src b/busybox-1_37_0/console-tools/Config.src new file mode 100644 index 000000000..c30caf0e1 --- /dev/null +++ b/busybox-1_37_0/console-tools/Config.src @@ -0,0 +1,10 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Console Utilities" + +INSERT + +endmenu diff --git a/busybox-1_37_0/console-tools/Kbuild.src b/busybox-1_37_0/console-tools/Kbuild.src new file mode 100644 index 000000000..6b4fb7470 --- /dev/null +++ b/busybox-1_37_0/console-tools/Kbuild.src @@ -0,0 +1,9 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +lib-y:= + +INSERT diff --git a/busybox-1_37_0/console-tools/chvt.c b/busybox-1_37_0/console-tools/chvt.c new file mode 100644 index 000000000..2444e1f9d --- /dev/null +++ b/busybox-1_37_0/console-tools/chvt.c @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chvt implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CHVT +//config: bool "chvt (2.2 kb)" +//config: default y +//config: help +//config: This program is used to change to another terminal. +//config: Example: chvt 4 (change to terminal /dev/tty4) + +//applet:IF_CHVT(APPLET_NOEXEC(chvt, chvt, BB_DIR_USR_BIN, BB_SUID_DROP, chvt)) + +//kbuild:lib-$(CONFIG_CHVT) += chvt.o + +//usage:#define chvt_trivial_usage +//usage: "N" +//usage:#define chvt_full_usage "\n\n" +//usage: "Change the foreground virtual terminal to /dev/ttyN" + +#include "libbb.h" + +int chvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chvt_main(int argc UNUSED_PARAM, char **argv) +{ + int num = xatou_range(single_argv(argv), 1, 63); + console_make_active(get_console_fd_or_die(), num); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/clear.c b/busybox-1_37_0/console-tools/clear.c new file mode 100644 index 000000000..e1bf2c313 --- /dev/null +++ b/busybox-1_37_0/console-tools/clear.c @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini clear implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CLEAR +//config: bool "clear (371 bytes)" +//config: default y +//config: help +//config: This program clears the terminal screen. + +//applet:IF_CLEAR(APPLET_NOFORK(clear, clear, BB_DIR_USR_BIN, BB_SUID_DROP, clear)) + +//kbuild:lib-$(CONFIG_CLEAR) += clear.o + +//usage:#define clear_trivial_usage +//usage: "" +//usage:#define clear_full_usage "\n\n" +//usage: "Clear screen" + +#include "libbb.h" + +#define ESC "\033" + +int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int clear_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + /* home; clear to the end of screen */ + return full_write1_str(ESC"[H" ESC"[J") != 6; +} diff --git a/busybox-1_37_0/console-tools/deallocvt.c b/busybox-1_37_0/console-tools/deallocvt.c new file mode 100644 index 000000000..f03ad079b --- /dev/null +++ b/busybox-1_37_0/console-tools/deallocvt.c @@ -0,0 +1,45 @@ +/* vi: set sw=4 ts=4: */ +/* + * Disallocate virtual terminal(s) + * + * Copyright (C) 2003 by Tito Ragusa + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DEALLOCVT +//config: bool "deallocvt (2.2 kb)" +//config: default y +//config: help +//config: This program deallocates unused virtual consoles. + +//applet:IF_DEALLOCVT(APPLET_NOEXEC(deallocvt, deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP, deallocvt)) + +//kbuild:lib-$(CONFIG_DEALLOCVT) += deallocvt.o + +//usage:#define deallocvt_trivial_usage +//usage: "[N]" +//usage:#define deallocvt_full_usage "\n\n" +//usage: "Deallocate unused virtual terminal /dev/ttyN" + +#include "libbb.h" + +/* From */ +enum { VT_DISALLOCATE = 0x5608 }; /* free memory associated to vt */ + +int deallocvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int deallocvt_main(int argc UNUSED_PARAM, char **argv) +{ + /* num = 0 deallocate all unused consoles */ + int num = 0; + + if (argv[1]) { + if (argv[2]) + bb_show_usage(); + num = xatou_range(argv[1], 1, 63); + } + + /* double cast suppresses "cast to ptr from int of different size" */ + xioctl(get_console_fd_or_die(), VT_DISALLOCATE, (void *)(ptrdiff_t)num); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/dumpkmap.c b/busybox-1_37_0/console-tools/dumpkmap.c new file mode 100644 index 000000000..957d16529 --- /dev/null +++ b/busybox-1_37_0/console-tools/dumpkmap.c @@ -0,0 +1,88 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dumpkmap implementation for busybox + * + * Copyright (C) Arne Bernin + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DUMPKMAP +//config: bool "dumpkmap (1.9 kb)" +//config: default y +//config: help +//config: This program dumps the kernel's keyboard translation table to +//config: stdout, in binary format. You can then use loadkmap to load it. + +//applet:IF_DUMPKMAP(APPLET_NOEXEC(dumpkmap, dumpkmap, BB_DIR_BIN, BB_SUID_DROP, dumpkmap)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ + +//kbuild:lib-$(CONFIG_DUMPKMAP) += dumpkmap.o + +//usage:#define dumpkmap_trivial_usage +//usage: "> keymap" +//usage:#define dumpkmap_full_usage "\n\n" +//usage: "Print a binary keyboard translation table to stdout" +//usage: +//usage:#define dumpkmap_example_usage +//usage: "$ dumpkmap > keymap\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +/* From */ +struct kbentry { + unsigned char kb_table; + unsigned char kb_index; + unsigned short kb_value; +}; +#define KDGKBENT 0x4B46 /* gets one entry in translation table */ + +/* From */ +#define NR_KEYS 128 +#define MAX_NR_KEYMAPS 256 + +int dumpkmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dumpkmap_main(int argc UNUSED_PARAM, char **argv) +{ + struct kbentry ke; + int i, j, fd; + + /* When user accidentally runs "dumpkmap FILE" + * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. + * Let's prevent it: + */ + if (argv[1]) + bb_show_usage(); +/* bb_warn_ignoring_args(argv[1]);*/ + + fd = get_console_fd_or_die(); + +#define flags bb_common_bufsiz1 + setup_common_bufsiz(); + /* 0 1 2 3 4 5 6 7 8 9 a b c=12 */ + memcpy(flags, "bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1", + /* Can use sizeof, or sizeof-1. sizeof is even, using that */ + /****/ sizeof("bkeymap\1\1\1\0\1\1\1\0\1\1\1\0\1") + ); + write(STDOUT_FILENO, flags, 7 + MAX_NR_KEYMAPS); +#define flags7 (flags + 7) + + for (i = 0; i < 13; i++) { + if (flags7[i]) { + for (j = 0; j < NR_KEYS; j++) { + ke.kb_index = j; + ke.kb_table = i; + if (!ioctl_or_perror(fd, KDGKBENT, &ke, + "ioctl(KDGKBENT{%d,%d}) failed", + j, i) + ) { + write(STDOUT_FILENO, &ke.kb_value, 2); + } + } + } + } + if (ENABLE_FEATURE_CLEAN_UP) { + close(fd); + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/fgconsole.c b/busybox-1_37_0/console-tools/fgconsole.c new file mode 100644 index 000000000..b6dbc472b --- /dev/null +++ b/busybox-1_37_0/console-tools/fgconsole.c @@ -0,0 +1,44 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini fgconsole implementation for busybox + * + * Copyright (C) 2010 by Grigory Batalov + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config FGCONSOLE +//config: bool "fgconsole (1.8 kb)" +//config: default y +//config: help +//config: This program prints active (foreground) console number. + +//applet:IF_FGCONSOLE(APPLET_NOEXEC(fgconsole, fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP, fgconsole)) + +//kbuild:lib-$(CONFIG_FGCONSOLE) += fgconsole.o + +//usage:#define fgconsole_trivial_usage +//usage: "" +//usage:#define fgconsole_full_usage "\n\n" +//usage: "Get active console" + +#include "libbb.h" + +/* From */ +struct vt_stat { + unsigned short v_active; /* active vt */ + unsigned short v_signal; /* signal to send */ + unsigned short v_state; /* vt bitmask */ +}; +enum { VT_GETSTATE = 0x5603 }; /* get global vt state info */ + +int fgconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fgconsole_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + struct vt_stat vtstat; + + vtstat.v_active = 0; + xioctl(get_console_fd_or_die(), VT_GETSTATE, &vtstat); + printf("%d\n", vtstat.v_active); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/kbd_mode.c b/busybox-1_37_0/console-tools/kbd_mode.c new file mode 100644 index 000000000..1ec25757d --- /dev/null +++ b/busybox-1_37_0/console-tools/kbd_mode.c @@ -0,0 +1,94 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini kbd_mode implementation for busybox + * + * Copyright (C) 2007 Loic Grenie + * written using Andries Brouwer 's kbd_mode from + * console-utils v0.2.3, licensed under GNU GPLv2 + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config KBD_MODE +//config: bool "kbd_mode (4.3 kb)" +//config: default y +//config: help +//config: This program reports and sets keyboard mode. + +//applet:IF_KBD_MODE(APPLET_NOEXEC(kbd_mode, kbd_mode, BB_DIR_BIN, BB_SUID_DROP, kbd_mode)) + +//kbuild:lib-$(CONFIG_KBD_MODE) += kbd_mode.o + +//usage:#define kbd_mode_trivial_usage +//usage: "[-a|k|s|u] [-C TTY]" +//usage:#define kbd_mode_full_usage "\n\n" +//usage: "Report or set VT console keyboard mode\n" +//usage: "\n -a Default (ASCII)" +//usage: "\n -k Medium-raw (keycode)" +//usage: "\n -s Raw (scancode)" +//usage: "\n -u Unicode (utf-8)" +//usage: "\n -C TTY Affect TTY" + +#include "libbb.h" +#include + +int kbd_mode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int kbd_mode_main(int argc UNUSED_PARAM, char **argv) +{ + enum { + SCANCODE = (1 << 0), + ASCII = (1 << 1), + MEDIUMRAW = (1 << 2), + UNICODE = (1 << 3), + }; + int fd; + unsigned opt; + const char *tty_name; + + opt = getopt32(argv, "sakuC:", &tty_name); + if (opt & 0x10) { + opt &= 0xf; /* clear -C bit, see (*) */ + fd = xopen_nonblocking(tty_name); + } else { + /* kbd-2.0.3 tries in sequence: + * fd#0, /dev/tty, /dev/tty0. + * get_console_fd_or_die: /dev/console, /dev/tty0, /dev/tty. + * kbd-2.0.3 checks KDGKBTYPE, get_console_fd_or_die checks too. + */ + fd = get_console_fd_or_die(); + } + + if (!opt) { /* print current setting */ + const char *mode = "unknown"; + int m; + + xioctl(fd, KDGKBMODE, &m); + if (m == K_RAW) + mode = "raw (scancode)"; + else if (m == K_XLATE) + mode = "default (ASCII)"; + else if (m == K_MEDIUMRAW) + mode = "mediumraw (keycode)"; + else if (m == K_UNICODE) + mode = "Unicode (UTF-8)"; + else if (m == 4 /*K_OFF*/) /* kbd-2.0.3 does not show this mode, says "unknown" */ + mode = "off"; + printf("The keyboard is in %s mode\n", mode); + } else { + /* here we depend on specific bits assigned to options (*) + * KDSKBMODE constants have these values: + * #define K_RAW 0x00 + * #define K_XLATE 0x01 + * #define K_MEDIUMRAW 0x02 + * #define K_UNICODE 0x03 + * #define K_OFF 0x04 + * (looks like "-ak" together would cause the same effect as -u) + */ + opt = opt & UNICODE ? 3 : opt >> 1; + /* double cast prevents warnings about widening conversion */ + xioctl(fd, KDSKBMODE, (void*)(ptrdiff_t)opt); + } + + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/loadfont.c b/busybox-1_37_0/console-tools/loadfont.c new file mode 100644 index 000000000..cec5e19cd --- /dev/null +++ b/busybox-1_37_0/console-tools/loadfont.c @@ -0,0 +1,533 @@ +/* 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.) + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config LOADFONT +//config: bool "loadfont (5.4 kb)" +//config: default y +//config: help +//config: This program loads a console font from standard input. +//config: +//config:config SETFONT +//config: bool "setfont (24 kb)" +//config: default y +//config: help +//config: Allows to load console screen map. Useful for i18n. +//config: +//config:config FEATURE_SETFONT_TEXTUAL_MAP +//config: bool "Support reading textual screen maps" +//config: default y +//config: depends on SETFONT +//config: help +//config: Support reading textual screen maps. +//config: +//config:config DEFAULT_SETFONT_DIR +//config: string "Default directory for console-tools files" +//config: default "" +//config: depends on SETFONT +//config: help +//config: Directory to use if setfont's params are simple filenames +//config: (not /path/to/file or ./file). Default is "" (no default directory). +//config: +//config:comment "Common options for loadfont and setfont" +//config: depends on LOADFONT || SETFONT +//config: +//config:config FEATURE_LOADFONT_PSF2 +//config: bool "Support PSF2 console fonts" +//config: default y +//config: depends on LOADFONT || SETFONT +//config: +//config:config FEATURE_LOADFONT_RAW +//config: bool "Support old (raw) console fonts" +//config: default y +//config: depends on LOADFONT || SETFONT + +//applet:IF_LOADFONT(APPLET_NOEXEC(loadfont, loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP, loadfont)) +//applet:IF_SETFONT(APPLET_NOEXEC(setfont, setfont, BB_DIR_USR_SBIN, BB_SUID_DROP, setfont)) + +//kbuild:lib-$(CONFIG_LOADFONT) += loadfont.o +//kbuild:lib-$(CONFIG_SETFONT) += loadfont.o + +#include "libbb.h" +#include + +#ifndef KDFONTOP +# define KDFONTOP 0x4B72 +struct console_font_op { + unsigned op; /* KD_FONT_OP_* */ + unsigned flags; /* KD_FONT_FLAG_* */ + unsigned width, height; + unsigned charcount; + unsigned char *data; /* font data with height fixed to 32 */ +}; +# define KD_FONT_OP_SET 0 /* Set font */ +# define KD_FONT_OP_GET 1 /* Get font */ +# define KD_FONT_OP_SET_DEFAULT 2 /* Set font to default, data points to name / NULL */ +# define KD_FONT_OP_COPY 3 /* Copy from another console */ +# define KD_FONT_FLAG_OLD 0x80000000 /* Invoked via old interface */ +# define KD_FONT_FLAG_DONT_RECALC 1 /* Don't call adjust_height() */ + /* (Used internally for PIO_FONT support) */ +#endif /* KDFONTOP */ + + +enum { + PSF1_MAGIC0 = 0x36, + PSF1_MAGIC1 = 0x04, + PSF1_MODE512 = 0x01, + PSF1_MODEHASTAB = 0x02, + PSF1_MODEHASSEQ = 0x04, + PSF1_MAXMODE = 0x05, + PSF1_STARTSEQ = 0xfffe, + PSF1_SEPARATOR = 0xffff, +}; + +struct psf1_header { + unsigned char magic[2]; /* Magic number */ + unsigned char mode; /* PSF font mode */ + unsigned char charsize; /* Character size */ +}; + +#define psf1h(x) ((struct psf1_header*)(x)) + +#define PSF1_MAGIC_OK(x) ( \ + (x)->magic[0] == PSF1_MAGIC0 \ + && (x)->magic[1] == PSF1_MAGIC1 \ +) + +#if ENABLE_FEATURE_LOADFONT_PSF2 +enum { + PSF2_MAGIC0 = 0x72, + PSF2_MAGIC1 = 0xb5, + PSF2_MAGIC2 = 0x4a, + PSF2_MAGIC3 = 0x86, + PSF2_HAS_UNICODE_TABLE = 0x01, + PSF2_MAXVERSION = 0, + PSF2_STARTSEQ = 0xfe, + PSF2_SEPARATOR = 0xff +}; + +struct psf2_header { + unsigned char magic[4]; + unsigned int version; + unsigned int headersize; /* offset of bitmaps in file */ + unsigned int flags; + unsigned int length; /* number of glyphs */ + unsigned int charsize; /* number of bytes for each character */ + unsigned int height; /* max dimensions of glyphs */ + unsigned int width; /* charsize = height * ((width + 7) / 8) */ +}; + +#define psf2h(x) ((struct psf2_header*)(x)) + +#define PSF2_MAGIC_OK(x) ( \ + (x)->magic[0] == PSF2_MAGIC0 \ + && (x)->magic[1] == PSF2_MAGIC1 \ + && (x)->magic[2] == PSF2_MAGIC2 \ + && (x)->magic[3] == PSF2_MAGIC3 \ +) +#endif /* ENABLE_FEATURE_LOADFONT_PSF2 */ + + +static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int charsize, int fontsize) +{ + unsigned char *buf; + int charwidth = 32 * ((width+7)/8); + int i; + + if (height < 1 || height > 32 || width < 1 || width > 32) + bb_error_msg_and_die("bad character size %dx%d", height, width); + + buf = xzalloc(charwidth * ((fontsize < 128) ? 128 : fontsize)); + for (i = 0; i < fontsize; i++) + memcpy(buf + (i*charwidth), inbuf + (i*charsize), charsize); + + { /* KDFONTOP */ + struct console_font_op cfo; + cfo.op = KD_FONT_OP_SET; + cfo.flags = 0; + cfo.width = width; + cfo.height = height; + cfo.charcount = fontsize; + cfo.data = buf; + xioctl(fd, KDFONTOP, &cfo); + } + + free(buf); +} + +/* + * Format of the Unicode information: + * + * For each font position ** + * where is a 2-byte little endian Unicode value (PSF1) + * or an UTF-8 coded value (PSF2), + * = *, = psf1 ? 0xFFFE : 0xFE, + * = psf1 ? 0xFFFF : 0xFF. + * and * denotes zero or more occurrences of the preceding item. + * + * Semantics: + * The leading * part gives Unicode symbols that are all + * represented by this font position. The following sequences + * are sequences of Unicode symbols - probably a symbol + * together with combining accents - also represented by + * this font position. + * + * Example: + * At the font position for a capital A-ring glyph, we + * may have: + * 00C5,212B,FFFE,0041,030A,FFFF + * Some font positions may be described by sequences only, + * namely when there is no precomposed Unicode value for the glyph. + */ +#if !ENABLE_FEATURE_LOADFONT_PSF2 +#define do_loadtable(fd, inbuf, tailsz, fontsize, psf2) \ + do_loadtable(fd, inbuf, tailsz, fontsize) +#endif +static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int psf2) +{ +#if !ENABLE_FEATURE_LOADFONT_PSF2 +/* gcc 4.3.1 code size: */ +# define psf2 0 /* +0 bytes */ +// const int psf2 = 0; /* +8 bytes */ +// enum { psf2 = 0 }; /* +13 bytes */ +#endif + struct unimapinit advice; + struct unimapdesc ud; + struct unipair *up; + int ct = 0, maxct; + int glyph; + uint16_t unicode; + + maxct = tailsz; /* more than enough */ + up = xmalloc(maxct * sizeof(*up)); + + for (glyph = 0; glyph < fontsize; glyph++) { + while (tailsz > 0) { + if (!psf2) { /* PSF1 */ + unicode = (((uint16_t) inbuf[1]) << 8) + inbuf[0]; + tailsz -= 2; + inbuf += 2; + if (unicode == PSF1_SEPARATOR) + break; + } else { /* PSF2 */ +#if ENABLE_FEATURE_LOADFONT_PSF2 + --tailsz; + unicode = *inbuf++; + if (unicode == PSF2_SEPARATOR) { + break; + } else if (unicode == PSF2_STARTSEQ) { + bb_simple_error_msg_and_die("unicode sequences not implemented"); + } else if (unicode >= 0xC0) { + if (unicode >= 0xFC) + unicode &= 0x01, maxct = 5; + else if (unicode >= 0xF8) + unicode &= 0x03, maxct = 4; + else if (unicode >= 0xF0) + unicode &= 0x07, maxct = 3; + else if (unicode >= 0xE0) + unicode &= 0x0F, maxct = 2; + else + unicode &= 0x1F, maxct = 1; + do { + if (tailsz <= 0 || *inbuf < 0x80 || *inbuf > 0xBF) + bb_simple_error_msg_and_die("illegal UTF-8 character"); + --tailsz; + unicode = (unicode << 6) + (*inbuf++ & 0x3F); + } while (--maxct > 0); + } else if (unicode >= 0x80) { + bb_simple_error_msg_and_die("illegal UTF-8 character"); + } +#else + return; +#endif + } + 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; + xioctl(fd, PIO_UNIMAPCLR, &advice); + ud.entry_ct = ct; + ud.entries = up; + xioctl(fd, PIO_UNIMAP, &ud); +#undef psf2 +} + +static void do_load(int fd, unsigned char *buffer, size_t len) +{ + int height; + int width = 8; + int charsize; + int fontsize = 256; + int has_table = 0; + unsigned char *font = buffer; + unsigned char *table; + + if (len >= sizeof(struct psf1_header) && PSF1_MAGIC_OK(psf1h(buffer))) { + if (psf1h(buffer)->mode > PSF1_MAXMODE) + bb_simple_error_msg_and_die("unsupported psf file mode"); + if (psf1h(buffer)->mode & PSF1_MODE512) + fontsize = 512; + if (psf1h(buffer)->mode & PSF1_MODEHASTAB) + has_table = 1; + height = charsize = psf1h(buffer)->charsize; + font += sizeof(struct psf1_header); + } else +#if ENABLE_FEATURE_LOADFONT_PSF2 + if (len >= sizeof(struct psf2_header) && PSF2_MAGIC_OK(psf2h(buffer))) { + if (psf2h(buffer)->version > PSF2_MAXVERSION) + bb_simple_error_msg_and_die("unsupported psf file version"); + fontsize = psf2h(buffer)->length; + if (psf2h(buffer)->flags & PSF2_HAS_UNICODE_TABLE) + has_table = 2; + charsize = psf2h(buffer)->charsize; + height = psf2h(buffer)->height; + width = psf2h(buffer)->width; + font += psf2h(buffer)->headersize; + } else +#endif +#if ENABLE_FEATURE_LOADFONT_RAW + if (len == 9780) { /* file with three code pages? */ + charsize = height = 16; + font += 40; + } else if ((len & 0377) == 0) { /* bare font */ + charsize = height = len / 256; + } else +#endif + { + bb_simple_error_msg_and_die("input file: bad length or unsupported font type"); + } + +#if !defined(PIO_FONTX) || defined(__sparc__) + if (fontsize != 256) + bb_simple_error_msg_and_die("only fontsize 256 supported"); +#endif + + table = font + fontsize * charsize; + buffer += len; + + if (table > buffer || (!has_table && table != buffer)) + bb_simple_error_msg_and_die("input file: bad length"); + + do_loadfont(fd, font, height, width, charsize, fontsize); + + if (has_table) + do_loadtable(fd, table, buffer - table, fontsize, has_table - 1); +} + + +#if ENABLE_LOADFONT +//usage:#define loadfont_trivial_usage +//usage: "< font" +//usage:#define loadfont_full_usage "\n\n" +//usage: "Load a console font from stdin" +/* //usage: "\n -C TTY Affect TTY instead of /dev/tty" */ +//usage: +//usage:#define loadfont_example_usage +//usage: "$ loadfont < /etc/i18n/fontname\n" +int loadfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int loadfont_main(int argc UNUSED_PARAM, char **argv) +{ + size_t len; + unsigned char *buffer; + + // no arguments allowed! + getopt32(argv, "^" "" "\0" "=0"); + + /* + * We used to look at the length of the input file + * with stat(); now that we accept compressed files, + * just read the entire file. + * Len was 32k, but latarcyrheb-sun32.psfu is 34377 bytes + * (it has largish Unicode map). + */ + len = 128*1024; + buffer = xmalloc_read(STDIN_FILENO, &len); + // xmalloc_open_zipped_read_close(filename, &len); + if (!buffer) + bb_simple_perror_msg_and_die("error reading input font"); + do_load(get_console_fd_or_die(), buffer, len); + + return EXIT_SUCCESS; +} +#endif + + +#if ENABLE_SETFONT +/* kbd-1.12: +setfont [-O font+umap.orig] [-o font.orig] [-om cmap.orig] +[-ou umap.orig] [-N] [font.new ...] [-m cmap] [-u umap] [-C console] +[-hNN] [-v] [-V] + +-h NN Override font height +-o file + Save previous font in file +-O file + Save previous font and Unicode map in file +-om file + Store console map in file +-ou file + Save previous Unicode map in file +-m file + Load console map or Unicode console map from file +-u file + Load Unicode table describing the font from file + Example: + # cp866 + 0x00-0x7f idem + # + 0x80 U+0410 # CYRILLIC CAPITAL LETTER A + 0x81 U+0411 # CYRILLIC CAPITAL LETTER BE + 0x82 U+0412 # CYRILLIC CAPITAL LETTER VE +-C console + Set the font for the indicated console +-v Verbose +-V Version +*/ +//usage:#define setfont_trivial_usage +//usage: "[-m MAPFILE] [-C TTY] FILE" +//usage:#define setfont_full_usage "\n\n" +//usage: "Load a console font\n" +//usage: "\n -m MAPFILE Load console screen map" +//usage: "\n -C TTY Affect TTY instead of /dev/tty" +//usage: +//usage:#define setfont_example_usage +//usage: "$ setfont -m koi8-r /etc/i18n/fontname\n" + +# if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP +static int ctoi(char *s) +{ + if (s[0] == '\'' && s[1] != '\0' && s[2] == '\'' && s[3] == '\0') + return s[1]; + // U+ means 0x + if (s[0] == 'U' && s[1] == '+') { + s[0] = '0'; + s[1] = 'x'; + } + if (!isdigit(s[0])) + return -1; + return xstrtoul(s, 0); +} +# endif + +int setfont_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setfont_main(int argc UNUSED_PARAM, char **argv) +{ + size_t len; + unsigned opts; + int fd; + unsigned char *buffer; + char *mapfilename; + const char *tty_name = CURRENT_TTY; + + opts = getopt32(argv, "^" "m:C:" "\0" "=1", &mapfilename, &tty_name); + argv += optind; + + fd = xopen_nonblocking(tty_name); + + if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not "" + if (*argv[0] != '/') { + // goto default fonts location. don't die if doesn't exist + chdir(CONFIG_DEFAULT_SETFONT_DIR "/consolefonts"); + } + } + // load font + len = 128*1024; + buffer = xmalloc_open_zipped_read_close(*argv, &len); + if (!buffer) + bb_simple_perror_msg_and_die(*argv); + do_load(fd, buffer, len); + + // load the screen map, if any + if (opts & 1) { // -m + unsigned mode = PIO_SCRNMAP; + void *map; + + if (sizeof(CONFIG_DEFAULT_SETFONT_DIR) > 1) { // if not "" + if (mapfilename[0] != '/') { + // goto default keymaps location + chdir(CONFIG_DEFAULT_SETFONT_DIR "/consoletrans"); + } + } + // fetch keymap + map = xmalloc_open_zipped_read_close(mapfilename, &len); + if (!map) + bb_simple_perror_msg_and_die(mapfilename); + // file size is 256 or 512 bytes? -> assume binary map + if (len == E_TABSZ || len == 2*E_TABSZ) { + if (len == 2*E_TABSZ) + mode = PIO_UNISCRNMAP; + } +# if ENABLE_FEATURE_SETFONT_TEXTUAL_MAP + // assume textual Unicode console maps: + // 0x00 U+0000 # NULL (NUL) + // 0x01 U+0001 # START OF HEADING (SOH) + // 0x02 U+0002 # START OF TEXT (STX) + // 0x03 U+0003 # END OF TEXT (ETX) + else { + int i; + char *token[2]; + parser_t *parser; + + if (ENABLE_FEATURE_CLEAN_UP) + free(map); + map = xmalloc(E_TABSZ * sizeof(unsigned short)); + +#define unicodes ((unsigned short *)map) + // fill vanilla map + for (i = 0; i < E_TABSZ; i++) + unicodes[i] = 0xf000 + i; + + parser = config_open(mapfilename); + while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL | PARSE_MIN_DIE)) { + // parse code/value pair + int a = ctoi(token[0]); + int b = ctoi(token[1]); + if (a < 0 || a >= E_TABSZ + || b < 0 || b > 65535 + ) { + bb_simple_error_msg_and_die("map format"); + } + // patch map + unicodes[a] = b; + // unicode character is met? + if (b > 255) + mode = PIO_UNISCRNMAP; + } + if (ENABLE_FEATURE_CLEAN_UP) + config_close(parser); + + if (mode != PIO_UNISCRNMAP) { +#define asciis ((unsigned char *)map) + for (i = 0; i < E_TABSZ; i++) + asciis[i] = unicodes[i]; +#undef asciis + } +#undef unicodes + } +# endif // ENABLE_FEATURE_SETFONT_TEXTUAL_MAP + + // do set screen map + xioctl(fd, mode, map); + + if (ENABLE_FEATURE_CLEAN_UP) + free(map); + } + + return EXIT_SUCCESS; +} +#endif diff --git a/busybox-1_37_0/console-tools/loadkmap.c b/busybox-1_37_0/console-tools/loadkmap.c new file mode 100644 index 000000000..22e918dbf --- /dev/null +++ b/busybox-1_37_0/console-tools/loadkmap.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini loadkmap implementation for busybox + * + * Copyright (C) 1998 Enrique Zanardi + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config LOADKMAP +//config: bool "loadkmap (2.1 kb)" +//config: default y +//config: help +//config: This program loads a keyboard translation table from +//config: standard input. + +//applet:IF_LOADKMAP(APPLET_NOEXEC(loadkmap, loadkmap, BB_DIR_SBIN, BB_SUID_DROP, loadkmap)) + +//kbuild:lib-$(CONFIG_LOADKMAP) += loadkmap.o + +//usage:#define loadkmap_trivial_usage +//usage: "< keymap" +//usage:#define loadkmap_full_usage "\n\n" +//usage: "Load a binary keyboard translation table from stdin" +////usage: "\n" +////usage: "\n -C TTY Affect TTY instead of /dev/tty" +//usage: +//usage:#define loadkmap_example_usage +//usage: "$ loadkmap < /etc/i18n/lang-keymap\n" + +#include "libbb.h" + +#define BINARY_KEYMAP_MAGIC "bkeymap" + +/* From */ +struct kbentry { + unsigned char kb_table; + unsigned char kb_index; + unsigned short kb_value; +}; +/* sets one entry in translation table */ +#define KDSKBENT 0x4B47 + +/* From */ +#define NR_KEYS 128 +#define MAX_NR_KEYMAPS 256 + +int loadkmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int loadkmap_main(int argc UNUSED_PARAM, char **argv) +{ + struct kbentry ke; + int i, j, fd; + uint16_t ibuff[NR_KEYS]; +/* const char *tty_name = CURRENT_TTY; */ + RESERVE_CONFIG_BUFFER(flags, MAX_NR_KEYMAPS); + + /* When user accidentally runs "loadkmap FILE" + * instead of "loadkmap + * hacked by Tito + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config OPENVT +//config: bool "openvt (7.4 kb)" +//config: default y +//config: help +//config: This program is used to start a command on an unused +//config: virtual terminal. + +//applet:IF_OPENVT(APPLET(openvt, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_OPENVT) += openvt.o + +//usage:#define openvt_trivial_usage +//usage: "[-c N] [-sw] [PROG ARGS]" +//usage:#define openvt_full_usage "\n\n" +//usage: "Start PROG on a new virtual terminal\n" +//usage: "\n -c N Use specified VT" +//usage: "\n -s Switch to the VT" +/* //usage: "\n -l Run PROG as login shell (by prepending '-')" */ +//usage: "\n -w Wait for PROG to exit" +//usage: +//usage:#define openvt_example_usage +//usage: "openvt 2 /bin/ash\n" + +#include +#include "libbb.h" + +/* "Standard" openvt's man page (we do not support all of this): + +openvt [-c NUM] [-fsulv] [--] [command [args]] + +Find the first available VT, and run command on it. Stdio is directed +to that VT. If no command is specified then $SHELL is used. + +-c NUM + Use the given VT number, not the first free one. +-f + Force opening a VT: don't try to check if VT is already in use. +-s + Switch to the new VT when starting the command. + The VT of the new command will be made the new current VT. +-u + Figure out the owner of the current VT, and run login as that user. + Suitable to be called by init. Shouldn't be used with -c or -l. +-l + Make the command a login shell: a "-" is prepended to the argv[0] + when command is executed. +-v + Verbose. +-w + Wait for command to complete. If -w and -s are used together, + switch back to the controlling terminal when the command completes. + +bbox: +-u: not implemented +-f: always in effect +-l: not implemented, ignored +-v: ignored +-ws: does NOT switch back +*/ + +/* Helper: does this fd understand VT_xxx? */ +static int not_vt_fd(int fd) +{ + struct vt_stat vtstat; + return ioctl(fd, VT_GETSTATE, &vtstat); /* !0: error, it's not VT fd */ +} + +/* Helper: get a fd suitable for VT_xxx */ +static int get_vt_fd(void) +{ + int fd; + + /* Do we, by chance, already have it? */ + for (fd = 0; fd < 3; fd++) + if (!not_vt_fd(fd)) + return fd; + fd = open(DEV_CONSOLE, O_RDONLY | O_NONBLOCK); + if (fd >= 0 && !not_vt_fd(fd)) + return fd; + bb_simple_error_msg_and_die("can't find open VT"); +} + +static int find_free_vtno(void) +{ + int vtno; + int fd = get_vt_fd(); + + errno = 0; + /*xfunc_error_retval = 3; - do we need compat? */ + if (ioctl(fd, VT_OPENQRY, &vtno) != 0 || vtno <= 0) + bb_simple_perror_msg_and_die("can't find open VT"); +// Not really needed, grep for DAEMON_CLOSE_EXTRA_FDS +// if (fd > 2) +// close(fd); + return vtno; +} + +/* vfork scares gcc, it generates bigger code. + * Keep it away from main program. + * TODO: move to libbb; or adapt existing libbb's spawn(). + */ +static NOINLINE void vfork_child(char **argv) +{ + if (vfork() == 0) { + /* CHILD */ + /* Try to make this VT our controlling tty */ + setsid(); /* lose old ctty */ + ioctl(STDIN_FILENO, TIOCSCTTY, 0 /* 0: don't forcibly steal */); + //bb_error_msg("our sid %d", getsid(0)); + //bb_error_msg("our pgrp %d", getpgrp()); + //bb_error_msg("VT's sid %d", tcgetsid(0)); + //bb_error_msg("VT's pgrp %d", tcgetpgrp(0)); + BB_EXECVP_or_die(argv); + } +} + +int openvt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int openvt_main(int argc UNUSED_PARAM, char **argv) +{ + char vtname[sizeof(VC_FORMAT) + sizeof(int)*3]; + struct vt_stat vtstat; + char *str_c; + int vtno; + int flags; + enum { + OPT_c = (1 << 0), + OPT_w = (1 << 1), + OPT_s = (1 << 2), + OPT_l = (1 << 3), + OPT_f = (1 << 4), + OPT_v = (1 << 5), + }; + + /* "+" - stop on first non-option */ + flags = getopt32(argv, "+c:wslfv", &str_c); + argv += optind; + + if (flags & OPT_c) { + /* Check for illegal vt number: < 1 or > 63 */ + vtno = xatou_range(str_c, 1, 63); + } else { + vtno = find_free_vtno(); + } + + /* Grab new VT */ + sprintf(vtname, VC_FORMAT, vtno); + /* (Try to) clean up stray open fds above fd 2 */ + bb_daemon_helper(DAEMON_CLOSE_EXTRA_FDS); + close(STDIN_FILENO); + /*setsid(); - BAD IDEA: after we exit, child is SIGHUPed... */ + xopen(vtname, O_RDWR); + xioctl(STDIN_FILENO, VT_GETSTATE, &vtstat); + + if (flags & OPT_s) { + console_make_active(STDIN_FILENO, vtno); + } + + if (!argv[0]) { + argv--; + argv[0] = (char *) get_shell_name(); + /*argv[1] = NULL; - already is */ + } + + xdup2(STDIN_FILENO, STDOUT_FILENO); + xdup2(STDIN_FILENO, STDERR_FILENO); + +#ifdef BLOAT + { + /* Handle -l (login shell) option */ + const char *prog = argv[0]; + if (flags & OPT_l) + argv[0] = xasprintf("-%s", argv[0]); + } +#endif + + vfork_child(argv); + if (flags & OPT_w) { + /* We have only one child, wait for it */ + safe_waitpid(-1, NULL, 0); /* loops on EINTR */ + if (flags & OPT_s) { + console_make_active(STDIN_FILENO, vtstat.v_active); + // Compat: even with -c N (try to) disallocate: + // # /usr/app/kbd-1.12/bin/openvt -f -c 9 -ws sleep 5 + // openvt: could not deallocate console 9 + xioctl(STDIN_FILENO, VT_DISALLOCATE, (void*)(ptrdiff_t)vtno); + } + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/reset.c b/busybox-1_37_0/console-tools/reset.c new file mode 100644 index 000000000..655a5ef7a --- /dev/null +++ b/busybox-1_37_0/console-tools/reset.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini reset implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * Written by Erik Andersen and Kent Robotti + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RESET +//config: bool "reset (676 bytes)" +//config: default y +//config: help +//config: This program is used to reset the terminal screen, if it +//config: gets messed up. + +//applet:IF_RESET(APPLET_NOEXEC(reset, reset, BB_DIR_USR_BIN, BB_SUID_DROP, reset)) + +//kbuild:lib-$(CONFIG_RESET) += reset.o + +//usage:#define reset_trivial_usage +//usage: "" +//usage:#define reset_full_usage "\n\n" +//usage: "Reset terminal (ESC codes) and termios (signals, buffering, echo)" + +/* "Standard" version of this tool is in ncurses package */ + +#include "libbb.h" + +#define ESC "\033" + +#if ENABLE_STTY +int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +#endif + +int reset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + static const char *const args[] ALIGN_PTR = { + "stty", "sane", NULL + }; + + /* no options, no getopt */ + + if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) { + /* See 'man 4 console_codes' for details: + * "ESC c" -- Reset + * "ESC ( B" -- Select G0 Character Set (B = US) + * "ESC [ m" -- Reset all display attributes + * "ESC [ J" -- Erase to the end of screen + * "ESC [ ? 25 h" -- Make cursor visible + */ + printf(ESC"c" ESC"(B" ESC"[m" ESC"[J" ESC"[?25h"); + /* http://bugs.busybox.net/view.php?id=1414: + * people want it to reset echo etc: */ +#if ENABLE_STTY + return stty_main(2, (char**)args); +#else + /* Make sure stdout gets drained before we execvp */ + fflush_all(); + execvp("stty", (char**)args); +#endif + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/resize.c b/busybox-1_37_0/console-tools/resize.c new file mode 100644 index 000000000..6fa7ce9ea --- /dev/null +++ b/busybox-1_37_0/console-tools/resize.c @@ -0,0 +1,115 @@ +/* vi: set sw=4 ts=4: */ +/* + * resize - set terminal width and height. + * + * Copyright 2006 Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RESIZE +//config: bool "resize (1.2 kb)" +//config: default y +//config: help +//config: This program is used to (re)set the width and height of your current +//config: terminal. +//config: +//config:config FEATURE_RESIZE_PRINT +//config: bool "Print environment variables" +//config: default y +//config: depends on RESIZE +//config: help +//config: Prints the newly set size (number of columns and rows) of +//config: the terminal. +//config: E.g.: +//config: COLUMNS=80;LINES=44;export COLUMNS LINES; + +//applet:IF_RESIZE(APPLET_NOEXEC(resize, resize, BB_DIR_USR_BIN, BB_SUID_DROP, resize)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ + +//kbuild:lib-$(CONFIG_RESIZE) += resize.o + +//usage:#define resize_trivial_usage +//usage: "" +//usage:#define resize_full_usage "\n\n" +//usage: "Resize the screen" + +#include "libbb.h" +#include "common_bufsiz.h" + +#define ESC "\033" + +#define old_termios_p ((struct termios*)bb_common_bufsiz1) +#define INIT_G() do { setup_common_bufsiz(); } while (0) + +static void +onintr(int sig UNUSED_PARAM) +{ + tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p); + _exit_FAILURE(); +} + +int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + struct termios new; + struct winsize w = { 0, 0, 0, 0 }; + int ret; + + INIT_G(); + + /* We use _stderr_ in order to make resize usable + * in shell backticks (those redirect stdout away from tty). + * NB: other versions of resize open "/dev/tty" + * and operate on it - should we do the same? + */ + + tcgetattr(STDERR_FILENO, old_termios_p); /* fiddle echo */ +//TODO: die if the above fails? + memcpy(&new, old_termios_p, sizeof(new)); + new.c_cflag |= (CLOCAL | CREAD); + new.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); + bb_signals(0 + + (1 << SIGINT) + + (1 << SIGQUIT) + + (1 << SIGTERM) + + (1 << SIGALRM) + , onintr); + /* Users report: + * The resize command messes up the terminal. + * In my case it looks like it is hanging and + * I need to press ctrl-c to get a prompt. + * Actually the program does not hang but just + * the terminal is messed up. + * Replaced TCSANOW with TCSAFLUSH: + * "the change occurs after all output written to fd + * has been transmitted, and all input that has been + * received but not read will be discarded before + * the change is made. + */ + tcsetattr(STDERR_FILENO, TCSAFLUSH, &new); + + /* save_cursor_pos 7 + * scroll_whole_screen [r + * put_cursor_waaaay_off [$x;$yH + * get_cursor_pos [6n + * restore_cursor_pos 8 + */ + fprintf(stderr, ESC"7" ESC"[r" ESC"[999;999H" ESC"[6n"); + alarm(3); /* Just in case terminal won't answer */ +//BUG: death by signal won't restore termios + scanf(ESC"[%hu;%huR", &w.ws_row, &w.ws_col); + fprintf(stderr, ESC"8"); + + /* BTW, other versions of resize recalculate w.ws_xpixel, ws.ws_ypixel + * by calculating character cell HxW from old values + * (gotten via TIOCGWINSZ) and recomputing *pixel values */ + ret = ioctl(STDERR_FILENO, TIOCSWINSZ, &w); + + tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p); + + if (ENABLE_FEATURE_RESIZE_PRINT) + printf("COLUMNS=%d;LINES=%d;export COLUMNS LINES;\n", + w.ws_col, w.ws_row); + + return ret; +} diff --git a/busybox-1_37_0/console-tools/setconsole.c b/busybox-1_37_0/console-tools/setconsole.c new file mode 100644 index 000000000..4e625890a --- /dev/null +++ b/busybox-1_37_0/console-tools/setconsole.c @@ -0,0 +1,64 @@ +/* vi: set sw=4 ts=4: */ +/* + * setconsole.c - redirect system console output + * + * Copyright (C) 2004,2005 Enrik Berkhan + * Copyright (C) 2008 Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SETCONSOLE +//config: bool "setconsole (3.8 kb)" +//config: default y +//config: help +//config: Redirect writes to /dev/console to another device, +//config: like the current tty while logged in via telnet. +//config: This does not redirect kernel log, only writes +//config: from user space. +//config: +//config:config FEATURE_SETCONSOLE_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on SETCONSOLE && LONG_OPTS + +//applet:IF_SETCONSOLE(APPLET_NOEXEC(setconsole, setconsole, BB_DIR_SBIN, BB_SUID_DROP, setconsole)) + +//kbuild:lib-$(CONFIG_SETCONSOLE) += setconsole.o + +//usage:#define setconsole_trivial_usage +//usage: "[-r] [DEVICE]" +//usage:#define setconsole_full_usage "\n\n" +//usage: "Make writes to /dev/console appear on DEVICE (default: /dev/tty)." +//usage: "\n""Does not redirect kernel log output or reads from /dev/console." +//usage: "\n" +//usage: "\n"" -r Reset: writes to /dev/console go to kernel log tty(s)" + +/* It was a bbox-specific invention, but SUSE does have a similar utility. + * SUSE has no -r option, though. + */ + +#include "libbb.h" + +int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setconsole_main(int argc UNUSED_PARAM, char **argv) +{ + const char *device = CURRENT_TTY; + int reset; + + /* at most one non-option argument */ + reset = getopt32(argv, "^" "r" "\0" "?1"); + + argv += 1 + reset; + if (*argv) { + device = *argv; + } else { + if (reset) + device = DEV_CONSOLE; + } + +//TODO: fails if TIOCCONS redir is already active to some tty. +//I think SUSE version first does TIOCCONS on /dev/console fd (iow: resets) +//then TIOCCONS to new tty? + xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/setkeycodes.c b/busybox-1_37_0/console-tools/setkeycodes.c new file mode 100644 index 000000000..03accec2f --- /dev/null +++ b/busybox-1_37_0/console-tools/setkeycodes.c @@ -0,0 +1,70 @@ +/* vi: set sw=4 ts=4: */ +/* + * setkeycodes + * + * Copyright (C) 1994-1998 Andries E. Brouwer + * + * Adjusted for BusyBox by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SETKEYCODES +//config: bool "setkeycodes (2.4 kb)" +//config: default y +//config: help +//config: This program loads entries into the kernel's scancode-to-keycode +//config: map, allowing unusual keyboards to generate usable keycodes. + +//applet:IF_SETKEYCODES(APPLET_NOEXEC(setkeycodes, setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP, setkeycodes)) + +//kbuild:lib-$(CONFIG_SETKEYCODES) += setkeycodes.o + +//usage:#define setkeycodes_trivial_usage +//usage: "{ SCANCODE KEYCODE }..." +//usage:#define setkeycodes_full_usage "\n\n" +//usage: "Modify kernel's scancode-to-keycode map,\n" +//usage: "allowing unusual keyboards to generate usable keycodes.\n\n" +//usage: "SCANCODE is either xx or e0xx (hexadecimal), KEYCODE is decimal." +//usage: +//usage:#define setkeycodes_example_usage +//usage: "$ setkeycodes e030 127\n" + +#include "libbb.h" + +/* From */ +struct kbkeycode { + unsigned scancode, keycode; +}; +enum { + KDSETKEYCODE = 0x4B4D /* write kernel keycode table entry */ +}; + +int setkeycodes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setkeycodes_main(int argc, char **argv) +{ + int fd; + + if (!(argc & 1) /* if even */ || argc < 2) { + bb_show_usage(); + } + + fd = get_console_fd_or_die(); + + while (argv[1]) { + struct kbkeycode a; + int sc; + + sc = xstrtoul_range(argv[1], 16, 0, 0xe07f); + if (sc >= 0xe000) { + sc -= 0xe000; + sc += 0x0080; + } + a.scancode = sc; + a.keycode = xatou_range(argv[2], 0, 255); + ioctl_or_perror_and_die(fd, KDSETKEYCODE, &a, + "can't set SCANCODE %x to KEYCODE %d", + sc, a.keycode); + argv += 2; + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/setlogcons.c b/busybox-1_37_0/console-tools/setlogcons.c new file mode 100644 index 000000000..a94c0035a --- /dev/null +++ b/busybox-1_37_0/console-tools/setlogcons.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * setlogcons: Send kernel messages to the current console or to console N + * + * Copyright (C) 2006 by Jan Kiszka + * + * Based on setlogcons (kbd-1.12) by Andries E. Brouwer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SETLOGCONS +//config: bool "setlogcons (2 kb)" +//config: default y +//config: help +//config: This program redirects the output console of kernel messages. + +//applet:IF_SETLOGCONS(APPLET_NOEXEC(setlogcons, setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP, setlogcons)) + +//kbuild:lib-$(CONFIG_SETLOGCONS) += setlogcons.o + +//usage:#define setlogcons_trivial_usage +//usage: "[N]" +//usage:#define setlogcons_full_usage "\n\n" +//usage: "Pin kernel output to VT console N. Default:0 (do not pin)" + +// Comment from kernel source: +/* ... + * By default, the kernel messages are always printed on the current virtual + * console. However, the user may modify that default with the + * TIOCL_SETKMSGREDIRECT ioctl call. + * + * This function sets the kernel message console to be @new. It returns the old + * virtual console number. The virtual terminal number 0 (both as parameter and + * return value) means no redirection (i.e. always printed on the currently + * active console). + */ + +#include "libbb.h" + +int setlogcons_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setlogcons_main(int argc UNUSED_PARAM, char **argv) +{ + char *devname; + struct { + char fn; + char subarg; + } arg = { + 11, /* redirect kernel messages (TIOCL_SETKMSGREDIRECT) */ + 0 + }; + + if (argv[1]) + arg.subarg = xatou_range(argv[1], 0, 63); + + /* Can just call it on "/dev/tty1" always, but... + * in my testing, inactive (never opened) VTs are not + * redirected to, despite ioctl not failing. + * + * By using "/dev/ttyN", ensure it is activated. + */ + devname = xasprintf("/dev/tty%u", arg.subarg); + xioctl(xopen(devname, O_RDONLY), TIOCLINUX, &arg); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/console-tools/showkey.c b/busybox-1_37_0/console-tools/showkey.c new file mode 100644 index 000000000..87532a8ac --- /dev/null +++ b/busybox-1_37_0/console-tools/showkey.c @@ -0,0 +1,158 @@ +/* vi: set sw=4 ts=4: */ +/* + * shows keys pressed. inspired by kbd package + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config SHOWKEY +//config: bool "showkey (4.9 kb)" +//config: default y +//config: help +//config: Shows keys pressed. + +//applet:IF_SHOWKEY(APPLET(showkey, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SHOWKEY) += showkey.o + +//usage:#define showkey_trivial_usage +//usage: "[-a | -k | -s]" +//usage:#define showkey_full_usage "\n\n" +//usage: "Show keys pressed\n" +//usage: "\n -a Display decimal/octal/hex values of the keys" +//usage: "\n -k Display interpreted keycodes (default)" +//usage: "\n -s Display raw scan-codes" + +#include "libbb.h" +#include + + +struct globals { + int kbmode; + struct termios tio, tio0; +}; +#define G (*ptr_to_globals) +#define kbmode (G.kbmode) +#define tio (G.tio) +#define tio0 (G.tio0) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + + +// set raw tty mode +// also used by microcom +// libbb candidates? +static void xget1(struct termios *t, struct termios *oldt) +{ + tcgetattr(STDIN_FILENO, oldt); + *t = *oldt; + cfmakeraw(t); +} + +static void xset1(struct termios *t) +{ + int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, t); + if (ret) { + bb_simple_perror_msg("can't tcsetattr for stdin"); + } +} + +int showkey_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int showkey_main(int argc UNUSED_PARAM, char **argv) +{ + enum { + OPT_a = (1<<0), // display the decimal/octal/hex values of the keys + OPT_k = (1<<1), // display only the interpreted keycodes (default) + OPT_s = (1<<2), // display only the raw scan-codes + }; + + INIT_G(); + + // FIXME: aks are all mutually exclusive + getopt32(argv, "aks"); + + // prepare for raw mode + xget1(&tio, &tio0); + // put stdin in raw mode + xset1(&tio); + +#define press_keys "Press any keys, program terminates %s:\r\n\n" + + if (option_mask32 & OPT_a) { + // just read stdin char by char + unsigned char c; + + printf(press_keys, "on EOF (ctrl-D)"); + + // read and show byte values + while (1 == read(STDIN_FILENO, &c, 1)) { + printf("%3u 0%03o 0x%02x\r\n", c, c, c); + if (04 /*CTRL-D*/ == c) + break; + } + } else { + // we assume a PC keyboard + xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); + printf("Keyboard mode was %s.\r\n\n", + kbmode == K_RAW ? "RAW" : + (kbmode == K_XLATE ? "XLATE" : + (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : + (kbmode == K_UNICODE ? "UNICODE" : "UNKNOWN"))) + ); + + // set raw keyboard mode + xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)((option_mask32 & OPT_k) ? K_MEDIUMRAW : K_RAW)); + + // we should exit on any signal; signals should interrupt read + bb_signals_norestart(BB_FATAL_SIGS, record_signo); + + // inform user that program ends after time of inactivity + printf(press_keys, "10s after last keypress"); + + // read and show scancodes + while (!bb_got_signal) { + char buf[18]; + int i, n; + + // setup 10s watchdog + alarm(10); + + // read scancodes + n = read(STDIN_FILENO, buf, sizeof(buf)); + i = 0; + while (i < n) { + if (option_mask32 & OPT_s) { + // show raw scancodes + printf("0x%02x ", buf[i++]); + } else { + // show interpreted scancodes (default) + char c = buf[i]; + int kc; + if (i+2 < n + && (c & 0x7f) == 0 + && (buf[i+1] & 0x80) != 0 + && (buf[i+2] & 0x80) != 0 + ) { + kc = ((buf[i+1] & 0x7f) << 7) | (buf[i+2] & 0x7f); + i += 3; + } else { + kc = (c & 0x7f); + i++; + } + printf("keycode %3u %s", kc, (c & 0x80) ? "release" : "press"); + } + } + puts("\r"); + } + + // restore keyboard mode + xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); + } + + // restore console settings + xset1(&tio0); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/Config.src b/busybox-1_37_0/coreutils/Config.src new file mode 100644 index 000000000..6c9e47551 --- /dev/null +++ b/busybox-1_37_0/coreutils/Config.src @@ -0,0 +1,51 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Coreutils" + +config FEATURE_VERBOSE + bool "Support verbose options (usually -v) for various applets" + default y + help + Enable cp -v, rm -v and similar messages. + Also enables long option (--verbose) if it exists. + Without this option, -v is accepted but ignored. + +comment "Common options for date and touch" + +config FEATURE_TIMEZONE + bool "Allow timezone in dates" + default y + depends on DESKTOP + help + Permit the use of timezones when parsing user-provided data + strings, e.g. '1996-04-09 12:45:00 -0500'. + + This requires support for the '%z' extension to strptime() which + may not be available in all implementations. + +comment "Common options for cp and mv" + depends on CP || MV + +config FEATURE_PRESERVE_HARDLINKS + bool "Preserve hard links" + default y + depends on CP || MV + help + Allow cp and mv to preserve hard links. + +comment "Common options for df, du, ls" + depends on DF || DU || LS + +config FEATURE_HUMAN_READABLE + bool "Support human readable output (example 13k, 23M, 235G)" + default y + depends on DF || DU || LS + help + Allow df, du, and ls to have human readable output. + +INSERT + +endmenu diff --git a/busybox-1_37_0/coreutils/Kbuild.src b/busybox-1_37_0/coreutils/Kbuild.src new file mode 100644 index 000000000..a805b64fe --- /dev/null +++ b/busybox-1_37_0/coreutils/Kbuild.src @@ -0,0 +1,18 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +libs-y += libcoreutils/ + +lib-y:= + +INSERT + +lib-$(CONFIG_MORE) += cat.o # more uses it if stdout isn't a tty +lib-$(CONFIG_LESS) += cat.o # less too +lib-$(CONFIG_CRONTAB) += cat.o # crontab -l +lib-$(CONFIG_ADDUSER) += chown.o # used by adduser +lib-$(CONFIG_ADDGROUP) += chown.o # used by addgroup +lib-$(CONFIG_FTPD) += ls.o # used by ftpd diff --git a/busybox-1_37_0/coreutils/basename.c b/busybox-1_37_0/coreutils/basename.c new file mode 100644 index 000000000..bf7bd62e0 --- /dev/null +++ b/busybox-1_37_0/coreutils/basename.c @@ -0,0 +1,92 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini basename implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Changes: + * 1) Now checks for too many args. Need at least one and at most two. + * 2) Don't check for options, as per SUSv3. + * 3) Save some space by using strcmp(). Calling strncmp() here was silly. + */ +//config:config BASENAME +//config: bool "basename (3.7 kb)" +//config: default y +//config: help +//config: basename is used to strip the directory and suffix from filenames, +//config: leaving just the filename itself. Enable this option if you wish +//config: to enable the 'basename' utility. + +//applet:IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename)) + +//kbuild:lib-$(CONFIG_BASENAME) += basename.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/basename.html */ + +//usage:#define basename_trivial_usage +//usage: "FILE [SUFFIX] | -a FILE... | -s SUFFIX FILE..." +//usage:#define basename_full_usage "\n\n" +//usage: "Strip directory path and SUFFIX from FILE\n" +//usage: "\n -a All arguments are FILEs" +//usage: "\n -s SUFFIX Remove SUFFIX (implies -a)" +//usage: +//usage:#define basename_example_usage +//usage: "$ basename /usr/local/bin/foo\n" +//usage: "foo\n" +//usage: "$ basename /usr/local/bin/\n" +//usage: "bin\n" +//usage: "$ basename /foo/bar.txt .txt\n" +//usage: "bar" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int basename_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int basename_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + const char *suffix = NULL; + + /* '+': stop at first non-option */ + opts = getopt32(argv, "^+" "as:" + "\0" "-1" /* At least one argument */ + , &suffix + ); + argv += optind; + + do { + char *s; + size_t m; + + /* It should strip slash: /abc/def/ -> def */ + s = bb_get_last_path_component_strip(*argv++); + m = strlen(s); + if (!opts) { + if (*argv) { + suffix = *argv; + if (argv[1]) + bb_show_usage(); + } + } + if (suffix) { + size_t n = strlen(suffix); + if ((m > n) && (strcmp(s + m - n, suffix) == 0)) { + m -= n; + /*s[m] = '\0'; - redundant */ + } + } + /* puts(s) will do, but we can do without stdio this way: */ + s[m++] = '\n'; + /* NB: != is correct here: */ + if (full_write(STDOUT_FILENO, s, m) != (ssize_t)m) + return EXIT_FAILURE; + } while (opts && *argv); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/cat.c b/busybox-1_37_0/coreutils/cat.c new file mode 100644 index 000000000..558869b2a --- /dev/null +++ b/busybox-1_37_0/coreutils/cat.c @@ -0,0 +1,217 @@ +/* vi: set sw=4 ts=4: */ +/* + * cat implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config CAT +//config: bool "cat (5.8 kb)" +//config: default y +//config: help +//config: cat is used to concatenate files and print them to the standard +//config: output. Enable this option if you wish to enable the 'cat' utility. +//config: +//config:config FEATURE_CATN +//config: bool "Enable -n and -b options" +//config: default y +//config: depends on CAT +//config: help +//config: -n numbers all output lines while -b numbers nonempty output lines. +//config: +//config:config FEATURE_CATV +//config: bool "cat -v[etA]" +//config: default y +//config: depends on CAT +//config: help +//config: Display nonprinting characters as escape sequences + +//applet:IF_CAT(APPLET(cat, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CAT) += cat.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/cat.html */ + +//usage:#if ENABLE_FEATURE_CATN || ENABLE_FEATURE_CATV +//usage:#define cat_trivial_usage +//usage: "[-" IF_FEATURE_CATN("nb") IF_FEATURE_CATV("vteA") "] [FILE]..." +//usage:#else +//usage:#define cat_trivial_usage +//usage: "[FILE]..." +//usage:#endif +//usage:#define cat_full_usage "\n\n" +//usage: "Print FILEs to stdout\n" +//usage: IF_FEATURE_CATN( +//usage: "\n -n Number output lines" +//usage: "\n -b Number nonempty lines" +//usage: ) +//usage: IF_FEATURE_CATV( +//usage: "\n -v Show nonprinting characters as ^x or M-x" +//usage: "\n -t ...and tabs as ^I" +//usage: "\n -e ...and end lines with $" +//usage: "\n -A Same as -vte" +//usage: ) +/* + Longopts not implemented yet: + --number-nonblank number nonempty output lines, overrides -n + --number number all output lines + --show-nonprinting use ^ and M- notation, except for LFD and TAB + --show-all equivalent to -vet + Not implemented yet: + -E, --show-ends display $ at end of each line (-e sans -v) + -T, --show-tabs display TAB characters as ^I (-t sans -v) + -s, --squeeze-blank suppress repeated empty output lines +*/ +//usage: +//usage:#define cat_example_usage +//usage: "$ cat /proc/uptime\n" +//usage: "110716.72 17.67" + +#include "libbb.h" +#include "common_bufsiz.h" + +#if ENABLE_FEATURE_CATV +/* + * cat -v implementation for busybox + * + * Copyright (C) 2006 Rob Landley + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Rob had "cat -v" implemented as a separate applet, catv. + * See "cat -v considered harmful" at + * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz + * From USENIX Summer Conference Proceedings, 1983 + * """ + * The talk reviews reasons for UNIX's popularity and shows, using UCB cat + * as a primary example, how UNIX has grown fat. cat isn't for printing + * files with line numbers, it isn't for compressing multiple blank lines, + * it's not for looking at non-printing ASCII characters, it's for + * concatenating files. + * We are reminded that ls isn't the place for code to break a single column + * into multiple ones, and that mailnews shouldn't have its own more + * processing or joke encryption code. + * """ + * + * I agree with the argument. Unfortunately, this ship has sailed (1983...). + * There are dozens of Linux distros and each of them has "cat" which supports -v. + * It's unrealistic for us to "reeducate" them to use our, incompatible way + * to achieve "cat -v" effect. The actual effect would be "users pissed off + * by gratuitous incompatibility". + */ +#define CAT_OPT_e (1<<0) +#define CAT_OPT_t (1<<1) +#define CAT_OPT_v (1<<2) +/* -A occupies bit (1<<3) */ +#define CAT_OPT_n ((1<<4) * ENABLE_FEATURE_CATN) +#define CAT_OPT_b ((1<<5) * ENABLE_FEATURE_CATN) +static int catv(unsigned opts, char **argv) +{ + int retval = EXIT_SUCCESS; + int fd; +#if ENABLE_FEATURE_CATN + bool eol_seen = (opts & (CAT_OPT_n|CAT_OPT_b)); + unsigned eol_char = (eol_seen ? '\n' : 0x100); + unsigned skip_num_on = (opts & CAT_OPT_b) ? '\n' : 0x100; + unsigned lineno = 0; +#endif + + BUILD_BUG_ON(CAT_OPT_e != VISIBLE_ENDLINE); + BUILD_BUG_ON(CAT_OPT_t != VISIBLE_SHOW_TABS); +#if 0 /* These consts match, we can just pass "opts" to visible() */ + if (opts & CAT_OPT_e) + flags |= VISIBLE_ENDLINE; + if (opts & CAT_OPT_t) + flags |= VISIBLE_SHOW_TABS; +#endif + +#define read_buf bb_common_bufsiz1 + setup_common_bufsiz(); + do { + fd = open_or_warn_stdin(*argv); + if (fd < 0) { + retval = EXIT_FAILURE; + continue; + } + for (;;) { + int i, res; + + res = read(fd, read_buf, COMMON_BUFSIZE); + if (res < 0) + retval = EXIT_FAILURE; + if (res <= 0) + break; + for (i = 0; i < res; i++) { + unsigned char c = read_buf[i]; + char buf[sizeof("M-^c")]; +#if ENABLE_FEATURE_CATN + if (eol_seen && c != skip_num_on) + printf("%6u ", ++lineno); + eol_seen = (c == eol_char); +#endif + visible(c, buf, opts); + fputs_stdout(buf); + } + } + if (ENABLE_FEATURE_CLEAN_UP && fd) + close(fd); + } while (*++argv); + + fflush_stdout_and_exit(retval); +} +#undef CAT_OPT_n +#undef CAT_OPT_b +#endif + +int cat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cat_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_FEATURE_CATV || ENABLE_FEATURE_CATN + unsigned opts; + + opts = +#endif + getopt32(argv, IF_FEATURE_CATV("^") + /* -u is ignored ("unbuffered") */ + IF_FEATURE_CATV("etvA")IF_FEATURE_CATN("nb")"u" + IF_FEATURE_CATV("\0" "Aetv" /* -A == -vet */) + ); + argv += optind; + + /* Read from stdin if there's nothing else to do. */ + if (!argv[0]) + *--argv = (char*)"-"; + +#if ENABLE_FEATURE_CATV + if (opts & 7) + return catv(opts, argv); + opts >>= 4; +#endif + +#if ENABLE_FEATURE_CATN +# define CAT_OPT_n (1<<0) +# define CAT_OPT_b (1<<1) + if (opts & (CAT_OPT_n|CAT_OPT_b)) { /* -n or -b */ + struct number_state ns; + int exitcode; + + ns.width = 6; + ns.start = 1; + ns.inc = 1; + ns.sep = "\t"; + ns.empty_str = NULL; + ns.all = !(opts & CAT_OPT_b); /* -n without -b */ + ns.nonempty = (opts & CAT_OPT_b); /* -b (with or without -n) */ + exitcode = EXIT_SUCCESS; + do { + exitcode |= print_numbered_lines(&ns, *argv); + } while (*++argv); + fflush_stdout_and_exit(exitcode); + } + /*opts >>= 2;*/ +#endif + + return bb_cat(argv); +} diff --git a/busybox-1_37_0/coreutils/chgrp.c b/busybox-1_37_0/coreutils/chgrp.c new file mode 100644 index 000000000..e6ac316e5 --- /dev/null +++ b/busybox-1_37_0/coreutils/chgrp.c @@ -0,0 +1,66 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chgrp implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CHGRP +//config: bool "chgrp (7.6 kb)" +//config: default y +//config: help +//config: chgrp is used to change the group ownership of files. + +//applet:IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, BB_DIR_BIN, BB_SUID_DROP, chgrp)) + +//kbuild:lib-$(CONFIG_CHGRP) += chgrp.o chown.o + +/* BB_AUDIT SUSv3 defects - none? */ +/* BB_AUDIT GNU defects - unsupported long options. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/chgrp.html */ + +//usage:#define chgrp_trivial_usage +//usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... GROUP FILE..." +//usage:#define chgrp_full_usage "\n\n" +//usage: "Change the group membership of FILEs to GROUP" +//usage: "\n" +//usage: "\n -h Affect symlinks instead of symlink targets" +//usage: IF_DESKTOP( +//usage: "\n -L Traverse all symlinks to directories" +//usage: "\n -H Traverse symlinks on command line only" +//usage: "\n -P Don't traverse symlinks (default)" +//usage: ) +//next 4 options are the same for chmod/chown/chgrp: +//usage: "\n -R Recurse" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v Verbose" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chgrp_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chgrp root /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + + +int chgrp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chgrp_main(int argc, char **argv) +{ + /* "chgrp [opts] abc file(s)" == "chown [opts] :abc file(s)" */ + char **p = argv; + while (*++p) { + if (p[0][0] != '-') { + p[0] = xasprintf(":%s", p[0]); + break; + } + } + return chown_main(argc, argv); +} diff --git a/busybox-1_37_0/coreutils/chmod.c b/busybox-1_37_0/coreutils/chmod.c new file mode 100644 index 000000000..5832cc51b --- /dev/null +++ b/busybox-1_37_0/coreutils/chmod.c @@ -0,0 +1,194 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chmod implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Reworked by (C) 2002 Vladimir Oleynik + * to correctly parse '-rwxgoa' + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CHMOD +//config: bool "chmod (5.5 kb)" +//config: default y +//config: help +//config: chmod is used to change the access permission of files. + +//applet:IF_CHMOD(APPLET_NOEXEC(chmod, chmod, BB_DIR_BIN, BB_SUID_DROP, chmod)) + +//kbuild:lib-$(CONFIG_CHMOD) += chmod.o + +/* BB_AUDIT SUSv3 compliant */ +/* BB_AUDIT GNU defects - unsupported long options. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ + +//usage:#define chmod_trivial_usage +//usage: "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..." +//usage:#define chmod_full_usage "\n\n" +//usage: "MODE is octal number (bit pattern sstrwxrwxrwx) or [ugoa]{+|-|=}[rwxXst]" +//usage: "\n" +//next 4 options are the same for chmod/chown/chgrp: +//usage: "\n -R Recurse" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v Verbose" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chmod_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chmod u+x /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" +//usage: "$ chmod 444 /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + + +#define OPT_RECURSE (option_mask32 & 1) +#define OPT_VERBOSE (IF_DESKTOP(option_mask32 & 2) IF_NOT_DESKTOP(0)) +#define OPT_CHANGED (IF_DESKTOP(option_mask32 & 4) IF_NOT_DESKTOP(0)) +#define OPT_QUIET (IF_DESKTOP(option_mask32 & 8) IF_NOT_DESKTOP(0)) +#define OPT_STR "R" IF_DESKTOP("vcf") + +/* coreutils: + * chmod never changes the permissions of symbolic links; the chmod + * system call cannot change their permissions. This is not a problem + * since the permissions of symbolic links are never used. + * However, for each symbolic link listed on the command line, chmod changes + * the permissions of the pointed-to file. In contrast, chmod ignores + * symbolic links encountered during recursive directory traversals. + */ + +static int FAST_FUNC fileAction(struct recursive_state *state, + const char *fileName, + struct stat *statbuf) +{ + mode_t newmode; + + /* match coreutils behavior */ + if (state->depth == 0) { + /* statbuf holds lstat result, but we need stat (follow link) */ + if (stat(fileName, statbuf)) + goto err; + } else { /* depth > 0: skip links */ + if (S_ISLNK(statbuf->st_mode)) + return TRUE; + } + + newmode = bb_parse_mode((char *)state->userData, statbuf->st_mode); + if (newmode == (mode_t)-1) + bb_error_msg_and_die("invalid mode '%s'", (char *)state->userData); + + if (chmod(fileName, newmode) == 0) { + if (OPT_VERBOSE + || (OPT_CHANGED + && (statbuf->st_mode & 07777) != (newmode & 07777)) + ) { + char modestr[12]; + printf("mode of '%s' changed to %04o (%s)\n", fileName, + newmode & 07777, bb_mode_string(modestr, newmode)+1); + } + return TRUE; + } + err: + if (!OPT_QUIET) + bb_simple_perror_msg(fileName); + return FALSE; +} + +int chmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chmod_main(int argc UNUSED_PARAM, char **argv) +{ + int retval = EXIT_SUCCESS; + char *arg, **argp; + char *smode; + + /* Convert first encountered -r into ar, -w into aw etc + * so that getopt would not eat it */ + argp = argv; + while ((arg = *++argp)) { + /* Mode spec must be the first arg (sans -R etc) */ + /* (protect against mishandling e.g. "chmod 644 -r") */ + if (arg[0] != '-') { + arg = NULL; + break; + } + /* An option. Not a -- or valid option? */ + if (arg[1] && !strchr("-"OPT_STR, arg[1])) { + arg[0] = 'a'; + break; + } + } + + /* Parse options */ + getopt32(argv, "^" OPT_STR "\0" "-2"); + argv += optind; + + /* Restore option-like mode if needed */ + if (arg) arg[0] = '-'; + + /* Ok, ready to do the deed now */ + smode = *argv++; + do { + if (!recursive_action(*argv, + OPT_RECURSE, // recurse + fileAction, // file action + fileAction, // dir action + smode) // user data + ) { + retval = EXIT_FAILURE; + } + } while (*++argv); + + return retval; +} + +/* +Security: chmod is too important and too subtle. +This is a test script (busybox chmod versus coreutils). +Run it in empty directory. + +#!/bin/sh +t1="/tmp/busybox chmod" +t2="/usr/bin/chmod" +create() { + rm -rf $1; mkdir $1 + ( + cd $1 || exit 1 + mkdir dir + >up + >file + >dir/file + ln -s dir linkdir + ln -s file linkfile + ln -s ../up dir/up + ) +} +tst() { + (cd test1; $t1 $1) + (cd test2; $t2 $1) + (cd test1; ls -lR) >out1 + (cd test2; ls -lR) >out2 + echo "chmod $1" >out.diff + if ! diff -u out1 out2 >>out.diff; then exit 1; fi + rm out.diff +} +echo "If script produced 'out.diff' file, then at least one testcase failed" +create test1; create test2 +tst "a+w file" +tst "a-w dir" +tst "a+w linkfile" +tst "a-w linkdir" +tst "-R a+w file" +tst "-R a-w dir" +tst "-R a+w linkfile" +tst "-R a-w linkdir" +tst "a-r,a+x linkfile" +*/ diff --git a/busybox-1_37_0/coreutils/chown.c b/busybox-1_37_0/coreutils/chown.c new file mode 100644 index 000000000..528a2a05a --- /dev/null +++ b/busybox-1_37_0/coreutils/chown.c @@ -0,0 +1,235 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chown implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CHOWN +//config: bool "chown (7.6 kb)" +//config: default y +//config: help +//config: chown is used to change the user and/or group ownership +//config: of files. +//config: +//config:config FEATURE_CHOWN_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on CHOWN && LONG_OPTS + +//applet:IF_CHOWN(APPLET_NOEXEC(chown, chown, BB_DIR_BIN, BB_SUID_DROP, chown)) + +//kbuild:lib-$(CONFIG_CHOWN) += chown.o + +/* BB_AUDIT SUSv3 defects - none? */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */ + +//usage:#define chown_trivial_usage +//usage: "[-Rh"IF_DESKTOP("LHPcvf")"]... USER[:[GRP]] FILE..." +//usage:#define chown_full_usage "\n\n" +//usage: "Change the owner and/or group of FILEs to USER and/or GRP" +//usage: "\n" +//usage: "\n -h Affect symlinks instead of symlink targets" +//usage: IF_DESKTOP( +//usage: "\n -L Traverse all symlinks to directories" +//usage: "\n -H Traverse symlinks on command line only" +//usage: "\n -P Don't traverse symlinks (default)" +//usage: ) +//next 4 options are the same for chmod/chown/chgrp: +//usage: "\n -R Recurse" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v Verbose" +//usage: "\n -f Hide errors" +//usage: ) +//usage: +//usage:#define chown_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chown root /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" +//usage: "$ chown root.root /tmp/foo\n" +//usage: "ls -l /tmp/foo\n" +//usage: "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + + +#define OPT_STR "Rh" IF_DESKTOP("vcfLHP") +#define BIT_RECURSE 1 +#define OPT_RECURSE (opt & 1) +#define OPT_NODEREF (opt & 2) +#define OPT_VERBOSE (IF_DESKTOP(opt & 0x04) IF_NOT_DESKTOP(0)) +#define OPT_CHANGED (IF_DESKTOP(opt & 0x08) IF_NOT_DESKTOP(0)) +#define OPT_QUIET (IF_DESKTOP(opt & 0x10) IF_NOT_DESKTOP(0)) +/* POSIX options + * -L traverse every symbolic link to a directory encountered + * -H if a command line argument is a symbolic link to a directory, traverse it + * -P do not traverse any symbolic links (default) + * We do not conform to the following: + * "Specifying more than one of -H, -L, and -P is not an error. + * The last option specified shall determine the behavior of the utility." */ +/* -L */ +#define BIT_TRAVERSE 0x20 +#define OPT_TRAVERSE (IF_DESKTOP(opt & BIT_TRAVERSE) IF_NOT_DESKTOP(0)) +/* -H or -L */ +#define BIT_TRAVERSE_TOP (0x20|0x40) +#define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0)) + +#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS +static const char chown_longopts[] ALIGN1 = + "recursive\0" No_argument "R" + "dereference\0" No_argument "\xff" + "no-dereference\0" No_argument "h" +# if ENABLE_DESKTOP + "changes\0" No_argument "c" + "silent\0" No_argument "f" + "quiet\0" No_argument "f" + "verbose\0" No_argument "v" +# endif + ; +#endif + +typedef int (*chown_fptr)(const char *, uid_t, gid_t); + +struct param_t { + struct bb_uidgid_t ugid; + chown_fptr chown_func; +}; + +static int FAST_FUNC fileAction(struct recursive_state *state UNUSED_PARAM, + const char *fileName, struct stat *statbuf) +{ +#define param (*(struct param_t*)state->userData) +#define opt option_mask32 + uid_t u = (param.ugid.uid == (uid_t)-1L) ? statbuf->st_uid : param.ugid.uid; + gid_t g = (param.ugid.gid == (gid_t)-1L) ? statbuf->st_gid : param.ugid.gid; + + if (param.chown_func(fileName, u, g) == 0) { + if (OPT_VERBOSE + || (OPT_CHANGED && (statbuf->st_uid != u || statbuf->st_gid != g)) + ) { + printf("changed ownership of '%s' to %u:%u\n", + fileName, (unsigned)u, (unsigned)g); + } + return TRUE; + } + if (!OPT_QUIET) + bb_simple_perror_msg(fileName); + return FALSE; +#undef opt +#undef param +} + +int chown_main(int argc UNUSED_PARAM, char **argv) +{ + int retval = EXIT_SUCCESS; + int opt, flags; + struct param_t param; + +#if ENABLE_FEATURE_CHOWN_LONG_OPTIONS + opt = getopt32long(argv, "^" OPT_STR "\0" "-2", chown_longopts); +#else + opt = getopt32(argv, "^" OPT_STR "\0" "-2"); +#endif + argv += optind; + + /* This matches coreutils behavior (almost - see below) */ + param.chown_func = chown; + if (OPT_NODEREF + /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */ + IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE) + ) { + param.chown_func = lchown; + } + + flags = ACTION_DEPTHFIRST; /* match coreutils order */ + if (OPT_RECURSE) + flags |= ACTION_RECURSE; + if (OPT_TRAVERSE_TOP) + flags |= ACTION_FOLLOWLINKS_L0; /* -H/-L: follow links on depth 0 */ + if (OPT_TRAVERSE) + flags |= ACTION_FOLLOWLINKS; /* follow links if -L */ + + parse_chown_usergroup_or_die(¶m.ugid, argv[0]); + + /* Ok, ready to do the deed now */ + while (*++argv) { + if (!recursive_action(*argv, + flags, /* flags */ + fileAction, /* file action */ + fileAction, /* dir action */ + ¶m) /* user data */ + ) { + retval = EXIT_FAILURE; + } + } + + return retval; +} + +/* +Testcase. Run in empty directory. + +#!/bin/sh +t1="/tmp/busybox chown" +t2="/usr/bin/chown" +create() { + rm -rf $1; mkdir $1 + ( + cd $1 || exit 1 + mkdir dir dir2 + >up + >file + >dir/file + >dir2/file + ln -s dir linkdir + ln -s file linkfile + ln -s ../up dir/linkup + ln -s ../dir2 dir/linkupdir2 + ) + chown -R 0:0 $1 +} +tst() { + create test1 + create test2 + echo "[$1]" >>test1.out + echo "[$1]" >>test2.out + (cd test1; $t1 $1) >>test1.out 2>&1 + (cd test2; $t2 $1) >>test2.out 2>&1 + (cd test1; ls -lnR) >out1 + (cd test2; ls -lnR) >out2 + echo "chown $1" >out.diff + if ! diff -u out1 out2 >>out.diff; then exit 1; fi + rm out.diff +} +tst_for_each() { + tst "$1 1:1 file" + tst "$1 1:1 dir" + tst "$1 1:1 linkdir" + tst "$1 1:1 linkfile" +} +echo "If script produced 'out.diff' file, then at least one testcase failed" +>test1.out +>test2.out +# These match coreutils 6.8: +tst_for_each "-v" +tst_for_each "-vR" +tst_for_each "-vRP" +tst_for_each "-vRL" +tst_for_each "-vRH" +tst_for_each "-vh" +tst_for_each "-vhR" +tst_for_each "-vhRP" +tst_for_each "-vhRL" +tst_for_each "-vhRH" +# Fix `name' in coreutils output +sed 's/`/'"'"'/g' -i test2.out +# Compare us with coreutils output +diff -u test1.out test2.out + +*/ diff --git a/busybox-1_37_0/coreutils/chroot.c b/busybox-1_37_0/coreutils/chroot.c new file mode 100644 index 000000000..0b45aa80c --- /dev/null +++ b/busybox-1_37_0/coreutils/chroot.c @@ -0,0 +1,55 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini chroot implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CHROOT +//config: bool "chroot (4 kb)" +//config: default y +//config: help +//config: chroot is used to change the root directory and run a command. +//config: The default command is '/bin/sh'. + +//applet:IF_CHROOT(APPLET_NOEXEC(chroot, chroot, BB_DIR_USR_SBIN, BB_SUID_DROP, chroot)) + +//kbuild:lib-$(CONFIG_CHROOT) += chroot.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define chroot_trivial_usage +//usage: "NEWROOT [PROG ARGS]" +//usage:#define chroot_full_usage "\n\n" +//usage: "Run PROG with root directory set to NEWROOT" +//usage: +//usage:#define chroot_example_usage +//usage: "$ ls -l /bin/ls\n" +//usage: "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" +//usage: "# mount /dev/hdc1 /mnt -t minix\n" +//usage: "# chroot /mnt\n" +//usage: "# ls -l /bin/ls\n" +//usage: "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" + +#include "libbb.h" + +int chroot_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chroot_main(int argc UNUSED_PARAM, char **argv) +{ + ++argv; + if (!*argv) + bb_show_usage(); + + xchroot(*argv); + + ++argv; + if (!*argv) { /* no 2nd param (PROG), use shell */ + argv -= 2; + argv[0] = (char *) get_shell_name(); + argv[1] = (char *) "-i"; /* GNU coreutils 8.4 compat */ + /*argv[2] = NULL; - already is */ + } + + BB_EXECVP_or_die(argv); +} diff --git a/busybox-1_37_0/coreutils/cksum.c b/busybox-1_37_0/coreutils/cksum.c new file mode 100644 index 000000000..1fb6ef2d0 --- /dev/null +++ b/busybox-1_37_0/coreutils/cksum.c @@ -0,0 +1,106 @@ +/* vi: set sw=4 ts=4: */ +/* + * cksum - calculate the CRC32 checksum of a file + * + * Copyright (C) 2006 by Rob Sullivan, with ideas from code by Walter Harms + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CKSUM +//config: bool "cksum (4.3 kb)" +//config: default y +//config: +//config:config CRC32 +//config: bool "crc32 (4.2 kb)" +//config: default y + +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) +//applet:IF_CRC32(APPLET_NOEXEC(crc32, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ + +//kbuild:lib-$(CONFIG_CKSUM) += cksum.o +//kbuild:lib-$(CONFIG_CRC32) += cksum.o + +//usage:#define cksum_trivial_usage +//usage: "FILE..." +//usage:#define cksum_full_usage "\n\n" +//usage: "Calculate CRC32 checksum of FILEs" + +#include "libbb.h" +#include "common_bufsiz.h" + +/* This is a NOEXEC applet. Be very careful! */ + +#define IS_CKSUM (ENABLE_CKSUM && (!ENABLE_CRC32 || applet_name[1] == 'k')) +#define IS_CRC32 (ENABLE_CRC32 && (!ENABLE_CKSUM || applet_name[1] == 'r')) + +int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cksum_main(int argc UNUSED_PARAM, char **argv) +{ + uint32_t *crc32_table = crc32_filltable(NULL, IS_CKSUM); + exitcode_t exit_code = EXIT_SUCCESS; + +#if ENABLE_DESKTOP + getopt32(argv, ""); /* cksum coreutils 6.9 compat */ + argv += optind; +#else + argv++; +#endif + + setup_common_bufsiz(); + do { + uint32_t crc; + IF_CKSUM(off_t filesize;) + const char *fname = *argv ? *argv : bb_msg_standard_input; + int fd = open_or_warn_stdin(fname); + + if (fd < 0) { + exit_code = EXIT_FAILURE; + continue; + } + + crc = IS_CKSUM ? 0 : 0xffffffff; + IF_CKSUM(filesize = 0;) +#define read_buf bb_common_bufsiz1 + for (;;) { + int bytes_read = safe_read(fd, read_buf, COMMON_BUFSIZE); + if (bytes_read < 0) + bb_simple_perror_msg_and_die(fname); + if (bytes_read > 0) { + IF_CKSUM(filesize += bytes_read;) + } else { + IF_CKSUM(uoff_t t;) + + close(fd); + if (IS_CRC32) + break; +#if ENABLE_CKSUM + fd = -1; /* break flag */ + /* Checksum filesize bytes, LSB first */ + t = filesize; + /*bytes_read = 0; - already is */ + while (t != 0) { + read_buf[bytes_read++] = (uint8_t)t; + t >>= 8; + } +#endif + } + crc = (IS_CKSUM ? crc32_block_endian1 : crc32_block_endian0)(crc, read_buf, bytes_read, crc32_table); + if (ENABLE_CKSUM && fd < 0) + break; + } + + crc = ~crc; +#if ENABLE_CKSUM + if (IS_CKSUM) + printf((*argv ? "%u %"OFF_FMT"u %s\n" : "%u %"OFF_FMT"u\n"), + (unsigned)crc, filesize, *argv); + else +#endif + printf((*argv ? "%08x %s\n" : "%08x\n"), + (unsigned)crc, *argv); + } while (*argv && *++argv); + + fflush_stdout_and_exit(exit_code); +} diff --git a/busybox-1_37_0/coreutils/comm.c b/busybox-1_37_0/coreutils/comm.c new file mode 100644 index 000000000..6cbdceaa9 --- /dev/null +++ b/busybox-1_37_0/coreutils/comm.c @@ -0,0 +1,117 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini comm implementation for busybox + * + * Copyright (C) 2005 by Robert Sullivan + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config COMM +//config: bool "comm (4.4 kb)" +//config: default y +//config: help +//config: comm is used to compare two files line by line and return +//config: a three-column output. + +//applet:IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_COMM) += comm.o + +//usage:#define comm_trivial_usage +//usage: "[-123] FILE1 FILE2" +//usage:#define comm_full_usage "\n\n" +//usage: "Compare FILE1 with FILE2\n" +//usage: "\n -1 Suppress lines unique to FILE1" +//usage: "\n -2 Suppress lines unique to FILE2" +//usage: "\n -3 Suppress lines common to both files" + +#include "libbb.h" + +#define COMM_OPT_1 (1 << 0) +#define COMM_OPT_2 (1 << 1) +#define COMM_OPT_3 (1 << 2) + +/* writeline outputs the input given, appropriately aligned according to class */ +static void writeline(char *line, int class) +{ + int flags = option_mask32; + if (class == 0) { + if (flags & COMM_OPT_1) + return; + } else if (class == 1) { + if (flags & COMM_OPT_2) + return; + if (!(flags & COMM_OPT_1)) + putchar('\t'); + } else /*if (class == 2)*/ { + if (flags & COMM_OPT_3) + return; + if (!(flags & COMM_OPT_1)) + putchar('\t'); + if (!(flags & COMM_OPT_2)) + putchar('\t'); + } + puts(line); +} + +int comm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int comm_main(int argc UNUSED_PARAM, char **argv) +{ + char *thisline[2]; + FILE *stream[2]; + int i; + int order; + + getopt32(argv, "^" "123" "\0" "=2"); + argv += optind; + + for (i = 0; i < 2; ++i) { + stream[i] = xfopen_stdin(argv[i]); + } + + order = 0; + thisline[1] = thisline[0] = NULL; + while (1) { + if (order <= 0) { + free(thisline[0]); + thisline[0] = xmalloc_fgetline(stream[0]); + } + if (order >= 0) { + free(thisline[1]); + thisline[1] = xmalloc_fgetline(stream[1]); + } + + i = !thisline[0] + (!thisline[1] << 1); + if (i) + break; + order = strcmp(thisline[0], thisline[1]); + + if (order >= 0) + writeline(thisline[1], order ? 1 : 2); + else + writeline(thisline[0], 0); + } + + /* EOF at least on one of the streams */ + i &= 1; + if (thisline[i]) { + /* stream[i] is not at EOF yet */ + /* we did not print thisline[i] yet */ + char *p = thisline[i]; + writeline(p, i); + while (1) { + free(p); + p = xmalloc_fgetline(stream[i]); + if (!p) + break; + writeline(p, i); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + fclose(stream[0]); + fclose(stream[1]); + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/cp.c b/busybox-1_37_0/coreutils/cp.c new file mode 100644 index 000000000..ee40af50b --- /dev/null +++ b/busybox-1_37_0/coreutils/cp.c @@ -0,0 +1,285 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cp implementation for busybox + * + * Copyright (C) 2000 by Matt Kraai + * SELinux support by Yuichi Nakamura + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Size reduction. + */ +//config:config CP +//config: bool "cp (10 kb)" +//config: default y +//config: help +//config: cp is used to copy files and directories. +//config: +//config:config FEATURE_CP_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on CP && LONG_OPTS +//config: help +//config: Enable long options. +//config: Also add support for --parents option. +//config: +//config:config FEATURE_CP_REFLINK +//config: bool "Enable --reflink[=auto]" +//config: default y +//config: depends on FEATURE_CP_LONG_OPTIONS + +//applet:IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) +/* NOEXEC despite cases when it can be a "runner" (cp -r LARGE_DIR NEW_DIR) */ + +//kbuild:lib-$(CONFIG_CP) += cp.o + +/* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ + +// Options of cp from GNU coreutils 6.10: +// -a, --archive +// -f, --force +// -i, --interactive +// -l, --link +// -L, --dereference +// -P, --no-dereference +// -R, -r, --recursive +// -s, --symbolic-link +// -v, --verbose +// -H follow command-line symbolic links in SOURCE +// -d same as --no-dereference --preserve=links +// -p same as --preserve=mode,ownership,timestamps +// -c same as --preserve=context +// -u, --update +// copy only when the SOURCE file is newer than the destination +// file or when the destination file is missing +// --remove-destination +// remove each existing destination file before attempting to open +// --parents +// use full source file name under DIRECTORY +// -T, --no-target-directory +// treat DEST as a normal file +// NOT SUPPORTED IN BBOX: +// --backup[=CONTROL] +// make a backup of each existing destination file +// -b like --backup but does not accept an argument +// --copy-contents +// copy contents of special files when recursive +// --preserve[=ATTR_LIST] +// preserve attributes (default: mode,ownership,timestamps), +// if possible additional attributes: security context,links,all +// --no-preserve=ATTR_LIST +// --sparse=WHEN +// control creation of sparse files +// --strip-trailing-slashes +// remove any trailing slashes from each SOURCE argument +// -S, --suffix=SUFFIX +// override the usual backup suffix +// -t, --target-directory=DIRECTORY +// copy all SOURCE arguments into DIRECTORY +// -x, --one-file-system +// stay on this file system +// -Z, --context=CONTEXT +// (SELinux) set SELinux security context of copy to CONTEXT + +//usage:#define cp_trivial_usage +//usage: "[-arPLHpfinlsTu] SOURCE DEST\n" +//usage: "or: cp [-arPLHpfinlsu] SOURCE... { -t DIRECTORY | DIRECTORY }" +//usage:#define cp_full_usage "\n\n" +//usage: "Copy SOURCEs to DEST\n" +//usage: "\n -a Same as -dpR" +//usage: IF_SELINUX( +//usage: "\n -c Preserve security context" +//usage: ) +//usage: "\n -R,-r Recurse" +//usage: "\n -d,-P Preserve symlinks (default if -R)" +//usage: "\n -L Follow all symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: "\n -p Preserve file attributes if possible" +//usage: "\n -f Overwrite" +//usage: "\n -i Prompt before overwrite" +//usage: "\n -n Don't overwrite" +//usage: "\n -l,-s Create (sym)links" +//usage: "\n -T Refuse to copy if DEST is a directory" +//usage: "\n -t DIR Copy all SOURCEs into DIR" +//usage: "\n -u Copy only newer files" + +#include "libbb.h" +#include "libcoreutils/coreutils.h" + +/* This is a NOEXEC applet. Be very careful! */ + +int cp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cp_main(int argc, char **argv) +{ + struct stat source_stat; + struct stat dest_stat; + const char *last; + const char *dest; + int s_flags; + int d_flags; + int flags; + int status; +#if ENABLE_FEATURE_CP_LONG_OPTIONS + enum { + /*OPT_rmdest = FILEUTILS_RMDEST = 1 << FILEUTILS_CP_OPTBITS */ + OPT_parents = 1 << (FILEUTILS_CP_OPTBITS+1), + OPT_reflink = 1 << (FILEUTILS_CP_OPTBITS+2), + }; +# if ENABLE_FEATURE_CP_REFLINK + char *reflink = NULL; +# endif + flags = getopt32long(argv, "^" + FILEUTILS_CP_OPTSTR + "\0" + // Need at least one argument. (Usually two+, but -t DIR can have only one) + // Soft- and hardlinking doesn't mix + // -P and -d are the same (-P is POSIX, -d is GNU) + // -r and -R are the same + // -R (and therefore -r) turns on -d (coreutils does this) + // -a = -pdR + // -i overrides -n and vice versa (last wins) + "-1:l--s:s--l:Pd:rRd:Rd:apdR:i-n:n-i", + "archive\0" No_argument "a" + "force\0" No_argument "f" + "interactive\0" No_argument "i" + "no-clobber\0" No_argument "n" + "link\0" No_argument "l" + "dereference\0" No_argument "L" + "no-dereference\0" No_argument "P" + "recursive\0" No_argument "R" + "symbolic-link\0" No_argument "s" + "no-target-directory\0" No_argument "T" + "target-directory\0" Required_argument "t" + "verbose\0" No_argument "v" + "update\0" No_argument "u" + "remove-destination\0" No_argument "\xff" + "parents\0" No_argument "\xfe" +# if ENABLE_FEATURE_CP_REFLINK + "reflink\0" Optional_argument "\xfd" +# endif + , &last +# if ENABLE_FEATURE_CP_REFLINK + , &reflink +# endif + ); +# if ENABLE_FEATURE_CP_REFLINK + BUILD_BUG_ON((int)OPT_reflink != (int)FILEUTILS_REFLINK); + if (flags & FILEUTILS_REFLINK) { + if (!reflink) + flags |= FILEUTILS_REFLINK_ALWAYS; + else if (strcmp(reflink, "always") == 0) + flags |= FILEUTILS_REFLINK_ALWAYS; + else if (strcmp(reflink, "auto") != 0) + bb_show_usage(); + } +# endif +#else + flags = getopt32(argv, "^" + FILEUTILS_CP_OPTSTR + "\0" + "-1:l--s:s--l:Pd:rRd:Rd:apdR" + , &last + ); +#endif + argc -= optind; + argv += optind; + /* Reverse this bit. If there is -d, bit is not set: */ + flags ^= FILEUTILS_DEREFERENCE; + /* coreutils 6.9 compat: + * by default, "cp" derefs symlinks (creates regular dest files), + * but "cp -R" does not. We switch off deref if -r or -R (see above). + * However, "cp -RL" must still deref symlinks: */ + if (flags & FILEUTILS_DEREF_SOFTLINK) /* -L */ + flags |= FILEUTILS_DEREFERENCE; + +#if ENABLE_SELINUX + if (flags & FILEUTILS_PRESERVE_SECURITY_CONTEXT) { + selinux_or_die(); + } +#endif + + status = EXIT_SUCCESS; + if (!(flags & FILEUTILS_TARGET_DIR)) { + last = argv[argc - 1]; + if (argc < 2) + bb_show_usage(); + if (argc != 2) { + if (flags & FILEUTILS_NO_TARGET_DIR) + bb_show_usage(); + /* "cp A B C... DIR" - target must be dir */ + } else /* argc == 2 */ { + /* "cp A B" - only case where target can be not a dir */ + s_flags = cp_mv_stat2(*argv, &source_stat, + (flags & FILEUTILS_DEREFERENCE) ? stat : lstat); + if (s_flags < 0) /* error other than ENOENT */ + return EXIT_FAILURE; + d_flags = cp_mv_stat(last, &dest_stat); + if (d_flags < 0) /* error other than ENOENT */ + return EXIT_FAILURE; + + if (flags & FILEUTILS_NO_TARGET_DIR) { /* -T */ + if (!(s_flags & 2) && (d_flags & 2)) + /* cp -T NOTDIR DIR */ + bb_error_msg_and_die("'%s' is a directory", last); + } + +#if ENABLE_FEATURE_CP_LONG_OPTIONS + //bb_error_msg("flags:%x FILEUTILS_RMDEST:%x OPT_parents:%x", + // flags, FILEUTILS_RMDEST, OPT_parents); + if (flags & OPT_parents) { + if (!(d_flags & 2)) { + bb_simple_error_msg_and_die("with --parents, the destination must be a directory"); + } + } + if (flags & FILEUTILS_RMDEST) { + flags |= FILEUTILS_FORCE; + } +#endif + + /* ...if neither is a directory... */ + if (!((s_flags | d_flags) & 2) + /* ...or: recursing, the 1st is a directory, and the 2nd doesn't exist... */ + || ((flags & FILEUTILS_RECUR) && (s_flags & 2) && !d_flags) + || (flags & FILEUTILS_NO_TARGET_DIR) + ) { + /* Do a simple copy */ + dest = last; + goto DO_COPY; /* NB: argc==2 -> *++argv==last */ + } + } + } + /* else: last is DIR from "-t DIR" */ + + while (1) { +#if ENABLE_FEATURE_CP_LONG_OPTIONS + if (flags & OPT_parents) { + char *dest_dup; + char *dest_dir; + dest = concat_path_file(last, *argv); + dest_dup = xstrdup(dest); + dest_dir = dirname(dest_dup); + if (bb_make_directory(dest_dir, -1, FILEUTILS_RECUR)) { + return EXIT_FAILURE; + } + free(dest_dup); + goto DO_COPY; + } +#endif + dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); + DO_COPY: + if (copy_file(*argv, dest, flags) < 0) { + status = EXIT_FAILURE; + } + if (!*++argv || *argv == last) { + /* possibly leaking dest... */ + break; + } + /* don't move up: dest may be == last and not malloced! */ + free((void*)dest); + } + + /* Exit. We are NOEXEC, not NOFORK. We do exit at the end of main() */ + return status; +} diff --git a/busybox-1_37_0/coreutils/cut.c b/busybox-1_37_0/coreutils/cut.c new file mode 100644 index 000000000..d129f9b9d --- /dev/null +++ b/busybox-1_37_0/coreutils/cut.c @@ -0,0 +1,333 @@ +/* vi: set sw=4 ts=4: */ +/* + * cut.c - minimalist version of cut + * + * Copyright (C) 1999,2000,2001 by Lineo, inc. + * Written by Mark Whitley + * debloated by Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CUT +//config: bool "cut (6.7 kb)" +//config: default y +//config: help +//config: cut is used to print selected parts of lines from +//config: each file to stdout. +//config: +//config:config FEATURE_CUT_REGEX +//config: bool "cut -F" +//config: default y +//config: depends on CUT +//config: help +//config: Allow regex based delimiters. + +//applet:IF_CUT(APPLET_NOEXEC(cut, cut, BB_DIR_USR_BIN, BB_SUID_DROP, cut)) + +//kbuild:lib-$(CONFIG_CUT) += cut.o + +//usage:#define cut_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define cut_full_usage "\n\n" +//usage: "Print selected fields from FILEs to stdout\n" +//usage: "\n -b LIST Output only bytes from LIST" +//usage: "\n -c LIST Output only characters from LIST" +//usage: "\n -d SEP Field delimiter for input (default -f TAB, -F run of whitespace)" +//usage: "\n -O SEP Field delimeter for output (default = -d for -f, one space for -F)" +//usage: "\n -D Don't sort/collate sections or match -fF lines without delimeter" +//usage: "\n -f LIST Print only these fields (-d is single char)" +//usage: IF_FEATURE_CUT_REGEX( +//usage: "\n -F LIST Print only these fields (-d is regex)" +//usage: ) +//usage: "\n -s Output only lines containing delimiter" +//usage: "\n -n Ignored" +//(manpage:-n with -b: don't split multibyte characters) +//usage: +//usage:#define cut_example_usage +//usage: "$ echo \"Hello world\" | cut -f 1 -d ' '\n" +//usage: "Hello\n" +//usage: "$ echo \"Hello world\" | cut -f 2 -d ' '\n" +//usage: "world\n" + +#include "libbb.h" + +#if ENABLE_FEATURE_CUT_REGEX +#include "xregex.h" +#else +#define regex_t int +typedef struct { int rm_eo, rm_so; } regmatch_t; +#define xregcomp(x, ...) *(x) = 0 +#define regexec(...) 0 +#endif + +/* This is a NOEXEC applet. Be very careful! */ + + +/* option vars */ +#define OPT_STR "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" +#define CUT_OPT_BYTE_FLGS (1 << 0) +#define CUT_OPT_CHAR_FLGS (1 << 1) +#define CUT_OPT_FIELDS_FLGS (1 << 2) +#define CUT_OPT_DELIM_FLGS (1 << 3) +#define CUT_OPT_ODELIM_FLGS (1 << 4) +#define CUT_OPT_SUPPRESS_FLGS (1 << 5) +#define CUT_OPT_NOSORT_FLGS (1 << 6) +#define CUT_OPT_REGEX_FLGS ((1 << 7) * ENABLE_FEATURE_CUT_REGEX) + +struct cut_list { + int startpos; + int endpos; +}; + +static int cmpfunc(const void *a, const void *b) +{ + return (((struct cut_list *) a)->startpos - + ((struct cut_list *) b)->startpos); +} + +static void cut_file(FILE *file, const char *delim, const char *odelim, + const struct cut_list *cut_lists, unsigned nlists) +{ + char *line; + unsigned linenum = 0; /* keep these zero-based to be consistent */ + regex_t reg; + int spos, shoe = option_mask32 & CUT_OPT_REGEX_FLGS; + + if (shoe) xregcomp(®, delim, REG_EXTENDED); + + /* go through every line in the file */ + while ((line = xmalloc_fgetline(file)) != NULL) { + + /* set up a list so we can keep track of what's been printed */ + int linelen = strlen(line); + char *printed = xzalloc(linelen + 1); + char *orig_line = line; + unsigned cl_pos = 0; + + /* cut based on chars/bytes XXX: only works when sizeof(char) == byte */ + if (option_mask32 & (CUT_OPT_CHAR_FLGS | CUT_OPT_BYTE_FLGS)) { + /* print the chars specified in each cut list */ + for (; cl_pos < nlists; cl_pos++) { + for (spos = cut_lists[cl_pos].startpos; spos < linelen;) { + if (!printed[spos]) { + printed[spos] = 'X'; + putchar(line[spos]); + } + if (++spos > cut_lists[cl_pos].endpos) { + break; + } + } + } + } else if (*delim == '\n') { /* cut by lines */ + spos = cut_lists[cl_pos].startpos; + + /* get out if we have no more lists to process or if the lines + * are lower than what we're interested in */ + if (((int)linenum < spos) || (cl_pos >= nlists)) + goto next_line; + + /* if the line we're looking for is lower than the one we were + * passed, it means we displayed it already, so move on */ + while (spos < (int)linenum) { + spos++; + /* go to the next list if we're at the end of this one */ + if (spos > cut_lists[cl_pos].endpos) { + cl_pos++; + /* get out if there's no more lists to process */ + if (cl_pos >= nlists) + goto next_line; + spos = cut_lists[cl_pos].startpos; + /* get out if the current line is lower than the one + * we just became interested in */ + if ((int)linenum < spos) + goto next_line; + } + } + + /* If we made it here, it means we've found the line we're + * looking for, so print it */ + puts(line); + goto next_line; + } else { /* cut by fields */ + unsigned uu = 0, start = 0, end = 0, out = 0; + int dcount = 0; + + /* Loop through bytes, finding next delimiter */ + for (;;) { + /* End of current range? */ + if (end == linelen || dcount > cut_lists[cl_pos].endpos) { + if (++cl_pos >= nlists) break; + if (option_mask32 & CUT_OPT_NOSORT_FLGS) + start = dcount = uu = 0; + end = 0; + } + /* End of current line? */ + if (uu == linelen) { + /* If we've seen no delimiters, check -s */ + if (!cl_pos && !dcount && !shoe) { + if (option_mask32 & CUT_OPT_SUPPRESS_FLGS) + goto next_line; + } else if (dcount < cut_lists[cl_pos].startpos) + start = linelen; + end = linelen; + } else { + /* Find next delimiter */ + if (shoe) { + regmatch_t rr = {-1, -1}; + + if (!regexec(®, line+uu, 1, &rr, REG_NOTBOL|REG_NOTEOL)) { + end = uu + rr.rm_so; + uu += rr.rm_eo; + } else { + uu = linelen; + continue; + } + } else if (line[end = uu++] != *delim) + continue; + + /* Got delimiter. Loop if not yet within range. */ + if (dcount++ < cut_lists[cl_pos].startpos) { + start = uu; + continue; + } + } + if (end != start || !shoe) + printf("%s%.*s", out++ ? odelim : "", end-start, line + start); + start = uu; + if (!dcount) + break; + } + } + /* if we printed anything, finish with newline */ + putchar('\n'); + next_line: + linenum++; + free(printed); + free(orig_line); + } +} + +int cut_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cut_main(int argc UNUSED_PARAM, char **argv) +{ + /* growable array holding a series of lists */ + struct cut_list *cut_lists = NULL; + unsigned nlists = 0; /* number of elements in above list */ + char *sopt, *ltok; + const char *delim = NULL; + const char *odelim = NULL; + unsigned opt; + +#define ARG "bcf"IF_FEATURE_CUT_REGEX("F") + opt = getopt32(argv, "^" + OPT_STR // = "b:c:f:d:O:sD"IF_FEATURE_CUT_REGEX("F:")"n" + "\0" "b--"ARG":c--"ARG":f--"ARG IF_FEATURE_CUT_REGEX("F--"ARG), + &sopt, &sopt, &sopt, &delim, &odelim IF_FEATURE_CUT_REGEX(, &sopt) + ); + if (!delim || !*delim) + delim = (opt & CUT_OPT_REGEX_FLGS) ? "[[:space:]]+" : "\t"; + if (!odelim) odelim = (opt & CUT_OPT_REGEX_FLGS) ? " " : delim; + +// argc -= optind; + argv += optind; + if (!(opt & (CUT_OPT_BYTE_FLGS | CUT_OPT_CHAR_FLGS | CUT_OPT_FIELDS_FLGS | CUT_OPT_REGEX_FLGS))) + bb_simple_error_msg_and_die("expected a list of bytes, characters, or fields"); + + /* non-field (char or byte) cutting has some special handling */ + if (!(opt & (CUT_OPT_FIELDS_FLGS|CUT_OPT_REGEX_FLGS))) { + static const char _op_on_field[] ALIGN1 = " only when operating on fields"; + + if (opt & CUT_OPT_SUPPRESS_FLGS) { + bb_error_msg_and_die + ("suppressing non-delimited lines makes sense%s", _op_on_field); + } + if (opt & CUT_OPT_DELIM_FLGS) { + bb_error_msg_and_die + ("a delimiter may be specified%s", _op_on_field); + } + } + + /* + * parse list and put values into startpos and endpos. + * valid list formats: N, N-, N-M, -M + * more than one list can be separated by commas + */ + { + char *ntok; + int s = 0, e = 0; + + /* take apart the lists, one by one (they are separated with commas) */ + while ((ltok = strsep(&sopt, ",")) != NULL) { + + /* it's actually legal to pass an empty list */ + if (!ltok[0]) + continue; + + /* get the start pos */ + ntok = strsep(<ok, "-"); + if (!ntok[0]) { + s = 0; + } else { + s = xatoi_positive(ntok); + /* account for the fact that arrays are zero based, while + * the user expects the first char on the line to be char #1 */ + if (s != 0) + s--; + } + + /* get the end pos */ + if (ltok == NULL) { + e = s; + } else if (!ltok[0]) { + e = INT_MAX; + } else { + e = xatoi_positive(ltok); + /* if the user specified and end position of 0, + * that means "til the end of the line" */ + if (!*ltok) + e = INT_MAX; + else if (e < s) + bb_error_msg_and_die("%d<%d", e, s); + e--; /* again, arrays are zero based, lines are 1 based */ + } + + /* add the new list */ + cut_lists = xrealloc_vector(cut_lists, 4, nlists); + /* NB: startpos is always >= 0 */ + cut_lists[nlists].startpos = s; + cut_lists[nlists].endpos = e; + nlists++; + } + + /* make sure we got some cut positions out of all that */ + if (nlists == 0) + bb_simple_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 + */ + if (!(opt & CUT_OPT_NOSORT_FLGS)) + qsort(cut_lists, nlists, sizeof(cut_lists[0]), cmpfunc); + } + + { + exitcode_t retval = EXIT_SUCCESS; + + if (!*argv) + *--argv = (char *)"-"; + + do { + FILE *file = fopen_or_warn_stdin(*argv); + if (!file) { + retval = EXIT_FAILURE; + continue; + } + cut_file(file, delim, odelim, cut_lists, nlists); + fclose_if_not_stdin(file); + } while (*++argv); + + if (ENABLE_FEATURE_CLEAN_UP) + free(cut_lists); + fflush_stdout_and_exit(retval); + } +} diff --git a/busybox-1_37_0/coreutils/date.c b/busybox-1_37_0/coreutils/date.c new file mode 100644 index 000000000..3a89b6caf --- /dev/null +++ b/busybox-1_37_0/coreutils/date.c @@ -0,0 +1,387 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini date implementation for busybox + * + * by Matthew Grant + * + * iso-format handling added by Robert Griebl + * bugfixes and cleanup by Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* 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 it, as well as + an RFC 2822 compliant date output for shell scripting + mail commands */ + +/* Input parsing code is always bulky - used heavy duty libc stuff as + much as possible, missed out a lot of bounds checking */ + +//config:config DATE +//config: bool "date (7.2 kb)" +//config: default y +//config: help +//config: date is used to set the system date or display the +//config: current time in the given format. +//config: +//config:config FEATURE_DATE_ISOFMT +//config: bool "Enable ISO date format output (-I)" +//config: default y +//config: depends on DATE +//config: help +//config: Enable option (-I) to output an ISO-8601 compliant +//config: date/time string. +//config: +//config:config FEATURE_DATE_NANO +//config: bool "Support %[num]N nanosecond format specifier" +//config: default n # stat's nanosecond field is a bit non-portable +//config: depends on DATE +//config: help +//config: Support %[num]N format specifier. Adds ~250 bytes of code. +//config: +//config:config FEATURE_DATE_COMPAT +//config: bool "Support weird 'date MMDDhhmm[[YY]YY][.ss]' format" +//config: default y +//config: depends on DATE +//config: help +//config: System time can be set by 'date -s DATE' and simply 'date DATE', +//config: but formats of DATE string are different. 'date DATE' accepts +//config: a rather weird MMDDhhmm[[YY]YY][.ss] format with completely +//config: unnatural placement of year between minutes and seconds. +//config: date -s (and other commands like touch -d) use more sensible +//config: formats (for one, ISO format YYYY-MM-DD hh:mm:ss.ssssss). +//config: +//config: With this option off, 'date DATE' and 'date -s DATE' support +//config: the same format. With it on, 'date DATE' additionally supports +//config: MMDDhhmm[[YY]YY][.ss] format. + +//applet:IF_DATE(APPLET_NOEXEC(date, date, BB_DIR_BIN, BB_SUID_DROP, date)) +/* bb_common_bufsiz1 usage here is safe wrt NOEXEC: not expecting it to be zeroed. */ + +//kbuild:lib-$(CONFIG_DATE) += date.o + +/* GNU coreutils 6.9 man page: + * date [OPTION]... [+FORMAT] + * date [-u|--utc|--universal] [MMDDhhmm[[CC]YY][.ss]] + * -d, --date=STRING + * display time described by STRING, not 'now' + * -f, --file=DATEFILE + * like --date once for each line of DATEFILE + * -r, --reference=FILE + * display the last modification time of FILE + * -R, --rfc-2822 + * output date and time in RFC 2822 format. + * Example: Mon, 07 Aug 2006 12:34:56 -0600 + * --rfc-3339=TIMESPEC + * output date and time in RFC 3339 format. + * TIMESPEC='date', 'seconds', or 'ns' + * Date and time components are separated by a single space: + * 2006-08-07 12:34:56-06:00 + * -s, --set=STRING + * set time described by STRING + * -u, --utc, --universal + * print or set Coordinated Universal Time + * + * Busybox: + * long options are not supported + * -f is not supported + * -I seems to roughly match --rfc-3339, but -I has _optional_ param + * (thus "-I seconds" doesn't work, only "-Iseconds"), + * and does not support -Ins + * -D FMT is a bbox extension for _input_ conversion of -d DATE + */ + +//usage:#define date_trivial_usage +//usage: "[OPTIONS] [+FMT] [[-s] TIME]" +//usage:#define date_full_usage "\n\n" +//usage: "Display time (using +FMT), or set time\n" +//usage: "\n -u Work in UTC (don't convert to local time)" +//usage: "\n [-s] TIME Set time to TIME" +//usage: "\n -d TIME Display TIME, not 'now'" +//usage: IF_FEATURE_DATE_ISOFMT( +//usage: "\n -D FMT FMT (strptime format) for -s/-d TIME conversion" +////////^^^^^^^^^^^^^^^^^^^^^^ busybox invention, not compat +//usage: ) +//usage: "\n -r FILE Display last modification time of FILE" +//usage: "\n -R Output RFC-2822 date" +//usage: IF_FEATURE_DATE_ISOFMT( +//usage: "\n -I[SPEC] Output ISO-8601 date" +//usage: "\n SPEC=date (default), hours, minutes, seconds or ns" +//usage: ) +//usage: "\n" +//usage: "\nRecognized TIME formats:" +//usage: "\n @seconds_since_1970" +//usage: "\n hh:mm[:ss]" +//usage: "\n [YYYY.]MM.DD-hh:mm[:ss]" +//usage: "\n YYYY-MM-DD hh:mm[:ss]" +//usage: "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" +//usage: IF_FEATURE_DATE_COMPAT( +//usage: "\n 'date TIME' form accepts MMDDhhmm[[YY]YY][.ss] instead" +//usage: ) +//usage: +//usage:#define date_example_usage +//usage: "$ date\n" +//usage: "Wed Apr 12 18:52:41 MDT 2000\n" + +#include "libbb.h" +#include "common_bufsiz.h" +#if ENABLE_FEATURE_DATE_NANO +# include +#endif + +enum { + OPT_RFC2822 = (1 << 0), /* R */ + OPT_SET = (1 << 1), /* s */ + OPT_UTC = (1 << 2), /* u */ + OPT_DATE = (1 << 3), /* d */ + OPT_REFERENCE = (1 << 4), /* r */ + OPT_ISO8601 = (1 << 5) * ENABLE_FEATURE_DATE_ISOFMT, /* I */ + OPT_STR2DT = (1 << 6) * ENABLE_FEATURE_DATE_ISOFMT, /* D */ +}; + +#if ENABLE_LONG_OPTS +static const char date_longopts[] ALIGN1 = + "rfc-822\0" No_argument "R" + "rfc-2822\0" No_argument "R" + "set\0" Required_argument "s" + "utc\0" No_argument "u" + /* "universal\0" No_argument "u" */ + "date\0" Required_argument "d" + "reference\0" Required_argument "r" + ; +#endif + +/* We are a NOEXEC applet. + * Obstacles to NOFORK: + * - we change env + * - xasprintf result not freed + * - after xasprintf we use other xfuncs + */ + +int date_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int date_main(int argc UNUSED_PARAM, char **argv) +{ + struct timespec ts; + struct tm tm_time; + char buf_fmt_dt2str[64]; + unsigned opt; + int isofmt = -1; + char *date_str; + char *fmt_dt2str; + char *fmt_str2dt; + char *filename; + char *isofmt_arg = NULL; + + opt = getopt32long(argv, "^" + "Rs:ud:r:" + IF_FEATURE_DATE_ISOFMT("I::D:") + "\0" + "d--s:s--d" + IF_FEATURE_DATE_ISOFMT(":R--I:I--R"), + date_longopts, + &date_str, &date_str, &filename + IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt) + ); + argv += optind; + + if (opt & OPT_UTC) + putenv((char*)"TZ=UTC0"); + + if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_ISO8601)) { + isofmt = 0; /* default is date */ + if (isofmt_arg) { + static const char isoformats[] ALIGN1 = + "date\0""hours\0""minutes\0""seconds\0ns\0"; + isofmt = index_in_substrings(isoformats, isofmt_arg); + if (isofmt < 0) + bb_show_usage(); + } + } + + fmt_dt2str = NULL; + if (argv[0] && argv[0][0] == '+') { + fmt_dt2str = &argv[0][1]; /* skip over the '+' */ + argv++; + } + if (!(opt & (OPT_SET | OPT_DATE))) { /* neither -s TIME nor -d TIME? */ + opt |= OPT_SET; + date_str = argv[0]; /* can be NULL */ + if (date_str) { +#if ENABLE_FEATURE_DATE_COMPAT + int len = strspn(date_str, "0123456789"); + if (date_str[len] == '\0' + || (date_str[len] == '.' + && isdigit(date_str[len+1]) + && isdigit(date_str[len+2]) + && date_str[len+3] == '\0' + ) + ) { + /* Dreaded MMDDhhmm[[CC]YY][.ss] format! + * It does not match -d or -s format. + * Some users actually do use it. + */ + len -= 8; + if (len < 0 || len > 4 || (len & 1)) + bb_error_msg_and_die(bb_msg_invalid_date, date_str); + if (len != 0) { /* move YY or CCYY to front */ + char buf[4]; + memcpy(buf, date_str + 8, len); + memmove(date_str + len, date_str, 8); + memcpy(date_str, buf, len); + } + } +#endif + argv++; + } + } + if (*argv) + bb_show_usage(); + + /* Now we have parsed all the information except the date format + * which depends on whether the clock is being set or read */ + + if (opt & OPT_REFERENCE) { + struct stat statbuf; + xstat(filename, &statbuf); + ts.tv_sec = statbuf.st_mtime; +#if ENABLE_FEATURE_DATE_NANO + ts.tv_nsec = statbuf.st_mtim.tv_nsec; + /* Some toolchains use .st_mtimensec instead of st_mtim.tv_nsec. + * If you need #define _SVID_SOURCE 1 to enable st_mtim.tv_nsec, + * drop a mail to project mailing list please + */ +#endif + } else { +#if ENABLE_FEATURE_DATE_NANO + clock_gettime(CLOCK_REALTIME, &ts); +#else + time(&ts.tv_sec); +#endif + } +#if !ENABLE_FEATURE_DATE_NANO + ts.tv_nsec = 0; +#endif + localtime_r(&ts.tv_sec, &tm_time); + + /* If date string is given, update tm_time, and maybe set date */ + if (date_str != NULL) { + int check_dst = 1; + /* Zero out fields - take her back to midnight! */ + tm_time.tm_sec = 0; + tm_time.tm_min = 0; + tm_time.tm_hour = 0; + + /* Process any date input to UNIX time since 1 Jan 1970 */ + if (ENABLE_FEATURE_DATE_ISOFMT && (opt & OPT_STR2DT)) { + if (strptime(date_str, fmt_str2dt, &tm_time) == NULL) + bb_error_msg_and_die(bb_msg_invalid_date, date_str); + } else { + check_dst = parse_datestr(date_str, &tm_time); + } + + /* Correct any day of week and day of year etc. fields */ + /* Be sure to recheck dst (but not if date is UTC) */ + if (check_dst) + tm_time.tm_isdst = -1; + ts.tv_sec = validate_tm_time(date_str, &tm_time); + ts.tv_nsec = 0; + + /* if setting time, set it */ + if ((opt & OPT_SET) && clock_settime(CLOCK_REALTIME, &ts) < 0) { + bb_simple_perror_msg("can't set date"); + } + } + + /* Display output */ + + /* Deal with format string */ + if (fmt_dt2str == NULL) { + int i; + fmt_dt2str = buf_fmt_dt2str; + if (ENABLE_FEATURE_DATE_ISOFMT && isofmt >= 0) { + /* -I[SPEC]: 0:date 1:hours 2:minutes 3:seconds 4:ns*/ + strcpy(fmt_dt2str, "%Y-%m-%dT%H:%M:%S"); + i = 8 + 3 * isofmt; + if (isofmt != 0) { + int n; + if (isofmt == 4) { + i -= 3; + i += sprintf(&fmt_dt2str[i], ",%09u", (unsigned)ts.tv_nsec); + } + /* %z prints "+hhmm" timezone, but coreutils-8.30 prints "+hh:mm"! */ + /* ...therefore this atrocity: */ + n = strftime(&fmt_dt2str[i], 8, "%z", &tm_time); + i += n; + if (n == 5 && (fmt_dt2str[i-5] == '+' || fmt_dt2str[i-5] == '-')) { + /* "mm" -> ":mm" */ + fmt_dt2str[i ] = fmt_dt2str[i - 1]; + fmt_dt2str[i - 1] = fmt_dt2str[i - 2]; + fmt_dt2str[i - 2] = ':'; + i++; + } + } + fmt_dt2str[i] = '\0'; + } else if (opt & OPT_RFC2822) { + /* -R. undo busybox.c setlocale */ + if (ENABLE_LOCALE_SUPPORT) + setlocale(LC_TIME, "C"); + fmt_dt2str = (char*)"%a, %d %b %Y %H:%M:%S %z"; + } else { /* default case */ + fmt_dt2str = (char*)"%a %b %e %H:%M:%S %Z %Y"; + } + } +#if ENABLE_FEATURE_DATE_NANO + else { + /* User-specified fmt_dt2str */ + /* Search for and process "%N" */ + char *p = fmt_dt2str; + while ((p = strchr(p, '%')) != NULL) { + int n, m; + unsigned pres, scale; + + p++; + if (*p == '%') { + p++; + continue; + } + n = strspn(p, "0123456789"); + if (p[n] != 'N') { + p += n; + continue; + } + /* We have "%[nnn]N" */ + p[-1] = '\0'; + p[n] = '\0'; + scale = 1; + pres = 9; + if (n) { + pres = xatoi_positive(p); + if (pres == 0) + pres = 9; + m = 9 - pres; + while (--m >= 0) + scale *= 10; + } + + m = p - fmt_dt2str; + p += n + 1; + fmt_dt2str = xasprintf("%s%0*u%s", fmt_dt2str, pres, (unsigned)ts.tv_nsec / scale, p); + p = fmt_dt2str + m; + } + } +#endif + +#define date_buf bb_common_bufsiz1 + setup_common_bufsiz(); + if (*fmt_dt2str == '\0') { + /* With no format string, just print a blank line */ + date_buf[0] = '\0'; + } else { + /* Generate output string */ + strftime(date_buf, COMMON_BUFSIZE, fmt_dt2str, &tm_time); + } + puts(date_buf); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/dd.c b/busybox-1_37_0/coreutils/dd.c new file mode 100644 index 000000000..8bb782781 --- /dev/null +++ b/busybox-1_37_0/coreutils/dd.c @@ -0,0 +1,689 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dd implementation for busybox + * + * Copyright (C) 2000,2001 Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DD +//config: bool "dd (8.3 kb)" +//config: default y +//config: help +//config: dd copies a file (from standard input to standard output, +//config: by default) using specific input and output blocksizes, +//config: while optionally performing conversions on it. +//config: +//config:config FEATURE_DD_SIGNAL_HANDLING +//config: bool "Enable signal handling for status reporting" +//config: default y +//config: depends on DD +//config: help +//config: Sending a SIGUSR1 signal to a running 'dd' process makes it +//config: print to standard error the number of records read and written +//config: so far, then to resume copying. +//config: +//config: $ dd if=/dev/zero of=/dev/null & +//config: $ pid=$!; kill -USR1 $pid; sleep 1; kill $pid +//config: 10899206+0 records in +//config: 10899206+0 records out +//config: +//config:config FEATURE_DD_THIRD_STATUS_LINE +//config: bool "Enable the third status line upon signal" +//config: default y +//config: depends on DD && FEATURE_DD_SIGNAL_HANDLING +//config: help +//config: Displays a coreutils-like third status line with transferred bytes, +//config: elapsed time and speed. +//config: +//config:config FEATURE_DD_IBS_OBS +//config: bool "Enable ibs, obs, iflag, oflag and conv options" +//config: default y +//config: depends on DD +//config: help +//config: Enable support for writing a certain number of bytes in and out, +//config: at a time, and performing conversions on the data stream. +//config: +//config:config FEATURE_DD_STATUS +//config: bool "Enable status display options" +//config: default y +//config: depends on DD +//config: help +//config: Enable support for status=noxfer/none option. + +//applet:IF_DD(APPLET_NOEXEC(dd, dd, BB_DIR_BIN, BB_SUID_DROP, dd)) + +//kbuild:lib-$(CONFIG_DD) += dd.o + +//usage:#define dd_trivial_usage +//usage: "[if=FILE] [of=FILE] [" IF_FEATURE_DD_IBS_OBS("ibs=N obs=N/") "bs=N] [count=N] [skip=N] [seek=N]" +//usage: IF_FEATURE_DD_IBS_OBS("\n" +//usage: " [conv=notrunc|noerror|sync|fsync]\n" +//usage: " [iflag=skip_bytes|count_bytes|fullblock|direct] [oflag=seek_bytes|append|direct]" +//usage: ) +//usage:#define dd_full_usage "\n\n" +//usage: "Copy a file with converting and formatting\n" +//usage: "\n if=FILE Read from FILE instead of stdin" +//usage: "\n of=FILE Write to FILE instead of stdout" +//usage: "\n bs=N Read and write N bytes at a time" +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n ibs=N Read N bytes at a time" +//usage: ) +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n obs=N Write N bytes at a time" +//usage: ) +//usage: "\n count=N Copy only N input blocks" +//usage: "\n skip=N Skip N input blocks" +//usage: "\n seek=N Skip N output blocks" +//usage: IF_FEATURE_DD_IBS_OBS( +//usage: "\n conv=notrunc Don't truncate output file" +//usage: "\n conv=noerror Continue after read errors" +//usage: "\n conv=sync Pad blocks with zeros" +//usage: "\n conv=fsync Physically write data out before finishing" +//usage: "\n conv=swab Swap every pair of bytes" +//usage: "\n iflag=skip_bytes skip=N is in bytes" +//usage: "\n iflag=count_bytes count=N is in bytes" +//usage: "\n oflag=seek_bytes seek=N is in bytes" +//usage: "\n iflag=direct O_DIRECT input" +//usage: "\n oflag=direct O_DIRECT output" +//usage: "\n iflag=fullblock Read full blocks" +//usage: "\n oflag=append Open output in append mode" +//usage: ) +//usage: IF_FEATURE_DD_STATUS( +//usage: "\n status=noxfer Suppress rate output" +//usage: "\n status=none Suppress all output" +//usage: ) +//usage: "\n" +//usage: "\nN may be suffixed by c (1), w (2), b (512), kB (1000), k (1024), MB, M, GB, G" +//usage: +//usage:#define dd_example_usage +//usage: "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" +//usage: "4+0 records in\n" +//usage: "4+0 records out\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +/* This is a NOEXEC applet. Be very careful! */ + + +enum { + ifd = STDIN_FILENO, + ofd = STDOUT_FILENO, +}; + +struct globals { + off_t out_full, out_part, in_full, in_part; +#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE + unsigned long long total_bytes; + unsigned long long begin_time_us; +#endif + int flags; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* we have to zero it out because of NOEXEC */ \ + memset(&G, 0, sizeof(G)); \ +} while (0) + +enum { + /* Must be in the same order as OP_conv_XXX! */ + /* (see "flags |= (1 << what)" below) */ + FLAG_NOTRUNC = (1 << 0) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_SYNC = (1 << 1) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_NOERROR = (1 << 2) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_FSYNC = (1 << 3) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_SWAB = (1 << 4) * ENABLE_FEATURE_DD_IBS_OBS, + /* end of conv flags */ + /* start of input flags */ + FLAG_IFLAG_SHIFT = 5, + FLAG_SKIP_BYTES = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_COUNT_BYTES = (1 << 6) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_FULLBLOCK = (1 << 7) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_IDIRECT = (1 << 8) * ENABLE_FEATURE_DD_IBS_OBS, + /* end of input flags */ + /* start of output flags */ + FLAG_OFLAG_SHIFT = 9, + FLAG_SEEK_BYTES = (1 << 9) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_APPEND = (1 << 10) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_ODIRECT = (1 << 11) * ENABLE_FEATURE_DD_IBS_OBS, + /* end of output flags */ + FLAG_TWOBUFS = (1 << 12) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_COUNT = 1 << 13, + FLAG_STATUS_NONE = 1 << 14, + FLAG_STATUS_NOXFER = 1 << 15, +}; + +static void dd_output_status(int UNUSED_PARAM cur_signal) +{ +#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE + double seconds; + unsigned long long bytes_sec; + unsigned long long now_us = monotonic_us(); /* before fprintf */ +#endif + + /* Deliberately using %u, not %d */ + fprintf(stderr, "%"OFF_FMT"u+%"OFF_FMT"u records in\n" + "%"OFF_FMT"u+%"OFF_FMT"u records out\n", + G.in_full, G.in_part, + G.out_full, G.out_part); + +#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE +# if ENABLE_FEATURE_DD_STATUS + if (G.flags & FLAG_STATUS_NOXFER) /* status=noxfer active? */ + return; + //TODO: should status=none make dd stop reacting to USR1 entirely? + //So far we react to it (we print the stats), + //status=none only suppresses final, non-USR1 generated status message. +# endif + fprintf(stderr, /*G.total_bytes < 1024 + ? "%llu bytes copied, " : */ "%llu bytes (%sB) copied, " + , G.total_bytes, + /* show fractional digit, use suffixes */ + make_human_readable_str(G.total_bytes, 1, 0) + ); + /* Corner cases: + * ./busybox dd /dev/null + * ./busybox dd bs=1M count=2000 /dev/null + * (echo DONE) | ./busybox dd >/dev/null + * (sleep 1; echo DONE) | ./busybox dd >/dev/null + */ + seconds = (now_us - G.begin_time_us) / 1000000.0; + bytes_sec = G.total_bytes / seconds; + fprintf(stderr, "%f seconds, %sB/s\n", + seconds, + /* show fractional digit, use suffixes */ + make_human_readable_str(bytes_sec, 1, 0) + ); +#endif +} + +#if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT +static int clear_O_DIRECT(int fd) +{ + if (errno == EINVAL) { + int fl = fcntl(fd, F_GETFL); + if (fl & O_DIRECT) { + fcntl(fd, F_SETFL, fl & ~O_DIRECT); + return 1; + } + } + return 0; +} +# endif +#endif + +static ssize_t dd_read(void *ibuf, size_t ibs) +{ + ssize_t n; + +#if ENABLE_FEATURE_DD_IBS_OBS + read_again: + if (G.flags & FLAG_FULLBLOCK) + n = full_read(ifd, ibuf, ibs); + else +#endif + n = safe_read(ifd, ibuf, ibs); +#if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT + if (n < 0 && (G.flags & FLAG_IDIRECT) && clear_O_DIRECT(ifd)) + goto read_again; +# endif +#endif + return n; +} + +static bool write_and_stats(const void *buf, size_t len, size_t obs, + const char *filename) +{ + ssize_t n; + + IF_FEATURE_DD_IBS_OBS(write_again:) + n = full_write(ofd, buf, len); +#if ENABLE_FEATURE_DD_IBS_OBS +# ifdef O_DIRECT + if (n < 0 && (G.flags & FLAG_ODIRECT) && clear_O_DIRECT(ofd)) + goto write_again; +# endif +#endif + +#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE + if (n > 0) + G.total_bytes += n; +#endif + if ((size_t)n == obs) { + G.out_full++; + return 0; + } + if ((size_t)n == len) { + G.out_part++; + return 0; + } + /* n is < len (and possibly is -1). + * Even if n >= 0, errno is usually set correctly. + * For example, if writing to block device and getting ENOSPC, + * full_write() first sees a short write, then tries to write + * the remainder and gets errno set to ENOSPC. + * It returns n > 0 (the amount which it did write). + */ + bb_perror_msg("error writing '%s'", filename); + return 1; +} + +#if ENABLE_LFS +# define XATOU_SFX xatoull_sfx +#else +# define XATOU_SFX xatoul_sfx +#endif + +#if ENABLE_FEATURE_DD_IBS_OBS +static int parse_comma_flags(char *val, const char *words, const char *error_in) +{ + int flags = 0; + while (1) { + int n; + char *arg; + /* find ',', replace them with NUL so we can use val for + * index_in_strings() without copying. + * We rely on val being non-null, else strchr would fault. + */ + arg = strchr(val, ','); + if (arg) + *arg = '\0'; + n = index_in_strings(words, val); + if (n < 0) + bb_error_msg_and_die(bb_msg_invalid_arg_to, val, error_in); + flags |= (1 << n); + if (!arg) /* no ',' left, so this was the last specifier */ + break; + *arg = ','; /* to preserve ps listing */ + val = arg + 1; /* skip this keyword and ',' */ + } + return flags; +} +#endif + +static void *alloc_buf(size_t size) +{ + /* Important for "{i,o}flag=direct" - buffers must be page aligned */ + if (size >= bb_getpagesize()) + return xmmap_anon(size); + return xmalloc(size); +} + +int dd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dd_main(int argc UNUSED_PARAM, char **argv) +{ + static const char keywords[] ALIGN1 = + "bs\0""count\0""seek\0""skip\0""if\0""of\0"IF_FEATURE_DD_STATUS("status\0") +#if ENABLE_FEATURE_DD_IBS_OBS + "ibs\0""obs\0""conv\0""iflag\0""oflag\0" +#endif + ; +#if ENABLE_FEATURE_DD_IBS_OBS + static const char conv_words[] ALIGN1 = + "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; + static const char iflag_words[] ALIGN1 = + "skip_bytes\0""count_bytes\0""fullblock\0""direct\0"; + static const char oflag_words[] ALIGN1 = + "seek_bytes\0append\0""direct\0"; +#endif +#if ENABLE_FEATURE_DD_STATUS + static const char status_words[] ALIGN1 = + "none\0""noxfer\0"; +#endif + enum { + OP_bs = 0, + OP_count, + OP_seek, + OP_skip, + OP_if, + OP_of, + IF_FEATURE_DD_STATUS(OP_status,) +#if ENABLE_FEATURE_DD_IBS_OBS + OP_ibs, + OP_obs, + OP_conv, + OP_iflag, + OP_oflag, + /* Must be in the same order as FLAG_XXX! */ + OP_conv_notrunc = 0, + OP_conv_sync, + OP_conv_noerror, + OP_conv_fsync, + OP_conv_swab, + /* Unimplemented conv=XXX: */ + //nocreat do not create the output file + //excl fail if the output file already exists + //fdatasync physically write output file data before finishing + //lcase change upper case to lower case + //ucase change lower case to upper case + //block pad newline-terminated records with spaces to cbs-size + //unblock replace trailing spaces in cbs-size records with newline + //ascii from EBCDIC to ASCII + //ebcdic from ASCII to EBCDIC + //ibm from ASCII to alternate EBCDIC + /* Partially implemented: */ + //swab swap every pair of input bytes: will abort on non-even reads + OP_iflag_skip_bytes, + OP_iflag_count_bytes, + OP_iflag_fullblock, + OP_iflag_direct, + OP_oflag_seek_bytes, + OP_oflag_direct, +#endif + }; + exitcode_t exitcode = EXIT_FAILURE; + int i; + size_t ibs = 512; + char *ibuf; +#if ENABLE_FEATURE_DD_IBS_OBS + size_t obs = 512; + char *obuf; +#else +# define obs ibs +# define obuf ibuf +#endif + /* These are all zeroed at once! */ + struct { + IF_FEATURE_DD_IBS_OBS(size_t ocount;) + ssize_t prev_read_size; /* for detecting swab failure */ + off_t count; + off_t seek, skip; + const char *infile, *outfile; + } Z; +#define ocount (Z.ocount ) +#define prev_read_size (Z.prev_read_size) +#define count (Z.count ) +#define seek (Z.seek ) +#define skip (Z.skip ) +#define infile (Z.infile ) +#define outfile (Z.outfile) + + memset(&Z, 0, sizeof(Z)); + INIT_G(); + //fflush_all(); - is this needed because of NOEXEC? + + for (i = 1; argv[i]; i++) { + int what; + char *val; + char *arg = argv[i]; + +#if ENABLE_DESKTOP + /* "dd --". NB: coreutils 6.9 will complain if they see + * more than one of them. We wouldn't. */ + if (arg[0] == '-' && arg[1] == '-' && arg[2] == '\0') + continue; +#endif + val = strchr(arg, '='); + if (val == NULL) + bb_show_usage(); + *val = '\0'; + what = index_in_strings(keywords, arg); + if (what < 0) + bb_show_usage(); + /* *val = '='; - to preserve ps listing? */ + val++; +#if ENABLE_FEATURE_DD_IBS_OBS + if (what == OP_ibs) { + /* Must fit into positive ssize_t */ + ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); + /*continue;*/ + } + if (what == OP_obs) { + obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); + /*continue;*/ + } + if (what == OP_conv) { + G.flags |= parse_comma_flags(val, conv_words, "conv"); + /*continue;*/ + } + if (what == OP_iflag) { + G.flags |= parse_comma_flags(val, iflag_words, "iflag") << FLAG_IFLAG_SHIFT; + /*continue;*/ + } + if (what == OP_oflag) { + G.flags |= parse_comma_flags(val, oflag_words, "oflag") << FLAG_OFLAG_SHIFT; + /*continue;*/ + } +#endif + if (what == OP_bs) { + ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, cwbkMG_suffixes); + obs = ibs; + /*continue;*/ + } + /* These can be large: */ + if (what == OP_count) { + G.flags |= FLAG_COUNT; + count = XATOU_SFX(val, cwbkMG_suffixes); + /*continue;*/ + } + if (what == OP_seek) { + seek = XATOU_SFX(val, cwbkMG_suffixes); + /*continue;*/ + } + if (what == OP_skip) { + skip = XATOU_SFX(val, cwbkMG_suffixes); + /*continue;*/ + } + if (what == OP_if) { + infile = val; + /*continue;*/ + } + if (what == OP_of) { + outfile = val; + /*continue;*/ + } +#if ENABLE_FEATURE_DD_STATUS + if (what == OP_status) { + int n; + n = index_in_strings(status_words, val); + if (n < 0) + bb_error_msg_and_die(bb_msg_invalid_arg_to, val, "status"); + G.flags |= FLAG_STATUS_NONE << n; + /*continue;*/ + } +#endif + } /* end of "for (argv[i])" */ + + ibuf = alloc_buf(ibs); + obuf = ibuf; +#if ENABLE_FEATURE_DD_IBS_OBS + if (ibs != obs) { + G.flags |= FLAG_TWOBUFS; + obuf = alloc_buf(obs); + } +#endif + +#if ENABLE_FEATURE_DD_SIGNAL_HANDLING + signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); +#endif +#if ENABLE_FEATURE_DD_THIRD_STATUS_LINE + G.begin_time_us = monotonic_us(); +#endif + + if (infile) { + int iflag = O_RDONLY; +#if ENABLE_FEATURE_DD_IBS_OBS + if (G.flags & FLAG_IDIRECT) { +# ifdef O_DIRECT + iflag |= O_DIRECT; +# else + bb_error_msg_and_die("O_DIRECT not supported on this platform"); +# endif + } +#endif + xmove_fd(xopen(infile, iflag), ifd); + } else { + infile = bb_msg_standard_input; + } + if (outfile) { + int oflag = O_WRONLY | O_CREAT; + + if (!seek && !(G.flags & FLAG_NOTRUNC)) + oflag |= O_TRUNC; + if (G.flags & FLAG_APPEND) + oflag |= O_APPEND; +#if ENABLE_FEATURE_DD_IBS_OBS + if (G.flags & FLAG_ODIRECT) { +# ifdef O_DIRECT + oflag |= O_DIRECT; +# else + bb_error_msg_and_die("O_DIRECT not supported on this platform"); +# endif + } +#endif + xmove_fd(xopen(outfile, oflag), ofd); + + if (seek && !(G.flags & FLAG_NOTRUNC)) { + size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; + if (ftruncate(ofd, seek * blocksz) < 0) { + struct stat st; + + if (fstat(ofd, &st) < 0 + || S_ISREG(st.st_mode) + || S_ISDIR(st.st_mode) + ) { + goto die_outfile; + } + } + } + } else { + outfile = bb_msg_standard_output; + } + if (skip) { + size_t blocksz = (G.flags & FLAG_SKIP_BYTES) ? 1 : ibs; + if (lseek(ifd, skip * blocksz, SEEK_CUR) < 0) { + do { + ssize_t n = dd_read(ibuf, blocksz); + if (n < 0) + goto die_infile; + if (n == 0) + break; + } while (--skip != 0); + } + } + if (seek) { + size_t blocksz = (G.flags & FLAG_SEEK_BYTES) ? 1 : obs; + if (lseek(ofd, seek * blocksz, SEEK_CUR) < 0) + goto die_outfile; + } + + while (1) { + ssize_t n = ibs; + + if (G.flags & FLAG_COUNT) { + if (count == 0) + break; + if ((G.flags & FLAG_COUNT_BYTES) && count < ibs) + n = count; + } + + n = dd_read(ibuf, n); + if (n == 0) + break; + if (n < 0) { + /* "Bad block" */ + if (!(G.flags & FLAG_NOERROR)) + goto die_infile; + bb_simple_perror_msg(infile); + /* GNU dd with conv=noerror skips over bad blocks */ + xlseek(ifd, ibs, SEEK_CUR); + /* conv=noerror,sync writes NULs, + * conv=noerror just ignores input bad blocks */ + n = 0; + } + if (G.flags & FLAG_SWAB) { + uint16_t *p16; + ssize_t n2; + + /* Our code allows only last read to be odd-sized */ + if (prev_read_size & 1) + bb_error_msg_and_die("can't swab %lu byte buffer", + (unsigned long)prev_read_size); + prev_read_size = n; + + /* If n is odd, last byte is not swapped: + * echo -n "qwe" | dd conv=swab + * prints "wqe". + */ + p16 = (void*) ibuf; + n2 = (n >> 1); + while (--n2 >= 0) { + *p16 = bswap_16(*p16); + p16++; + } + } + count -= (G.flags & FLAG_COUNT_BYTES) ? n : 1; + if ((size_t)n == ibs) + G.in_full++; + else { + G.in_part++; + if (G.flags & FLAG_SYNC) { + memset(ibuf + n, 0, ibs - n); + n = ibs; + } + } +#if ENABLE_FEATURE_DD_IBS_OBS + if (G.flags & FLAG_TWOBUFS) { + char *tmp = ibuf; + while (n) { + size_t d = obs - ocount; + if (d > (size_t)n) + d = n; + memcpy(obuf + ocount, tmp, d); + n -= d; + tmp += d; + ocount += d; + if (ocount == obs) { + if (write_and_stats(obuf, obs, obs, outfile)) + goto out_status; + ocount = 0; + } + } + } else +#endif + { + if (write_and_stats(ibuf, n, obs, outfile)) + goto out_status; + } + } + + if (G.flags & FLAG_FSYNC) { + if (fsync(ofd) < 0) + goto die_outfile; + } + +#if ENABLE_FEATURE_DD_IBS_OBS + if (ocount != 0) { + if (write_and_stats(obuf, ocount, obs, outfile)) + goto out_status; + } +#endif + if (close(ifd) < 0) { + die_infile: + bb_simple_perror_msg_and_die(infile); + } + + if (close(ofd) < 0) { + die_outfile: + bb_simple_perror_msg_and_die(outfile); + } + + exitcode = EXIT_SUCCESS; + out_status: + if (!ENABLE_FEATURE_DD_STATUS || !(G.flags & FLAG_STATUS_NONE)) + dd_output_status(0); + +#if 0 /* can't just free(), they can be mmap()ed */ + if (ENABLE_FEATURE_CLEAN_UP) { + free(obuf); + if (G.flags & FLAG_TWOBUFS) + free(ibuf); + } +#endif + + return exitcode; +} diff --git a/busybox-1_37_0/coreutils/df.c b/busybox-1_37_0/coreutils/df.c new file mode 100644 index 000000000..03aa78148 --- /dev/null +++ b/busybox-1_37_0/coreutils/df.c @@ -0,0 +1,351 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini df implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * based on original code by (I think) Bruce Perens . + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Size reduction. Removed floating point dependency. Added error checking + * on output. Output stats on 0-sized filesystems if specifically listed on + * the command line. Properly round *-blocks, Used, and Available quantities. + * + * Aug 28, 2008 Bernhard Reutner-Fischer + * + * Implement -P and -B; better coreutils compat; cleanup + */ +//config:config DF +//config: bool "df (7.1 kb)" +//config: default y +//config: help +//config: df reports the amount of disk space used and available +//config: on filesystems. +//config: +//config:config FEATURE_DF_FANCY +//config: bool "Enable -a, -i, -B" +//config: default y +//config: depends on DF +//config: help +//config: -a Show all filesystems +//config: -i Inodes +//config: -B Blocksize +//config: +//config:config FEATURE_SKIP_ROOTFS +//config: bool "Skip rootfs in mount table" +//config: default y +//config: depends on DF +//config: help +//config: Ignore rootfs entry in mount table. +//config: +//config: In Linux, kernel has a special filesystem, rootfs, which is initially +//config: mounted on /. It contains initramfs data, if kernel is configured +//config: to have one. Usually, another file system is mounted over / early +//config: in boot process, and therefore most tools which manipulate +//config: mount table, such as df, will skip rootfs entry. +//config: +//config: However, some systems do not mount anything on /. +//config: If you need to configure busybox for one of these systems, +//config: you may find it useful to turn this option off to make df show +//config: initramfs statistics. +//config: +//config: Otherwise, choose Y. + +//applet:IF_DF(APPLET_NOEXEC(df, df, BB_DIR_BIN, BB_SUID_DROP, df)) + +//kbuild:lib-$(CONFIG_DF) += df.o + +/* BB_AUDIT SUSv3 _NOT_ compliant -- option -t missing. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/df.html */ + +//usage:#define df_trivial_usage +//usage: "[-Pk" +//usage: IF_FEATURE_HUMAN_READABLE("mh") +//usage: "T" +//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") +//usage: "] [-t TYPE] [FILESYSTEM]..." +//usage:#define df_full_usage "\n\n" +//usage: "Print filesystem usage statistics\n" +//usage: "\n -P POSIX output format" +//usage: "\n -k 1024-byte blocks (default)" +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -m 1M-byte blocks" +//usage: "\n -h Human readable (e.g. 1K 243M 2G)" +//usage: ) +//usage: "\n -T Print filesystem type" +//usage: "\n -t TYPE Print only mounts of this type" +//usage: IF_FEATURE_DF_FANCY( +//usage: "\n -a Show all filesystems" +//usage: "\n -i Inodes" +//usage: "\n -B SIZE Blocksize" +//usage: ) +//usage: +//usage:#define df_example_usage +//usage: "$ df\n" +//usage: "Filesystem 1K-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 8690864 8553540 137324 98% /\n" +//usage: "/dev/sda1 64216 36364 27852 57% /boot\n" +//usage: "$ df /dev/sda3\n" +//usage: "Filesystem 1K-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 8690864 8553540 137324 98% /\n" +//usage: "$ POSIXLY_CORRECT=sure df /dev/sda3\n" +//usage: "Filesystem 512B-blocks Used Available Use% Mounted on\n" +//usage: "/dev/sda3 17381728 17107080 274648 98% /\n" +//usage: "$ POSIXLY_CORRECT=yep df -P /dev/sda3\n" +//usage: "Filesystem 512-blocks Used Available Capacity Mounted on\n" +//usage: "/dev/sda3 17381728 17107080 274648 98% /\n" + +#include +#include +#include "libbb.h" +#include "unicode.h" + +#if !ENABLE_FEATURE_HUMAN_READABLE +static unsigned long kscale(unsigned long b, unsigned long bs) +{ + return (b * (unsigned long long) bs + 1024/2) / 1024; +} +#endif + +int df_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int df_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned long df_disp_hr = 1024; + exitcode_t status = EXIT_SUCCESS; + unsigned opt; + FILE *mount_table; + struct mntent *mount_entry; + struct statvfs s; + enum { + OPT_KILO = (1 << 0), + OPT_POSIX = (1 << 1), + OPT_FSTYPE = (1 << 2), + OPT_t = (1 << 3), + OPT_ALL = (1 << 4) * ENABLE_FEATURE_DF_FANCY, + OPT_INODE = (1 << 5) * ENABLE_FEATURE_DF_FANCY, + OPT_BSIZE = (1 << 6) * ENABLE_FEATURE_DF_FANCY, + OPT_HUMAN = (1 << (4 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_HUMANDEC = (1 << (5 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_MEGA = (1 << (6 + 3*ENABLE_FEATURE_DF_FANCY)) * ENABLE_FEATURE_HUMAN_READABLE, + }; + const char *disp_units_hdr = NULL; + char *chp, *opt_t; + + init_unicode(); + + /* From the manpage of df from coreutils-6.10: + * Disk space is shown in 1K blocks by default, unless the environment + * variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. + */ + if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */ + df_disp_hr = 512; + + opt = getopt32(argv, "^" + "kPTt:" + IF_FEATURE_DF_FANCY("aiB:") + IF_FEATURE_HUMAN_READABLE("hHm") + "\0" +#if ENABLE_FEATURE_HUMAN_READABLE && ENABLE_FEATURE_DF_FANCY + "k-mB:m-Bk:B-km" +#elif ENABLE_FEATURE_HUMAN_READABLE + "k-m:m-k" +#endif + , &opt_t + IF_FEATURE_DF_FANCY(, &chp) + ); + if (opt & OPT_MEGA) + df_disp_hr = 1024*1024; + + if (opt & OPT_BSIZE) { + /* GNU coreutils 8.25 accepts "-BMiB" form too */ + int i; + for (i = 0; kmg_i_suffixes[i].suffix[0]; i++) { + if (strcmp(kmg_i_suffixes[i].suffix, chp) == 0) { + df_disp_hr = kmg_i_suffixes[i].mult; + goto got_it; + } + } + /* Range used to disallow 0 */ + df_disp_hr = xatoul_range_sfx(chp, 1, ULONG_MAX, kmg_i_suffixes); + got_it: ; + } + + if (opt & (OPT_HUMAN|OPT_HUMANDEC)) { + df_disp_hr = 0; +//TODO: need to add support in make_human_readable_str() for "decimal human readable" + //if (opt & OPT_HUMANDEC) + // df_disp_hr--; + disp_units_hdr = " Size"; + } + if (opt & OPT_INODE) + disp_units_hdr = " Inodes"; + + if (disp_units_hdr == NULL) { +#if ENABLE_FEATURE_HUMAN_READABLE + disp_units_hdr = xasprintf("%s-blocks", + /* print df_disp_hr, show no fractionals, + * use suffixes if OPT_POSIX is set in opt */ + make_human_readable_str(df_disp_hr, 0, !!(opt & OPT_POSIX)) + ); +#else + disp_units_hdr = xasprintf("%lu-blocks", df_disp_hr); +#endif + } + + printf("Filesystem %s%-15sUsed Available %s Mounted on\n", + (opt & OPT_FSTYPE) ? "Type " : "", + disp_units_hdr, + (opt & OPT_POSIX) ? "Capacity" : "Use%"); + + mount_table = NULL; + argv += optind; + if (!argv[0]) { + mount_table = setmntent(bb_path_mtab_file, "r"); + if (!mount_table) + bb_simple_perror_msg_and_die(bb_path_mtab_file); + } + + while (1) { + const char *device; + const char *mount_point; + const char *fs_type; + + if (mount_table) { + mount_entry = getmntent(mount_table); + if (!mount_entry) { + endmntent(mount_table); + break; + } + } else { + mount_point = *argv++; + if (!mount_point) + break; + mount_entry = find_mount_point(mount_point, 1); + if (!mount_entry) { + bb_error_msg("%s: can't find mount point", mount_point); + set_error: + status = EXIT_FAILURE; + continue; + } + } + + device = mount_entry->mnt_fsname; + + /* GNU coreutils 6.10 skips certain mounts, try to be compatible */ + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) + continue; + + mount_point = mount_entry->mnt_dir; + fs_type = mount_entry->mnt_type; + + if (opt & OPT_t) { + if (strcmp(fs_type, opt_t) != 0) + continue; + } + + if (statvfs(mount_point, &s) != 0) { + bb_simple_perror_msg(mount_point); + goto set_error; + } + /* Some uclibc versions were seen to lose f_frsize + * (kernel does return it, but then uclibc does not copy it) + */ + if (s.f_frsize == 0) + s.f_frsize = s.f_bsize; + + if ((s.f_blocks > 0) || !mount_table || (opt & OPT_ALL)) { + unsigned long long blocks_used; + unsigned long long blocks_total; + unsigned blocks_percent_used; + + if (opt & OPT_INODE) { + s.f_blocks = s.f_files; + s.f_bavail = s.f_bfree = s.f_ffree; + s.f_frsize = 1; + if (df_disp_hr) + df_disp_hr = 1; + } + blocks_used = s.f_blocks - s.f_bfree; + blocks_total = blocks_used + s.f_bavail; + blocks_percent_used = blocks_total; /* 0% if blocks_total == 0, else... */ + if (blocks_total != 0) { + /* Downscale sizes for narrower division */ + unsigned u; + while (blocks_total >= INT_MAX / 101) { + blocks_total >>= 1; + blocks_used >>= 1; + } + u = (unsigned)blocks_used * 100u + (unsigned)blocks_total / 2; + blocks_percent_used = u / (unsigned)blocks_total; + } + +#ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY + 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_block_device("/"); + if (!device) { + goto set_error; + } + } +#endif + +#if ENABLE_UNICODE_SUPPORT + { + uni_stat_t uni_stat; + char *uni_dev = unicode_conv_to_printable(&uni_stat, device); + if (uni_stat.unicode_width > 20 && !(opt & OPT_POSIX)) { + printf("%s\n%20s", uni_dev, ""); + } else { + printf("%s%*s", uni_dev, 20 - (int)uni_stat.unicode_width, ""); + } + free(uni_dev); + if (opt & OPT_FSTYPE) { + char *uni_type = unicode_conv_to_printable(&uni_stat, fs_type); + if (uni_stat.unicode_width > 10 && !(opt & OPT_POSIX)) + printf(" %s\n%31s", uni_type, ""); + else + printf(" %s%*s", uni_type, 10 - (int)uni_stat.unicode_width, ""); + free(uni_type); + } + } +#else + if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX)) + printf("\n%-20s", ""); + if (opt & OPT_FSTYPE) { + if (printf(" %-10s", fs_type) > 11 && !(opt & OPT_POSIX)) + printf("\n%-30s", ""); + } +#endif + +#if ENABLE_FEATURE_HUMAN_READABLE + printf(" %9s ", + /* f_blocks x f_frsize / df_disp_hr, show one fractional, + * use suffixes if df_disp_hr == 0 */ + make_human_readable_str(s.f_blocks, s.f_frsize, df_disp_hr)); + + printf(" %9s " + 1, + /* EXPR x f_frsize / df_disp_hr, show one fractional, + * use suffixes if df_disp_hr == 0 */ + make_human_readable_str((s.f_blocks - s.f_bfree), + s.f_frsize, df_disp_hr)); + + printf("%9s %3u%% %s\n", + /* f_bavail x f_frsize / df_disp_hr, show one fractional, + * use suffixes if df_disp_hr == 0 */ + make_human_readable_str(s.f_bavail, s.f_frsize, df_disp_hr), + blocks_percent_used, mount_point); +#else + printf(" %9lu %9lu %9lu %3u%% %s\n", + kscale(s.f_blocks, s.f_frsize), + kscale(s.f_blocks - s.f_bfree, s.f_frsize), + kscale(s.f_bavail, s.f_frsize), + blocks_percent_used, mount_point); +#endif + } + } + + return status; +} diff --git a/busybox-1_37_0/coreutils/dirname.c b/busybox-1_37_0/coreutils/dirname.c new file mode 100644 index 000000000..71e1e2b7b --- /dev/null +++ b/busybox-1_37_0/coreutils/dirname.c @@ -0,0 +1,43 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini dirname implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DIRNAME +//config: bool "dirname (611 bytes)" +//config: default y +//config: help +//config: dirname is used to strip a non-directory suffix from +//config: a file name. + +//applet:IF_DIRNAME(APPLET_NOFORK(dirname, dirname, BB_DIR_USR_BIN, BB_SUID_DROP, dirname)) + +//kbuild:lib-$(CONFIG_DIRNAME) += dirname.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/dirname.html */ + +//usage:#define dirname_trivial_usage +//usage: "FILENAME" +//usage:#define dirname_full_usage "\n\n" +//usage: "Strip non-directory suffix from FILENAME" +//usage: +//usage:#define dirname_example_usage +//usage: "$ dirname /tmp/foo\n" +//usage: "/tmp\n" +//usage: "$ dirname /tmp/foo/\n" +//usage: "/tmp\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int dirname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dirname_main(int argc UNUSED_PARAM, char **argv) +{ + puts(dirname(single_argv(argv))); + return fflush_all(); +} diff --git a/busybox-1_37_0/coreutils/dos2unix.c b/busybox-1_37_0/coreutils/dos2unix.c new file mode 100644 index 000000000..c227cd50c --- /dev/null +++ b/busybox-1_37_0/coreutils/dos2unix.c @@ -0,0 +1,137 @@ +/* vi: set sw=4 ts=4: */ +/* + * dos2unix for BusyBox + * + * dos2unix '\n' converter 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. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config DOS2UNIX +//config: bool "dos2unix (5.5 kb)" +//config: default y +//config: help +//config: dos2unix is used to convert a text file from DOS format to +//config: UNIX format, and vice versa. +//config: +//config:config UNIX2DOS +//config: bool "unix2dos (5.5 kb)" +//config: default y +//config: help +//config: unix2dos is used to convert a text file from UNIX format to +//config: DOS format, and vice versa. + +//applet:IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, dos2unix)) +//applet:IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, unix2dos)) + +//kbuild:lib-$(CONFIG_DOS2UNIX) += dos2unix.o +//kbuild:lib-$(CONFIG_UNIX2DOS) += dos2unix.o + +//usage:#define dos2unix_trivial_usage +//usage: "[-ud] [FILE]" +//usage:#define dos2unix_full_usage "\n\n" +//usage: "Convert FILE in-place from DOS to Unix format.\n" +//usage: "When no file is given, use stdin/stdout.\n" +//usage: "\n -u dos2unix" +//usage: "\n -d unix2dos" +//usage: +//usage:#define unix2dos_trivial_usage +//usage: "[-ud] [FILE]" +//usage:#define unix2dos_full_usage "\n\n" +//usage: "Convert FILE in-place from Unix to DOS format.\n" +//usage: "When no file is given, use stdin/stdout.\n" +//usage: "\n -u dos2unix" +//usage: "\n -d unix2dos" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +enum { + CT_UNIX2DOS = 1, + CT_DOS2UNIX +}; + +/* if fn is NULL then input is stdin and output is stdout */ +static void convert(char *fn, int conv_type) +{ + FILE *in, *out; + int ch; + char *temp_fn = temp_fn; /* for compiler */ + char *resolved_fn = resolved_fn; + + in = stdin; + out = stdout; + if (fn != NULL) { + struct stat st; + int fd; + + resolved_fn = xmalloc_follow_symlinks(fn); + if (resolved_fn == NULL) + bb_simple_perror_msg_and_die(fn); + in = xfopen_for_read(resolved_fn); + xfstat(fileno(in), &st, resolved_fn); + + temp_fn = xasprintf("%sXXXXXX", resolved_fn); + fd = xmkstemp(temp_fn); + if (fchmod(fd, st.st_mode) == -1) + bb_simple_perror_msg_and_die(temp_fn); + fchown(fd, st.st_uid, st.st_gid); + + out = xfdopen_for_write(fd); + } + + while ((ch = fgetc(in)) != EOF) { + if (ch == '\r') + continue; + if (ch == '\n') + if (conv_type == CT_UNIX2DOS) + fputc('\r', out); + fputc(ch, out); + } + + if (fn != NULL) { + if (fclose(in) < 0 || fclose(out) < 0) { + unlink(temp_fn); + bb_perror_nomsg_and_die(); + } + xrename(temp_fn, resolved_fn); + free(temp_fn); + free(resolved_fn); + } +} + +int dos2unix_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dos2unix_main(int argc UNUSED_PARAM, char **argv) +{ + int o, conv_type; + + /* See if we are supposed to be doing dos2unix or unix2dos */ + if (ENABLE_DOS2UNIX + && (!ENABLE_UNIX2DOS || applet_name[0] == 'd') + ) { + conv_type = CT_DOS2UNIX; + } else { + conv_type = CT_UNIX2DOS; + } + + /* -u convert to unix, -d convert to dos */ + o = getopt32(argv, "^" "du" "\0" "u--d:d--u"); /* mutually exclusive */ + + /* Do the conversion requested by an argument else do the default + * conversion depending on our name. */ + if (o) + conv_type = o; + + argv += optind; + do { + /* might be convert(NULL) if there is no filename given */ + convert(*argv, conv_type); + } while (*argv && *++argv); + + return 0; +} diff --git a/busybox-1_37_0/coreutils/du.c b/busybox-1_37_0/coreutils/du.c new file mode 100644 index 000000000..4652b6300 --- /dev/null +++ b/busybox-1_37_0/coreutils/du.c @@ -0,0 +1,311 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini du implementation for busybox + * + * Copyright (C) 1999,2000,2001 by Lineo, inc. and John Beppu + * Copyright (C) 1999,2000,2001 by John Beppu + * Copyright (C) 2002 Edward Betts + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Mostly rewritten for SUSv3 compliance and to fix bugs/defects. + * 1) Added support for SUSv3 -a, -H, -L, gnu -c, and (busybox) -d options. + * The -d option allows setting of max depth (similar to gnu --max-depth). + * 2) Fixed incorrect size calculations for links and directories, especially + * when errors occurred. Calculates sizes should now match gnu du output. + * 3) Added error checking of output. + * 4) Fixed busybox bug #1284 involving long overflow with human_readable. + */ +//config:config DU +//config: bool "du (6.5 kb)" +//config: default y +//config: help +//config: du is used to report the amount of disk space used +//config: for specified files. +//config: +//config:config FEATURE_DU_DEFAULT_BLOCKSIZE_1K +//config: bool "Use default blocksize of 1024 bytes (else it's 512 bytes)" +//config: default y +//config: depends on DU + +//applet:IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_DU) += du.o + +/* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/du.html */ + +//usage:#define du_trivial_usage +//usage: "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." +//usage:#define du_full_usage "\n\n" +//usage: "Summarize disk space used for FILEs (or directories)\n" +//usage: "\n -a Show file sizes too" +//usage: "\n -b Apparent size (including holes)" +//usage: "\n -L Follow all symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: "\n -d N Limit output to directories (and files with -a) of depth < N" +//usage: "\n -c Show grand total" +//usage: "\n -l Count sizes many times if hard linked" +//usage: "\n -s Display only a total for each argument" +//usage: "\n -x Skip directories on different filesystems" +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h Sizes in human readable format (e.g., 1K 243M 2G)" +//usage: "\n -m Sizes in megabytes" +//usage: ) +//usage: "\n -k Sizes in kilobytes" IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") +//usage: IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K( +//usage: "\n Default unit is 512 bytes" +//usage: ) +//usage: +//usage:#define du_example_usage +//usage: "$ du\n" +//usage: "16 ./CVS\n" +//usage: "12 ./kernel-patches/CVS\n" +//usage: "80 ./kernel-patches\n" +//usage: "12 ./tests/CVS\n" +//usage: "36 ./tests\n" +//usage: "12 ./scripts/CVS\n" +//usage: "16 ./scripts\n" +//usage: "12 ./docs/CVS\n" +//usage: "104 ./docs\n" +//usage: "2417 .\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +enum { + OPT_a_files_too = (1 << 0), + OPT_H_follow_links = (1 << 1), + OPT_k_kbytes = (1 << 2), + OPT_L_follow_links = (1 << 3), + OPT_s_total_norecurse = (1 << 4), + OPT_x_one_FS = (1 << 5), + OPT_d_maxdepth = (1 << 6), + OPT_l_hardlinks = (1 << 7), + OPT_c_total = (1 << 8), + OPT_b = (1 << 9), + OPT_h_for_humans = (1 << 10), + OPT_m_mbytes = (1 << 11), +}; + +struct globals { +#if ENABLE_FEATURE_HUMAN_READABLE + unsigned long disp_unit; +#else + unsigned disp_k; +#endif + int max_print_depth; + bool status; + int slink_depth; + int du_depth; + dev_t dir_dev; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { setup_common_bufsiz(); } while (0) + + +static void print(unsigned long long size, const char *filename) +{ + /* TODO - May not want to defer error checking here. */ +#if ENABLE_FEATURE_HUMAN_READABLE +# if ENABLE_DESKTOP + /* ~30 bytes of code for extra compat: + * coreutils' du rounds sizes up: + * for example, 1025k file is shown as "2" by du -m. + * We round to nearest if human-readable [too hard to fix], + * else (fixed scale such as -m), we round up. To that end, + * add yet another half of the unit before displaying: + */ + if (G.disp_unit) + size += (G.disp_unit-1) / (unsigned)(512 * 2); +# endif + printf("%s\t%s\n", + /* size x 512 / G.disp_unit. + * If G.disp_unit == 0, show one fractional + * and use suffixes + */ + make_human_readable_str(size, (option_mask32 & OPT_b) ? 1 : 512, G.disp_unit), + filename); +#else + if (G.disp_k) { + if (!(option_mask32 & OPT_b)) { + size++; + size >>= 1; + } else { + size >>= 10; + } + } + printf("%llu\t%s\n", size, filename); +#endif +} + +/* tiny recursive du */ +static unsigned long long du(const char *filename) +{ + struct stat statbuf; + unsigned long long sum; + + if (lstat(filename, &statbuf) != 0) { + bb_simple_perror_msg(filename); + G.status = EXIT_FAILURE; + return 0; + } + + if (option_mask32 & OPT_x_one_FS) { + if (G.du_depth == 0) { + G.dir_dev = statbuf.st_dev; + } else if (G.dir_dev != statbuf.st_dev) { + return 0; + } + } + + sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks); + + if (S_ISLNK(statbuf.st_mode)) { + if (G.slink_depth > G.du_depth) { /* -H or -L */ + if (stat(filename, &statbuf) != 0) { + bb_simple_perror_msg(filename); + G.status = EXIT_FAILURE; + return 0; + } + sum = ((option_mask32 & OPT_b) ? statbuf.st_size : statbuf.st_blocks); + if (G.slink_depth == 1) { + /* Convert -H to -L */ + G.slink_depth = INT_MAX; + } + } + } + + if (!(option_mask32 & OPT_l_hardlinks) + && statbuf.st_nlink > 1 + ) { + /* Add files/directories with links only once */ + if (is_in_ino_dev_hashtable(&statbuf)) { + return 0; + } + add_to_ino_dev_hashtable(&statbuf, NULL); + } + + if (S_ISDIR(statbuf.st_mode)) { + DIR *dir; + struct dirent *entry; + char *newfile; + + dir = warn_opendir(filename); + if (!dir) { + G.status = EXIT_FAILURE; + return sum; + } + + while ((entry = readdir(dir))) { + newfile = concat_subpath_file(filename, entry->d_name); + if (newfile == NULL) + continue; + ++G.du_depth; + sum += du(newfile); + --G.du_depth; + free(newfile); + } + closedir(dir); + } else { + if (!(option_mask32 & OPT_a_files_too) && G.du_depth != 0) + return sum; + } + if (G.du_depth <= G.max_print_depth) { + print(sum, filename); + } + return sum; +} + +int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int du_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned long long total; + int slink_depth_save; + unsigned opt; + + INIT_G(); + +#if ENABLE_FEATURE_HUMAN_READABLE + IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 1024;) + IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_unit = 512;) + if (getenv("POSIXLY_CORRECT")) /* TODO - a new libbb function? */ + G.disp_unit = 512; +#else + IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;) + /* IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */ +#endif + G.max_print_depth = INT_MAX; + + /* Note: SUSv3 specifies that -a and -s options cannot be used together + * in strictly conforming applications. However, it also says that some + * du implementations may produce output when -a and -s are used together. + * gnu du exits with an error code in this case. We choose to simply + * ignore -a. This is consistent with -s being equivalent to -d 0. + */ +#if ENABLE_FEATURE_HUMAN_READABLE + opt = getopt32(argv, "^" + "aHkLsxd:+lcbhm" + "\0" "h-km:k-hm:m-hk:H-L:L-H:s-d:d-s", + &G.max_print_depth + ); + argv += optind; + if (opt & OPT_b) { + G.disp_unit = 1; + } + if (opt & OPT_h_for_humans) { + G.disp_unit = 0; + } + if (opt & OPT_m_mbytes) { + G.disp_unit = 1024*1024; + } + if (opt & OPT_k_kbytes) { + G.disp_unit = 1024; + } +#else + opt = getopt32(argv, "^" + "aHkLsxd:+lcb" + "\0" "H-L:L-H:s-d:d-s", + &G.max_print_depth + ); + argv += optind; +# if !ENABLE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K + if (opt & OPT_k_kbytes) { + G.disp_k = 1; + } +# endif +#endif + if (opt & OPT_H_follow_links) { + G.slink_depth = 1; + } + if (opt & OPT_L_follow_links) { + G.slink_depth = INT_MAX; + } + if (opt & OPT_s_total_norecurse) { + G.max_print_depth = 0; + } + + /* go through remaining args (if any) */ + if (!*argv) { + *--argv = (char*)"."; + if (G.slink_depth == 1) { + G.slink_depth = 0; + } + } + + slink_depth_save = G.slink_depth; + total = 0; + do { + total += du(*argv); + G.slink_depth = slink_depth_save; + } while (*++argv); + + if (ENABLE_FEATURE_CLEAN_UP) + reset_ino_dev_hashtable(); + if (opt & OPT_c_total) + print(total, "total"); + + fflush_stdout_and_exit(G.status); +} diff --git a/busybox-1_37_0/coreutils/echo.c b/busybox-1_37_0/coreutils/echo.c new file mode 100644 index 000000000..2a48d4a90 --- /dev/null +++ b/busybox-1_37_0/coreutils/echo.c @@ -0,0 +1,351 @@ +/* vi: set sw=4 ts=4: */ +/* + * echo implementation for busybox + * + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Original copyright notice is retained at the end of this file. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Because of behavioral differences, implemented configurable SUSv3 + * or 'fancy' gnu-ish behaviors. Also, reduced size and fixed bugs. + * 1) In handling '\c' escape, the previous version only suppressed the + * trailing newline. SUSv3 specifies _no_ output after '\c'. + * 2) SUSv3 specifies that octal escapes are of the form \0{#{#{#}}}. + * The previous version did not allow 4-digit octals. + */ +//config:config ECHO +//config: bool "echo (2 kb)" +//config: default y +//config: help +//config: echo prints a specified string to stdout. +//config: +//config:# this entry also appears in shell/Config.in, next to the echo builtin +//config:config FEATURE_FANCY_ECHO +//config: bool "Enable -n and -e options" +//config: default y +//config: depends on ECHO || ASH_ECHO || HUSH_ECHO + +//applet:IF_ECHO(APPLET_NOFORK(echo, echo, BB_DIR_BIN, BB_SUID_DROP, echo)) + +//kbuild:lib-$(CONFIG_ECHO) += echo.o + +//kbuild:lib-$(CONFIG_ASH_ECHO) += echo.o +//kbuild:lib-$(CONFIG_HUSH_ECHO) += echo.o + +/* BB_AUDIT SUSv3 compliant -- unless configured as fancy echo. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/echo.html */ + +//usage:#define echo_trivial_usage +//usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." +//usage:#define echo_full_usage "\n\n" +//usage: "Print ARGs to stdout" +//usage: IF_FEATURE_FANCY_ECHO( "\n" +//usage: "\n -n No trailing newline" +//usage: "\n -e Interpret backslash escapes (\\t=tab etc)" +//usage: "\n -E Don't interpret backslash escapes (default)" +//usage: ) +//usage: +//usage:#define echo_example_usage +//usage: "$ echo \"Erik is cool\"\n" +//usage: "Erik is cool\n" +//usage: IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" +//usage: "Erik\n" +//usage: "is\n" +//usage: "cool\n" +//usage: "$ echo \"Erik\\nis\\ncool\"\n" +//usage: "Erik\\nis\\ncool\n") + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +/* NB: can be used by shell even if not enabled as applet */ + +/* + * NB2: we don't use stdio, we need better error handing. + * Examples include writing into non-opened stdout and error on write. + * + * With stdio, output gets shoveled into stdout buffer, and even + * fflush cannot clear it out. It seems that even if libc receives + * EBADF on write attempts, it feels determined to output data no matter what. + * If echo is called by shell, it will try writing again later, and possibly + * will clobber future output. Not good. + * + * Solaris has fpurge which discards buffered input. glibc has __fpurge. + * But this function is not standard. + */ + +int echo_main(int argc UNUSED_PARAM, char **argv) +{ + char **pp; + const char *arg; + char *out; + char *buffer; + unsigned buflen; + int err; +#if !ENABLE_FEATURE_FANCY_ECHO + enum { + eflag = 0, /* 0 -- disable escape sequences */ + nflag = 1, /* 1 -- print '\n' */ + }; + + argv++; +#else + char nflag = 1; + char eflag = 0; + + while ((arg = *++argv) != NULL) { + char n, e; + + if (arg[0] != '-') + break; /* not an option arg, echo it */ + + /* 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. + */ + arg++; + n = nflag; + e = eflag; + do { + if (*arg == 'n') + n = 0; + else if (*arg == 'e') + e = '\\'; + else if (*arg != 'E') { + /* "-ccc" arg with one of c's invalid, echo it */ + /* arg consisting from just "-" also handled here */ + goto just_echo; + } + } while (*++arg); + nflag = n; + eflag = e; + } + just_echo: +#endif + + buflen = 0; + pp = argv; + while ((arg = *pp) != NULL) { + buflen += strlen(arg) + 1; + pp++; + } + out = buffer = xmalloc(buflen + 1); /* +1 is needed for "no args" case */ + + while ((arg = *argv) != NULL) { + int c; + + if (!eflag) { + /* optimization for very common case */ + out = stpcpy(out, arg); + } else + while ((c = *arg++) != '\0') { + if (c == eflag) { + /* This is an "\x" sequence */ + + if (*arg == 'c') { + /* "\c" means cancel newline and + * ignore all subsequent chars. */ + goto do_write; + } + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0') { + if ((unsigned char)(arg[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + arg++; + } + } + /* bb_process_escape_sequence handles NUL correctly + * ("...\" case). */ + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. ~30 bytes win */ + const char *z = arg; + c = bb_process_escape_sequence(&z); + arg = z; + } + } + *out++ = c; + } + + if (!*++argv) + break; + *out++ = ' '; + } + + if (nflag) { + *out++ = '\n'; + } + + do_write: + /* Careful to error out on partial writes too (think ENOSPC!) */ + errno = 0; + err = full_write(STDOUT_FILENO, buffer, out - buffer) != out - buffer; + if (err) { + bb_simple_perror_msg(bb_msg_write_error); + } + free(buffer); + return err; +} + +/* + * 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 + */ + +#ifdef VERSION_WITH_WRITEV +/* We can't use stdio. + * The reason for this is highly non-obvious. + * echo_main is used from shell. Shell must correctly handle "echo foo" + * if stdout is closed. With stdio, output gets shoveled into + * stdout buffer, and even fflush cannot clear it out. It seems that + * even if libc receives EBADF on write attempts, it feels determined + * to output data no matter what. So it will try later, + * and possibly will clobber future output. Not good. + * + * Using writev instead, with 'direct' conversion of argv vector. + */ + +int echo_main(int argc, char **argv) +{ + struct iovec io[argc]; + struct iovec *cur_io = io; + char *arg; + char *p; +#if !ENABLE_FEATURE_FANCY_ECHO + enum { + eflag = '\\', + nflag = 1, /* 1 -- print '\n' */ + }; + arg = *++argv; + if (!arg) + goto newline_ret; +#else + char nflag = 1; + char eflag = 0; + + while (1) { + arg = *++argv; + if (!arg) + goto newline_ret; + if (*arg != '-') + break; + + /* If it appears that we are handling options, then make sure + * that all of the options specified are actually valid. + * Otherwise, the string should just be echoed. + */ + p = arg + 1; + if (!*p) /* A single '-', so echo it. */ + goto just_echo; + + do { + if (!strchr("neE", *p)) + goto just_echo; + } while (*++p); + + /* All of the options in this arg are valid, so handle them. */ + p = arg + 1; + do { + if (*p == 'n') + nflag = 0; + if (*p == 'e') + eflag = '\\'; + } while (*++p); + } + just_echo: +#endif + + while (1) { + /* arg is already == *argv and isn't NULL */ + int c; + + cur_io->iov_base = p = arg; + + if (!eflag) { + /* optimization for very common case */ + p += strlen(arg); + } else while ((c = *arg++)) { + if (c == eflag) { + /* This is an "\x" sequence */ + + if (*arg == 'c') { + /* "\c" means cancel newline and + * ignore all subsequent chars. */ + cur_io->iov_len = p - (char*)cur_io->iov_base; + cur_io++; + goto ret; + } + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) { + arg++; + } +//FIXME? we also accept non-0 starting sequences (see echo-prints-slash_41 test) +// echo -ne '-\41-' prints "-!-". bash 5.0.17 does not (prints "-\41-"). + /* bb_process_escape_sequence can handle nul correctly */ + c = bb_process_escape_sequence( (void*) &arg); + } + *p++ = c; + } + + arg = *++argv; + if (arg) + *p++ = ' '; + cur_io->iov_len = p - (char*)cur_io->iov_base; + cur_io++; + if (!arg) + break; + } + + newline_ret: + if (nflag) { + cur_io->iov_base = (char*)"\n"; + cur_io->iov_len = 1; + cur_io++; + } + ret: + /* TODO: implement and use full_writev? */ + return writev(1, io, (cur_io - io)) >= 0; +} +#endif diff --git a/busybox-1_37_0/coreutils/env.c b/busybox-1_37_0/coreutils/env.c new file mode 100644 index 000000000..e9d3e883e --- /dev/null +++ b/busybox-1_37_0/coreutils/env.c @@ -0,0 +1,137 @@ +/* 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. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Original copyright notice is retained at the end of this file. + * + * Modified for BusyBox by Erik Andersen + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Fixed bug involving exit return codes if execvp fails. Also added + * output error checking. + */ +/* + * Modified by Vladimir Oleynik (C) 2003 + * - correct "-" option usage + * - multiple "-u unsetenv" support + * - GNU long option support + * - use xfunc_error_retval + */ +//config:config ENV +//config: bool "env (4.3 kb)" +//config: default y +//config: help +//config: env is used to set an environment variable and run +//config: a command; without options it displays the current +//config: environment. + +//applet:IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) + +//kbuild:lib-$(CONFIG_ENV) += env.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/env.html */ + +//usage:#define env_trivial_usage +//usage: "[-i0] [-u NAME]... [-] [NAME=VALUE]... [PROG ARGS]" +// The "-" can occur only once (unlike, say, -i): it terminates option processing, +// so if it is followed by another "-" arg (or any option-looking arg), +// that arg will be taken as PROG (or even as NAME=VALUE, example: "-z=QWE"). +//usage:#define env_full_usage "\n\n" +//usage: "Print current environment or run PROG after setting up environment\n" +//usage: "\n -, -i Start with empty environment" +//usage: "\n -0 NUL terminated output" +//usage: "\n -u NAME Remove variable from environment" + +#include "libbb.h" + +int env_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int env_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + llist_t *unset_env = NULL; + + opts = getopt32long(argv, "+i0u:*", + "ignore-environment\0" No_argument "i" + "null\0" No_argument "0" + "unset\0" Required_argument "u" + , &unset_env + ); + argv += optind; + if (argv[0] && LONE_DASH(argv[0])) { + opts |= 1; + ++argv; + } + if (opts & 1) { + clearenv(); + } + while (unset_env) { + char *var = llist_pop(&unset_env); + /* This does not handle -uVAR=VAL + * (coreutils _sets_ the variable in that case): */ + /*unsetenv(var);*/ + /* This does, but uses somewhan undocumented feature that + * putenv("name_without_equal_sign") unsets the variable: */ + putenv(var); + } + + while (*argv && (strchr(*argv, '=') != NULL)) { + if (putenv(*argv) < 0) { + bb_simple_perror_msg_and_die("putenv"); + } + ++argv; + } + + if (argv[0]) { + BB_EXECVP_or_die(argv); + } + + if (environ) { /* clearenv() may set environ == NULL! */ + char **ep; + opts = (opts & 2) ? 0 : '\n'; + for (ep = environ; *ep; ep++) { + printf("%s%c", *ep, opts); + } + } + + fflush_stdout_and_exit_SUCCESS(); +} + +/* + * 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. BSD Advertising Clause omitted per the July 22, 1999 licensing change + * ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change + * + * 4. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ''AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ diff --git a/busybox-1_37_0/coreutils/expand.c b/busybox-1_37_0/coreutils/expand.c new file mode 100644 index 000000000..c4db26055 --- /dev/null +++ b/busybox-1_37_0/coreutils/expand.c @@ -0,0 +1,253 @@ +/* expand - convert tabs to spaces + * unexpand - convert spaces to tabs + * + * Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * David MacKenzie + * + * Options for expand: + * -t num --tabs NUM Convert tabs to num spaces (default 8 spaces). + * -i --initial Only convert initial tabs on each line to spaces. + * + * Options for unexpand: + * -a --all Convert all blanks, instead of just initial blanks. + * -f --first-only Convert only leading sequences of blanks (default). + * -t num --tabs NUM Have tabs num characters apart instead of 8. + * + * Busybox version (C) 2007 by Tito Ragusa + * + * Caveat: this versions of expand and unexpand don't accept tab lists. + */ +//config:config EXPAND +//config: bool "expand (5.3 kb)" +//config: default y +//config: help +//config: By default, convert all tabs to spaces. +//config: +//config:config UNEXPAND +//config: bool "unexpand (5.5 kb)" +//config: default y +//config: help +//config: By default, convert only leading sequences of blanks to tabs. + +//applet:IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, BB_DIR_USR_BIN, BB_SUID_DROP, unexpand)) + +//kbuild:lib-$(CONFIG_EXPAND) += expand.o +//kbuild:lib-$(CONFIG_UNEXPAND) += expand.o + +//usage:#define expand_trivial_usage +//usage: "[-i] [-t N] [FILE]..." +//usage:#define expand_full_usage "\n\n" +//usage: "Convert tabs to spaces, writing to stdout\n" +//usage: "\n -i Don't convert tabs after non blanks" +//usage: "\n -t Tabstops every N chars" + +//usage:#define unexpand_trivial_usage +//usage: "[-fa][-t N] [FILE]..." +//usage:#define unexpand_full_usage "\n\n" +//usage: "Convert spaces to tabs, writing to stdout\n" +//usage: "\n -a Convert all blanks" +//usage: "\n -f Convert only leading blanks" +//usage: "\n -t N Tabstops every N chars" + +#include "libbb.h" +#include "unicode.h" + +enum { + OPT_INITIAL = 1 << 0, + OPT_TABS = 1 << 1, + OPT_ALL = 1 << 2, +}; + +//FIXME: does not work properly with input containing NULs +//coreutils 8.30 preserves NULs but treats them as chars of width zero: +//ABC will expand to 6 spaces, not 5. + +#if ENABLE_EXPAND +static void expand(FILE *file, unsigned tab_size, unsigned opt) +{ + + for (;;) { + char *line; + char *ptr; + char *ptr_strbeg; +//commented-out code handles NULs, +90 bytes of code, not tested much +// size_t linelen; +// unsigned len = 0; + +// linelen = 1024 * 1024; +// line = xmalloc_fgets_str_len(file, "\n", &linelen); + line = xmalloc_fgets(file); // + if (!line) + break; + ptr = ptr_strbeg = line; + for (;;) { + unsigned char c = *ptr; + if (c == '\0') { +// size_t rem = line + linelen - ptr; +// if (rem > 0) { +//# if ENABLE_UNICODE_SUPPORT +// len += unicode_strwidth(ptr_strbeg); +//# else +// len += ptr - ptr_strbeg; +//# endif +// printf("%s%c", ptr_strbeg, '\0'); +// memmove(ptr, ptr + 1, rem + 1); +// ptr_strbeg = ptr; +// linelen--; +// continue; +// } + break; + } + if ((opt & OPT_INITIAL) && !isblank(c)) { + /* not space or tab */ + break; + } + if (c == '\t') { + unsigned len = 0; // + *ptr = '\0'; +# if ENABLE_UNICODE_SUPPORT + len += unicode_strwidth(ptr_strbeg); +# else + len += ptr - ptr_strbeg; +# endif + len = tab_size - (len % tab_size); + /*while (ptr[1] == '\t') { ptr++; len += tab_size; } - can handle many tabs at once */ + printf("%s%*s", ptr_strbeg, len, ""); +// len = 0; + ptr_strbeg = ptr + 1; + } + ptr++; + } + fputs_stdout(ptr_strbeg); + free(line); + } +} +#endif + +#if ENABLE_UNEXPAND +static void unexpand(FILE *file, unsigned tab_size, unsigned opt) +{ + char *line; + + while ((line = xmalloc_fgets(file)) != NULL) { + char *ptr = line; + unsigned column = 0; + + while (*ptr) { + unsigned n; + unsigned len = 0; + + while (*ptr == ' ') { + ptr++; + len++; + } + column += len; + if (*ptr == '\t') { + column += tab_size - (column % tab_size); + ptr++; + continue; + } + + n = column / tab_size; + if (n) { + len = column = column % tab_size; + while (n--) + putchar('\t'); + } + + if (!(opt & OPT_ALL) && ptr != line) { + printf("%*s%s", len, "", ptr); + break; + } + n = strcspn(ptr, "\t "); + printf("%*s%.*s", len, "", n, ptr); +# if ENABLE_UNICODE_SUPPORT + { + char c = ptr[n]; + ptr[n] = '\0'; + len = unicode_strwidth(ptr); + ptr[n] = c; + } +# else + len = n; +# endif + ptr += n; + column = (column + len) % tab_size; + } + free(line); + } +} +#endif + +int expand_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int expand_main(int argc UNUSED_PARAM, char **argv) +{ + /* Default 8 spaces for 1 tab */ + const char *opt_t = "8"; + FILE *file; + unsigned tab_size; + unsigned opt; + exitcode_t exit_status = EXIT_SUCCESS; + + init_unicode(); + + if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) { + opt = getopt32long(argv, "it:", + "initial\0" No_argument "i" + "tabs\0" Required_argument "t" + , &opt_t + ); + } else { + opt = getopt32long(argv, "^" + "ft:a" + "\0" + "ta" /* -t NUM sets -a */, + "first-only\0" No_argument "f" + "tabs\0" Required_argument "t" + "all\0" No_argument "a" + , &opt_t + ); + /* -t implies -a, but an explicit -f overrides */ + if (opt & OPT_INITIAL) opt &= ~OPT_ALL; + } + tab_size = xatou_range(opt_t, 1, UINT_MAX); + + argv += optind; + + if (!*argv) { + *--argv = (char*)bb_msg_standard_input; + } + do { + file = fopen_or_warn_stdin(*argv); + if (!file) { + exit_status = EXIT_FAILURE; + continue; + } + + if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) + IF_EXPAND(expand(file, tab_size, opt)); + else + IF_UNEXPAND(unexpand(file, tab_size, opt)); + + /* Check and close the file */ + if (fclose_if_not_stdin(file)) { + bb_simple_perror_msg(*argv); + exit_status = EXIT_FAILURE; + } + /* If stdin also clear EOF */ + if (file == stdin) + clearerr(file); + } while (*++argv); + + /* Now close stdin also */ + /* (if we didn't read from it, it's a no-op) */ + if (fclose(stdin)) + bb_simple_perror_msg_and_die(bb_msg_standard_input); + + fflush_stdout_and_exit(exit_status); +} diff --git a/busybox-1_37_0/coreutils/expr.c b/busybox-1_37_0/coreutils/expr.c new file mode 100644 index 000000000..47ebe2fca --- /dev/null +++ b/busybox-1_37_0/coreutils/expr.c @@ -0,0 +1,559 @@ +/* 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 . + * Copyright (C) 2003-2005 Vladimir Oleynik + * - reduced 464 bytes. + * - 64 math support + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* This program evaluates expressions. Each token (operator, operand, + * parenthesis) of the expression must be a separate argument. The + * parser used is a reasonably general one, though any incarnation of + * it is language-specific. It is especially nice for expressions. + * + * 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). + */ +//config:config EXPR +//config: bool "expr (6.8 kb)" +//config: default y +//config: help +//config: expr is used to calculate numbers and print the result +//config: to standard output. +//config: +//config:config EXPR_MATH_SUPPORT_64 +//config: bool "Extend Posix numbers support to 64 bit" +//config: default y +//config: depends on EXPR +//config: help +//config: Enable 64-bit math support in the expr applet. This will make +//config: the applet slightly larger, but will allow computation with very +//config: large numbers. + +//applet:IF_EXPR(APPLET_NOEXEC(expr, expr, BB_DIR_USR_BIN, BB_SUID_DROP, expr)) + +//kbuild:lib-$(CONFIG_EXPR) += expr.o + +//usage:#define expr_trivial_usage +//usage: "EXPRESSION" +//usage:#define expr_full_usage "\n\n" +//usage: "Print the value of EXPRESSION\n" +//usage: "\n" +//usage: "EXPRESSION may be:\n" +//usage: " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" +//usage: " ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" +//usage: " ARG1 < ARG2 1 if ARG1 is less than ARG2, else 0. Similarly:\n" +//usage: " ARG1 <= ARG2\n" +//usage: " ARG1 = ARG2\n" +//usage: " ARG1 != ARG2\n" +//usage: " ARG1 >= ARG2\n" +//usage: " ARG1 > ARG2\n" +//usage: " ARG1 + ARG2 Sum of ARG1 and ARG2. Similarly:\n" +//usage: " ARG1 - ARG2\n" +//usage: " ARG1 * ARG2\n" +//usage: " ARG1 / ARG2\n" +//usage: " ARG1 % ARG2\n" +//usage: " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" +//usage: " match STRING REGEXP Same as STRING : REGEXP\n" +//usage: " substr STRING POS LEN Substring of STRING, POS counts from 1\n" +//usage: " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" +//usage: " length STRING Length of STRING\n" +//usage: " quote TOKEN Interpret TOKEN as a string, even if\n" +//usage: " it is a keyword like 'match' or an\n" +//usage: " operator like '/'\n" +//usage: " (EXPRESSION) Value of EXPRESSION\n" +//usage: "\n" +//usage: "Beware that many operators need to be escaped or quoted for shells.\n" +//usage: "Comparisons are arithmetic if both ARGs are numbers, else\n" +//usage: "lexicographical. Pattern matches return the string matched between\n" +//usage: "\\( and \\) or null; if \\( and \\) are not used, they return the number\n" +//usage: "of characters matched or 0." + +#include "libbb.h" +#include "common_bufsiz.h" +#include "xregex.h" + +#if ENABLE_EXPR_MATH_SUPPORT_64 +typedef int64_t arith_t; + +#define PF_REZ "ll" +#define PF_REZ_TYPE (long long) +#define STRTOL(s, e, b) strtoll(s, e, b) +#else +typedef long arith_t; + +#define PF_REZ "l" +#define PF_REZ_TYPE (long) +#define STRTOL(s, e, b) strtol(s, e, b) +#endif + +/* TODO: use bb_strtol[l]? It's easier to check for errors... */ + +/* The kinds of value we can have. */ +enum { + INTEGER, + STRING +}; + +/* A value is.... */ +struct valinfo { + smallint type; /* Which kind. */ + union { /* The value itself. */ + arith_t i; + char *s; + } u; +}; +typedef struct valinfo VALUE; + +/* The arguments given to the program, minus the program name. */ +struct globals { + char **args; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* NB: noexec applet - globals not zeroed */ \ +} while (0) + +/* forward declarations */ +static VALUE *eval(void); + + +/* Return a VALUE for I. */ + +static VALUE *int_value(arith_t i) +{ + VALUE *v; + + v = xzalloc(sizeof(VALUE)); + if (INTEGER) /* otherwise xzalloc did it already */ + v->type = INTEGER; + v->u.i = i; + return v; +} + +/* Return a VALUE for S. */ + +static VALUE *str_value(const char *s) +{ + VALUE *v; + + v = xzalloc(sizeof(VALUE)); + if (STRING) /* otherwise xzalloc did it already */ + v->type = STRING; + v->u.s = xstrdup(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) +{ + if (v->type == INTEGER) + return v->u.i == 0; + /* STRING: */ + return v->u.s[0] == '\0' || LONE_CHAR(v->u.s, '0'); +} + +/* Coerce V to a STRING value (can't fail). */ + +static void tostring(VALUE *v) +{ + if (v->type == INTEGER) { + v->u.s = xasprintf("%" PF_REZ "d", PF_REZ_TYPE v->u.i); + v->type = STRING; + } +} + +/* Coerce V to an INTEGER value. Return 1 on success, 0 on failure. */ + +static bool toarith(VALUE *v) +{ + if (v->type == STRING) { + arith_t i; + char *e; + + /* Don't interpret the empty string as an integer. */ + /* Currently does not worry about overflow or int/long differences. */ + i = STRTOL(v->u.s, &e, 10); + if ((v->u.s == e) || *e) + return 0; + free(v->u.s); + v->u.i = i; + v->type = INTEGER; + } + return 1; +} + +/* Return str[0]+str[1] if the next token matches STR exactly. + STR must not be NULL. */ + +static int nextarg(const char *str) +{ + if (*G.args == NULL || strcmp(*G.args, str) != 0) + return 0; + return (unsigned char)str[0] + (unsigned char)str[1]; +} + +/* The comparison operator handling functions. */ + +static int cmp_common(VALUE *l, VALUE *r, int op) +{ + arith_t ll, rr; + + ll = l->u.i; + rr = r->u.i; + if (l->type == STRING || r->type == STRING) { + tostring(l); + tostring(r); + ll = strcmp(l->u.s, r->u.s); + rr = 0; + } + /* calculating ll - rr and checking the result is prone to overflows. + * We'll do it differently: */ + if (op == '<') + return ll < rr; + if (op == ('<' + '=')) + return ll <= rr; + if (op == '=' || (op == '=' + '=')) + return ll == rr; + if (op == '!' + '=') + return ll != rr; + if (op == '>') + return ll > rr; + /* >= */ + return ll >= rr; +} + +/* The arithmetic operator handling functions. */ + +static arith_t arithmetic_common(VALUE *l, VALUE *r, int op) +{ + arith_t li, ri; + + if (!toarith(l) || !toarith(r)) + bb_simple_error_msg_and_die("non-numeric argument"); + li = l->u.i; + ri = r->u.i; + if (op == '+') + return li + ri; + if (op == '-') + return li - ri; + if (op == '*') + return li * ri; + if (ri == 0) + bb_simple_error_msg_and_die("division by zero"); + if (op == '/') + return li / ri; + return li % ri; +} + +/* 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) +{ + enum { NMATCH = 2 }; + VALUE *v; + regex_t re_buffer; + regmatch_t re_regs[NMATCH]; + + tostring(sv); + tostring(pv); + + if (pv->u.s[0] == '^') { + bb_error_msg( +"warning: '%s': using '^' as the first character\n" +"of a basic regular expression is not portable; it is ignored", pv->u.s); + } + + memset(&re_buffer, 0, sizeof(re_buffer)); + memset(re_regs, 0, sizeof(re_regs)); + xregcomp(&re_buffer, pv->u.s, 0); + + /* expr uses an anchored pattern match, so check that there was a + * match and that the match starts at offset 0. */ + if (regexec(&re_buffer, sv->u.s, NMATCH, re_regs, 0) != REG_NOMATCH + && re_regs[0].rm_so == 0 + ) { + /* Were \(...\) used? */ + if (re_buffer.re_nsub > 0 && re_regs[1].rm_so >= 0) { + sv->u.s[re_regs[1].rm_eo] = '\0'; + v = str_value(sv->u.s + re_regs[1].rm_so); + } else { + v = int_value(re_regs[0].rm_eo); + } + } else { + /* Match failed -- return the right kind of null. */ + if (re_buffer.re_nsub > 0) + v = str_value(""); + else + v = int_value(0); + } + regfree(&re_buffer); + return v; +} + +/* Handle bare operands and ( expr ) syntax. */ + +static VALUE *eval7(void) +{ + VALUE *v; + + if (!*G.args) + bb_simple_error_msg_and_die("syntax error"); + + if (nextarg("(")) { + G.args++; + v = eval(); + if (!nextarg(")")) + bb_simple_error_msg_and_die("syntax error"); + G.args++; + return v; + } + + if (nextarg(")")) + bb_simple_error_msg_and_die("syntax error"); + + return str_value(*G.args++); +} + +/* Handle match, substr, index, length, and quote keywords. */ + +static VALUE *eval6(void) +{ + static const char keywords[] ALIGN1 = + "quote\0""length\0""match\0""index\0""substr\0"; + + VALUE *r, *i1, *i2; + VALUE *l = l; /* silence gcc */ + VALUE *v = v; /* silence gcc */ + int key = *G.args ? index_in_strings(keywords, *G.args) + 1 : 0; + + if (key == 0) /* not a keyword */ + return eval7(); + G.args++; /* We have a valid token, so get the next argument. */ + if (key == 1) { /* quote */ + if (!*G.args) + bb_simple_error_msg_and_die("syntax error"); + return str_value(*G.args++); + } + if (key == 2) { /* length */ + r = eval6(); + tostring(r); + v = int_value(strlen(r->u.s)); + freev(r); + } else + l = eval6(); + + if (key == 3) { /* match */ + r = eval6(); + v = docolon(l, r); + freev(l); + freev(r); + } + if (key == 4) { /* index */ + r = eval6(); + tostring(l); + tostring(r); + v = int_value(strcspn(l->u.s, r->u.s) + 1); + if (v->u.i == (arith_t) strlen(l->u.s) + 1) + v->u.i = 0; + freev(l); + freev(r); + } + if (key == 5) { /* substr */ + i1 = eval6(); + i2 = eval6(); + tostring(l); + if (!toarith(i1) || !toarith(i2) + || i1->u.i > (arith_t) strlen(l->u.s) + || i1->u.i <= 0 || i2->u.i <= 0) + v = str_value(""); + else { + v = xmalloc(sizeof(VALUE)); + v->type = STRING; + v->u.s = xstrndup(l->u.s + i1->u.i - 1, i2->u.i); + } + freev(l); + freev(i1); + freev(i2); + } + return v; +} + +/* Handle : operator (pattern matching). + Calls docolon to do the real work. */ + +static VALUE *eval5(void) +{ + VALUE *l, *r, *v; + + l = eval6(); + while (nextarg(":")) { + G.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 op; + arith_t val; + + l = eval5(); + while (1) { + op = nextarg("*"); + if (!op) { op = nextarg("/"); + if (!op) { op = nextarg("%"); + if (!op) return l; + }} + G.args++; + r = eval5(); + val = arithmetic_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); + } +} + +/* Handle +, - operators. */ + +static VALUE *eval3(void) +{ + VALUE *l, *r; + int op; + arith_t val; + + l = eval4(); + while (1) { + op = nextarg("+"); + if (!op) { + op = nextarg("-"); + if (!op) return l; + } + G.args++; + r = eval4(); + val = arithmetic_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); + } +} + +/* Handle comparisons. */ + +static VALUE *eval2(void) +{ + VALUE *l, *r; + int op; + arith_t val; + + l = eval3(); + while (1) { + op = nextarg("<"); + if (!op) { op = nextarg("<="); + if (!op) { op = nextarg("="); + if (!op) { op = nextarg("=="); + if (!op) { op = nextarg("!="); + if (!op) { op = nextarg(">="); + if (!op) { op = nextarg(">"); + if (!op) return l; + }}}}}} + G.args++; + r = eval3(); + toarith(l); + toarith(r); + val = cmp_common(l, r, op); + freev(l); + freev(r); + l = int_value(val); + } +} + +/* Handle &. */ + +static VALUE *eval1(void) +{ + VALUE *l, *r; + + l = eval2(); + while (nextarg("&")) { + G.args++; + r = eval2(); + if (null(l) || null(r)) { + freev(l); + freev(r); + l = int_value(0); + } else + freev(r); + } + return l; +} + +/* Handle |. */ + +static VALUE *eval(void) +{ + VALUE *l, *r; + + l = eval1(); + while (nextarg("|")) { + G.args++; + r = eval1(); + if (null(l)) { + freev(l); + l = r; + } else + freev(r); + } + return l; +} + +int expr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int expr_main(int argc UNUSED_PARAM, char **argv) +{ + VALUE *v; + + INIT_G(); + + xfunc_error_retval = 2; /* coreutils compat */ + G.args = argv + 1; + if (*G.args == NULL) { + bb_simple_error_msg_and_die("too few arguments"); + } + v = eval(); + if (*G.args) + bb_simple_error_msg_and_die("syntax error"); + if (v->type == INTEGER) + printf("%" PF_REZ "d\n", PF_REZ_TYPE v->u.i); + else + puts(v->u.s); + fflush_stdout_and_exit(null(v)); +} diff --git a/busybox-1_37_0/coreutils/factor.c b/busybox-1_37_0/coreutils/factor.c new file mode 100644 index 000000000..90e9ed761 --- /dev/null +++ b/busybox-1_37_0/coreutils/factor.c @@ -0,0 +1,273 @@ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config FACTOR +//config: bool "factor (3.2 kb)" +//config: default y +//config: help +//config: factor factorizes integers + +//applet:IF_FACTOR(APPLET(factor, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_FACTOR) += factor.o + +//usage:#define factor_trivial_usage +//usage: "[NUMBER]..." +//usage:#define factor_full_usage "\n\n" +//usage: "Print prime factors" + +#include "libbb.h" +#include "common_bufsiz.h" + +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif + +typedef unsigned long long wide_t; + +#if ULLONG_MAX == (UINT_MAX * UINT_MAX + 2 * UINT_MAX) +/* "unsigned" is half as wide as ullong */ +typedef unsigned half_t; +#define HALF_MAX UINT_MAX +#define HALF_FMT "" +#elif ULLONG_MAX == (ULONG_MAX * ULONG_MAX + 2 * ULONG_MAX) +/* long is half as wide as ullong */ +typedef unsigned long half_t; +#define HALF_MAX ULONG_MAX +#define HALF_FMT "l" +#else +#error Cant find an integer type which is half as wide as ullong +#endif + +/* The trial divisor increment wheel. Use it to skip over divisors that + * are composites of 2, 3, 5, 7, or 11. + * Larger wheels improve sieving only slightly, but quickly grow in size + * (adding just one prime, 13, results in 5766 element sieve). + */ +#define R(a,b,c,d,e,f,g,h,i,j,A,B,C,D,E,F,G,H,I,J,x) \ + (((uint64_t)(a<<0) | (b<<3) | (c<<6) | (d<<9) | (e<<12) | (f<<15) | (g<<18) | (h<<21) | (i<<24) | (j<<27)) << 1) | \ + (((uint64_t)(A<<0) | (B<<3) | (C<<6) | (D<<9) | (E<<12) | (F<<15) | (G<<18) | (H<<21) | (I<<24) | (J<<27)) << 31) | \ + ((uint64_t)x << 61) +#define P(a,b,c,d,e,f,g,h,i,j,A,B,C,D,E,F,G,H,I,J,x) \ + R( (a/2),(b/2),(c/2),(d/2),(e/2),(f/2),(g/2),(h/2),(i/2),(j/2), \ + (A/2),(B/2),(C/2),(D/2),(E/2),(F/2),(G/2),(H/2),(I/2),(J/2), \ + (x/2) \ + ) +static const uint64_t packed_wheel[] = { + /* 1, 2, */ + P( 2, 4, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2, 6, 4, 6), + P( 8, 4, 2, 4, 2, 4,14, 4, 6, 2,10, 2, 6, 6, 4, 2, 4, 6, 2,10, 2), + P( 4, 2,12,10, 2, 4, 2, 4, 6, 2, 6, 4, 6, 6, 6, 2, 6, 4, 2, 6, 4), + P( 6, 8, 4, 2, 4, 6, 8, 6,10, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6), + P( 4, 2, 6,10, 2,10, 2, 4, 2, 4, 6, 8, 4, 2, 4,12, 2, 6, 4, 2, 6), + P( 4, 6,12, 2, 4, 2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6,10, 2, 4, 6, 2), + P( 6, 4, 2, 4, 2,10, 2,10, 2, 4, 6, 6, 2, 6, 6, 4, 6, 6, 2, 6, 4), + P( 2, 6, 4, 6, 8, 4, 2, 6, 4, 8, 6, 4, 6, 2, 4, 6, 8, 6, 4, 2,10), + P( 2, 6, 4, 2, 4, 2,10, 2,10, 2, 4, 2, 4, 8, 6, 4, 2, 4, 6, 6, 2), + P( 6, 4, 8, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 6, 6, 6, 2, 6, 6, 4), + P( 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2,10, 2, 6, 4, 6, 2, 6, 4, 2, 4), + P( 6, 6, 8, 4, 2, 6,10, 8, 4, 2, 4, 2, 4, 8,10, 6, 2, 4, 8, 6, 6), + P( 4, 2, 4, 6, 2, 6, 4, 6, 2,10, 2,10, 2, 4, 2, 4, 6, 2, 6, 4, 2), + P( 4, 6, 6, 2, 6, 6, 6, 4, 6, 8, 4, 2, 4, 2, 4, 8, 6, 4, 8, 4, 6), + P( 2, 6, 6, 4, 2, 4, 6, 8, 4, 2, 4, 2,10, 2,10, 2, 4, 2, 4, 6, 2), + P(10, 2, 4, 6, 8, 6, 4, 2, 6, 4, 6, 8, 4, 6, 2, 4, 8, 6, 4, 6, 2), + P( 4, 6, 2, 6, 6, 4, 6, 6, 2, 6, 6, 4, 2,10, 2,10, 2, 4, 2, 4, 6), + P( 2, 6, 4, 2,10, 6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4, 2,12, 6, 4), + P( 6, 2, 4, 6, 2,12, 4, 2, 4, 8, 6, 4, 2, 4, 2,10, 2,10, 6, 2, 4), + P( 6, 2, 6, 4, 2, 4, 6, 6, 2, 6, 4, 2,10, 6, 8, 6, 4, 2, 4, 8, 6), + P( 4, 6, 2, 4, 6, 2, 6, 6, 6, 4, 6, 2, 6, 4, 2, 4, 2,10,12, 2, 4), + P( 2,10, 2, 6, 4, 2, 4, 6, 6, 2,10, 2, 6, 4,14, 4, 2, 4, 2, 4, 8), + P( 6, 4, 6, 2, 4, 6, 2, 6, 6, 4, 2, 4, 6, 2, 6, 4, 2, 4,12, 2,12), +}; +#undef P +#undef R +#define WHEEL_START 5 +#define WHEEL_SIZE (5 + 24 * 20) +#define square_count (((uint8_t*)&bb_common_bufsiz1)[0]) +#define wheel_tab (((uint8_t*)&bb_common_bufsiz1) + 1) +/* + * Why, you ask? + * plain byte array: + * function old new delta + * wheel_tab - 485 +485 + * 3-bit-packed insanity: + * packed_wheel - 184 +184 + * factor_main 108 163 +55 + */ +static void unpack_wheel(void) +{ + int i; + uint8_t *p; + + setup_common_bufsiz(); + wheel_tab[0] = 1; + wheel_tab[1] = 2; + p = &wheel_tab[2]; + for (i = 0; i < ARRAY_SIZE(packed_wheel); i++) { + uint64_t v = packed_wheel[i]; + while ((v & 0xe) != 0) { + *p = v & 0xe; + //printf("%2u,", *p); + p++; + v >>= 3; + } + //printf("\n"); + } +} + +/* Prevent inlining, factorize() needs all help it can get with reducing register pressure */ +static NOINLINE void print_w(wide_t n) +{ + unsigned rep = square_count; + do + printf(" %llu", n); + while (--rep != 0); +} +static NOINLINE void print_h(half_t n) +{ + print_w(n); +} + +static void factorize(wide_t N); + +static half_t isqrt_odd(wide_t N) +{ + half_t s = isqrt(N); + /* s^2 is <= N, (s+1)^2 > N */ + + /* If s^2 in fact is EQUAL to N, it's very lucky. + * Examples: + * factor 18446743988964486098 = 2 * 3037000493 * 3037000493 + * factor 18446743902517389507 = 3 * 2479700513 * 2479700513 + */ + if ((wide_t)s * s == N) { + /* factorize sqrt(N), printing each factor twice */ + square_count *= 2; + factorize(s); + /* Let caller know we recursed */ + return 0; + } + + /* Subtract 1 from even s, odd s won't change: */ + /* (doesnt work for zero, but we know that s != 0 here) */ + s = (s - 1) | 1; + return s; +} + +static NOINLINE void factorize(wide_t N) +{ + unsigned w; + half_t factor; + half_t max_factor; + + if (N < 4) + goto end; + + /* The code needs to be optimized for the case where + * there are large prime factors. For example, + * this is not hard: + * 8262075252869367027 = 3 7 17 23 47 101 113 127 131 137 823 + * (the largest divisor to test for largest factor 823 + * is only ~sqrt(823) = 28, the entire factorization needs + * only ~33 trial divisions) + * but this is: + * 18446744073709551601 = 53 348051774975651917 + * the last factor requires testing up to + * 589959129 - about 100 million iterations. + * The slowest case (largest prime) for N < 2^64 is + * factor 18446744073709551557 (0xffffffffffffffc5). + */ + max_factor = isqrt_odd(N); + if (!max_factor) + return; /* square was detected and recursively factored */ + factor = 2; + w = 0; + for (;;) { + half_t fw; + + /* The division is the most costly part of the loop. + * On 64bit CPUs, takes at best 12 cycles, often ~20. + */ + while ((N % factor) == 0) { /* not likely */ + N = N / factor; + print_h(factor); + max_factor = isqrt_odd(N); + if (!max_factor) + return; /* square was detected */ + } + if (factor >= max_factor) + break; + fw = factor + wheel_tab[w]; + if (fw < factor) + break; /* overflow */ + factor = fw; + w++; + if (w < WHEEL_SIZE) + continue; + w = WHEEL_START; + } + end: + if (N > 1) + print_w(N); + bb_putchar('\n'); +} + +static void factorize_numstr(const char *numstr) +{ + wide_t N; + + /* Leading + is ok (coreutils compat) */ + if (*numstr == '+') + numstr++; + N = bb_strtoull(numstr, NULL, 10); + if (errno) + bb_show_usage(); + printf("%llu:", N); + square_count = 1; + factorize(N); +} + +int factor_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int factor_main(int argc UNUSED_PARAM, char **argv) +{ + unpack_wheel(); + + //// coreutils has undocumented option ---debug (three dashes) + //getopt32(argv, ""); + //argv += optind; + argv++; + + if (!*argv) { + /* Read from stdin, several numbers per line are accepted */ + for (;;) { + char *numstr, *line; + line = xmalloc_fgetline(stdin); + if (!line) + return EXIT_SUCCESS; + numstr = line; + for (;;) { + char *end; + numstr = skip_whitespace(numstr); + if (!numstr[0]) + break; + end = skip_non_whitespace(numstr); + if (*end != '\0') + *end++ = '\0'; + factorize_numstr(numstr); + numstr = end; + } + free(line); + } + } + + do { + /* Leading spaces are ok (coreutils compat) */ + factorize_numstr(skip_whitespace(*argv)); + } while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/false.c b/busybox-1_37_0/coreutils/false.c new file mode 100644 index 000000000..ee175a9a2 --- /dev/null +++ b/busybox-1_37_0/coreutils/false.c @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini false implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config FALSE +//config: bool "false (314 bytes)" +//config: default y +//config: help +//config: false returns an exit code of FALSE (1). + +//applet:IF_FALSE(APPLET_NOFORK(false, false, BB_DIR_BIN, BB_SUID_DROP, false)) + +//kbuild:lib-$(CONFIG_FALSE) += false.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */ + +/* "false --help" is special-cased to ignore --help */ +//usage:#define false_trivial_usage NOUSAGE_STR +//usage:#define false_full_usage "" +//usage:#define false_example_usage +//usage: "$ false\n" +//usage: "$ echo $?\n" +//usage: "1\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int false_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int false_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/coreutils/fold.c b/busybox-1_37_0/coreutils/fold.c new file mode 100644 index 000000000..8112fe911 --- /dev/null +++ b/busybox-1_37_0/coreutils/fold.c @@ -0,0 +1,186 @@ +/* vi: set sw=4 ts=4: */ +/* + * fold -- wrap each input line to fit in specified width. + * + * Written by David MacKenzie, djm@gnu.ai.mit.edu. + * Copyright (C) 91, 1995-2002 Free Software Foundation, Inc. + * + * Modified for busybox based on coreutils v 5.0 + * Copyright (C) 2003 Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config FOLD +//config: bool "fold (4.8 kb)" +//config: default y +//config: help +//config: Wrap text to fit a specific width. + +//applet:IF_FOLD(APPLET_NOEXEC(fold, fold, BB_DIR_USR_BIN, BB_SUID_DROP, fold)) + +//kbuild:lib-$(CONFIG_FOLD) += fold.o + +//usage:#define fold_trivial_usage +//usage: "[-bs] [-w WIDTH] [FILE]..." +//usage:#define fold_full_usage "\n\n" +//usage: "Wrap input lines in FILEs (or stdin), writing to stdout\n" +//usage: "\n -b Count bytes rather than columns" +//usage: "\n -s Break at spaces" +//usage: "\n -w Use WIDTH columns instead of 80" + +#include "libbb.h" +#include "unicode.h" + +/* This is a NOEXEC applet. Be very careful! */ + +/* Must match getopt32 call */ +#define FLAG_COUNT_BYTES 1 +#define FLAG_BREAK_SPACES 2 +#define FLAG_WIDTH 4 + +/* Assuming the current column is COLUMN, return the column that + printing C will move the cursor to. + The first column is 0. */ +static int adjust_column(unsigned column, char c) +{ + if (option_mask32 & FLAG_COUNT_BYTES) + return ++column; + + if (c == '\t') + return column + 8 - column % 8; + + if (c == '\b') { + if ((int)--column < 0) + column = 0; + } + else if (c == '\r') + column = 0; + else { /* just a printable char */ + if (unicode_status != UNICODE_ON /* every byte is a new char */ + || (c & 0xc0) != 0x80 /* it isn't a 2nd+ byte of a Unicode char */ + ) { + column++; + } + } + return column; +} + +/* Note that this function can write NULs, unlike fputs etc. */ +static void write2stdout(const void *buf, unsigned size) +{ + fwrite(buf, 1, size, stdout); +} + +int fold_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fold_main(int argc UNUSED_PARAM, char **argv) +{ + char *line_out = NULL; + const char *w_opt = "80"; + unsigned width; + exitcode_t exitcode = EXIT_SUCCESS; + + init_unicode(); + + if (ENABLE_INCLUDE_SUSv2) { + /* Turn any numeric options into -w options. */ + int i; + for (i = 1; argv[i]; i++) { + const char *a = argv[i]; + if (*a == '-') { + a++; + if (*a == '-' && !a[1]) /* "--" */ + break; + if (isdigit(*a)) + argv[i] = xasprintf("-w%s", a); + } + } + } + + getopt32(argv, "bsw:", &w_opt); + width = xatou_range(w_opt, 1, 10000); + + argv += optind; + if (!*argv) + *--argv = (char*)"-"; + + do { + FILE *istream = fopen_or_warn_stdin(*argv); + int c; + unsigned column = 0; /* Screen column where next char will go */ + unsigned offset_out = 0; /* Index in 'line_out' for next char */ + + if (istream == NULL) { + exitcode = EXIT_FAILURE; + continue; + } + + while ((c = getc(istream)) != EOF) { + /* We grow line_out in chunks of 0x1000 bytes */ + if ((offset_out & 0xfff) == 0) { + line_out = xrealloc(line_out, offset_out + 0x1000); + } + rescan: + line_out[offset_out] = c; + if (c == '\n') { + write2stdout(line_out, offset_out + 1); + column = offset_out = 0; + continue; + } + column = adjust_column(column, c); + if (column <= width || offset_out == 0) { + /* offset_out == 0 case happens + * with small width (say, 1) and tabs. + * The very first tab already goes to column 8, + * but we must not wrap it */ + offset_out++; + continue; + } + + /* This character would make the line too long. + * Print the line plus a newline, and make this character + * start the next line */ + if (option_mask32 & FLAG_BREAK_SPACES) { + unsigned i; + unsigned logical_end; + + /* Look for the last blank. */ + for (logical_end = offset_out - 1; (int)logical_end >= 0; logical_end--) { + if (!isblank(line_out[logical_end])) + continue; + + /* Found a space or tab. + * Output up to and including it, and start a new line */ + logical_end++; + /*line_out[logical_end] = '\n'; - NO! this nukes one buffered character */ + write2stdout(line_out, logical_end); + putchar('\n'); + /* Move the remainder to the beginning of the next line. + * The areas being copied here might overlap. */ + memmove(line_out, line_out + logical_end, offset_out - logical_end); + offset_out -= logical_end; + for (column = i = 0; i < offset_out; i++) { + column = adjust_column(column, line_out[i]); + } + goto rescan; + } + /* No blank found, wrap will split the overlong word */ + } + /* Output what we accumulated up to now, and start a new line */ + line_out[offset_out] = '\n'; + write2stdout(line_out, offset_out + 1); + column = offset_out = 0; + goto rescan; + } /* while (not EOF) */ + + if (offset_out) { + write2stdout(line_out, offset_out); + } + + if (fclose_if_not_stdin(istream)) { + bb_simple_perror_msg(*argv); + exitcode = EXIT_FAILURE; + } + } while (*++argv); + + fflush_stdout_and_exit(exitcode); +} diff --git a/busybox-1_37_0/coreutils/head.c b/busybox-1_37_0/coreutils/head.c new file mode 100644 index 000000000..ec83a284a --- /dev/null +++ b/busybox-1_37_0/coreutils/head.c @@ -0,0 +1,272 @@ +/* vi: set sw=4 ts=4: */ +/* + * head implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config HEAD +//config: bool "head (4 kb)" +//config: default y +//config: help +//config: head is used to print the first specified number of lines +//config: from files. +//config: +//config:config FEATURE_FANCY_HEAD +//config: bool "Enable -c, -q, and -v" +//config: default y +//config: depends on HEAD + +//applet:IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) + +//kbuild:lib-$(CONFIG_HEAD) += head.o + +/* BB_AUDIT SUSv3 compliant */ +/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/head.html */ + +//usage:#define head_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define head_full_usage "\n\n" +//usage: "Print first 10 lines of FILEs (or stdin).\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -n N[bkm] Print first N lines" +//usage: IF_FEATURE_FANCY_HEAD( +//usage: "\n -n -N[bkm] Print all except N last lines" +//usage: "\n -c [-]N[bkm] Print first N bytes" +//usage: ) +//usage: "\n (b:*512 k:*1024 m:*1024^2)" +//usage: IF_FEATURE_FANCY_HEAD( +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: ) +//usage: +//usage:#define head_example_usage +//usage: "$ head -n 2 /etc/passwd\n" +//usage: "root:x:0:0:root:/root:/bin/bash\n" +//usage: "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +#if !ENABLE_FEATURE_FANCY_HEAD +# define print_first_N(fp,count,bytes) print_first_N(fp,count) +#endif +static void +print_first_N(FILE *fp, unsigned long count, bool count_bytes) +{ +#if !ENABLE_FEATURE_FANCY_HEAD + const int count_bytes = 0; +#endif + while (count) { + int c = getc(fp); + if (c == EOF) + break; + if (count_bytes || (c == '\n')) + --count; + putchar(c); + } +} + +#if ENABLE_FEATURE_FANCY_HEAD +static void +print_except_N_last_bytes(FILE *fp, unsigned count) +{ + unsigned char *circle = xmalloc(++count); + unsigned head = 0; + for (;;) { + int c; + c = getc(fp); + if (c == EOF) + goto ret; + circle[head++] = c; + if (head == count) + break; + } + for (;;) { + int c; + if (head == count) + head = 0; + putchar(circle[head]); + c = getc(fp); + if (c == EOF) + goto ret; + circle[head] = c; + head++; + } + ret: + free(circle); +} + +static void +print_except_N_last_lines(FILE *fp, unsigned count) +{ + char **circle = xzalloc((++count) * sizeof(circle[0])); + unsigned head = 0; + for (;;) { + char *c; + c = xmalloc_fgets(fp); + if (!c) + goto ret; + circle[head++] = c; + if (head == count) + break; + } + for (;;) { + char *c; + if (head == count) + head = 0; + fputs_stdout(circle[head]); + c = xmalloc_fgets(fp); + if (!c) + goto ret; + free(circle[head]); + circle[head++] = c; + } + ret: + head = 0; + for (;;) { + free(circle[head++]); + if (head == count) + break; + } + free(circle); +} +#else +/* Must never be called */ +void print_except_N_last_bytes(FILE *fp, unsigned count); +void print_except_N_last_lines(FILE *fp, unsigned count); +#endif + +#if !ENABLE_FEATURE_FANCY_HEAD +# define eat_num(negative_N,p) eat_num(p) +#endif +static unsigned long +eat_num(bool *negative_N, const char *p) +{ +#if ENABLE_FEATURE_FANCY_HEAD + if (*p == '-') { + *negative_N = 1; + p++; + } +#endif + return xatoul_sfx(p, bkm_suffixes); +} + +static const char head_opts[] ALIGN1 = + "n:" +#if ENABLE_FEATURE_FANCY_HEAD + "c:qv" +#endif + ; + +#define header_fmt_str "\n==> %s <==\n" + +int head_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int head_main(int argc, char **argv) +{ + unsigned long count = 10; +#if ENABLE_FEATURE_FANCY_HEAD + int header_threshhold = 1; + bool count_bytes = 0; + bool negative_N = 0; +#else +# define header_threshhold 1 +# define count_bytes 0 +# define negative_N 0 +#endif + FILE *fp; + const char *fmt; + char *p; + int opt; + int retval = EXIT_SUCCESS; + +#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD + /* Allow legacy syntax of an initial numeric option without -n. */ + if (argv[1] && argv[1][0] == '-' + && isdigit(argv[1][1]) + ) { + --argc; + ++argv; + p = argv[0] + 1; + goto GET_COUNT; + } +#endif + + /* No size benefit in converting this to getopt32 */ + while ((opt = getopt(argc, argv, head_opts)) > 0) { + switch (opt) { +#if ENABLE_FEATURE_FANCY_HEAD + case 'q': + header_threshhold = INT_MAX; + break; + case 'v': + header_threshhold = -1; + break; + case 'c': + count_bytes = 1; + /* fall through */ +#endif + case 'n': + p = optarg; +#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD + GET_COUNT: +#endif + count = eat_num(&negative_N, p); + break; + default: + bb_show_usage(); + } + } + + argc -= optind; + argv += optind; + if (!*argv) + *--argv = (char*)"-"; + + fmt = header_fmt_str + 1; + if (argc <= header_threshhold) { +#if ENABLE_FEATURE_FANCY_HEAD + header_threshhold = 0; +#else + fmt += 11; /* "" */ +#endif + } + if (negative_N) { + if (count >= INT_MAX / sizeof(char*)) + bb_error_msg("count is too big: %lu", count); + } + + do { + fp = fopen_or_warn_stdin(*argv); + if (fp) { + if (fp == stdin) { + *argv = (char *) bb_msg_standard_input; + } + if (header_threshhold) { + printf(fmt, *argv); + } + if (negative_N) { + if (count_bytes) { + print_except_N_last_bytes(fp, count); + } else { + print_except_N_last_lines(fp, count); + } + } else { + print_first_N(fp, count, count_bytes); + } + die_if_ferror_stdout(); + if (fclose_if_not_stdin(fp)) { + bb_simple_perror_msg(*argv); + retval = EXIT_FAILURE; + } + } else { + retval = EXIT_FAILURE; + } + fmt = header_fmt_str; + } while (*++argv); + + fflush_stdout_and_exit(retval); +} diff --git a/busybox-1_37_0/coreutils/hostid.c b/busybox-1_37_0/coreutils/hostid.c new file mode 100644 index 000000000..0dd18ffd9 --- /dev/null +++ b/busybox-1_37_0/coreutils/hostid.c @@ -0,0 +1,42 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini hostid implementation for busybox + * + * Copyright (C) 2000 Edward Betts . + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config HOSTID +//config: bool "hostid (566 bytes)" +//config: default y +//config: help +//config: hostid prints the numeric identifier (in hexadecimal) for +//config: the current host. + +//applet:IF_HOSTID(APPLET_NOFORK(hostid, hostid, BB_DIR_USR_BIN, BB_SUID_DROP, hostid)) + +//kbuild:lib-$(CONFIG_HOSTID) += hostid.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define hostid_trivial_usage +//usage: "" +//usage:#define hostid_full_usage "\n\n" +//usage: "Print out a unique 32-bit identifier for the machine" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int hostid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + if (argv[1]) { + bb_show_usage(); + } + + /* POSIX says gethostid returns a "32-bit identifier" */ + printf("%08x\n", (unsigned)(uint32_t)gethostid()); + + return fflush_all(); +} diff --git a/busybox-1_37_0/coreutils/id.c b/busybox-1_37_0/coreutils/id.c new file mode 100644 index 000000000..a4f178bda --- /dev/null +++ b/busybox-1_37_0/coreutils/id.c @@ -0,0 +1,269 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini id implementation for busybox + * + * Copyright (C) 2000 by Randolph Chung + * Copyright (C) 2008 by Tito Ragusa + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Hacked by Tito Ragusa (C) 2004 to handle usernames of whatever + * length and to be more similar to GNU id. + * -Z option support: by Yuichi Nakamura + * Added -G option Tito Ragusa (C) 2008 for SUSv3. + */ +//config:config ID +//config: bool "id (7.1 kb)" +//config: default y +//config: help +//config: id displays the current user and group ID names. +//config: +//config:config GROUPS +//config: bool "groups (6.8 kb)" +//config: default y +//config: help +//config: Print the group names associated with current user id. + +//applet:IF_GROUPS(APPLET_NOEXEC(groups, id, BB_DIR_USR_BIN, BB_SUID_DROP, groups)) +//applet:IF_ID( APPLET_NOEXEC(id, id, BB_DIR_USR_BIN, BB_SUID_DROP, id )) + +//kbuild:lib-$(CONFIG_GROUPS) += id.o +//kbuild:lib-$(CONFIG_ID) += id.o + +/* BB_AUDIT SUSv3 compliant. */ + +//usage:#define id_trivial_usage +//usage: "[-ugGnr"IF_SELINUX("Z")"] [USER]" +//usage:#define id_full_usage "\n\n" +//usage: "Print information about USER or the current user\n" +//usage: IF_SELINUX( +//usage: "\n -Z Security context" +//usage: ) +//usage: "\n -u User ID" +//usage: "\n -g Group ID" +//usage: "\n -G Supplementary group IDs" +//usage: "\n -n Print names instead of numbers" +//usage: "\n -r Print real ID instead of effective ID" +//usage: +//usage:#define id_example_usage +//usage: "$ id\n" +//usage: "uid=1000(andersen) gid=1000(andersen)\n" + +//usage:#define groups_trivial_usage +//usage: "[USER]" +//usage:#define groups_full_usage "\n\n" +//usage: "Print the groups USER is in" +//usage: +//usage:#define groups_example_usage +//usage: "$ groups\n" +//usage: "andersen lp dialout cdrom floppy\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +#if !ENABLE_USE_BB_PWD_GRP +#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 30) +#error "Sorry, you need at least uClibc version 0.9.30 for id applet to build" +#endif +#endif + +enum { + PRINT_REAL = (1 << 0), + NAME_NOT_NUMBER = (1 << 1), + JUST_USER = (1 << 2), + JUST_GROUP = (1 << 3), + JUST_ALL_GROUPS = (1 << 4), +#if ENABLE_SELINUX + JUST_CONTEXT = (1 << 5), +#endif +}; + +static int print_common(unsigned id, const char *name, const char *prefix) +{ + if (prefix) { + printf("%s", prefix); + } + if (!(option_mask32 & NAME_NOT_NUMBER) || !name) { + printf("%u", id); + } + if (!option_mask32 || (option_mask32 & NAME_NOT_NUMBER)) { + if (name) { + printf(option_mask32 ? "%s" : "(%s)", name); + } else { + /* Don't set error status flag in default mode */ + if (option_mask32) { + if (ENABLE_DESKTOP) + bb_error_msg("unknown ID %u", id); + return EXIT_FAILURE; + } + } + } + return EXIT_SUCCESS; +} + +static int print_group(gid_t id, const char *prefix) +{ + return print_common(id, gid2group(id), prefix); +} + +static int print_user(uid_t id, const char *prefix) +{ + return print_common(id, uid2uname(id), prefix); +} + +/* On error set *n < 0 and return >= 0 + * If *n is too small, update it and return < 0 + * (ok to trash groups[] in both cases) + * Otherwise fill in groups[] and return >= 0 + */ +static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n) +{ + int m; + + if (username) { + /* If the user is a member of more than + * *n groups, then -1 is returned. Otherwise >= 0. + * (and no defined way of detecting errors?!) */ + m = getgrouplist(username, rgid, groups, n); + /* I guess *n < 0 might indicate error. Anyway, + * malloc'ing -1 bytes won't be good, so: */ + if (*n < 0) + return 0; + return m; + } + + *n = getgroups(*n, groups); + if (*n >= 0) + return *n; + /* Error */ + if (errno == EINVAL) /* *n is too small? */ + *n = getgroups(0, groups); /* get needed *n */ + /* if *n >= 0, return -1 (got new *n), else return 0 (error): */ + return -(*n >= 0); +} + +int id_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int id_main(int argc UNUSED_PARAM, char **argv) +{ + uid_t ruid; + gid_t rgid; + uid_t euid; + gid_t egid; + unsigned opt; + int i; + int status = EXIT_SUCCESS; + const char *prefix; + const char *username; +#if ENABLE_SELINUX + security_context_t scontext = NULL; +#endif + + if (ENABLE_GROUPS && (!ENABLE_ID || applet_name[0] == 'g')) { + /* TODO: coreutils groups prepend "USER : " prefix, + * and accept many usernames. Example: + * # groups root root + * root : root + * root : root + */ + opt = option_mask32 = getopt32(argv, "") | JUST_ALL_GROUPS | NAME_NOT_NUMBER; + } else { + /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ + /* Don't allow more than one username */ + opt = getopt32(argv, "^" + "rnugG" IF_SELINUX("Z") + "\0" + "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" + IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G") + ); + } + + username = argv[optind]; + if (username) { + struct passwd *p = xgetpwnam(username); + euid = ruid = p->pw_uid; + egid = rgid = p->pw_gid; + } else { + egid = getegid(); + rgid = getgid(); + euid = geteuid(); + ruid = getuid(); + } + /* JUST_ALL_GROUPS ignores -r PRINT_REAL flag even if man page for */ + /* id says: print the real ID instead of the effective ID, with -ugG */ + /* in fact in this case egid is always printed if egid != rgid */ + if (!opt || (opt & JUST_ALL_GROUPS)) { + gid_t *groups; + int n; + + if (!opt) { + /* Default Mode */ + status |= print_user(ruid, "uid="); + status |= print_group(rgid, " gid="); + if (euid != ruid) + status |= print_user(euid, " euid="); + if (egid != rgid) + status |= print_group(egid, " egid="); + } else { + /* JUST_ALL_GROUPS */ + status |= print_group(rgid, NULL); + if (egid != rgid) + status |= print_group(egid, " "); + } + /* We are supplying largish buffer, trying + * to not run get_groups() twice. That might be slow + * ("user database in remote SQL server" case) */ + groups = xmalloc(64 * sizeof(groups[0])); + n = 64; + if (get_groups(username, rgid, groups, &n) < 0) { + /* Need bigger buffer after all */ + groups = xrealloc(groups, n * sizeof(groups[0])); + get_groups(username, rgid, groups, &n); + } + if (n > 0) { + /* Print the list */ + prefix = " groups="; + for (i = 0; i < n; i++) { + if (opt && (groups[i] == rgid || groups[i] == egid)) + continue; + status |= print_group(groups[i], opt ? " " : prefix); + prefix = ","; + } + } else if (n < 0) { /* error in get_groups() */ + if (ENABLE_DESKTOP) + bb_simple_error_msg_and_die("can't get groups"); + return EXIT_FAILURE; + } + if (ENABLE_FEATURE_CLEAN_UP) + free(groups); +#if ENABLE_SELINUX + if (is_selinux_enabled()) { + if (getcon(&scontext) == 0) + printf(" context=%s", scontext); + } +#endif + } else if (opt & PRINT_REAL) { + euid = ruid; + egid = rgid; + } + + if (opt & JUST_USER) + status |= print_user(euid, NULL); + else if (opt & JUST_GROUP) + status |= print_group(egid, NULL); +#if ENABLE_SELINUX + else if (opt & JUST_CONTEXT) { + selinux_or_die(); + if (username || getcon(&scontext)) { + bb_error_msg_and_die("can't get process context%s", + username ? " for a different user" : ""); + } + fputs_stdout(scontext); + } + /* freecon(NULL) seems to be harmless */ + if (ENABLE_FEATURE_CLEAN_UP) + freecon(scontext); +#endif + bb_putchar('\n'); + fflush_stdout_and_exit(status); +} diff --git a/busybox-1_37_0/coreutils/id_test.sh b/busybox-1_37_0/coreutils/id_test.sh new file mode 100755 index 000000000..0d65f2ae3 --- /dev/null +++ b/busybox-1_37_0/coreutils/id_test.sh @@ -0,0 +1,244 @@ +#!/bin/bash +# Test script for busybox id vs. coreutils id. +# Needs root privileges for some tests. + +cp /usr/bin/id . +BUSYBOX=./busybox +ID=./id +LIST=`awk -F: '{ printf "%s\n", $1 }' /etc/passwd` +FLAG_USER_EXISTS="no" +TEST_USER="f583ca884c1d93458fb61ed137ff44f6" + +echo "test 1: id [options] nousername" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar +done + +echo "test 2: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + if test "$i" = "$TEST_USER"; then + FLAG_USER_EXISTS="yes" + fi + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +if test $FLAG_USER_EXISTS = "yes"; then + echo "test 3,4,5,6,7,8,9,10,11,12 skipped because test user $TEST_USER already exists" + rm -f foo bar + exit 1 +fi + +adduser -s /bin/true -g "" -H -D "$TEST_USER" || exit 1 + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod u+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod u+s $ID 2>&1 /dev/null + +echo "test 3 setuid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 4 setuid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod g+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod g+s $ID 2>&1 /dev/null + +echo "test 5 setgid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 6 setgid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown $TEST_USER.$TEST_USER $BUSYBOX +chmod u+s,g+s $BUSYBOX 2>&1 /dev/null +chown $TEST_USER.$TEST_USER $ID +chmod u+s,g+s $ID 2>&1 /dev/null + +echo "test 7 setuid, setgid, existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 8 setuid, setgid, existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +deluser $TEST_USER || exit 1 + +echo "test 9 setuid, setgid, not existing user: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar +done + +echo "test 10 setuid, setgid, not existing user: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown .root $BUSYBOX 2>&1 /dev/null +chown .root $ID 2>&1 /dev/null +chmod g+s $BUSYBOX 2>&1 /dev/null +chmod g+s $ID 2>&1 /dev/null + +echo "test 11 setgid, not existing group: id [options] no username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + $BUSYBOX id $OPTIONS >foo 2>/dev/null + RET1=$? + $ID $OPTIONS >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + #done +done + +echo "test 12 setgid, not existing group: id [options] username" +rm -f foo bar +for OPTIONS in "" "-u" "-un" "-unr" "-g" "-gn" "-gnr" "-G" "-Gn" "-Gnr" +do + #echo "$OPTIONS" + for i in $LIST ; do + $BUSYBOX id $OPTIONS $i >foo 2>/dev/null + RET1=$? + $ID $OPTIONS $i >bar 2>/dev/null + RET2=$? + if test "$RET1" != "$RET2"; then + echo "Return Values differ ($RET1 != $RET2): options $OPTIONS" + fi + diff foo bar + done +done + +chown root.root $BUSYBOX 2>&1 /dev/null +chown root.root $ID 2>&1 /dev/null +rm -f $ID +rm -f foo bar diff --git a/busybox-1_37_0/coreutils/install.c b/busybox-1_37_0/coreutils/install.c new file mode 100644 index 000000000..00f8be87e --- /dev/null +++ b/busybox-1_37_0/coreutils/install.c @@ -0,0 +1,272 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2003 by Glenn McGrath + * SELinux support: by Yuichi Nakamura + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config INSTALL +//config: bool "install (12 kb)" +//config: default y +//config: help +//config: Copy files and set attributes. +//config: +//config:config FEATURE_INSTALL_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on INSTALL && LONG_OPTS + +//applet:IF_INSTALL(APPLET(install, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_INSTALL) += install.o + +/* -v, -b, -c are ignored */ +//usage:#define install_trivial_usage +//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [-t DIR] [SOURCE]... DEST" +//usage:#define install_full_usage "\n\n" +//usage: "Copy files and set attributes\n" +//usage: "\n -c Just copy (default)" +//usage: "\n -d Create directories" +//usage: "\n -D Create leading target directories" +//usage: "\n -s Strip symbol table" +//usage: "\n -p Preserve date" +//usage: "\n -o USER Set ownership" +//usage: "\n -g GRP Set group ownership" +//usage: "\n -m MODE Set permissions" +//usage: "\n -t DIR Install to DIR" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) + +#include "libbb.h" +#include "libcoreutils/coreutils.h" + +#if ENABLE_FEATURE_INSTALL_LONG_OPTIONS +static const char install_longopts[] ALIGN1 = + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + "directory\0" No_argument "d" + "preserve-timestamps\0" No_argument "p" + "strip\0" No_argument "s" + "group\0" Required_argument "g" + "mode\0" Required_argument "m" + "owner\0" Required_argument "o" + "target-directory\0" Required_argument "t" +/* autofs build insists of using -b --suffix=.orig */ +/* TODO? (short option for --suffix is -S) */ +# if ENABLE_SELINUX + "context\0" Required_argument "Z" + "preserve_context\0" No_argument "\xff" + "preserve-context\0" No_argument "\xff" +# endif + ; +# define GETOPT32 getopt32long +# define LONGOPTS install_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS +#endif + + +#if ENABLE_SELINUX +static void setdefaultfilecon(const char *path) +{ + struct stat s; + security_context_t scontext = NULL; + + if (!is_selinux_enabled()) { + return; + } + if (lstat(path, &s) != 0) { + return; + } + + if (matchpathcon(path, s.st_mode, &scontext) < 0) { + goto out; + } + if (strcmp(scontext, "<>") == 0) { + goto out; + } + + if (lsetfilecon(path, scontext) < 0) { + if (errno != ENOTSUP) { + bb_perror_msg("warning: can't change context" + " of %s to %s", path, scontext); + } + } + + out: + freecon(scontext); +} + +#endif + +int install_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int install_main(int argc, char **argv) +{ + struct stat statbuf; + mode_t mode; + uid_t uid; + gid_t gid; + char *arg, *last; + const char *gid_str; + const char *uid_str; + const char *mode_str; + int mkdir_flags = FILEUTILS_RECUR; + int copy_flags = FILEUTILS_DEREFERENCE | FILEUTILS_FORCE; + int opts; + int ret = EXIT_SUCCESS; + int isdir; +#if ENABLE_SELINUX + security_context_t scontext; + bool use_default_selinux_context = 1; +#endif + enum { + OPT_c = 1 << 0, + OPT_v = 1 << 1, + OPT_b = 1 << 2, + OPT_MKDIR_LEADING = 1 << 3, + OPT_DIRECTORY = 1 << 4, + OPT_PRESERVE_TIME = 1 << 5, + OPT_STRIP = 1 << 6, + OPT_GROUP = 1 << 7, + OPT_MODE = 1 << 8, + OPT_OWNER = 1 << 9, + OPT_TARGET = 1 << 10, +#if ENABLE_SELINUX + OPT_SET_SECURITY_CONTEXT = 1 << 11, + OPT_PRESERVE_SECURITY_CONTEXT = 1 << 12, +#endif + }; + + /* -c exists for backwards compatibility, it's needed */ + /* -b is ignored ("make a backup of each existing destination file") */ + opts = GETOPT32(argv, "^" + "cvb" "Ddpsg:m:o:t:" IF_SELINUX("Z:") + "\0" + "t--d:d--t:s--d:d--s" + IF_FEATURE_INSTALL_LONG_OPTIONS(IF_SELINUX(":Z--\xff:\xff--Z")), + LONGOPTS + &gid_str, &mode_str, &uid_str, &last + IF_SELINUX(, &scontext) + ); + argc -= optind; + argv += optind; + +#if ENABLE_SELINUX + if (opts & (OPT_PRESERVE_SECURITY_CONTEXT|OPT_SET_SECURITY_CONTEXT)) { + selinux_or_die(); + use_default_selinux_context = 0; + if (opts & OPT_PRESERVE_SECURITY_CONTEXT) { + copy_flags |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; + } + if (opts & OPT_SET_SECURITY_CONTEXT) { + setfscreatecon_or_die(scontext); + copy_flags |= FILEUTILS_SET_SECURITY_CONTEXT; + } + } +#endif + + if ((opts & OPT_v) && FILEUTILS_VERBOSE) { + mkdir_flags |= FILEUTILS_VERBOSE; + copy_flags |= FILEUTILS_VERBOSE; + } + + /* preserve access and modification time, this is GNU behaviour, + * BSD only preserves modification time */ + if (opts & OPT_PRESERVE_TIME) { + copy_flags |= FILEUTILS_PRESERVE_STATUS; + } + mode = 0755; /* GNU coreutils 6.10 compat */ + if (opts & OPT_MODE) + mode = bb_parse_mode(mode_str, mode); + uid = (opts & OPT_OWNER) ? get_ug_id(uid_str, xuname2uid) : getuid(); + gid = (opts & OPT_GROUP) ? get_ug_id(gid_str, xgroup2gid) : getgid(); + + /* If -t DIR is in use, then isdir=true, last="DIR" */ + isdir = (opts & OPT_TARGET); + if (!(opts & (OPT_TARGET|OPT_DIRECTORY))) { + /* Neither -t DIR nor -d is in use */ + argc--; + last = argv[argc]; + argv[argc] = NULL; + /* coreutils install resolves link in this case, don't use lstat */ + isdir = stat(last, &statbuf) < 0 ? 0 : S_ISDIR(statbuf.st_mode); + } + + if (argc < 1) + bb_show_usage(); + + while ((arg = *argv++) != NULL) { + char *dest; + + if (opts & OPT_DIRECTORY) { + dest = arg; + /* GNU coreutils 6.9 does not set uid:gid + * on intermediate created directories + * (only on last one) */ + if (bb_make_directory(dest, 0755, mkdir_flags)) { + ret = EXIT_FAILURE; + goto next; + } + } else { + dest = last; + if (opts & OPT_MKDIR_LEADING) { + char *ddir = xstrdup(dest); + /* + * -D -t DIR1/DIR2/F3 FILE: create DIR1/DIR2/F3, copy FILE there + * -D FILE DIR1/DIR2/F3: create DIR1/DIR2, copy FILE there as F3 + */ + bb_make_directory((opts & OPT_TARGET) ? ddir : dirname(ddir), 0755, mkdir_flags); + /* errors are not checked. copy_file + * will fail if dir is not created. + */ + free(ddir); + } + if (isdir) + dest = concat_path_file(last, bb_basename(arg)); + if (copy_file(arg, dest, copy_flags) != 0) { + /* copy is not made */ + ret = EXIT_FAILURE; + goto next; + } + if (opts & OPT_STRIP) { + char *args[4]; + args[0] = (char*)"strip"; + args[1] = (char*)"-p"; /* -p --preserve-dates */ + args[2] = dest; + args[3] = NULL; + if (spawn_and_wait(args)) { + bb_simple_perror_msg("strip"); + ret = EXIT_FAILURE; + } + } + } + + /* Set the user and group id */ + /* (must be before chmod, or else chown may clear suid/gid bits) */ + if ((opts & (OPT_OWNER|OPT_GROUP)) + && lchown(dest, uid, gid) == -1 + ) { + bb_perror_msg("can't change %s of %s", "ownership", dest); + ret = EXIT_FAILURE; + } + + /* Set the file mode (always, not only with -m). + * GNU coreutils 6.10 is not affected by umask. */ + if (chmod(dest, mode) == -1) { + bb_perror_msg("can't change %s of %s", "permissions", dest); + ret = EXIT_FAILURE; + } +#if ENABLE_SELINUX + if (use_default_selinux_context) + setdefaultfilecon(dest); +#endif + next: + if (ENABLE_FEATURE_CLEAN_UP && isdir) + free(dest); + } + + return ret; +} diff --git a/busybox-1_37_0/coreutils/libcoreutils/Kbuild.src b/busybox-1_37_0/coreutils/libcoreutils/Kbuild.src new file mode 100644 index 000000000..2042d5f84 --- /dev/null +++ b/busybox-1_37_0/coreutils/libcoreutils/Kbuild.src @@ -0,0 +1,14 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2004 by Erik Andersen +# +# Licensed under GPLv2 or later, see file LICENSE in this source tree. + +lib-y:= + +INSERT +lib-$(CONFIG_MKFIFO) += getopt_mk_fifo_nod.o +lib-$(CONFIG_MKNOD) += getopt_mk_fifo_nod.o +lib-$(CONFIG_INSTALL) += cp_mv_stat.o +lib-$(CONFIG_CP) += cp_mv_stat.o +lib-$(CONFIG_MV) += cp_mv_stat.o diff --git a/busybox-1_37_0/coreutils/libcoreutils/coreutils.h b/busybox-1_37_0/coreutils/libcoreutils/coreutils.h new file mode 100644 index 000000000..ad102e423 --- /dev/null +++ b/busybox-1_37_0/coreutils/libcoreutils/coreutils.h @@ -0,0 +1,19 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#ifndef COREUTILS_H +#define COREUTILS_H 1 + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +typedef int (*stat_func)(const char *fn, struct stat *ps); + +int cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf) FAST_FUNC; +int cp_mv_stat(const char *fn, struct stat *fn_stat) FAST_FUNC; + +mode_t getopt_mk_fifo_nod(char **argv) FAST_FUNC; + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/busybox-1_37_0/coreutils/libcoreutils/cp_mv_stat.c b/busybox-1_37_0/coreutils/libcoreutils/cp_mv_stat.c new file mode 100644 index 000000000..26c0e1645 --- /dev/null +++ b/busybox-1_37_0/coreutils/libcoreutils/cp_mv_stat.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * coreutils utility routine + * + * Copyright (C) 2003 Manuel Novoa III + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "libbb.h" +#include "coreutils.h" + +int FAST_FUNC cp_mv_stat2(const char *fn, struct stat *fn_stat, stat_func sf) +{ + if (sf(fn, fn_stat) < 0) { + if (errno != ENOENT) { +#if ENABLE_FEATURE_VERBOSE_CP_MESSAGE + if (errno == ENOTDIR) { + bb_error_msg("can't stat '%s': Path has non-directory component", fn); + return -1; + } +#endif + bb_perror_msg("can't stat '%s'", fn); + return -1; + } + return 0; + } + if (S_ISDIR(fn_stat->st_mode)) { + return 3; + } + return 1; +} + +int FAST_FUNC cp_mv_stat(const char *fn, struct stat *fn_stat) +{ + return cp_mv_stat2(fn, fn_stat, stat); +} diff --git a/busybox-1_37_0/coreutils/libcoreutils/getopt_mk_fifo_nod.c b/busybox-1_37_0/coreutils/libcoreutils/getopt_mk_fifo_nod.c new file mode 100644 index 000000000..dafe70edf --- /dev/null +++ b/busybox-1_37_0/coreutils/libcoreutils/getopt_mk_fifo_nod.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * coreutils utility routine + * + * Copyright (C) 2003 Manuel Novoa III + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ +#include "libbb.h" +#include "coreutils.h" + +mode_t FAST_FUNC getopt_mk_fifo_nod(char **argv) +{ + mode_t mode = 0666; + char *smode = NULL; +#if ENABLE_SELINUX + security_context_t scontext; +#endif + int opt; + opt = getopt32(argv, "m:" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); + if (opt & 1) { + mode = bb_parse_mode(smode, mode); + if (mode != (mode_t)-1) /* if mode is valid */ + /* make future mknod/mkfifo set mode bits exactly */ + umask(0); + } + +#if ENABLE_SELINUX + if (opt & 2) { + selinux_or_die(); + setfscreatecon_or_die(scontext); + } +#endif + + return mode; +} diff --git a/busybox-1_37_0/coreutils/link.c b/busybox-1_37_0/coreutils/link.c new file mode 100644 index 000000000..cb994da45 --- /dev/null +++ b/busybox-1_37_0/coreutils/link.c @@ -0,0 +1,39 @@ +/* + * link implementation for busybox + * + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config LINK +//config: bool "link (3.5 kb)" +//config: default y +//config: help +//config: link creates hard links between files. + +//applet:IF_LINK(APPLET_NOFORK(link, link, BB_DIR_BIN, BB_SUID_DROP, link)) + +//kbuild:lib-$(CONFIG_LINK) += link.o + +//usage:#define link_trivial_usage +//usage: "FILE LINK" +//usage:#define link_full_usage "\n\n" +//usage: "Create hard LINK to FILE" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int link_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int link_main(int argc UNUSED_PARAM, char **argv) +{ + getopt32(argv, "^" "" "\0" "=2"); + argv += optind; + if (link(argv[0], argv[1]) != 0) { + /* shared message */ + bb_perror_msg_and_die("can't create %slink '%s' to '%s'", + "hard", argv[1], argv[0] + ); + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/ln.c b/busybox-1_37_0/coreutils/ln.c new file mode 100644 index 000000000..080ba142e --- /dev/null +++ b/busybox-1_37_0/coreutils/ln.c @@ -0,0 +1,165 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini ln implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config LN +//config: bool "ln (5.1 kb)" +//config: default y +//config: help +//config: ln is used to create hard or soft links between files. + +//applet:IF_LN(APPLET_NOEXEC(ln, ln, BB_DIR_BIN, BB_SUID_DROP, ln)) + +//kbuild:lib-$(CONFIG_LN) += ln.o + +/* BB_AUDIT SUSv3 compliant */ +/* BB_AUDIT GNU options missing: -d, -F, -i, and -v. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/ln.html */ + +//usage:#define ln_trivial_usage +//usage: "[-sfnbtv] [-S SUF] TARGET... LINK|DIR" +//usage:#define ln_full_usage "\n\n" +//usage: "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" +//usage: "\n -s Make symlinks instead of hardlinks" +//usage: "\n -f Remove existing destinations" +//usage: "\n -n Don't dereference symlinks - treat like normal file" +//usage: "\n -b Make a backup of the target (if exists) before link operation" +//usage: "\n -S SUF Use suffix instead of ~ when making backup files" +//usage: "\n -T Treat LINK as a file, not DIR" +//usage: "\n -v Verbose" +//usage: +//usage:#define ln_example_usage +//usage: "$ ln -s BusyBox /tmp/ls\n" +//usage: "$ ls -l /tmp/ls\n" +//usage: "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +#define LN_SYMLINK (1 << 0) +#define LN_FORCE (1 << 1) +#define LN_NODEREFERENCE (1 << 2) +#define LN_BACKUP (1 << 3) +#define LN_SUFFIX (1 << 4) +#define LN_VERBOSE (1 << 5) +#define LN_LINKFILE (1 << 6) + +int ln_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ln_main(int argc, char **argv) +{ + exitcode_t status = EXIT_SUCCESS; + int opts; + char *last; + char *src_name; + char *src; + char *suffix = (char*)"~"; + struct stat statbuf; + int (*link_func)(const char *, const char *); + + opts = getopt32(argv, "^" "sfnbS:vT" "\0" "-1", &suffix); +/* + -s, --symbolic make symbolic links instead of hard links + -f, --force remove existing destination files + -n, --no-dereference treat LINK_NAME as a normal file if it is a symbolic link to a directory + -b like --backup but does not accept an argument + --backup[=CONTROL] make a backup of each existing destination file + -S, --suffix=SUFFIX override the usual backup suffix + -v, --verbose + -T, --no-target-directory + -d, -F, --directory allow the superuser to attempt to hard link directories + -i, --interactive prompt whether to remove destinations + -L, --logical dereference TARGETs that are symbolic links + -P, --physical make hard links directly to symbolic links + -r, --relative create symbolic links relative to link location + -t, --target-directory=DIRECTORY specify the DIRECTORY in which to create the links + */ + last = argv[argc - 1]; + argv += optind; + argc -= optind; + + if ((opts & LN_LINKFILE) && argc > 2) { + bb_simple_error_msg_and_die("-T accepts 2 args max"); + } + + if (!argv[1]) { + /* "ln PATH/TO/FILE" -> "ln PATH/TO/FILE FILE" */ + *--argv = last; + /* xstrdup is needed: "ln -s PATH/TO/FILE/" is equivalent to + * "ln -s PATH/TO/FILE/ FILE", not "ln -s PATH/TO/FILE FILE" + */ + last = bb_get_last_path_component_strip(xstrdup(last)); + } + + do { + src_name = NULL; + src = last; + + if (is_directory(src, + /*followlinks:*/ !(opts & (LN_NODEREFERENCE|LN_LINKFILE)) + /* Why LN_LINKFILE does not follow links: + * -T/--no-target-directory implies -n/--no-dereference + */ + ) + ) { + if (opts & LN_LINKFILE) { + bb_error_msg_and_die("'%s' is a directory", src); + } + src_name = xstrdup(*argv); + src = concat_path_file(src, bb_get_last_path_component_strip(src_name)); + free(src_name); + src_name = src; + } + if (!(opts & LN_SYMLINK) && stat(*argv, &statbuf)) { + // coreutils: "ln dangling_symlink new_hardlink" works + if (lstat(*argv, &statbuf) || !S_ISLNK(statbuf.st_mode)) { + bb_simple_perror_msg(*argv); + status = EXIT_FAILURE; + free(src_name); + continue; + } + } + + if (opts & LN_BACKUP) { + char *backup; + backup = xasprintf("%s%s", src, suffix); + if (rename(src, backup) < 0 && errno != ENOENT) { + bb_simple_perror_msg(src); + status = EXIT_FAILURE; + free(backup); + continue; + } + free(backup); + /* + * When the source and dest are both hard links to the same + * inode, a rename may succeed even though nothing happened. + * Therefore, always unlink(). + */ + unlink(src); + } else if (opts & LN_FORCE) { + unlink(src); + } + + link_func = link; + if (opts & LN_SYMLINK) { + link_func = symlink; + } + + if (opts & LN_VERBOSE) { + printf("'%s' -> '%s'\n", src, *argv); + } + + if (link_func(*argv, src) != 0) { + bb_simple_perror_msg(src); + status = EXIT_FAILURE; + } + + free(src_name); + } while ((++argv)[1]); + + return status; +} diff --git a/busybox-1_37_0/coreutils/logname.c b/busybox-1_37_0/coreutils/logname.c new file mode 100644 index 000000000..17c073a53 --- /dev/null +++ b/busybox-1_37_0/coreutils/logname.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini logname implementation for busybox + * + * Copyright (C) 2000 Edward Betts . + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * SUSv3 specifies the string used is that returned from getlogin(). + * The previous implementation used getpwuid() for geteuid(), which + * is _not_ the same. Erik apparently made this change almost 3 years + * ago to avoid failing when no utmp was available. However, the + * correct course of action wrt SUSv3 for a failing getlogin() is + * a diagnostic message and an error return. + */ +//config:config LOGNAME +//config: bool "logname (1.4 kb)" +//config: default y +//config: help +//config: logname is used to print the current user's login name. + +//applet:IF_LOGNAME(APPLET_NOFORK(logname, logname, BB_DIR_USR_BIN, BB_SUID_DROP, logname)) + +//kbuild:lib-$(CONFIG_LOGNAME) += logname.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/logname.html */ + +//usage:#define logname_trivial_usage +//usage: "" +//usage:#define logname_full_usage "\n\n" +//usage: "Print the name of the current user" +//usage: +//usage:#define logname_example_usage +//usage: "$ logname\n" +//usage: "root\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int logname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int logname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + char buf[64]; + + if (argv[1]) { + bb_show_usage(); + } + + /* Using _r function - avoid pulling in static buffer from libc */ + if (getlogin_r(buf, sizeof(buf)) == 0) { + puts(buf); + return fflush_all(); + } + + bb_simple_perror_msg_and_die("getlogin"); +} diff --git a/busybox-1_37_0/coreutils/ls.c b/busybox-1_37_0/coreutils/ls.c new file mode 100644 index 000000000..cc809b797 --- /dev/null +++ b/busybox-1_37_0/coreutils/ls.c @@ -0,0 +1,1272 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 1996 Brian Candler + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* [date unknown. Perhaps before year 2000] + * To achieve a small memory footprint, this version of 'ls' doesn't do any + * file sorting, and only has the most essential command line switches + * (i.e., the ones I couldn't live without :-) All features which involve + * 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. 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? + * + * [2009-03] + * ls sorts listing now, and supports almost all options. + */ +//config:config LS +//config: bool "ls (14 kb)" +//config: default y +//config: help +//config: ls is used to list the contents of directories. +//config: +//config:config FEATURE_LS_FILETYPES +//config: bool "Enable filetyping options (-p and -F)" +//config: default y +//config: depends on LS +//config: +//config:config FEATURE_LS_FOLLOWLINKS +//config: bool "Enable symlinks dereferencing (-L)" +//config: default y +//config: depends on LS +//config: +//config:config FEATURE_LS_RECURSIVE +//config: bool "Enable recursion (-R)" +//config: default y +//config: depends on LS +//config: +//config:config FEATURE_LS_WIDTH +//config: bool "Enable -w WIDTH and window size autodetection" +//config: default y +//config: depends on LS +//config: +//config:config FEATURE_LS_SORTFILES +//config: bool "Sort the file names" +//config: default y +//config: depends on LS +//config: help +//config: Allow ls to sort file names alphabetically. +//config: +//config:config FEATURE_LS_TIMESTAMPS +//config: bool "Show file timestamps" +//config: default y +//config: depends on LS +//config: help +//config: Allow ls to display timestamps for files. +//config: +//config:config FEATURE_LS_USERNAME +//config: bool "Show username/groupnames" +//config: default y +//config: depends on LS +//config: help +//config: Allow ls to display username/groupname for files. +//config: +//config:config FEATURE_LS_COLOR +//config: bool "Allow use of color to identify file types" +//config: default y +//config: depends on LS && LONG_OPTS +//config: help +//config: This enables the --color option to ls. +//config: +//config:config FEATURE_LS_COLOR_IS_DEFAULT +//config: bool "Produce colored ls output by default" +//config: default y +//config: depends on FEATURE_LS_COLOR +//config: help +//config: Saying yes here will turn coloring on by default, +//config: even if no "--color" option is given to the ls command. +//config: This is not recommended, since the colors are not +//config: configurable, and the output may not be legible on +//config: many output screens. + +//applet:IF_LS(APPLET_NOEXEC(ls, ls, BB_DIR_BIN, BB_SUID_DROP, ls)) + +//kbuild:lib-$(CONFIG_LS) += ls.o + +//usage:#define ls_trivial_usage +//usage: "[-1AaCxd" +//usage: IF_FEATURE_LS_FOLLOWLINKS("LH") +//usage: IF_FEATURE_LS_RECURSIVE("R") +//usage: IF_FEATURE_LS_FILETYPES("Fp") "lins" +//usage: IF_FEATURE_HUMAN_READABLE("h") +//usage: IF_FEATURE_LS_SORTFILES("rSXv") +//usage: IF_FEATURE_LS_TIMESTAMPS("ctu") +//usage: IF_SELINUX("kZ") "]" +//usage: IF_FEATURE_LS_WIDTH(" [-w WIDTH]") " [FILE]..." +//usage:#define ls_full_usage "\n\n" +//usage: "List directory contents\n" +//usage: "\n -1 One column output" +//usage: "\n -a Include names starting with ." +//usage: "\n -A Like -a, but exclude . and .." +////usage: "\n -C List by columns" - don't show, this is a default anyway +//usage: "\n -x List by lines" +//usage: "\n -d List directory names, not contents" +//usage: IF_FEATURE_LS_FOLLOWLINKS( +//usage: "\n -L Follow symlinks" +//usage: "\n -H Follow symlinks on command line" +//usage: ) +//usage: IF_FEATURE_LS_RECURSIVE( +//usage: "\n -R Recurse" +//usage: ) +//usage: IF_FEATURE_LS_FILETYPES( +//usage: "\n -p Append / to directory names" +//usage: "\n -F Append indicator (one of */=@|) to names" +//usage: ) +//usage: "\n -l Long format" +//usage: "\n -i List inode numbers" +//usage: "\n -n List numeric UIDs and GIDs instead of names" +//usage: "\n -s List allocated blocks" +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -lc List ctime" +//usage: "\n -lu List atime" +//usage: ) +//usage: IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS( +//usage: "\n --full-time List full date/time" +//usage: )) +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h Human readable sizes (1K 243M 2G)" +//usage: ) +//usage: IF_FEATURE_LS_SORTFILES( +//usage: IF_LONG_OPTS( +//usage: "\n --group-directories-first" +//usage: ) +//usage: "\n -S Sort by size" +//usage: "\n -X Sort by extension" +//usage: "\n -v Sort by version" +//usage: ) +//usage: IF_FEATURE_LS_TIMESTAMPS( +//usage: "\n -t Sort by mtime" +//usage: "\n -tc Sort by ctime" +//usage: "\n -tu Sort by atime" +//usage: ) +//usage: "\n -r Reverse sort order" +//usage: IF_SELINUX( +//usage: "\n -Z List security context and permission" +//usage: ) +//usage: IF_FEATURE_LS_WIDTH( +//usage: "\n -w N Format N columns wide" +//usage: ) +//usage: IF_FEATURE_LS_COLOR( +//usage: "\n --color[={always,never,auto}]" +//usage: ) + +#include "libbb.h" +#include "common_bufsiz.h" +#include "unicode.h" + + +/* This is a NOEXEC applet. Be very careful! */ + + +#if ENABLE_FTPD +/* ftpd uses ls, and without timestamps Mozilla won't understand + * ftpd's LIST output. + */ +# undef CONFIG_FEATURE_LS_TIMESTAMPS +# undef ENABLE_FEATURE_LS_TIMESTAMPS +# undef IF_FEATURE_LS_TIMESTAMPS +# undef IF_NOT_FEATURE_LS_TIMESTAMPS +# define CONFIG_FEATURE_LS_TIMESTAMPS 1 +# define ENABLE_FEATURE_LS_TIMESTAMPS 1 +# define IF_FEATURE_LS_TIMESTAMPS(...) __VA_ARGS__ +# define IF_NOT_FEATURE_LS_TIMESTAMPS(...) +#endif + + +enum { +TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ + +SPLIT_FILE = 0, +SPLIT_DIR = 1, +SPLIT_SUBDIR = 2, +}; + +/* -Cadi1l Std options, busybox always supports */ +/* -gnsxA Std options, busybox always supports */ +/* -Q GNU option, busybox always supports */ +/* -k Std option, busybox always supports (by ignoring) */ +/* It means "for -s, show sizes in kbytes" */ +/* Seems to only affect "POSIXLY_CORRECT=1 ls -sk" */ +/* since otherwise -s shows kbytes anyway */ +/* -LHRctur Std options, busybox optionally supports */ +/* -Fp Std options, busybox optionally supports */ +/* -SXvhTw GNU options, busybox optionally supports */ +/* -T WIDTH Ignored (we don't use tabs on output) */ +/* -Z SELinux mandated option, busybox optionally supports */ +#define ls_options \ + "Cadi1lgnsxAk" /* 12 opts, total 12 */ \ + IF_FEATURE_LS_FILETYPES("Fp") /* 2, 14 */ \ + IF_FEATURE_LS_RECURSIVE("R") /* 1, 15 */ \ + IF_SELINUX("Z") /* 1, 16 */ \ + "Q" /* 1, 17 */ \ + IF_FEATURE_LS_TIMESTAMPS("ctu") /* 3, 20 */ \ + IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 24 */ \ + IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 26 */ \ + IF_FEATURE_HUMAN_READABLE("h") /* 1, 27 */ \ + IF_FEATURE_LS_WIDTH("T:w:") /* 2, 29 */ + +enum { + OPT_C = (1 << 0), + OPT_a = (1 << 1), + OPT_d = (1 << 2), + OPT_i = (1 << 3), + OPT_1 = (1 << 4), + OPT_l = (1 << 5), + OPT_g = (1 << 6), + OPT_n = (1 << 7), + OPT_s = (1 << 8), + OPT_x = (1 << 9), + OPT_A = (1 << 10), + //OPT_k = (1 << 11), + + OPTBIT_F = 12, + OPTBIT_p, /* 13 */ + OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, + OPTBIT_Z = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, + OPTBIT_Q = OPTBIT_Z + 1 * ENABLE_SELINUX, + OPTBIT_c, /* 17 */ + OPTBIT_t, /* 18 */ + OPTBIT_u, /* 19 */ + OPTBIT_S = OPTBIT_c + 3 * ENABLE_FEATURE_LS_TIMESTAMPS, + OPTBIT_X, /* 21 */ + OPTBIT_r, /* 22 */ + OPTBIT_v, /* 23 */ + OPTBIT_L = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_H, /* 25 */ + OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, + OPTBIT_w, /* 28 */ + OPTBIT_full_time = OPTBIT_T + 2 * ENABLE_FEATURE_LS_WIDTH, + OPTBIT_dirs_first, + OPTBIT_color, /* 31 */ + /* with long opts, we use all 32 bits */ + + OPT_F = (1 << OPTBIT_F) * ENABLE_FEATURE_LS_FILETYPES, + OPT_p = (1 << OPTBIT_p) * ENABLE_FEATURE_LS_FILETYPES, + OPT_R = (1 << OPTBIT_R) * ENABLE_FEATURE_LS_RECURSIVE, + OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX, + OPT_Q = (1 << OPTBIT_Q), + OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_t = (1 << OPTBIT_t) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_u = (1 << OPTBIT_u) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_S = (1 << OPTBIT_S) * ENABLE_FEATURE_LS_SORTFILES, + OPT_X = (1 << OPTBIT_X) * ENABLE_FEATURE_LS_SORTFILES, + OPT_r = (1 << OPTBIT_r) * ENABLE_FEATURE_LS_SORTFILES, + OPT_v = (1 << OPTBIT_v) * ENABLE_FEATURE_LS_SORTFILES, + OPT_L = (1 << OPTBIT_L) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_H = (1 << OPTBIT_H) * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPT_h = (1 << OPTBIT_h) * ENABLE_FEATURE_HUMAN_READABLE, + OPT_T = (1 << OPTBIT_T) * ENABLE_FEATURE_LS_WIDTH, + OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_LS_WIDTH, + OPT_full_time = (1 << OPTBIT_full_time ) * ENABLE_LONG_OPTS, + OPT_dirs_first = (1 << OPTBIT_dirs_first) * ENABLE_LONG_OPTS, + OPT_color = (1 << OPTBIT_color ) * ENABLE_FEATURE_LS_COLOR, +}; + +/* + * a directory entry and its stat info + */ +struct dnode { + const char *name; /* usually basename, but think "ls -l dir/file" */ + const char *fullname; /* full name (usable for stat etc) */ + struct dnode *dn_next; /* for linked list */ + IF_SELINUX(security_context_t sid;) + smallint fname_allocated; + + /* Used to avoid re-doing [l]stat at printout stage + * if we already collected needed data in scan stage: + */ + mode_t dn_mode_lstat; /* obtained with lstat, or 0 */ + mode_t dn_mode_stat; /* obtained with stat, or 0 */ + +// struct stat dstat; +// struct stat is huge. We don't need it in full. +// At least we don't need st_dev and st_blksize, +// but there are invisible fields as well +// (such as nanosecond-resolution timespamps) +// and padding, which we also don't want to store. +// We also pre-parse dev_t dn_rdev (in glibc, it's huge). +// On 32-bit uclibc: dnode size went from 112 to 84 bytes. +// + /* Same names as in struct stat, but with dn_ instead of st_ pfx: */ + mode_t dn_mode; /* obtained with lstat OR stat, depending on -L etc */ + off_t dn_size; +#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES + time_t dn_time; +#endif + ino_t dn_ino; + blkcnt_t dn_blocks; + nlink_t dn_nlink; + uid_t dn_uid; + gid_t dn_gid; + int dn_rdev_maj; + int dn_rdev_min; +// dev_t dn_dev; +// blksize_t dn_blksize; +}; + +struct globals { +#if ENABLE_FEATURE_LS_COLOR + smallint show_color; +# define G_show_color (G.show_color) +#else +# define G_show_color 0 +#endif + smallint exit_code; + smallint show_dirname; +#if ENABLE_FEATURE_LS_WIDTH + unsigned terminal_width; +# define G_terminal_width (G.terminal_width) +#else +# define G_terminal_width TERMINAL_WIDTH +#endif +#if ENABLE_FEATURE_LS_TIMESTAMPS + /* Do time() just once. Saves one syscall per file for "ls -l" */ + time_t current_time_t; +#endif +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + /* we have to zero it out because of NOEXEC */ \ + memset(&G, 0, sizeof(G)); \ + IF_FEATURE_LS_WIDTH(G_terminal_width = TERMINAL_WIDTH;) \ + IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ +} while (0) + +#define ESC "\033" + + +/*** Output code ***/ + + +/* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket + * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file + * 3/7:multiplexed char/block device) + * and we use 0 for unknown and 15 for executables (see below) */ +#define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) +/* un fi chr - dir - blk - file - link - sock - - exe */ +#define APPCHAR(mode) ("\0""|""\0""\0""/""\0""\0""\0""\0""\0""@""\0""=""\0""\0""\0" [TYPEINDEX(mode)]) +/* 036 black foreground 050 black background + 037 red foreground 051 red background + 040 green foreground 052 green background + 041 brown foreground 053 brown background + 042 blue foreground 054 blue background + 043 magenta (purple) foreground 055 magenta background + 044 cyan (light blue) foreground 056 cyan background + 045 gray foreground 057 white background +*/ +#define COLOR(mode) ( \ + /*un fi chr - dir - blk - file - link - sock - - exe */ \ + "\037\043\043\045\042\045\043\043\000\045\044\045\043\045\045\040" \ + [TYPEINDEX(mode)]) +/* Select normal (0) [actually "reset all"] or bold (1) + * (other attributes are 2:dim 4:underline 5:blink 7:reverse, + * let's use 7 for "impossible" types, just for fun) + * Note: coreutils 6.9 uses inverted red for setuid binaries. + */ +#define ATTR(mode) ( \ + /*un fi chr - dir - blk - file- link- sock- - exe */ \ + "\01\00\01\07\01\07\01\07\00\07\01\07\01\07\07\01" \ + [TYPEINDEX(mode)]) + +#if ENABLE_FEATURE_LS_COLOR +/* mode of zero is interpreted as "unknown" (stat failed) */ +static char fgcolor(mode_t mode) +{ + if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return COLOR(0xF000); /* File is executable ... */ + return COLOR(mode); +} +static char bold(mode_t mode) +{ + if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return ATTR(0xF000); /* File is executable ... */ + return ATTR(mode); +} +#endif + +#if ENABLE_FEATURE_LS_FILETYPES +static char append_char(mode_t mode) +{ + if (!(option_mask32 & (OPT_F|OPT_p))) + return '\0'; + + if (S_ISDIR(mode)) + return '/'; + if (!(option_mask32 & OPT_F)) + return '\0'; + if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) + return '*'; + return APPCHAR(mode); +} +#endif + +static unsigned calc_name_len(const char *name) +{ + unsigned len; + uni_stat_t uni_stat; + + // TODO: quote tab as \t, etc, if -Q + name = printable_string2(&uni_stat, name); + + if (!(option_mask32 & OPT_Q)) { + return uni_stat.unicode_width; + } + + len = 2 + uni_stat.unicode_width; + while (*name) { + if (*name == '"' || *name == '\\') { + len++; + } + name++; + } + return len; +} + +/* Return the number of used columns. + * Note that only columnar output uses return value. + * -l and -1 modes don't care. + * coreutils 7.2 also supports: + * ls -b (--escape) = octal escapes (although it doesn't look like working) + * ls -N (--literal) = not escape at all + */ +static unsigned print_name(const char *name) +{ + unsigned len; + uni_stat_t uni_stat; + + // TODO: quote tab as \t, etc, if -Q + name = printable_string2(&uni_stat, name); + + if (!(option_mask32 & OPT_Q)) { + fputs_stdout(name); + return uni_stat.unicode_width; + } + + len = 2 + uni_stat.unicode_width; + putchar('"'); + while (*name) { + if (*name == '"' || *name == '\\') { + putchar('\\'); + len++; + } + putchar(*name); + name++; + } + putchar('"'); + return len; +} + +/* Return the number of used columns. + * Note that only columnar output uses return value, + * -l and -1 modes don't care. + */ +static NOINLINE unsigned display_single(const struct dnode *dn) +{ + unsigned column = 0; + char *lpath; + int opt; +#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR + struct stat statbuf; +#endif +#if ENABLE_FEATURE_LS_FILETYPES + char append = append_char(dn->dn_mode); +#endif + + opt = option_mask32; + + /* Do readlink early, so that if it fails, error message + * does not appear *inside* the "ls -l" line */ + lpath = NULL; + if (opt & OPT_l) + if (S_ISLNK(dn->dn_mode)) + lpath = xmalloc_readlink_or_warn(dn->fullname); + + if (opt & OPT_i) /* show inode# */ + column += printf("%7llu ", (long long) dn->dn_ino); + if (opt & OPT_s) { /* show allocated blocks */ + if (opt & OPT_h) { + column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", + /* print size, show one fractional, use suffixes */ + make_human_readable_str((off_t)dn->dn_blocks << 9, 1, 0) + ); + } else { + column += printf("%6"OFF_FMT"u ", (off_t)(dn->dn_blocks >> 1)); + } + } + if (opt & OPT_l) { + /* long listing: show mode */ + char modestr[12]; + column += printf("%-10s ", bb_mode_string(modestr, dn->dn_mode)); + /* long listing: show number of links */ + column += printf("%4lu ", (long) dn->dn_nlink); + /* long listing: show user/group */ + if (opt & OPT_n) { + if (opt & OPT_g) + column += printf("%-8u ", (int) dn->dn_gid); + else + column += printf("%-8u %-8u ", + (int) dn->dn_uid, + (int) dn->dn_gid); + } +#if ENABLE_FEATURE_LS_USERNAME + else { + if (opt & OPT_g) { + column += printf("%-8s ", + get_cached_groupname(dn->dn_gid)); + } else { + column += printf("%-8s %-8s ", + get_cached_username(dn->dn_uid), + get_cached_groupname(dn->dn_gid)); + } + } +#endif +#if ENABLE_SELINUX + } + if (opt & OPT_Z) { + column += printf("%-32s ", dn->sid ? dn->sid : "?"); + freecon(dn->sid); + } + if (opt & OPT_l) { +#endif + /* long listing: show size */ + if (S_ISBLK(dn->dn_mode) || S_ISCHR(dn->dn_mode)) { + column += printf("%4u, %3u ", + dn->dn_rdev_maj, + dn->dn_rdev_min); + } else { + if (opt & OPT_h) { + column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", + /* print size, show one fractional, use suffixes */ + make_human_readable_str(dn->dn_size, 1, 0) + ); + } else { + column += printf("%9"OFF_FMT"u ", dn->dn_size); + } + } +#if ENABLE_FEATURE_LS_TIMESTAMPS + /* long listing: show {m,c,a}time */ + if (opt & OPT_full_time) { /* --full-time */ + /* coreutils 8.4 ls --full-time prints: + * 2009-07-13 17:49:27.000000000 +0200 + * we don't show fractional seconds. + */ + char buf[sizeof("YYYY-mm-dd HH:MM:SS TIMEZONE")]; + strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S %z", + localtime(&dn->dn_time)); + column += printf("%s ", buf); + } else { /* ordinary time format */ + /* G.current_time_t is ~== time(NULL) */ + char *filetime = ctime(&dn->dn_time); + /* filetime's format: "Wed Jun 30 21:49:08 1993\n" */ + time_t age = G.current_time_t - dn->dn_time; + if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { + /* less than 6 months old */ + /* "mmm dd hh:mm " */ + printf("%.12s ", filetime + 4); + } else { + /* "mmm dd yyyy " */ + /* "mmm dd yyyyy " after year 9999 :) */ + strchr(filetime + 20, '\n')[0] = ' '; + printf("%.7s%6s", filetime + 4, filetime + 20); + } + column += 13; + } +#endif + } + +#if ENABLE_FEATURE_LS_COLOR + if (G_show_color) { + mode_t mode = dn->dn_mode_lstat; + if (!mode) + if (lstat(dn->fullname, &statbuf) == 0) + mode = statbuf.st_mode; + printf(ESC"[%u;%um", bold(mode), fgcolor(mode)); + } +#endif + column += print_name(dn->name); + if (G_show_color) { + printf(ESC"[m"); + } + + if (lpath) { + printf(" -> "); +#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR + if ((opt & (OPT_F|OPT_p)) + || G_show_color + ) { + mode_t mode = dn->dn_mode_stat; + if (!mode) + if (stat(dn->fullname, &statbuf) == 0) + mode = statbuf.st_mode; +# if ENABLE_FEATURE_LS_FILETYPES + append = append_char(mode); +# endif +# if ENABLE_FEATURE_LS_COLOR + if (G_show_color) { + printf(ESC"[%u;%um", bold(mode), fgcolor(mode)); + } +# endif + } +#endif + column += print_name(lpath) + 4; + free(lpath); + if (G_show_color) { + printf(ESC"[m"); + } + } +#if ENABLE_FEATURE_LS_FILETYPES + if (opt & (OPT_F|OPT_p)) { + if (append) { + putchar(append); + column++; + } + } +#endif + + return column; +} + +static void display_files(struct dnode **dn, unsigned nfiles) +{ + unsigned i, ncols, nrows, row, nc; + unsigned column; + unsigned nexttab; + unsigned column_width = 0; /* used only by coulmnal output */ + + if (option_mask32 & (OPT_l|OPT_1)) { + ncols = 1; + } else { + /* find the longest file name, use that as the column width */ + for (i = 0; dn[i]; i++) { + int len = calc_name_len(dn[i]->name); + if (column_width < len) + column_width = len; + } + column_width += 2 + + ((option_mask32 & OPT_Z) ? 33 : 0) /* context width */ + + ((option_mask32 & OPT_i) ? 8 : 0) /* inode# width */ + + ((option_mask32 & OPT_s) ? 5 : 0) /* "alloc block" width */ + ; + ncols = (unsigned)G_terminal_width / column_width; + } + + if (ncols > 1) { + nrows = nfiles / ncols; + if (nrows * ncols < nfiles) + nrows++; /* round up fractionals */ + } else { + nrows = nfiles; + ncols = 1; + } + + column = 0; + nexttab = 0; + for (row = 0; row < nrows; row++) { + for (nc = 0; nc < ncols; nc++) { + /* reach into the array based on the column and row */ + if (option_mask32 & OPT_x) + i = (row * ncols) + nc; /* display across row */ + else + i = (nc * nrows) + row; /* display by column */ + if (i < nfiles) { + if (column > 0) { + nexttab -= column; + printf("%*s", nexttab, ""); + column += nexttab; + } + nexttab = column + column_width; + column += display_single(dn[i]); + } + } + putchar('\n'); + column = 0; + } +} + + +/*** Dir scanning code ***/ + +static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) +{ + struct stat statbuf; + struct dnode *cur; + + cur = xzalloc(sizeof(*cur)); + cur->fullname = fullname; + cur->name = name; + + if ((option_mask32 & OPT_L) || force_follow) { +#if ENABLE_SELINUX + if (option_mask32 & OPT_Z) { + getfilecon(fullname, &cur->sid); + } +#endif + if (stat(fullname, &statbuf)) { + bb_simple_perror_msg(fullname); + G.exit_code = EXIT_FAILURE; + free(cur); + return NULL; + } + cur->dn_mode_stat = statbuf.st_mode; + } else { +#if ENABLE_SELINUX + if (option_mask32 & OPT_Z) { + lgetfilecon(fullname, &cur->sid); + } +#endif + if (lstat(fullname, &statbuf)) { + bb_simple_perror_msg(fullname); + G.exit_code = EXIT_FAILURE; + free(cur); + return NULL; + } + cur->dn_mode_lstat = statbuf.st_mode; + } + + /* cur->dstat = statbuf: */ + cur->dn_mode = statbuf.st_mode ; + cur->dn_size = statbuf.st_size ; +#if ENABLE_FEATURE_LS_TIMESTAMPS || ENABLE_FEATURE_LS_SORTFILES + cur->dn_time = statbuf.st_mtime ; + if (option_mask32 & OPT_u) + cur->dn_time = statbuf.st_atime; + if (option_mask32 & OPT_c) + cur->dn_time = statbuf.st_ctime; +#endif + cur->dn_ino = statbuf.st_ino ; + cur->dn_blocks = statbuf.st_blocks; + cur->dn_nlink = statbuf.st_nlink ; + cur->dn_uid = statbuf.st_uid ; + cur->dn_gid = statbuf.st_gid ; + cur->dn_rdev_maj = major(statbuf.st_rdev); + cur->dn_rdev_min = minor(statbuf.st_rdev); + + return cur; +} + +static unsigned count_dirs(struct dnode **dn, int which) +{ + unsigned dirs, all; + + if (!dn) + return 0; + + dirs = all = 0; + for (; *dn; dn++) { + const char *name; + + all++; + if (!S_ISDIR((*dn)->dn_mode)) + continue; + + name = (*dn)->name; + if (which != SPLIT_SUBDIR /* if not requested to skip . / .. */ + /* or if it's not . or .. */ + || name[0] != '.' + || (name[1] && (name[1] != '.' || name[2])) + ) { + dirs++; + } + } + return which != SPLIT_FILE ? dirs : all - dirs; +} + +/* get memory to hold an array of pointers */ +static struct dnode **dnalloc(unsigned num) +{ + if (num < 1) + return NULL; + + num++; /* so that we have terminating NULL */ + return xzalloc(num * sizeof(struct dnode *)); +} + +#if ENABLE_FEATURE_LS_RECURSIVE +static void dfree(struct dnode **dnp) +{ + unsigned i; + + if (dnp == NULL) + return; + + for (i = 0; dnp[i]; i++) { + struct dnode *cur = dnp[i]; + if (cur->fname_allocated) + free((char*)cur->fullname); + free(cur); + } + free(dnp); +} +#else +#define dfree(...) ((void)0) +#endif + +/* Returns NULL-terminated malloced vector of pointers (or NULL) */ +static struct dnode **splitdnarray(struct dnode **dn, int which) +{ + unsigned dncnt, d; + struct dnode **dnp; + + if (dn == NULL) + return NULL; + + /* count how many dirs or files there are */ + dncnt = count_dirs(dn, which); + + /* allocate a file array and a dir array */ + dnp = dnalloc(dncnt); + + /* copy the entrys into the file or dir array */ + for (d = 0; *dn; dn++) { + if (S_ISDIR((*dn)->dn_mode)) { + const char *name; + + if (which == SPLIT_FILE) + continue; + + name = (*dn)->name; + if ((which & SPLIT_DIR) /* any dir... */ + /* ... or not . or .. */ + || name[0] != '.' + || (name[1] && (name[1] != '.' || name[2])) + ) { + dnp[d++] = *dn; + } + } else + if (which == SPLIT_FILE) { + dnp[d++] = *dn; + } + } + return dnp; +} + +#if ENABLE_FEATURE_LS_SORTFILES +static int sortcmp(const void *a, const void *b) +{ + struct dnode *d1 = *(struct dnode **)a; + struct dnode *d2 = *(struct dnode **)b; + unsigned opt = option_mask32; + off_t dif; + + dif = 0; /* assume sort by name */ + // TODO: use pre-initialized function pointer + // instead of branch forest + if (opt & OPT_dirs_first) { + dif = S_ISDIR(d2->dn_mode) - S_ISDIR(d1->dn_mode); + if (dif != 0) + goto maybe_invert_and_ret; + } + + if (opt & OPT_S) { /* sort by size */ + dif = (d2->dn_size - d1->dn_size); + } else + if (opt & OPT_t) { /* sort by time */ + dif = (d2->dn_time - d1->dn_time); + } else +#if defined(HAVE_STRVERSCMP) && HAVE_STRVERSCMP == 1 + if (opt & OPT_v) { /* sort by version */ + dif = strverscmp(d1->name, d2->name); + } else +#endif + if (opt & OPT_X) { /* sort by extension */ + dif = strcmp(strchrnul(d1->name, '.'), strchrnul(d2->name, '.')); + } + if (dif == 0) { + /* sort by name, use as tie breaker for other sorts */ + if (ENABLE_LOCALE_SUPPORT) + dif = strcoll(d1->name, d2->name); + else + dif = strcmp(d1->name, d2->name); + } else { + /* Make dif fit into an int */ + if (sizeof(dif) > sizeof(int)) { + enum { BITS_TO_SHIFT = 8 * (sizeof(dif) - sizeof(int)) }; + /* shift leaving only "int" worth of bits */ + /* (this requires dif != 0, and here it is nonzero) */ + dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); + } + } + maybe_invert_and_ret: + return (opt & OPT_r) ? -(int)dif : (int)dif; +} + +static void dnsort(struct dnode **dn, int size) +{ + qsort(dn, size, sizeof(*dn), sortcmp); +} + +static void sort_and_display_files(struct dnode **dn, unsigned nfiles) +{ + dnsort(dn, nfiles); + display_files(dn, nfiles); +} +#else +# define dnsort(dn, size) ((void)0) +# define sort_and_display_files(dn, nfiles) display_files(dn, nfiles) +#endif + +/* Returns NULL-terminated malloced vector of pointers (or NULL) */ +static struct dnode **scan_one_dir(const char *path, unsigned *nfiles_p) +{ + struct dnode *dn, *cur, **dnp; + struct dirent *entry; + DIR *dir; + unsigned i, nfiles; + + *nfiles_p = 0; + dir = warn_opendir(path); + if (dir == NULL) { + G.exit_code = EXIT_FAILURE; + return NULL; /* could not open the dir */ + } + dn = NULL; + nfiles = 0; + while ((entry = readdir(dir)) != NULL) { + char *fullname; + + /* are we going to list the file- it may be . or .. or a hidden file */ + if (entry->d_name[0] == '.') { + if (!(option_mask32 & (OPT_a|OPT_A))) + continue; /* skip all dotfiles if no -a/-A */ + if (!(option_mask32 & OPT_a) + && (!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2])) + ) { + continue; /* if only -A, skip . and .. but show other dotfiles */ + } + } + fullname = concat_path_file(path, entry->d_name); + cur = my_stat(fullname, bb_basename(fullname), 0); + if (!cur) { + free(fullname); + continue; + } + cur->fname_allocated = 1; + cur->dn_next = dn; + dn = cur; + nfiles++; + } + closedir(dir); + + if (dn == NULL) + return NULL; + + /* now that we know how many files there are + * allocate memory for an array to hold dnode pointers + */ + *nfiles_p = nfiles; + dnp = dnalloc(nfiles); + for (i = 0; /* i < nfiles - detected via !dn below */; i++) { + dnp[i] = dn; /* save pointer to node in array */ + dn = dn->dn_next; + if (!dn) + break; + } + + return dnp; +} + +#if ENABLE_DESKTOP +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/ls.html + * If any of the -l, -n, -s options is specified, each list + * of files within the directory shall be preceded by a + * status line indicating the number of file system blocks + * occupied by files in the directory in 512-byte units if + * the -k option is not specified, or 1024-byte units if the + * -k option is specified, rounded up to the next integral + * number of units. + */ +/* by Jorgen Overgaard (jorgen AT antistaten.se) */ +static off_t calculate_blocks(struct dnode **dn) +{ + uoff_t blocks = 1; + if (dn) { + while (*dn) { + /* st_blocks is in 512 byte blocks */ + blocks += (*dn)->dn_blocks; + dn++; + } + } + + /* Even though standard says use 512 byte blocks, coreutils use 1k */ + /* Actually, we round up by calculating (blocks + 1) / 2, + * "+ 1" was done when we initialized blocks to 1 */ + return blocks >> 1; +} +#endif + +static void scan_and_display_dirs_recur(struct dnode **dn, int first) +{ + unsigned nfiles; + struct dnode **subdnp; + + for (; *dn; dn++) { + if (G.show_dirname || (option_mask32 & OPT_R)) { + if (!first) + bb_putchar('\n'); + first = 0; + printf("%s:\n", (*dn)->fullname); + } + subdnp = scan_one_dir((*dn)->fullname, &nfiles); +#if ENABLE_DESKTOP + if (option_mask32 & (OPT_s|OPT_l)) { + if (option_mask32 & OPT_h) { + printf("total %-"HUMAN_READABLE_MAX_WIDTH_STR"s\n", + /* print size, no fractions, use suffixes */ + make_human_readable_str(calculate_blocks(subdnp) * 1024, + 0, 0) + ); + } else { + printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); + } + } +#endif + if (nfiles > 0) { + /* list all files at this level */ + sort_and_display_files(subdnp, nfiles); + + if (ENABLE_FEATURE_LS_RECURSIVE + && (option_mask32 & OPT_R) + ) { + struct dnode **dnd; + unsigned dndirs; + /* recursive - list the sub-dirs */ + dnd = splitdnarray(subdnp, SPLIT_SUBDIR); + dndirs = count_dirs(subdnp, SPLIT_SUBDIR); + if (dndirs > 0) { + dnsort(dnd, dndirs); + scan_and_display_dirs_recur(dnd, 0); + /* free the array of dnode pointers to the dirs */ + free(dnd); + } + } + /* free the dnodes and the fullname mem */ + dfree(subdnp); + } + } +} + + +int ls_main(int argc UNUSED_PARAM, char **argv) +{ /* ^^^^^^^^^^^^^^^^^ note: if FTPD, argc can be wrong, see ftpd.c */ + struct dnode **dnd; + struct dnode **dnf; + struct dnode **dnp; + struct dnode *dn; + struct dnode *cur; + unsigned opt; + unsigned nfiles; + unsigned dnfiles; + unsigned dndirs; + unsigned i; +#if ENABLE_FEATURE_LS_COLOR + /* colored LS support by JaWi, janwillem.janssen@lxtreme.nl */ + /* coreutils 6.10: + * # ls --color=BOGUS + * ls: invalid argument 'BOGUS' for '--color' + * Valid arguments are: + * 'always', 'yes', 'force' + * 'never', 'no', 'none' + * 'auto', 'tty', 'if-tty' + * (and substrings: "--color=alwa" work too) + */ + static const char color_str[] ALIGN1 = + "always\0""yes\0""force\0" + "auto\0""tty\0""if-tty\0"; + /* need to initialize since --color has _an optional_ argument */ + const char *color_opt = color_str; /* "always" */ +#endif +#if ENABLE_LONG_OPTS + static const char ls_longopts[] ALIGN1 = + "full-time\0" No_argument "\xff" + "group-directories-first\0" No_argument "\xfe" + IF_FEATURE_LS_COLOR("color\0" Optional_argument "\xfd") + ; +#endif + + INIT_G(); + + init_unicode(); + +#if ENABLE_FEATURE_LS_WIDTH + /* obtain the terminal width */ + G_terminal_width = get_terminal_width(STDIN_FILENO); + /* go one less... */ + G_terminal_width--; +#endif + + /* process options */ + opt = getopt32long(argv, "^" + ls_options + "\0" + /* -n and -g imply -l */ + "nl:gl" + /* --full-time implies -l */ + IF_FEATURE_LS_TIMESTAMPS(IF_LONG_OPTS(":\xff""l")) + /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ls.html: + * in some pairs of opts, only last one takes effect: + */ + IF_FEATURE_LS_TIMESTAMPS(IF_FEATURE_LS_SORTFILES(":t-S:S-t")) /* time/size */ + // ":m-l:l-m" - we don't have -m + IF_FEATURE_LS_FOLLOWLINKS(":H-L:L-H") + ":C-xl:x-Cl:l-xC" /* bycols/bylines/long */ + ":C-1:1-C" /* bycols/oneline */ + ":x-1:1-x" /* bylines/oneline (not in SuS, but in GNU coreutils 8.4) */ + IF_FEATURE_LS_TIMESTAMPS(":c-u:u-c") /* mtime/atime */ + /* -w NUM: */ + IF_FEATURE_LS_WIDTH(":w+") + , ls_longopts + IF_FEATURE_LS_WIDTH(, /*-T*/ NULL, /*-w*/ &G_terminal_width) + IF_FEATURE_LS_COLOR(, &color_opt) + ); +#if 0 /* option bits debug */ + bb_error_msg("opt:0x%08x l:%x H:%x color:%x dirs:%x", opt, OPT_l, OPT_H, OPT_color, OPT_dirs_first); + if (opt & OPT_c ) bb_error_msg("-c"); + if (opt & OPT_l ) bb_error_msg("-l"); + if (opt & OPT_H ) bb_error_msg("-H"); + if (opt & OPT_color ) bb_error_msg("--color"); + if (opt & OPT_dirs_first) bb_error_msg("--group-directories-first"); + if (opt & OPT_full_time ) bb_error_msg("--full-time"); + exit(0); +#endif + +#if ENABLE_SELINUX + if (opt & OPT_Z) { + if (!is_selinux_enabled()) + option_mask32 &= ~OPT_Z; + } +#endif + +#if ENABLE_FEATURE_LS_COLOR + /* set G_show_color = 1/0 */ + if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && !is_TERM_dumb()) { + char *p = getenv("LS_COLORS"); + /* LS_COLORS is unset, or (not empty && not "none") ? */ + if (!p || (p[0] && strcmp(p, "none") != 0)) { + if (isatty(STDOUT_FILENO)) { + /* check isatty() last because it's expensive (syscall) */ + G_show_color = 1; + } + } + } + if (opt & OPT_color) { + if (color_opt[0] == 'n') + G_show_color = 0; + else switch (index_in_substrings(color_str, color_opt)) { + case 3: + case 4: + case 5: + if (!is_TERM_dumb() && isatty(STDOUT_FILENO)) { + case 0: + case 1: + case 2: + G_show_color = 1; + } + } + } +#endif + + /* sort out which command line options take precedence */ + if (ENABLE_FEATURE_LS_RECURSIVE && (opt & OPT_d)) + option_mask32 &= ~OPT_R; /* no recurse if listing only dir */ + if (!(opt & OPT_l)) { /* not -l? */ + if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { + /* when to sort by time? -t[cu] sorts by time even with -l */ + /* (this is achieved by opt_flags[] element for -t) */ + /* without -l, bare -c or -u enable sort too */ + /* (with -l, bare -c or -u just select which time to show) */ + if (opt & (OPT_c|OPT_u)) { + option_mask32 |= OPT_t; + } + } + } + + /* choose a display format if one was not already specified by an option */ + if (!(option_mask32 & (OPT_l|OPT_1|OPT_x|OPT_C))) + option_mask32 |= (isatty(STDOUT_FILENO) ? OPT_C : OPT_1); + + if (ENABLE_FTPD && applet_name[0] == 'f') { + /* ftpd secret backdoor. dirs first are much nicer */ + option_mask32 |= OPT_dirs_first; + } + + argv += optind; + if (!argv[0]) + *--argv = (char*)"."; + + if (argv[1]) + G.show_dirname = 1; /* 2 or more items? label directories */ + + /* stuff the command line file names into a dnode array */ + dn = NULL; + nfiles = 0; + do { + cur = my_stat(*argv, *argv, + /* follow links on command line unless -l, -i, -s or -F: */ + !(option_mask32 & (OPT_l|OPT_i|OPT_s|OPT_F)) + /* ... or if -H: */ + || (option_mask32 & OPT_H) + /* ... or if -L, but my_stat always follows links if -L */ + ); + argv++; + if (!cur) + continue; + /*cur->fname_allocated = 0; - already is */ + cur->dn_next = dn; + dn = cur; + nfiles++; + } while (*argv); + + /* nfiles _may_ be 0 here - try "ls doesnt_exist" */ + if (nfiles == 0) + return G.exit_code; + + /* now that we know how many files there are + * allocate memory for an array to hold dnode pointers + */ + dnp = dnalloc(nfiles); + for (i = 0; /* i < nfiles - detected via !dn below */; i++) { + dnp[i] = dn; /* save pointer to node in array */ + dn = dn->dn_next; + if (!dn) + break; + } + + if (option_mask32 & OPT_d) { + sort_and_display_files(dnp, nfiles); + } else { + dnd = splitdnarray(dnp, SPLIT_DIR); + dnf = splitdnarray(dnp, SPLIT_FILE); + dndirs = count_dirs(dnp, SPLIT_DIR); + dnfiles = nfiles - dndirs; + if (dnfiles > 0) { + sort_and_display_files(dnf, dnfiles); + if (ENABLE_FEATURE_CLEAN_UP) + free(dnf); + } + if (dndirs > 0) { + dnsort(dnd, dndirs); + scan_and_display_dirs_recur(dnd, dnfiles == 0); + if (ENABLE_FEATURE_CLEAN_UP) + free(dnd); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) + dfree(dnp); + return G.exit_code; +} diff --git a/busybox-1_37_0/coreutils/md5_sha1_sum.c b/busybox-1_37_0/coreutils/md5_sha1_sum.c new file mode 100644 index 000000000..978d328f1 --- /dev/null +++ b/busybox-1_37_0/coreutils/md5_sha1_sum.c @@ -0,0 +1,361 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003-2004 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config MD5SUM +//config: bool "md5sum (6.7 kb)" +//config: default y +//config: help +//config: Compute and check MD5 message digest +//config: +//config:config SHA1SUM +//config: bool "sha1sum (6.7 kb)" +//config: default y +//config: help +//config: Compute and check SHA1 message digest +//config: +//config:config SHA256SUM +//config: bool "sha256sum (8.2 kb)" +//config: default y +//config: help +//config: Compute and check SHA256 message digest +//config: +//config:config SHA512SUM +//config: bool "sha512sum (7.3 kb)" +//config: default y +//config: help +//config: Compute and check SHA512 message digest +//config: +//config:config SHA3SUM +//config: bool "sha3sum (6.3 kb)" +//config: default y +//config: help +//config: Compute and check SHA3 message digest +//config: +//config:comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum" +//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM +//config: +//config:config FEATURE_MD5_SHA1_SUM_CHECK +//config: bool "Enable -c, -s and -w options" +//config: default y +//config: depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM +//config: help +//config: Enabling the -c options allows files to be checked +//config: against pre-calculated hash values. +//config: -s and -w are useful options when verifying checksums. + +//applet:IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum)) +//applet:IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) +//applet:IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) +//applet:IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) +//applet:IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) + +//kbuild:lib-$(CONFIG_MD5SUM) += md5_sha1_sum.o +//kbuild:lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o +//kbuild:lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o +//kbuild:lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o +//kbuild:lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o + +//usage:#define md5sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define md5sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define md5sum_example_usage +//usage: "$ md5sum < busybox\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003\n" +//usage: "$ md5sum busybox\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" +//usage: "$ md5sum -c -\n" +//usage: "6fd11e98b98a58f64ff3398d7b324003 busybox\n" +//usage: "busybox: OK\n" +//usage: "^D\n" +//usage: +//usage:#define sha1sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha1sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define sha256sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha256sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define sha512sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[FILE]..." +//usage:#define sha512sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: +//usage:#define sha3sum_trivial_usage +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK("[-c[sw]] ")"[-a BITS] [FILE]..." +//usage:#define sha3sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA3 checksums" +//usage: IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" +//usage: "\n -c Check sums against list in FILEs" +//usage: "\n -s Don't output anything, status code shows success" +//usage: "\n -w Warn about improperly formatted checksum lines" +//usage: ) +//usage: "\n -a BITS 224 (default), 256, 384, 512" + +//FIXME: GNU coreutils 8.25 has no -s option, it has only these two long opts: +// --quiet don't print OK for each successfully verified file +// --status don't output anything, status code shows success + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +enum { + /* 4th letter of applet_name is... */ + HASH_MD5 = 's', /* "md5>s= 1600/2 /* input block can't be <= 0 */ + || sha3_width == 0 /* hash len can't be 0 */ + || (sha3_width & 0x1f) /* should be multiple of 32 */ + /* (because input uses up to 8 byte wide word XORs. 32/4=8) */ + ) { + bb_error_msg_and_die("bad -a%u", sha3_width); + } + sha3_width /= 4; + context.sha3.input_block_bytes = 1600/8 - sha3_width; + hash_len = sha3_width/2; + } +#endif + else { + xfunc_die(); /* can't reach this */ + } + + { + while ((count = safe_read(src_fd, in_buf, BUFSZ)) > 0) { + update(&context, in_buf, count); + } + hash_value = NULL; + if (count < 0) + bb_perror_msg("can't read '%s'", filename); + else /* count == 0 */ { + final(&context, in_buf); + hash_value = hash_bin_to_hex(in_buf, hash_len); + } + } + + if (src_fd != STDIN_FILENO) { + close(src_fd); + } + + return hash_value; +} + +int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned char *in_buf; + int return_value = EXIT_SUCCESS; + unsigned flags; +#if ENABLE_SHA3SUM + unsigned sha3_width = 224; +#endif + + if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { + /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ + /* -s and -w require -c */ +#if ENABLE_SHA3SUM + if (applet_name[3] == HASH_SHA3) + flags = getopt32(argv, "^" "scwbta:+" "\0" "s?c:w?c", &sha3_width); + else +#endif + flags = getopt32(argv, "^" "scwbt" "\0" "s?c:w?c"); + } else { +#if ENABLE_SHA3SUM + if (applet_name[3] == HASH_SHA3) + getopt32(argv, "a:+", &sha3_width); + else +#endif + getopt32(argv, ""); + } + argv += optind; + //argc -= optind; + if (!*argv) + *--argv = (char*)"-"; + + /* The buffer is not alloc/freed for each input file: + * for big values of COPYBUF_KB, this helps to keep its pages + * pre-faulted and possibly even fully cached on local CPU. + */ + in_buf = xmalloc(BUFSZ); + + do { + if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { + FILE *pre_computed_stream; + char *line; + int count_total = 0; + int count_failed = 0; + + pre_computed_stream = xfopen_stdin(*argv); + + while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { + uint8_t *hash_value; + char *filename_ptr; + + count_total++; + filename_ptr = strchr(line, ' '); + if (!filename_ptr) { + if (flags & FLAG_WARN) { + bb_simple_error_msg("invalid format"); + } + count_failed++; + return_value = EXIT_FAILURE; + free(line); + continue; + } + *filename_ptr++ = '\0'; + /* coreutils 9.1 allows "HASH FILENAME" format, + * with only one space. Skip the 'correct' + * " " or " *" delimiter if it is there: + */ + if (*filename_ptr == ' ' || *filename_ptr == '*') + filename_ptr++; + + hash_value = hash_file(in_buf, filename_ptr, sha3_width); + + if (hash_value && (strcasecmp((char*)hash_value, line) == 0)) { + if (!(flags & FLAG_SILENT)) + printf("%s: OK\n", filename_ptr); + } else { + if (!(flags & FLAG_SILENT)) + printf("%s: FAILED\n", filename_ptr); + count_failed++; + return_value = EXIT_FAILURE; + } + /* possible free(NULL) */ + free(hash_value); + free(line); + } + if (count_failed && !(flags & FLAG_SILENT)) { + bb_error_msg("WARNING: %d of %d computed checksums did NOT match", + count_failed, count_total); + } + if (count_total == 0) { + return_value = EXIT_FAILURE; + /* + * md5sum from GNU coreutils 8.25 says: + * md5sum: : no properly formatted MD5 checksum lines found + */ + bb_error_msg("%s: no checksum lines found", *argv); + } + fclose_if_not_stdin(pre_computed_stream); + } else { + uint8_t *hash_value = hash_file(in_buf, *argv, sha3_width); + if (hash_value == NULL) { + return_value = EXIT_FAILURE; + } else { + printf("%s %s\n", hash_value, *argv); + free(hash_value); + } + } + } while (*++argv); + + return return_value; +} diff --git a/busybox-1_37_0/coreutils/mkdir.c b/busybox-1_37_0/coreutils/mkdir.c new file mode 100644 index 000000000..e074c3561 --- /dev/null +++ b/busybox-1_37_0/coreutils/mkdir.c @@ -0,0 +1,103 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mkdir implementation for busybox + * + * Copyright (C) 2001 Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Fixed broken permission setting when -p was used; especially in + * conjunction with -m. + */ +/* Nov 28, 2006 Yoshinori Sato : Add SELinux Support. + */ +//config:config MKDIR +//config: bool "mkdir (4.7 kb)" +//config: default y +//config: help +//config: mkdir is used to create directories with the specified names. + +//applet:IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) + +//kbuild:lib-$(CONFIG_MKDIR) += mkdir.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkdir.html */ + +//usage:#define mkdir_trivial_usage +//usage: "[-m MODE] [-p] DIRECTORY..." +//usage:#define mkdir_full_usage "\n\n" +//usage: "Create DIRECTORY\n" +//usage: "\n -m MODE Mode" +//usage: "\n -p No error if exists; make parent directories as needed" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) +//usage: +//usage:#define mkdir_example_usage +//usage: "$ mkdir /tmp/foo\n" +//usage: "$ mkdir /tmp/foo\n" +//usage: "/tmp/foo: File exists\n" +//usage: "$ mkdir /tmp/foo/bar/baz\n" +//usage: "/tmp/foo/bar/baz: No such file or directory\n" +//usage: "$ mkdir -p /tmp/foo/bar/baz\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mkdir_main(int argc UNUSED_PARAM, char **argv) +{ + long mode = -1; + int status = EXIT_SUCCESS; + int flags = 0; + unsigned opt; + char *smode; +#if ENABLE_SELINUX + security_context_t scontext; +#endif + + opt = getopt32long(argv, "m:pv" IF_SELINUX("Z:"), + "mode\0" Required_argument "m" + "parents\0" No_argument "p" +# if ENABLE_SELINUX + "context\0" Required_argument "Z" +# endif +# if ENABLE_FEATURE_VERBOSE + "verbose\0" No_argument "v" +# endif + , &smode IF_SELINUX(,&scontext) + ); + if (opt & 1) { + mode_t mmode = bb_parse_mode(smode, 0777); + if (mmode == (mode_t)-1) { + bb_error_msg_and_die("invalid mode '%s'", smode); + } + mode = mmode; + } + if (opt & 2) + flags |= FILEUTILS_RECUR; + if ((opt & 4) && FILEUTILS_VERBOSE) + flags |= FILEUTILS_VERBOSE; +#if ENABLE_SELINUX + if (opt & 8) { + selinux_or_die(); + setfscreatecon_or_die(scontext); + } +#endif + + argv += optind; + if (!argv[0]) + bb_show_usage(); + + do { + if (bb_make_directory(*argv, mode, flags)) { + status = EXIT_FAILURE; + } + } while (*++argv); + + return status; +} diff --git a/busybox-1_37_0/coreutils/mkfifo.c b/busybox-1_37_0/coreutils/mkfifo.c new file mode 100644 index 000000000..f48a8e5db --- /dev/null +++ b/busybox-1_37_0/coreutils/mkfifo.c @@ -0,0 +1,58 @@ +/* vi: set sw=4 ts=4: */ +/* + * mkfifo implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config MKFIFO +//config: bool "mkfifo (4 kb)" +//config: default y +//config: help +//config: mkfifo is used to create FIFOs (named pipes). +//config: The 'mknod' program can also create FIFOs. + +//applet:IF_MKFIFO(APPLET_NOEXEC(mkfifo, mkfifo, BB_DIR_USR_BIN, BB_SUID_DROP, mkfifo)) + +//kbuild:lib-$(CONFIG_MKFIFO) += mkfifo.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/mkfifo.html */ + +//usage:#define mkfifo_trivial_usage +//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME" +//usage:#define mkfifo_full_usage "\n\n" +//usage: "Create named pipe\n" +//usage: "\n -m MODE Mode (default a=rw)" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) + +#include "libbb.h" +#include "libcoreutils/coreutils.h" + +/* This is a NOEXEC applet. Be very careful! */ + +int mkfifo_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mkfifo_main(int argc UNUSED_PARAM, char **argv) +{ + mode_t mode; + int retval = EXIT_SUCCESS; + + mode = getopt_mk_fifo_nod(argv); + + argv += optind; + if (!*argv) { + bb_show_usage(); + } + + do { + if (mkfifo(*argv, mode) < 0) { + bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */ + retval = EXIT_FAILURE; + } + } while (*++argv); + + return retval; +} diff --git a/busybox-1_37_0/coreutils/mknod.c b/busybox-1_37_0/coreutils/mknod.c new file mode 100644 index 000000000..e390a7203 --- /dev/null +++ b/busybox-1_37_0/coreutils/mknod.c @@ -0,0 +1,88 @@ +/* vi: set sw=4 ts=4: */ +/* + * mknod implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config MKNOD +//config: bool "mknod (4.6 kb)" +//config: default y +//config: help +//config: mknod is used to create FIFOs or block/character special +//config: files with the specified names. + +//applet:IF_MKNOD(APPLET_NOEXEC(mknod, mknod, BB_DIR_BIN, BB_SUID_DROP, mknod)) + +//kbuild:lib-$(CONFIG_MKNOD) += mknod.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define mknod_trivial_usage +//usage: "[-m MODE] " IF_SELINUX("[-Z] ") "NAME TYPE [MAJOR MINOR]" +//usage:#define mknod_full_usage "\n\n" +//usage: "Create a special file (block, character, or pipe)\n" +//usage: "\n -m MODE Creation mode (default a=rw)" +//usage: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) +//usage: "\nTYPE:" +//usage: "\n b Block device" +//usage: "\n c or u Character device" +//usage: "\n p Named pipe (MAJOR MINOR must be omitted)" +//usage: +//usage:#define mknod_example_usage +//usage: "$ mknod /dev/fd0 b 2 0\n" +//usage: "$ mknod -m 644 /tmp/pipe p\n" + +#ifdef __linux__ +# include // For makedev +#endif + +#include "libbb.h" +#include "libcoreutils/coreutils.h" + +/* This is a NOEXEC applet. Be very careful! */ + +static const char modes_chars[] ALIGN1 = { 'p', 'c', 'u', 'b', 0, 1, 1, 2 }; +static const mode_t modes_cubp[] = { S_IFIFO, S_IFCHR, S_IFBLK }; + +int mknod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mknod_main(int argc UNUSED_PARAM, char **argv) +{ + mode_t mode; + dev_t dev; + const char *type, *arg; + + mode = getopt_mk_fifo_nod(argv); + argv += optind; + //argc -= optind; + + if (!argv[0] || !argv[1]) + bb_show_usage(); + type = strchr(modes_chars, argv[1][0]); + if (!type) + bb_show_usage(); + + mode |= modes_cubp[(int)(type[4])]; + + dev = 0; + arg = argv[2]; + if (*type != 'p') { + if (!argv[2] || !argv[3]) + bb_show_usage(); + /* Autodetect what the system supports; these macros should + * optimize out to two constants. */ + dev = makedev(xatoul_range(argv[2], 0, major(UINT_MAX)), + xatoul_range(argv[3], 0, minor(UINT_MAX))); + arg = argv[4]; + } + if (arg) + bb_show_usage(); + + if (mknod(argv[0], mode, dev) != 0) { + bb_simple_perror_msg_and_die(argv[0]); + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/mktemp.c b/busybox-1_37_0/coreutils/mktemp.c new file mode 100644 index 000000000..91b2be6d3 --- /dev/null +++ b/busybox-1_37_0/coreutils/mktemp.c @@ -0,0 +1,133 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mktemp implementation for busybox + * + * Copyright (C) 2000 by Daniel Jacobowitz + * Written by Daniel Jacobowitz + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Coreutils 6.12 man page says: + * mktemp [OPTION]... [TEMPLATE] + * Create a temporary file or directory, safely, and print its name. If + * TEMPLATE is not specified, use tmp.XXXXXXXXXX. + * -d, --directory + * create a directory, not a file + * -q, --quiet + * suppress diagnostics about file/dir-creation failure + * -u, --dry-run + * do not create anything; merely print a name (unsafe) + * --tmpdir[=DIR] + * interpret TEMPLATE relative to DIR. If DIR is not specified, + * use $TMPDIR if set, else /tmp. With this option, TEMPLATE must + * not be an absolute name. Unlike with -t, TEMPLATE may contain + * slashes, but even here, mktemp still creates only the final com- + * ponent. + * -p DIR use DIR as a prefix; implies -t [deprecated] + * -t interpret TEMPLATE as a single file name component, relative to + * a directory: $TMPDIR, if set; else the directory specified via + * -p; else /tmp [deprecated] + */ +//config:config MKTEMP +//config: bool "mktemp (4.5 kb)" +//config: default y +//config: help +//config: mktemp is used to create unique temporary files + +//applet:IF_MKTEMP(APPLET_NOEXEC(mktemp, mktemp, BB_DIR_BIN, BB_SUID_DROP, mktemp)) + +//kbuild:lib-$(CONFIG_MKTEMP) += mktemp.o + +//usage:#define mktemp_trivial_usage +//usage: "[-dt] [-p DIR] [TEMPLATE]" +//usage:#define mktemp_full_usage "\n\n" +//usage: "Create a temporary file with name based on TEMPLATE and print its name.\n" +//usage: "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" +//usage: "Without TEMPLATE, -t tmp.XXXXXX is assumed.\n" +//usage: "\n -d Make directory, not file" +//usage: "\n -q Fail silently on errors" +//usage: "\n -t Prepend base directory name to TEMPLATE" +//usage: "\n -p DIR Use DIR as a base directory (implies -t)" +//usage: "\n -u Do not create anything; print a name" +//usage: "\n" +//usage: "\nBase directory is: -p DIR, else $TMPDIR, else /tmp" +//usage: +//usage:#define mktemp_example_usage +//usage: "$ mktemp /tmp/temp.XXXXXX\n" +//usage: "/tmp/temp.mWiLjM\n" +//usage: "$ ls -la /tmp/temp.mWiLjM\n" +//usage: "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" + +#include "libbb.h" + +int mktemp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mktemp_main(int argc UNUSED_PARAM, char **argv) +{ + const char *path; + char *chp; + unsigned opts; + enum { + OPT_d = 1 << 0, + OPT_q = 1 << 1, + OPT_t = 1 << 2, + OPT_p = 1 << 3, + OPT_u = 1 << 4, + OPT_tmpdir = (1 << 5) * ENABLE_LONG_OPTS, + }; + + path = getenv("TMPDIR"); + if (!path || path[0] == '\0') + path = "/tmp"; + +#if ENABLE_LONG_OPTS + opts = getopt32long(argv, "^" + "dqtp:u" + "\0" + "?1" /* 1 arg max */, + "directory\0" No_argument "d" + "quiet\0" No_argument "q" + "dry-run\0" No_argument "u" + "tmpdir\0" Optional_argument "\xff" + , &path, &path + ); +#else + opts = getopt32(argv, "^" "dqtp:u" "\0" "?1"/*1 arg max*/, &path); +#endif + + chp = argv[optind]; + if (!chp) { + /* GNU coreutils 8.4: + * bare "mktemp" -> "mktemp -t tmp.XXXXXX" + */ + chp = xstrdup("tmp.XXXXXX"); + opts |= OPT_t; + } +#if 0 + /* Don't allow directory separator in template */ + if ((opts & OPT_t) && bb_basename(chp) != chp) { + errno = EINVAL; + goto error; + } +#endif + if (opts & (OPT_t|OPT_p|OPT_tmpdir)) + chp = concat_path_file(path, chp); + + if (opts & OPT_u) { + chp = mktemp(chp); + if (chp[0] == '\0') + goto error; + } else if (opts & OPT_d) { + if (mkdtemp(chp) == NULL) + goto error; + } else { + if (mkstemp(chp) < 0) + goto error; + } + puts(chp); + return EXIT_SUCCESS; + error: + if (opts & OPT_q) + return EXIT_FAILURE; + /* don't use chp as it gets mangled in case of error */ + bb_perror_nomsg_and_die(); +} diff --git a/busybox-1_37_0/coreutils/mv.c b/busybox-1_37_0/coreutils/mv.c new file mode 100644 index 000000000..cf6169a1e --- /dev/null +++ b/busybox-1_37_0/coreutils/mv.c @@ -0,0 +1,191 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini mv implementation for busybox + * + * Copyright (C) 2000 by Matt Kraai + * SELinux support by Yuichi Nakamura + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Size reduction and improved error checking. + */ +//config:config MV +//config: bool "mv (10 kb)" +//config: default y +//config: help +//config: mv is used to move or rename files or directories. + +//applet:IF_MV(APPLET_NOEXEC(mv, mv, BB_DIR_BIN, BB_SUID_DROP, mv)) +/* NOEXEC despite cases when it can be a "runner" (mv LARGE_DIR OTHER_FS) */ + +//kbuild:lib-$(CONFIG_MV) += mv.o + +//usage:#define mv_trivial_usage +//usage: "[-finT] SOURCE DEST\n" +//usage: "or: mv [-fin] SOURCE... { -t DIRECTORY | DIRECTORY }" +//usage:#define mv_full_usage "\n\n" +//usage: "Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n" +//usage: "\n -f Don't prompt before overwriting" +//usage: "\n -i Interactive, prompt before overwrite" +//usage: "\n -n Don't overwrite an existing file" +//usage: "\n -T Refuse to move if DEST is a directory" +//usage: "\n -t DIR Move all SOURCEs into DIR" +//usage: +//usage:#define mv_example_usage +//usage: "$ mv /tmp/foo /bin/bar\n" + +#include "libbb.h" +#include "libcoreutils/coreutils.h" + +int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mv_main(int argc, char **argv) +{ + struct stat statbuf; + const char *last; + const char *dest; + unsigned flags; + int dest_exists; + int status = 0; + int copy_flag = 0; + +#define OPT_FORCE (1 << 0) +#define OPT_INTERACTIVE (1 << 1) +#define OPT_NOCLOBBER (1 << 2) +#define OPT_DESTNOTDIR (1 << 3) +#define OPT_DESTDIR (1 << 4) +#define OPT_VERBOSE ((1 << 5) * ENABLE_FEATURE_VERBOSE) + flags = getopt32long(argv, "^" + "finTt:v" + "\0" + /* At least one argument. (Usually two+, but -t DIR can have only one) */ + "-1" + /* only the final one of -f, -i, -n takes effect */ + ":f-in:i-fn:n-fi" + /* -t and -T don't mix */ + ":t--T:T--t", + "interactive\0" No_argument "i" + "force\0" No_argument "f" + "no-clobber\0" No_argument "n" + "no-target-directory\0" No_argument "T" + "target-directory\0" Required_argument "t" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + , &last + ); + argc -= optind; + argv += optind; + + if (!(flags & OPT_DESTDIR)) { + last = argv[argc - 1]; + if (argc < 2) + bb_show_usage(); + if (argc != 2) { + if (flags & OPT_DESTNOTDIR) + bb_show_usage(); + /* "mv A B C... DIR" - target must be dir */ + } else /* argc == 2 */ { + /* "mv A B" - only case where target can be not a dir */ + dest_exists = cp_mv_stat(last, &statbuf); + if (dest_exists < 0) { /* error other than ENOENT */ + return EXIT_FAILURE; + } + if (!(dest_exists & 2)) { + /* last is not a directory */ + dest = last; + goto DO_MOVE; + } + /* last is a directory */ + if (flags & OPT_DESTNOTDIR) { + if (stat(argv[0], &statbuf) == 0 && !S_ISDIR(statbuf.st_mode)) + bb_error_msg_and_die("'%s' is a directory", last); + /* "mv -T DIR1 DIR2" is allowed (renames a dir) */ + dest = last; + goto DO_MOVE; + } + /* else: fall through into "do { move SRC to DIR/SRC } while" loop */ + } + } + /* else: last is DIR from "-t DIR" */ + + do { + dest = concat_path_file(last, bb_get_last_path_component_strip(*argv)); + dest_exists = cp_mv_stat(dest, &statbuf); + if (dest_exists < 0) { + goto RET_1; + } + + DO_MOVE: + if (dest_exists) { + if (flags & OPT_NOCLOBBER) + goto RET_0; + if (!(flags & OPT_FORCE) + && ((access(dest, W_OK) < 0 && isatty(0)) + || (flags & OPT_INTERACTIVE)) + ) { + if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { + goto RET_1; /* Ouch! fprintf failed! */ + } + if (!bb_ask_y_confirmation()) { + goto RET_0; + } + } + } + + if (rename(*argv, dest) < 0) { + int source_exists; + + if (errno != EXDEV + || (source_exists = cp_mv_stat2(*argv, &statbuf, lstat)) < 1 + ) { + bb_perror_msg("can't rename '%s'", *argv); + } else { + static const char fmt[] ALIGN1 = + "can't overwrite %sdirectory with %sdirectory"; + + if (dest_exists) { + if (dest_exists == 3) { + if (source_exists != 3) { + bb_error_msg(fmt, "", "non-"); + goto RET_1; + } + } else { + if (source_exists == 3) { + bb_error_msg(fmt, "non-", ""); + goto RET_1; + } + } + if (unlink(dest) < 0) { + bb_perror_msg("can't remove '%s'", dest); + goto RET_1; + } + } + /* FILEUTILS_RECUR also prevents nasties like + * "read from device and write contents to dst" + * instead of "create same device node" */ + copy_flag = FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS; +#if ENABLE_SELINUX + copy_flag |= FILEUTILS_PRESERVE_SECURITY_CONTEXT; +#endif + if ((copy_file(*argv, dest, copy_flag) >= 0) + && (remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0) + ) { + goto RET_0; + } + } + RET_1: + status = 1; + } + RET_0: + if (flags & OPT_VERBOSE) { + printf("'%s' -> '%s'\n", *argv, dest); + } + if (dest != last) { + free((void *) dest); + } + } while (*++argv && *argv != last); + + return status; +} diff --git a/busybox-1_37_0/coreutils/nice.c b/busybox-1_37_0/coreutils/nice.c new file mode 100644 index 000000000..0648593ee --- /dev/null +++ b/busybox-1_37_0/coreutils/nice.c @@ -0,0 +1,68 @@ +/* vi: set sw=4 ts=4: */ +/* + * nice implementation for busybox + * + * Copyright (C) 2005 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config NICE +//config: bool "nice (2.3 kb)" +//config: default y +//config: help +//config: nice runs a program with modified scheduling priority. + +//applet:IF_NICE(APPLET_NOEXEC(nice, nice, BB_DIR_BIN, BB_SUID_DROP, nice)) + +//kbuild:lib-$(CONFIG_NICE) += nice.o + +//usage:#define nice_trivial_usage +//usage: "[-n ADJUST] [PROG ARGS]" +//usage:#define nice_full_usage "\n\n" +//usage: "Change scheduling priority, run PROG\n" +//usage: "\n -n ADJUST Adjust priority by ADJUST" + +#include "libbb.h" + +int nice_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nice_main(int argc UNUSED_PARAM, char **argv) +{ + int old_priority, adjustment; + + old_priority = getpriority(PRIO_PROCESS, 0); + + if (!*++argv) { /* No args, so (GNU) output current nice value. */ + printf("%d\n", old_priority); + fflush_stdout_and_exit_SUCCESS(); + } + + adjustment = 10; /* Set default adjustment. */ + + if (argv[0][0] == '-') { + char *nnn = argv[0] + 1; + if (nnn[0] == 'n') { /* -n */ + nnn += 1; + if (!nnn[0]) { /* "-n NNN" */ + nnn = *++argv; + } + /* else: "-nNNN" (w/o space) */ + } + /* else: "-NNN" (NNN may be negative) - same as "-n NNN" */ + + if (!nnn || !argv[1]) { /* Missing priority or PROG! */ + bb_show_usage(); + } + adjustment = xatoi_range(nnn, INT_MIN/2, INT_MAX/2); + argv++; + } + + { /* Set our priority. */ + int prio = old_priority + adjustment; + + if (setpriority(PRIO_PROCESS, 0, prio) < 0) { + bb_perror_msg_and_die("setpriority(%d)", prio); + } + } + + BB_EXECVP_or_die(argv); +} diff --git a/busybox-1_37_0/coreutils/nl.c b/busybox-1_37_0/coreutils/nl.c new file mode 100644 index 000000000..12120f7a0 --- /dev/null +++ b/busybox-1_37_0/coreutils/nl.c @@ -0,0 +1,83 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config NL +//config: bool "nl (4.9 kb)" +//config: default y +//config: help +//config: nl is used to number lines of files. + +//applet:IF_NL(APPLET(nl, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NL) += nl.o + +//usage:#define nl_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define nl_full_usage "\n\n" +//usage: "Write FILEs to standard output with line numbers added\n" +//usage: "\n -b STYLE Which lines to number - a: all, t: nonempty, n: none" +//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^TODO: support "pBRE": number only lines that match regexp BRE" +////usage: "\n -f STYLE footer lines" +////usage: "\n -h STYLE header lines" +////usage: "\n -d CC use CC for separating logical pages" +//usage: "\n -i N Line number increment" +////usage: "\n -l NUMBER group of NUMBER empty lines counted as one" +////usage: "\n -n FORMAT lneft justified, no leading zeros; rn or rz" +////usage: "\n -p do not reset line numbers at logical pages (huh?)" +//usage: "\n -s STRING Use STRING as line number separator" +//usage: "\n -v N Start from N" +//usage: "\n -w N Width of line numbers" + +/* By default, selects -v1 -i1 -l1 -sTAB -w6 -nrn -hn -bt -fn */ + +#include "libbb.h" + +int nl_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nl_main(int argc UNUSED_PARAM, char **argv) +{ + struct number_state ns; + const char *opt_b = "t"; + enum { + OPT_p = (1 << 0), + }; +#if ENABLE_LONG_OPTS + static const char nl_longopts[] ALIGN1 = + "body-numbering\0" Required_argument "b" + // "footer-numbering\0" Required_argument "f" - not implemented yet + // "header-numbering\0" Required_argument "h" - not implemented yet + // "section-delimiter\0" Required_argument "d" - not implemented yet + "line-increment\0" Required_argument "i" + // "join-blank-lines\0" Required_argument "l" - not implemented yet + // "number-format\0" Required_argument "n" - not implemented yet + "no-renumber\0" No_argument "p" // no-op so far + "number-separator\0" Required_argument "s" + "starting-line-number\0"Required_argument "v" + "number-width\0" Required_argument "w" + ; +#endif + int exitcode; + + ns.width = 6; + ns.start = 1; + ns.inc = 1; + ns.sep = "\t"; + getopt32long(argv, "pw:+s:v:+i:+b:", nl_longopts, + &ns.width, &ns.sep, &ns.start, &ns.inc, &opt_b); + ns.all = (opt_b[0] == 'a'); + ns.nonempty = (opt_b[0] == 't'); + ns.empty_str = xasprintf("%*s", ns.width + (int)strlen(ns.sep), ""); + + argv += optind; + if (!*argv) + *--argv = (char*)"-"; + + exitcode = EXIT_SUCCESS; + do { + exitcode |= print_numbered_lines(&ns, *argv); + } while (*++argv); + + fflush_stdout_and_exit(exitcode); +} diff --git a/busybox-1_37_0/coreutils/nohup.c b/busybox-1_37_0/coreutils/nohup.c new file mode 100644 index 000000000..69d8daff9 --- /dev/null +++ b/busybox-1_37_0/coreutils/nohup.c @@ -0,0 +1,98 @@ +/* vi: set sw=4 ts=4: */ +/* + * nohup - invoke a utility immune to hangups. + * + * Busybox version based on nohup specification at + * http://www.opengroup.org/onlinepubs/007904975/utilities/nohup.html + * + * Copyright 2006 Rob Landley + * Copyright 2006 Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config NOHUP +//config: bool "nohup (2.2 kb)" +//config: default y +//config: help +//config: run a command immune to hangups, with output to a non-tty. + +//applet:IF_NOHUP(APPLET_NOEXEC(nohup, nohup, BB_DIR_USR_BIN, BB_SUID_DROP, nohup)) + +//kbuild:lib-$(CONFIG_NOHUP) += nohup.o + +//usage:#define nohup_trivial_usage +//usage: "PROG ARGS" +//usage:#define nohup_full_usage "\n\n" +//usage: "Run PROG immune to hangups, with output to a non-tty" +//usage: +//usage:#define nohup_example_usage +//usage: "$ nohup make &" + +#include "libbb.h" + +/* Compat info: nohup (GNU coreutils 6.8) does this: +# nohup true +nohup: ignoring input and appending output to 'nohup.out' +# nohup true 1>/dev/null +nohup: ignoring input and redirecting stderr to stdout +# nohup true 2>zz +# cat zz +nohup: ignoring input and appending output to 'nohup.out' +# nohup true 2>zz 1>/dev/null +# cat zz +nohup: ignoring input +# nohup true /dev/null +nohup: redirecting stderr to stdout +# nohup true zz 1>/dev/null +# cat zz + (nothing) +# +*/ + +int nohup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nohup_main(int argc UNUSED_PARAM, char **argv) +{ + const char *nohupout; + char *home; + + xfunc_error_retval = 127; + + if (!argv[1]) { + bb_show_usage(); + } + + /* If stdin is a tty, detach from it. */ + if (isatty(STDIN_FILENO)) { + /* bb_error_msg("ignoring input"); */ + close(STDIN_FILENO); + xopen(bb_dev_null, O_RDONLY); /* will be fd 0 (STDIN_FILENO) */ + } + + nohupout = "nohup.out"; + /* Redirect stdout to nohup.out, either in "." or in "$HOME". */ + if (isatty(STDOUT_FILENO)) { + close(STDOUT_FILENO); + if (open(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR) < 0) { + home = getenv("HOME"); + if (home) { + nohupout = concat_path_file(home, nohupout); + xopen3(nohupout, O_CREAT|O_WRONLY|O_APPEND, S_IRUSR|S_IWUSR); + } else { + xopen(bb_dev_null, O_RDONLY); /* will be fd 1 */ + } + } + bb_error_msg("appending output to %s", nohupout); + } + + /* If we have a tty on stderr, redirect to stdout. */ + if (isatty(STDERR_FILENO)) { + /* if (stdout_wasnt_a_tty) + bb_error_msg("redirecting stderr to stdout"); */ + dup2(STDOUT_FILENO, STDERR_FILENO); + } + + signal(SIGHUP, SIG_IGN); + + argv++; + BB_EXECVP_or_die(argv); +} diff --git a/busybox-1_37_0/coreutils/nproc.c b/busybox-1_37_0/coreutils/nproc.c new file mode 100644 index 000000000..df63bf57a --- /dev/null +++ b/busybox-1_37_0/coreutils/nproc.c @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see LICENSE in this source tree + */ +//config:config NPROC +//config: bool "nproc (3.9 kb)" +//config: default y +//config: help +//config: Print number of CPUs + +//applet:IF_NPROC(APPLET_NOFORK(nproc, nproc, BB_DIR_USR_BIN, BB_SUID_DROP, nproc)) + +//kbuild:lib-$(CONFIG_NPROC) += nproc.o + +//usage:#define nproc_trivial_usage +//usage: ""IF_LONG_OPTS("[--all] [--ignore=N]") +//usage:#define nproc_full_usage "\n\n" +//usage: "Print number of available CPUs" +//usage: IF_LONG_OPTS( +//usage: "\n" +//usage: "\n --all Number of installed CPUs" +//usage: "\n --ignore=N Exclude N CPUs" +//usage: ) + +#include "libbb.h" + +int nproc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nproc_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + int count = 0; +#if ENABLE_LONG_OPTS + int ignore = 0; + int opts = getopt32long(argv, "\xfe:+", + "ignore\0" Required_argument "\xfe" + "all\0" No_argument "\xff" + , &ignore + ); + + if (opts & (1 << 1)) { + DIR *cpusd = opendir("/sys/devices/system/cpu"); + if (cpusd) { + struct dirent *de; + while (NULL != (de = readdir(cpusd))) { + char *cpuid = strstr(de->d_name, "cpu"); + if (cpuid && isdigit(cpuid[strlen(cpuid) - 1])) + count++; + } + IF_FEATURE_CLEAN_UP(closedir(cpusd);) + } + } else +#endif + { + int i; + unsigned sz = 2 * 1024; + unsigned long *mask = get_malloc_cpu_affinity(0, &sz); + sz /= sizeof(long); + for (i = 0; i < sz; i++) { + if (mask[i] != 0) /* most mask[i] are usually 0 */ + count += bb_popcnt_long(mask[i]); + } + IF_FEATURE_CLEAN_UP(free(mask);) + } + + IF_LONG_OPTS(count -= ignore;) + if (count <= 0) + count = 1; + + printf("%u\n", count); + + return 0; +} diff --git a/busybox-1_37_0/coreutils/od.c b/busybox-1_37_0/coreutils/od.c new file mode 100644 index 000000000..a7b1ba444 --- /dev/null +++ b/busybox-1_37_0/coreutils/od.c @@ -0,0 +1,262 @@ +/* vi: set sw=4 ts=4: */ +/* + * od implementation for busybox + * Based on code from util-linux v 2.11l + * + * Copyright (c) 1990 + * The Regents of the University of California. All rights reserved. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Original copyright notice is retained at the end of this file. + */ +//config:config OD +//config: bool "od (11 kb)" +//config: default y +//config: help +//config: od is used to dump binary files in octal and other formats. + +//applet:IF_OD(APPLET(od, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_OD) += od.o + +//usage:#if !ENABLE_DESKTOP +//usage:#define od_trivial_usage +//usage: "[-abcdeFfhiloxsv] [FILE]" +// We also support -BDOHXIL, but they are not documented in coreutils 9.1 +// manpage/help, so don't show them either. +//usage:#define od_full_usage "\n\n" +//usage: "Print FILE (or stdin) unambiguously, as octal bytes by default" +//usage:#endif + +#include "libbb.h" +#if ENABLE_DESKTOP +/* This one provides -t (busybox's own build script needs it) */ +#include "od_bloaty.c" +#else + +#include "dump.h" + +static void +odoffset(dumper_t *dumper, int argc, char ***argvp) +{ + char *num, *p; + int base; + char *end; + + /* + * The offset syntax of od(1) was genuinely bizarre. First, if + * it started with a plus it had to be an offset. Otherwise, if + * there were at least two arguments, a number or lower-case 'x' + * followed by a number makes it an offset. By default it was + * octal; if it started with 'x' or '0x' it was hex. If it ended + * in a '.', it was decimal. If a 'b' or 'B' was appended, it + * multiplied the number by 512 or 1024 byte units. There was + * no way to assign a block count to a hex offset. + * + * We assumes it's a file if the offset is bad. + */ + p = **argvp; + + if (!p) { + /* hey someone is probably piping to us ... */ + return; + } + + if ((*p != '+') + && (argc < 2 + || (!isdigit(p[0]) + && ((p[0] != 'x') || !isxdigit(p[1]))))) + return; + + base = 0; + /* + * skip over leading '+', 'x[0-9a-fA-f]' or '0x', and + * set base. + */ + if (p[0] == '+') + ++p; + if (p[0] == 'x' && isxdigit(p[1])) { + ++p; + base = 16; + } else if (p[0] == '0' && p[1] == 'x') { + p += 2; + base = 16; + } + + /* skip over the number */ + if (base == 16) + for (num = p; isxdigit(*p); ++p) + continue; + else + for (num = p; isdigit(*p); ++p) + continue; + + /* check for no number */ + if (num == p) + return; + + /* if terminates with a '.', base is decimal */ + if (*p == '.') { + if (base) + return; + base = 10; + } + + dumper->dump_skip = strtol(num, &end, base ? base : 8); + + /* if end isn't the same as p, we got a non-octal digit */ + if (end != p) + dumper->dump_skip = 0; + else { + if (*p) { + if (*p == 'b') { + dumper->dump_skip *= 512; + ++p; + } else if (*p == 'B') { + dumper->dump_skip *= 1024; + ++p; + } + } + if (*p) + dumper->dump_skip = 0; + else { + ++*argvp; + /* + * If the offset uses a non-octal base, the base of + * the offset is changed as well. This isn't pretty, + * but it's easy. + */ +#define TYPE_OFFSET 7 + { + char x_or_d; + if (base == 16) { + x_or_d = 'x'; + goto DO_X_OR_D; + } + if (base == 10) { + x_or_d = 'd'; + DO_X_OR_D: + dumper->fshead->nextfu->fmt[TYPE_OFFSET] + = dumper->fshead->nextfs->nextfu->fmt[TYPE_OFFSET] + = x_or_d; + } + } + } + } +} + +// bb_dump_add(): +// A format string contains format units separated by [optional] whitespace. +// A format unit contains up to three items: an iteration count, a byte count, +// and a format. +// The iteration count is an optional integer (default 1). +// Each format is applied iteration count times. +// The byte count is an optional integer. It defines the number +// of bytes to be interpreted by each iteration of the format. +// If an iteration count and/or a byte count is specified, a slash must be +// placed after the iteration count and/or before the byte count +// to disambiguate them. +// The printf-style format is required and must be surrounded by " "s. +// (Below, each string contains two format units) +static const char *const add_strings[] ALIGN_PTR = { + "16/1 \" %3_u\"" "\"\n\"", /* 0: a */ + "8/2 \" %06o\"" "\"\n\"", /* 1: B (undocumented in od), o */ + "16/1 \" %03o\"" "\"\n\"", /* 2: b */ + "16/1 \" %3_c\"" "\"\n\"", /* 3: c */ + "8/2 \" %5u\"" "\"\n\"", /* 4: d */ + "4/4 \" %10u\"" "\"\n\"", /* 5: D */ + "2/8 \" %24.14e\"" "\"\n\"", /* 6: e (undocumented in od), F */ + "4/4 \" %15.7e\"" "\"\n\"", /* 7: f */ + "4/4 \" %08x\"" "\"\n\"", /* 8: H, X */ + "8/2 \" %04x\"" "\"\n\"", /* 9: h, x */ + "4/4 \" %11d\"" "\"\n\"", /* 10: i */ + "4/4 \" %011o\"" "\"\n\"", /* 11: O */ + "8/2 \" %6d\"" "\"\n\"", /* 12: s */ + /* -I,L,l: depend on word width of the arch (what is "long"?) */ +#if ULONG_MAX > 0xffffffff + "2/8 \" %20lld\"" "\"\n\"", /* 13: I, L, l */ +#define L_ 13 +#else + /* 32-bit arch: -I,L,l are the same as -i */ +#define L_ 10 +#endif +}; + +static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxsv"; + +static const char od_o2si[] ALIGN1 = { + 0, 1, 2, 3, 5, /* aBbcD */ + 4, 6, 6, 7, 8, /* deFfH */ + 9, L_, 10, L_, L_, /* hIiLl */ + 11, 1, 8, 9, 12 /* OoXxs */ +}; + +int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int od_main(int argc, char **argv) +{ + int ch; + int first = 1; + char *p; + dumper_t *dumper = alloc_dumper(); + + while ((ch = getopt(argc, argv, od_opts)) > 0) { + if (ch == 'v') { + dumper->dump_vflag = ALL; + } else if (((p = strchr(od_opts, ch)) != NULL) && (*p != '\0')) { + if (first) { + first = 0; + bb_dump_add(dumper, "\"%07.7_Ao\n\""); + bb_dump_add(dumper, "\"%07.7_ao\""); + } else { + bb_dump_add(dumper, "\" \""); + } + bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); + } else { /* P, p, w, or other unhandled */ + bb_show_usage(); + } + } + if (!dumper->fshead) { + bb_dump_add(dumper, "\"%07.7_Ao\n\""); + bb_dump_add(dumper, "\"%07.7_ao\""); + bb_dump_add(dumper, add_strings[1]); /* -o format is default */ + } + dumper->od_eofstring = "\n"; + + argc -= optind; + argv += optind; + + odoffset(dumper, argc, &argv); + + return bb_dump_dump(dumper, argv); +} +#endif /* !ENABLE_DESKTOP */ + +/*- + * Copyright (c) 1990 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. 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-1_37_0/coreutils/od_bloaty.c b/busybox-1_37_0/coreutils/od_bloaty.c new file mode 100644 index 000000000..e886a4ed2 --- /dev/null +++ b/busybox-1_37_0/coreutils/od_bloaty.c @@ -0,0 +1,1413 @@ +/* od -- dump files in octal and other formats + Copyright (C) 92, 1995-2004 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +/* Written by Jim Meyering. */ +/* Busyboxed by Denys Vlasenko, based on od.c from coreutils-5.2.1 */ + + +/* #include "libbb.h" - done in od.c */ +#include "common_bufsiz.h" +#define assert(a) ((void)0) + + +//usage:#if ENABLE_DESKTOP +//usage:#define od_trivial_usage +//usage: "[-abcdfhilovxs] [-t TYPE] [-A RADIX] [-N SIZE] [-j SKIP] [-S MINSTR] [-w WIDTH] [FILE]..." +// We also support -BDOHXIL, but they are not documented in coreutils 9.1 +// manpage/help, so don't show them either. +// We don't support: +// ... [FILE] [[+]OFFSET[.][b]] +// Support is buggy for: +// od --traditional [OPTION]... [FILE] [[+]OFFSET[.][b] [+][LABEL][.][b]] + +//usage:#define od_full_usage "\n\n" +//usage: "Print FILEs (or stdin) unambiguously, as octal bytes by default" +//usage:#endif + +enum { + OPT_A = 1 << 0, + OPT_N = 1 << 1, + OPT_a = 1 << 2, + OPT_b = 1 << 3, + OPT_c = 1 << 4, + OPT_d = 1 << 5, + OPT_D = 1 << 6, /* undocumented in coreutils 9.1 */ + OPT_f = 1 << 7, + OPT_h = 1 << 8, + OPT_H = 1 << 9, /* undocumented in coreutils 9.1 */ + OPT_i = 1 << 10, + OPT_I = 1 << 11, /* undocumented in coreutils 9.1 */ + OPT_j = 1 << 12, + OPT_l = 1 << 13, + OPT_L = 1 << 14, /* undocumented in coreutils 9.1 */ + OPT_o = 1 << 15, + OPT_O = 1 << 16, /* undocumented in coreutils 9.1 */ + OPT_B = 1 << 17, /* undocumented synonym to -o */ + OPT_t = 1 << 18, + /* When zero and two or more consecutive blocks are equal, format + only the first block and output an asterisk alone on the following + line to indicate that identical blocks have been elided: */ + OPT_v = 1 << 19, + OPT_x = 1 << 20, + OPT_X = 1 << 21, /* undocumented in coreutils 9.1 */ + OPT_s = 1 << 22, + OPT_S = 1 << 23, + OPT_w = 1 << 24, + OPT_traditional = (1 << 25) * ENABLE_LONG_OPTS, +}; + +#define OD_GETOPT32() getopt32long(argv, \ + "A:N:abcdDfhHiIj:lLoOBt:*vxXsS:w:+:", od_longopts, \ + /* -w with optional param */ \ + /* -S was -s and also had optional parameter */ \ + /* but in coreutils 6.3 it was renamed and now has */ \ + /* _mandatory_ parameter */ \ + &str_A, &str_N, &str_j, &lst_t, &str_S, &G.bytes_per_block) + + +/* Check for 0x7f is a coreutils 6.3 addition */ +#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f) + +typedef long double longdouble_t; +typedef unsigned long long ulonglong_t; +typedef long long llong; + +#if ENABLE_LFS +# define xstrtooff_sfx xstrtoull_sfx +#else +# define xstrtooff_sfx xstrtoul_sfx +#endif + +/* The default number of input bytes per output line. */ +#define DEFAULT_BYTES_PER_BLOCK 16 + +/* The number of decimal digits of precision in a float. */ +#ifndef FLT_DIG +# define FLT_DIG 7 +#endif + +/* The number of decimal digits of precision in a double. */ +#ifndef DBL_DIG +# define DBL_DIG 15 +#endif + +/* The number of decimal digits of precision in a long double. */ +#ifndef LDBL_DIG +# define LDBL_DIG DBL_DIG +#endif + +enum size_spec { + NO_SIZE, + CHAR, + SHORT, + INT, + LONG, + LONG_LONG, + FLOAT_SINGLE, + FLOAT_DOUBLE, + FLOAT_LONG_DOUBLE, + N_SIZE_SPECS +}; + +enum output_format { + SIGNED_DECIMAL, + UNSIGNED_DECIMAL, + OCTAL, + HEXADECIMAL, + FLOATING_POINT, + NAMED_CHARACTER, + CHARACTER +}; + +/* Each output format specification (from '-t spec' or from + old-style options) is represented by one of these structures. */ +struct tspec { + enum output_format fmt; + enum size_spec size; + void (*print_function) (size_t, const char *, const char *); + char *fmt_string; + int hexl_mode_trailer; + int field_width; +}; + +/* Convert the number of 8-bit bytes of a binary representation to + the number of characters (digits + sign if the type is signed) + required to represent the same quantity in the specified base/type. + For example, a 32-bit (4-byte) quantity may require a field width + as wide as the following for these types: + 11 unsigned octal + 11 signed decimal + 10 unsigned decimal + 8 unsigned hexadecimal */ + +static const uint8_t bytes_to_oct_digits[] ALIGN1 = +{0, 3, 6, 8, 11, 14, 16, 19, 22, 25, 27, 30, 32, 35, 38, 41, 43}; + +static const uint8_t bytes_to_signed_dec_digits[] ALIGN1 = +{1, 4, 6, 8, 11, 13, 16, 18, 20, 23, 25, 28, 30, 33, 35, 37, 40}; + +static const uint8_t bytes_to_unsigned_dec_digits[] ALIGN1 = +{0, 3, 5, 8, 10, 13, 15, 17, 20, 22, 25, 27, 29, 32, 34, 37, 39}; + +static const uint8_t bytes_to_hex_digits[] ALIGN1 = +{0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32}; + +/* Convert enum size_spec to the size of the named type. */ +static const signed char width_bytes[] ALIGN1 = { + -1, + sizeof(char), + sizeof(short), + sizeof(int), + sizeof(long), + sizeof(ulonglong_t), + sizeof(float), + sizeof(double), + sizeof(longdouble_t) +}; +/* Ensure that for each member of 'enum size_spec' there is an + initializer in the width_bytes array. */ +struct ERR_width_bytes_has_bad_size { + char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1]; +}; + +struct globals { + smallint exit_code; + + unsigned string_min; + + /* An array of specs describing how to format each input block. */ + unsigned n_specs; + struct tspec *spec; + + /* Function that accepts an address and an optional following char, + and prints the address and char to stdout. */ + void (*format_address)(off_t, char); + + /* The difference between the old-style pseudo starting address and + the number of bytes to skip. */ +#if ENABLE_LONG_OPTS + off_t pseudo_offset; +# define G_pseudo_offset G.pseudo_offset +#endif + /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all + input is formatted. */ + + /* The number of input bytes formatted per output line. It must be + a multiple of the least common multiple of the sizes associated with + the specified output types. It should be as large as possible, but + no larger than 16 -- unless specified with the -w option. */ + unsigned bytes_per_block; /* have to use unsigned, not size_t */ + + /* A NULL-terminated list of the file-arguments from the command line. */ + const char *const *file_list; + + /* The input stream associated with the current file. */ + FILE *in_stream; + + bool not_first; + bool prev_pair_equal; + + char address_fmt[sizeof("%0n"OFF_FMT"xc")]; +} FIX_ALIASING; +/* Corresponds to 'x' above */ +#define address_base_char G.address_fmt[sizeof(G.address_fmt)-3] +/* Corresponds to 'n' above */ +#define address_pad_len_char G.address_fmt[2] + +#if !ENABLE_LONG_OPTS +enum { G_pseudo_offset = 0 }; +#endif +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ + G.bytes_per_block = 32; \ + strcpy(G.address_fmt, "%0n"OFF_FMT"xc"); \ +} while (0) + + +#define MAX_INTEGRAL_TYPE_SIZE sizeof(ulonglong_t) +static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 = { + [sizeof(char)] = CHAR, +#if USHRT_MAX != UCHAR_MAX + [sizeof(short)] = SHORT, +#endif +#if UINT_MAX != USHRT_MAX + [sizeof(int)] = INT, +#endif +#if ULONG_MAX != UINT_MAX + [sizeof(long)] = LONG, +#endif +#if ULLONG_MAX != ULONG_MAX + [sizeof(ulonglong_t)] = LONG_LONG, +#endif +}; + +#define MAX_FP_TYPE_SIZE sizeof(longdouble_t) +static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = { + /* gcc seems to allow repeated indexes. Last one wins */ + [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE, + [sizeof(double)] = FLOAT_DOUBLE, + [sizeof(float)] = FLOAT_SINGLE +}; + + +static unsigned +gcd(unsigned u, unsigned v) +{ + unsigned t; + while (v != 0) { + t = u % v; + u = v; + v = t; + } + return u; +} + +/* Compute the least common multiple of U and V. */ +static unsigned +lcm(unsigned u, unsigned v) { + unsigned t = gcd(u, v); + if (t == 0) + return 0; + return u * v / t; +} + +static void +print_s_char(size_t n_bytes, const char *block, const char *fmt_string) +{ + while (n_bytes--) { + int tmp = *(signed char *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned char); + } +} + +static void +print_char(size_t n_bytes, const char *block, const char *fmt_string) +{ + while (n_bytes--) { + unsigned tmp = *(unsigned char *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned char); + } +} + +static void +print_s_short(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(signed short); + while (n_bytes--) { + int tmp = *(signed short *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned short); + } +} + +static void +print_short(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(unsigned short); + while (n_bytes--) { + unsigned tmp = *(unsigned short *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned short); + } +} + +static void +print_int(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(unsigned); + while (n_bytes--) { + unsigned tmp = *(unsigned *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned); + } +} + +#if UINT_MAX == ULONG_MAX +# define print_long print_int +#else +static void +print_long(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(unsigned long); + while (n_bytes--) { + unsigned long tmp = *(unsigned long *) block; + printf(fmt_string, tmp); + block += sizeof(unsigned long); + } +} +#endif + +#if ULONG_MAX == ULLONG_MAX +# define print_long_long print_long +#else +static void +print_long_long(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(ulonglong_t); + while (n_bytes--) { + ulonglong_t tmp = *(ulonglong_t *) block; + printf(fmt_string, tmp); + block += sizeof(ulonglong_t); + } +} +#endif + +static void +print_float(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(float); + while (n_bytes--) { + float tmp = *(float *) block; + printf(fmt_string, tmp); + block += sizeof(float); + } +} + +static void +print_double(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(double); + while (n_bytes--) { + double tmp = *(double *) block; + printf(fmt_string, tmp); + block += sizeof(double); + } +} + +static void +print_long_double(size_t n_bytes, const char *block, const char *fmt_string) +{ + n_bytes /= sizeof(longdouble_t); + while (n_bytes--) { + longdouble_t tmp = *(longdouble_t *) block; + printf(fmt_string, tmp); + block += sizeof(longdouble_t); + } +} + +/* print_[named]_ascii are optimized for speed. + * Remember, someday you may want to pump gigabytes through this thing. + * Saving a dozen of .text bytes here is counter-productive */ + +static void +print_named_ascii(size_t n_bytes, const char *block, + const char *unused_fmt_string UNUSED_PARAM) +{ + /* Names for some non-printing characters. */ + static const char charname[33][3] ALIGN1 = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + " bs", " ht", " nl", " vt", " ff", " cr", " so", " si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", " em", "sub", "esc", " fs", " gs", " rs", " us", + " sp" + }; + // buf[N] pos: 01234 56789 + char buf[12] = " x\0 xxx\0"; + // [12] because we take three 32bit stack slots anyway, and + // gcc is too dumb to initialize with constant stores, + // it copies initializer from rodata. Oh well. + // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65410 + + while (n_bytes--) { + unsigned masked_c = *(unsigned char *) block++; + + masked_c &= 0x7f; + if (masked_c == 0x7f) { + fputs_stdout(" del"); + continue; + } + if (masked_c > ' ') { + buf[3] = masked_c; + fputs_stdout(buf); + continue; + } + /* Why? Because printf(" %3.3s") is much slower... */ + buf[6] = charname[masked_c][0]; + buf[7] = charname[masked_c][1]; + buf[8] = charname[masked_c][2]; + fputs_stdout(buf+5); + } +} + +static void +print_ascii(size_t n_bytes, const char *block, + const char *unused_fmt_string UNUSED_PARAM) +{ + // buf[N] pos: 01234 56789 + char buf[12] = " x\0 xxx\0"; + + while (n_bytes--) { + const char *s; + unsigned c = *(unsigned char *) block++; + + if (ISPRINT(c)) { + buf[3] = c; + fputs_stdout(buf); + continue; + } + switch (c) { + case '\0': + s = " \\0"; + break; + case '\007': + s = " \\a"; + break; + case '\b': + s = " \\b"; + break; + case '\f': + s = " \\f"; + break; + case '\n': + s = " \\n"; + break; + case '\r': + s = " \\r"; + break; + case '\t': + s = " \\t"; + break; + case '\v': + s = " \\v"; + break; + default: + buf[6] = (c >> 6 & 3) + '0'; + buf[7] = (c >> 3 & 7) + '0'; + buf[8] = (c & 7) + '0'; + s = buf + 5; + } + fputs_stdout(s); + } +} + +/* Given a list of one or more input filenames FILE_LIST, set the global + file pointer IN_STREAM and the global string INPUT_FILENAME to the + first one that can be successfully opened. Modify FILE_LIST to + reference the next filename in the list. A file name of "-" is + interpreted as standard input. If any file open fails, give an error + message and return nonzero. */ + +static void +open_next_file(void) +{ + while (1) { + if (!*G.file_list) + return; + G.in_stream = fopen_or_warn_stdin(*G.file_list++); + if (G.in_stream) { + break; + } + G.exit_code = 1; + } + + if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N) + setbuf(G.in_stream, NULL); +} + +/* Test whether there have been errors on in_stream, and close it if + it is not standard input. Return nonzero if there has been an error + on in_stream or stdout; return zero otherwise. This function will + report more than one error only if both a read and a write error + have occurred. IN_ERRNO, if nonzero, is the error number + corresponding to the most recent action for IN_STREAM. */ + +static void +check_and_close(void) +{ + if (G.in_stream) { + if (ferror(G.in_stream)) { + bb_error_msg("%s: read error", (G.in_stream == stdin) + ? bb_msg_standard_input + : G.file_list[-1] + ); + G.exit_code = 1; + } + fclose_if_not_stdin(G.in_stream); + G.in_stream = NULL; + } + + if (ferror(stdout)) { + bb_simple_error_msg_and_die(bb_msg_write_error); + } +} + +/* If S points to a single valid modern od format string, put + a description of that format in *TSPEC, return pointer to + character following the just-decoded format. + For example, if S were "d4afL", we will return a rtp to "afL" + and *TSPEC would be + { + fmt = SIGNED_DECIMAL; + size = INT or LONG; (whichever integral_type_size[4] resolves to) + print_function = print_int; (assuming size == INT) + fmt_string = "%011d%c"; + } + S_ORIG is solely for reporting errors. It should be the full format + string argument. */ + +static NOINLINE const char * +decode_one_format(const char *s_orig, const char *s, struct tspec *tspec) +{ + enum size_spec size_spec; + unsigned size; + enum output_format fmt; + const char *p; + char *end; + char *fmt_string = NULL; + void (*print_function) (size_t, const char *, const char *); + unsigned c; + unsigned field_width = 0; + int pos; + + switch (*s) { + case 'd': + case 'o': + case 'u': + case 'x': { + static const char CSIL[] ALIGN1 = "CSIL"; + + c = *s++; + p = strchr(CSIL, *s); + /* if *s == NUL, p != NULL! Testcase: "od -tx" */ + if (!p || *p == '\0') { + size = sizeof(int); + if (isdigit(s[0])) { + size = bb_strtou(s, &end, 0); + if (errno == ERANGE + || MAX_INTEGRAL_TYPE_SIZE < size + || integral_type_size[size] == NO_SIZE + ) { + bb_error_msg_and_die("invalid type string '%s'; " + "%u-byte %s type is not supported", + s_orig, size, "integral"); + } + s = end; + } + } else { + static const uint8_t CSIL_sizeof[4] = { + sizeof(char), + sizeof(short), + sizeof(int), + sizeof(long), + }; + size = CSIL_sizeof[p - CSIL]; + s++; /* skip C/S/I/L */ + } + +#define ISPEC_TO_FORMAT(Spec, Min_format, Long_format, Max_format) \ + ((Spec) == LONG_LONG ? (Max_format) \ + : ((Spec) == LONG ? (Long_format) : (Min_format))) + +#define FMT_BYTES_ALLOCATED 9 + size_spec = integral_type_size[size]; + + { + static const char doux[] ALIGN1 = "doux"; + static const char doux_fmt_letter[][4] = { + "lld", "llo", "llu", "llx" + }; + static const enum output_format doux_fmt[] = { + SIGNED_DECIMAL, + OCTAL, + UNSIGNED_DECIMAL, + HEXADECIMAL, + }; + static const uint8_t *const doux_bytes_to_XXX[] = { + bytes_to_signed_dec_digits, + bytes_to_oct_digits, + bytes_to_unsigned_dec_digits, + bytes_to_hex_digits, + }; + static const char doux_fmtstring[][sizeof(" %%0%u%s")] ALIGN1 = { + " %%%u%s", + " %%0%u%s", + " %%%u%s", + " %%0%u%s", + }; + + pos = strchr(doux, c) - doux; + fmt = doux_fmt[pos]; + field_width = doux_bytes_to_XXX[pos][size]; + p = doux_fmt_letter[pos] + 2; + if (size_spec == LONG) p--; + if (size_spec == LONG_LONG) p -= 2; + fmt_string = xasprintf(doux_fmtstring[pos], field_width, p); + } + + switch (size_spec) { + case CHAR: + print_function = (fmt == SIGNED_DECIMAL + ? print_s_char + : print_char); + break; + case SHORT: + print_function = (fmt == SIGNED_DECIMAL + ? print_s_short + : print_short); + break; + case INT: + print_function = print_int; + break; + case LONG: + print_function = print_long; + break; + default: /* case LONG_LONG: */ + print_function = print_long_long; + break; + } + break; + } + + case 'f': { + static const char FDL[] ALIGN1 = "FDL"; + + fmt = FLOATING_POINT; + ++s; + p = strchr(FDL, *s); + if (!p || *p == '\0') { + size = sizeof(double); + if (isdigit(s[0])) { + size = bb_strtou(s, &end, 0); + if (errno == ERANGE || size > MAX_FP_TYPE_SIZE + || fp_type_size[size] == NO_SIZE + ) { + bb_error_msg_and_die("invalid type string '%s'; " + "%u-byte %s type is not supported", + s_orig, size, "floating point"); + } + s = end; + } + } else { + static const uint8_t FDL_sizeof[] = { + sizeof(float), + sizeof(double), + sizeof(longdouble_t), + }; + + size = FDL_sizeof[p - FDL]; + s++; /* skip F/D/L */ + } + + size_spec = fp_type_size[size]; + + switch (size_spec) { + case FLOAT_SINGLE: + print_function = print_float; + field_width = FLT_DIG + 8; + /* Don't use %#e; not all systems support it. */ + fmt_string = xasprintf(" %%%d.%de", field_width, FLT_DIG); + break; + case FLOAT_DOUBLE: + print_function = print_double; + field_width = DBL_DIG + 8; + fmt_string = xasprintf(" %%%d.%de", field_width, DBL_DIG); + break; + default: /* case FLOAT_LONG_DOUBLE: */ + print_function = print_long_double; + field_width = LDBL_DIG + 8; + fmt_string = xasprintf(" %%%d.%dLe", field_width, LDBL_DIG); + break; + } + break; + } + + case 'a': + ++s; + fmt = NAMED_CHARACTER; + size_spec = CHAR; + print_function = print_named_ascii; + field_width = 3; + break; + case 'c': + ++s; + fmt = CHARACTER; + size_spec = CHAR; + print_function = print_ascii; + field_width = 3; + break; + default: + bb_error_msg_and_die("invalid character '%c' " + "in type string '%s'", *s, s_orig); + } + + tspec->size = size_spec; + tspec->fmt = fmt; + tspec->print_function = print_function; + tspec->fmt_string = fmt_string; + + tspec->field_width = field_width; + tspec->hexl_mode_trailer = (*s == 'z'); + if (tspec->hexl_mode_trailer) + s++; + + return s; +} + +/* Decode the modern od format string S. Append the decoded + representation to the global array SPEC, reallocating SPEC if + necessary. */ + +static void +decode_format_string(const char *s) +{ + const char *s_orig = s; + + while (*s != '\0') { + struct tspec tspec; + const char *next; + + next = decode_one_format(s_orig, s, &tspec); + + assert(s != next); + s = next; + G.spec = xrealloc_vector(G.spec, 4, G.n_specs); + memcpy(&G.spec[G.n_specs], &tspec, sizeof(G.spec[0])); + G.n_specs++; + } +} + +/* Given a list of one or more input filenames FILE_LIST, set the global + file pointer IN_STREAM to position N_SKIP in the concatenation of + those files. If any file operation fails or if there are fewer than + N_SKIP bytes in the combined input, give an error message and return + nonzero. When possible, use seek rather than read operations to + advance IN_STREAM. */ + +static void +skip(off_t n_skip) +{ + if (n_skip == 0) + return; + + while (G.in_stream) { /* !EOF */ + struct stat file_stats; + + /* First try seeking. For large offsets, this extra work is + worthwhile. If the offset is below some threshold it may be + more efficient to move the pointer by reading. There are two + issues when trying to seek: + - the file must be seekable. + - before seeking to the specified position, make sure + that the new position is in the current file. + Try to do that by getting file's size using fstat. + But that will work only for regular files. */ + + /* The st_size field is valid only for regular files + (and for symbolic links, which cannot occur here). + If the number of bytes left to skip is at least + as large as the size of the current file, we can + decrement n_skip and go on to the next file. */ + if (fstat(fileno(G.in_stream), &file_stats) == 0 + && S_ISREG(file_stats.st_mode) && file_stats.st_size > 0 + ) { + if (file_stats.st_size < n_skip) { + n_skip -= file_stats.st_size; + /* take "check & close / open_next" route */ + } else { + if (fseeko(G.in_stream, n_skip, SEEK_CUR) != 0) + G.exit_code = 1; + return; + } + } else { + /* If it's not a regular file with positive size, + position the file pointer by reading. */ + char buf[1024]; + size_t n_bytes_to_read = 1024; + size_t n_bytes_read; + + while (n_skip > 0) { + if (n_skip < n_bytes_to_read) + n_bytes_to_read = n_skip; + n_bytes_read = fread(buf, 1, n_bytes_to_read, G.in_stream); + n_skip -= n_bytes_read; + if (n_bytes_read != n_bytes_to_read) + break; /* EOF on this file or error */ + } + } + if (n_skip == 0) + return; + + check_and_close(); + open_next_file(); + } + + if (n_skip) + bb_simple_error_msg_and_die("can't skip past end of combined input"); +} + + +typedef void FN_format_address(off_t address, char c); + +static void +format_address_none(off_t address UNUSED_PARAM, char c UNUSED_PARAM) +{ +} + +static void +format_address_std(off_t address, char c) +{ + /* Corresponds to 'c' */ + G.address_fmt[sizeof(G.address_fmt)-2] = c; + printf(G.address_fmt, address); +} + +#if ENABLE_LONG_OPTS +/* only used with --traditional */ +static void +format_address_paren(off_t address, char c) +{ + putchar('('); + format_address_std(address, ')'); + if (c) putchar(c); +} + +static void +format_address_label(off_t address, char c) +{ + format_address_std(address, ' '); + format_address_paren(address + G_pseudo_offset, c); +} +#endif + +static void +dump_hexl_mode_trailer(size_t n_bytes, const char *block) +{ + fputs_stdout(" >"); + while (n_bytes--) { + unsigned c = *(unsigned char *) block++; + c = (ISPRINT(c) ? c : '.'); + putchar(c); + } + putchar('<'); +} + +/* Write N_BYTES bytes from CURR_BLOCK to standard output once for each + of the N_SPEC format specs. CURRENT_OFFSET is the byte address of + CURR_BLOCK in the concatenation of input files, and it is printed + (optionally) only before the output line associated with the first + format spec. When duplicate blocks are being abbreviated, the output + for a sequence of identical input blocks is the output for the first + block followed by an asterisk alone on a line. It is valid to compare + the blocks PREV_BLOCK and CURR_BLOCK only when N_BYTES == BYTES_PER_BLOCK. + That condition may be false only for the last input block -- and then + only when it has not been padded to length BYTES_PER_BLOCK. */ + +static void +write_block(off_t current_offset, size_t n_bytes, + const char *prev_block, const char *curr_block) +{ + unsigned i; + + if (!(option_mask32 & OPT_v) + && G.not_first + && n_bytes == G.bytes_per_block + && memcmp(prev_block, curr_block, G.bytes_per_block) == 0 + ) { + if (G.prev_pair_equal) { + /* The two preceding blocks were equal, and the current + block is the same as the last one, so print nothing. */ + } else { + puts("*"); + G.prev_pair_equal = 1; + } + } else { + G.not_first = 1; + G.prev_pair_equal = 0; + for (i = 0; i < G.n_specs; i++) { + if (i == 0) + G.format_address(current_offset, '\0'); + else + printf("%*s", address_pad_len_char - '0', ""); + (*G.spec[i].print_function) (n_bytes, curr_block, G.spec[i].fmt_string); + if (G.spec[i].hexl_mode_trailer) { + /* space-pad out to full line width, then dump the trailer */ + unsigned datum_width = width_bytes[G.spec[i].size]; + unsigned blank_fields = (G.bytes_per_block - n_bytes) / datum_width; + unsigned field_width = G.spec[i].field_width + 1; + printf("%*s", blank_fields * field_width, ""); + dump_hexl_mode_trailer(n_bytes, curr_block); + } + putchar('\n'); + } + } +} + +static void +read_block(size_t n, char *block, size_t *n_bytes_in_buffer) +{ + assert(0 < n && n <= G.bytes_per_block); + + *n_bytes_in_buffer = 0; + + if (n == 0) + return; + + while (G.in_stream != NULL) { /* EOF. */ + size_t n_needed; + size_t n_read; + + n_needed = n - *n_bytes_in_buffer; + n_read = fread(block + *n_bytes_in_buffer, 1, n_needed, G.in_stream); + *n_bytes_in_buffer += n_read; + if (n_read == n_needed) + break; + /* error check is done in check_and_close */ + check_and_close(); + open_next_file(); + } +} + +/* Return the least common multiple of the sizes associated + with the format specs. */ + +static int +get_lcm(void) +{ + size_t i; + int l_c_m = 1; + + for (i = 0; i < G.n_specs; i++) + l_c_m = lcm(l_c_m, width_bytes[(int) G.spec[i].size]); + return l_c_m; +} + +/* Read a chunk of size BYTES_PER_BLOCK from the input files, write the + formatted block to standard output, and repeat until the specified + maximum number of bytes has been read or until all input has been + processed. If the last block read is smaller than BYTES_PER_BLOCK + and its size is not a multiple of the size associated with a format + spec, extend the input block with zero bytes until its length is a + multiple of all format spec sizes. Write the final block. Finally, + write on a line by itself the offset of the byte after the last byte + read. */ + +static void +dump(off_t current_offset, off_t end_offset) +{ + char *block[2]; + int idx; + size_t n_bytes_read; + + block[0] = xmalloc(2 * G.bytes_per_block); + block[1] = block[0] + G.bytes_per_block; + + idx = 0; + if (option_mask32 & OPT_N) { + while (1) { + size_t n_needed; + if (current_offset >= end_offset) { + n_bytes_read = 0; + break; + } + n_needed = MIN(end_offset - current_offset, (off_t) G.bytes_per_block); + read_block(n_needed, block[idx], &n_bytes_read); + if (n_bytes_read < G.bytes_per_block) + break; + assert(n_bytes_read == G.bytes_per_block); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); + current_offset += n_bytes_read; + idx ^= 1; + } + } else { + while (1) { + read_block(G.bytes_per_block, block[idx], &n_bytes_read); + if (n_bytes_read < G.bytes_per_block) + break; + assert(n_bytes_read == G.bytes_per_block); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); + current_offset += n_bytes_read; + idx ^= 1; + } + } + + if (n_bytes_read > 0) { + int l_c_m; + size_t bytes_to_write; + + l_c_m = get_lcm(); + + /* Make bytes_to_write the smallest multiple of l_c_m that + is at least as large as n_bytes_read. */ + bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m); + + memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read); + write_block(current_offset, bytes_to_write, + block[idx ^ 1], block[idx]); + current_offset += n_bytes_read; + } + + G.format_address(current_offset, '\n'); + + if ((option_mask32 & OPT_N) && current_offset >= end_offset) + check_and_close(); + + free(block[0]); +} + +/* Read N bytes into BLOCK from the concatenation of the input files + named in the global array FILE_LIST. On the first call to this + function, the global variable IN_STREAM is expected to be an open + stream associated with the input file INPUT_FILENAME. If all N + bytes cannot be read from IN_STREAM, close IN_STREAM and update + the global variables IN_STREAM and INPUT_FILENAME. Then try to + read the remaining bytes from the newly opened file. Repeat if + necessary until EOF is reached for the last file in FILE_LIST. + On subsequent calls, don't modify BLOCK and return zero. Set + *N_BYTES_IN_BUFFER to the number of bytes read. If an error occurs, + it will be detected through ferror when the stream is about to be + closed. If there is an error, give a message but continue reading + as usual and return nonzero. Otherwise return zero. */ + +/* STRINGS mode. Find each "string constant" in the input. + A string constant is a run of at least 'string_min' ASCII + graphic (or formatting) characters terminated by a null. + Based on a function written by Richard Stallman for a + traditional version of od. */ + +static void +dump_strings(off_t address, off_t end_offset) +{ + unsigned bufsize = MAX(100, G.string_min); + unsigned char *buf = xmalloc(bufsize); + + while (1) { + size_t i; + int c; + + /* See if the next 'G.string_min' chars are all printing chars. */ + tryline: + if ((option_mask32 & OPT_N) && (end_offset - G.string_min <= address)) + break; + i = 0; + while (!(option_mask32 & OPT_N) || address < end_offset) { + if (i == bufsize) { + bufsize += bufsize/8; + buf = xrealloc(buf, bufsize); + } + + while (G.in_stream) { /* !EOF */ + c = fgetc(G.in_stream); + if (c != EOF) + goto got_char; + check_and_close(); + open_next_file(); + } + /* EOF */ + goto ret; + got_char: + address++; + if (!c) + break; + if (!ISPRINT(c)) + goto tryline; /* It isn't; give up on this string. */ + buf[i++] = c; /* String continues; store it all. */ + } + + if (i < G.string_min) /* Too short! */ + goto tryline; + + /* If we get here, the string is all printable and NUL-terminated */ + buf[i] = 0; + G.format_address(address - i - 1, ' '); + + for (i = 0; (c = buf[i]); i++) { + switch (c) { + case '\007': fputs_stdout("\\a"); break; + case '\b': fputs_stdout("\\b"); break; + case '\f': fputs_stdout("\\f"); break; + case '\n': fputs_stdout("\\n"); break; + case '\r': fputs_stdout("\\r"); break; + case '\t': fputs_stdout("\\t"); break; + case '\v': fputs_stdout("\\v"); break; + default: putchar(c); + } + } + putchar('\n'); + } + + /* We reach this point only if we search through + (max_bytes_to_format - G.string_min) bytes before reaching EOF. */ + check_and_close(); + ret: + free(buf); +} + +#if ENABLE_LONG_OPTS +/* If S is a valid traditional offset specification with an optional + leading '+' return nonzero and set *OFFSET to the offset it denotes. */ + +static int +parse_old_offset(const char *s, off_t *offset) +{ + static const struct suffix_mult Bb[] ALIGN_SUFFIX = { + { "B", 1024 }, + { "b", 512 }, + { "", 0 } + }; + char *p; + int radix; + + /* Skip over any leading '+'. */ + if (s[0] == '+') ++s; + if (!isdigit(s[0])) return 0; /* not a number */ + + /* Determine the radix we'll use to interpret S. If there is a '.', + * it's decimal, otherwise, if the string begins with '0X'or '0x', + * it's hexadecimal, else octal. */ + p = strchr(s, '.'); + radix = 8; + if (p) { + p[0] = '\0'; /* cheating */ + radix = 10; + } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) + radix = 16; + + *offset = xstrtooff_sfx(s, radix, Bb); + if (p) p[0] = '.'; + + return (*offset >= 0); +} +#endif + +int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int od_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_LONG_OPTS + static const char od_longopts[] ALIGN1 = + "skip-bytes\0" Required_argument "j" + "address-radix\0" Required_argument "A" + "read-bytes\0" Required_argument "N" + "format\0" Required_argument "t" + "output-duplicates\0" No_argument "v" + /* Yes, it's true: -S NUM, but --strings[=NUM]! + * that is, NUM is mandatory for -S but optional for --strings! + */ + "strings\0" Optional_argument "S" + "width\0" Optional_argument "w" + "traditional\0" No_argument "\xff" + ; +#endif + const char *str_A, *str_N, *str_j, *str_S = "3"; + llist_t *lst_t = NULL; + unsigned opt; + int l_c_m; + /* The number of input bytes to skip before formatting and writing. */ + off_t n_bytes_to_skip = 0; + /* The offset of the first byte after the last byte to be formatted. */ + off_t end_offset = 0; + /* The maximum number of bytes that will be formatted. */ + off_t max_bytes_to_format = 0; + + INIT_G(); + + /*G.spec = NULL; - already is */ + G.format_address = format_address_std; + address_base_char = 'o'; + address_pad_len_char = '7'; + + /* Parse command line */ + opt = OD_GETOPT32(); + argv += optind; + if (opt & OPT_A) { + static const char doxn[] ALIGN1 = "doxn"; + static const char doxn_address_base_char[] ALIGN1 = { + 'u', 'o', 'x', /* '?' fourth one is not important */ + }; + static const uint8_t doxn_address_pad_len_char[] ALIGN1 = { + '7', '7', '6', /* '?' */ + }; + char *p; + int pos; + p = strchr(doxn, str_A[0]); + if (!p) + bb_error_msg_and_die("bad output address radix " + "'%c' (must be [doxn])", str_A[0]); + pos = p - doxn; + if (pos == 3) G.format_address = format_address_none; + address_base_char = doxn_address_base_char[pos]; + address_pad_len_char = doxn_address_pad_len_char[pos]; + } + if (opt & OPT_N) { + max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm_suffixes); + } + + if (opt & OPT_a) decode_format_string("a"); + if (opt & OPT_b) decode_format_string("oC"); + if (opt & OPT_c) decode_format_string("c"); + if (opt & OPT_d) decode_format_string("u2"); + if (opt & OPT_D) decode_format_string("uI"); + if (opt & OPT_f) decode_format_string("fF"); + if (opt & (OPT_h|OPT_x)) decode_format_string("x2"); + if (opt & (OPT_H|OPT_X)) decode_format_string("xI"); + /* -I,L,l: depend on word width of the arch (what is "long"?) */ +#if ULONG_MAX > 0xffffffff + if (opt & OPT_i) decode_format_string("dI"); + if (opt & (OPT_I|OPT_l|OPT_L)) decode_format_string("dL"); +#else + /* 32-bit arch: -I,L,l are the same as -i */ + if (opt & (OPT_i|OPT_I|OPT_l|OPT_L)) decode_format_string("dI"); +#endif + if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes); + if (opt & (OPT_o|OPT_B)) decode_format_string("o2"); + if (opt & OPT_O) decode_format_string("oI"); + while (lst_t) { + decode_format_string(llist_pop(&lst_t)); + } + if (opt & OPT_s) decode_format_string("d2"); + if (opt & OPT_S) { + G.string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); + } + + // Bloat: + //if ((option_mask32 & OPT_S) && G.n_specs > 0) + // bb_error_msg_and_die("no type may be specified when dumping strings"); + + /* If the --traditional option is used, there may be from + * 0 to 3 remaining command line arguments; handle each case + * separately. + * od [FILE] [[+]OFFSET[.][b] [[+]LABEL[.][b]]] + * The offset and pseudo_start have the same syntax. + * + * FIXME: POSIX 1003.1-2001 with XSI requires support for the + * traditional syntax even if --traditional is not given. */ + +#if ENABLE_LONG_OPTS + if (opt & OPT_traditional) { + if (argv[0]) { + off_t pseudo_start = -1; + off_t o1, o2; + + if (!argv[1]) { /* one arg */ + if (parse_old_offset(argv[0], &o1)) { + /* od --traditional OFFSET */ + n_bytes_to_skip = o1; + argv++; + } + /* od --traditional FILE */ + } else if (!argv[2]) { /* two args */ + if (parse_old_offset(argv[0], &o1) + && parse_old_offset(argv[1], &o2) + ) { + /* od --traditional OFFSET LABEL */ + n_bytes_to_skip = o1; + pseudo_start = o2; + argv += 2; + } else if (parse_old_offset(argv[1], &o2)) { + /* od --traditional FILE OFFSET */ + n_bytes_to_skip = o2; + argv[1] = NULL; + } else { + bb_error_msg_and_die("invalid second argument '%s'", argv[1]); + } + } else if (!argv[3]) { /* three args */ + if (parse_old_offset(argv[1], &o1) + && parse_old_offset(argv[2], &o2) + ) { + /* od --traditional FILE OFFSET LABEL */ + n_bytes_to_skip = o1; + pseudo_start = o2; + argv[1] = NULL; + } else { + bb_simple_error_msg_and_die("the last two arguments must be offsets"); + } + } else { /* >3 args */ + bb_simple_error_msg_and_die("too many arguments"); + } + + if (pseudo_start >= 0) { + if (G.format_address == format_address_none) { + address_base_char = 'o'; + address_pad_len_char = '7'; + G.format_address = format_address_paren; + } else { + G.format_address = format_address_label; + } + G_pseudo_offset = pseudo_start - n_bytes_to_skip; + } + } + /* else: od --traditional (without args) */ + } +#endif + + if (option_mask32 & OPT_N) { + end_offset = n_bytes_to_skip + max_bytes_to_format; + if (end_offset < n_bytes_to_skip) + bb_simple_error_msg_and_die("SKIP + SIZE is too large"); + } + + if (G.n_specs == 0) { + decode_format_string("o2"); + /*G.n_specs = 1; - done by decode_format_string */ + } + + /* If no files were listed on the command line, + set the global pointer FILE_LIST so that it + references the null-terminated list of one name: "-". */ + G.file_list = bb_argv_dash; + if (argv[0]) { + /* Set the global pointer FILE_LIST so that it + references the first file-argument on the command-line. */ + G.file_list = (char const *const *) argv; + } + + /* Open the first input file */ + open_next_file(); + /* Skip over any unwanted header bytes */ + skip(n_bytes_to_skip); + if (!G.in_stream) + return EXIT_FAILURE; + + /* Compute output block length */ + l_c_m = get_lcm(); + + if (opt & OPT_w) { /* -w: width */ + if (!G.bytes_per_block || G.bytes_per_block % l_c_m != 0) { + bb_error_msg("warning: invalid width %u; using %d instead", + (unsigned)G.bytes_per_block, l_c_m); + G.bytes_per_block = l_c_m; + } + } else { + G.bytes_per_block = l_c_m; + if (l_c_m < DEFAULT_BYTES_PER_BLOCK) + G.bytes_per_block *= DEFAULT_BYTES_PER_BLOCK / l_c_m; + } + +#ifdef DEBUG + { + int i; + for (i = 0; i < G.n_specs; i++) { + printf("%d: fmt='%s' width=%d\n", + i, G.spec[i].fmt_string, + width_bytes[G.spec[i].size]); + } + } +#endif + + if (option_mask32 & OPT_S) + dump_strings(n_bytes_to_skip, end_offset); + else + dump(n_bytes_to_skip, end_offset); + + if (fclose(stdin)) + bb_simple_perror_msg_and_die(bb_msg_standard_input); + + return G.exit_code; +} diff --git a/busybox-1_37_0/coreutils/paste.c b/busybox-1_37_0/coreutils/paste.c new file mode 100644 index 000000000..3e5f20158 --- /dev/null +++ b/busybox-1_37_0/coreutils/paste.c @@ -0,0 +1,140 @@ +/* vi: set sw=4 ts=4: */ +/* + * paste.c - implementation of the posix paste command + * + * Written by Maxime Coste + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config PASTE +//config: bool "paste (5.1 kb)" +//config: default y +//config: help +//config: paste is used to paste lines of different files together +//config: and write the result to stdout + +//applet:IF_PASTE(APPLET_NOEXEC(paste, paste, BB_DIR_USR_BIN, BB_SUID_DROP, paste)) + +//kbuild:lib-$(CONFIG_PASTE) += paste.o + +//usage:#define paste_trivial_usage +//usage: "[-d LIST] [-s] [FILE]..." +//usage:#define paste_full_usage "\n\n" +//usage: "Paste lines from each input file, separated with tab\n" +//usage: "\n -d LIST Use delimiters from LIST, not tab" +//usage: "\n -s Serial: one file at a time" +//usage: +//usage:#define paste_example_usage +//usage: "# write out directory in four columns\n" +//usage: "$ ls | paste - - - -\n" +//usage: "# combine pairs of lines from a file into single lines\n" +//usage: "$ paste -s -d '\\t\\n' file\n" + +#include "libbb.h" + +static void paste_files(FILE** files, int file_cnt, char* delims, int del_cnt) +{ + char *line; + char delim; + int active_files = file_cnt; + int i; + + while (active_files > 0) { + int del_idx = 0; + + for (i = 0; i < file_cnt; ++i) { + if (files[i] == NULL) + continue; + + line = xmalloc_fgetline(files[i]); + if (!line) { + fclose_if_not_stdin(files[i]); + files[i] = NULL; + --active_files; + continue; + } + fputs_stdout(line); + free(line); + delim = '\n'; + if (i != file_cnt - 1) { + delim = delims[del_idx++]; + if (del_idx == del_cnt) + del_idx = 0; + } + if (delim != '\0') + fputc(delim, stdout); + } + } +} + +static void paste_files_separate(FILE** files, char* delims, int del_cnt) +{ + char *line, *next_line; + char delim; + int i; + + for (i = 0; files[i]; ++i) { + int del_idx = 0; + + line = NULL; + while ((next_line = xmalloc_fgetline(files[i])) != NULL) { + if (line) { + fputs_stdout(line); + free(line); + delim = delims[del_idx++]; + if (del_idx == del_cnt) + del_idx = 0; + if (delim != '\0') + fputc(delim, stdout); + } + line = next_line; + } + if (line) { + /* coreutils adds \n even if this is a final line + * of the last file and it was not \n-terminated. + */ + printf("%s\n", line); + free(line); + } + fclose_if_not_stdin(files[i]); + } +} + +#define PASTE_OPT_DELIMITERS (1 << 0) +#define PASTE_OPT_SEPARATE (1 << 1) + +int paste_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int paste_main(int argc UNUSED_PARAM, char **argv) +{ + char *delims = (char*)"\t"; + int del_cnt = 1; + unsigned opt; + int i; + + opt = getopt32(argv, "d:s", &delims); + argv += optind; + + if (opt & PASTE_OPT_DELIMITERS) { + if (!delims[0]) + bb_simple_error_msg_and_die("-d '' is not supported"); + /* unknown mappings are not changed: "\z" -> '\\' 'z' */ + /* trailing backslash, if any, is preserved */ + del_cnt = strcpy_and_process_escape_sequences(delims, delims) - delims; + /* note: handle NUL properly (do not stop at it!): try -d'\t\0\t' */ + } + + if (!argv[0]) + (--argv)[0] = (char*) "-"; + for (i = 0; argv[i]; ++i) { + argv[i] = (void*) fopen_or_warn_stdin(argv[i]); + if (!argv[i]) + xfunc_die(); + } + + if (opt & PASTE_OPT_SEPARATE) + paste_files_separate((FILE**)argv, delims, del_cnt); + else + paste_files((FILE**)argv, i, delims, del_cnt); + + fflush_stdout_and_exit(0); +} diff --git a/busybox-1_37_0/coreutils/printenv.c b/busybox-1_37_0/coreutils/printenv.c new file mode 100644 index 000000000..0ca9e6114 --- /dev/null +++ b/busybox-1_37_0/coreutils/printenv.c @@ -0,0 +1,59 @@ +/* vi: set sw=4 ts=4: */ +/* + * printenv implementation for busybox + * + * Copyright (C) 2005 by Erik Andersen + * Copyright (C) 2005 by Mike Frysinger + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config PRINTENV +//config: bool "printenv (1.6 kb)" +//config: default y +//config: help +//config: printenv is used to print all or part of environment. + +//applet:IF_PRINTENV(APPLET_NOFORK(printenv, printenv, BB_DIR_BIN, BB_SUID_DROP, printenv)) + +//kbuild:lib-$(CONFIG_PRINTENV) += printenv.o + +//usage:#define printenv_trivial_usage +//usage: "[VARIABLE]..." +//usage:#define printenv_full_usage "\n\n" +//usage: "Print environment VARIABLEs.\n" +//usage: "If no VARIABLE specified, print all." + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int printenv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int printenv_main(int argc UNUSED_PARAM, char **argv) +{ + int exit_code = EXIT_SUCCESS; + + /* no variables specified, show whole env */ + if (!argv[1]) { + char **e = environ; + + /* environ can be NULL! (for example, after clearenv()) + * Check for that: + */ + if (e) + while (*e) + puts(*e++); + } else { + /* search for specified variables and print them out if found */ + char *arg, *env; + + while ((arg = *++argv) != NULL) { + env = getenv(arg); + if (env) + puts(env); + else + exit_code = EXIT_FAILURE; + } + } + + fflush_stdout_and_exit(exit_code); +} diff --git a/busybox-1_37_0/coreutils/printf.c b/busybox-1_37_0/coreutils/printf.c new file mode 100644 index 000000000..4edcfa9b5 --- /dev/null +++ b/busybox-1_37_0/coreutils/printf.c @@ -0,0 +1,456 @@ +/* vi: set sw=4 ts=4: */ +/* + * printf - format and print data + * + * Copyright 1999 Dave Cinege + * Portions copyright (C) 1990-1996 Free Software Foundation, Inc. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* 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 */ + +//config:config PRINTF +//config: bool "printf (4.1 kb)" +//config: default y +//config: help +//config: printf is used to format and print specified strings. +//config: It's similar to 'echo' except it has more options. + +//applet:IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) + +//kbuild:lib-$(CONFIG_PRINTF) += printf.o +//kbuild:lib-$(CONFIG_ASH_PRINTF) += printf.o +//kbuild:lib-$(CONFIG_HUSH_PRINTF) += printf.o + +//usage:#define printf_trivial_usage +//usage: "FORMAT [ARG]..." +//usage:#define printf_full_usage "\n\n" +//usage: "Format and print ARG(s) according to FORMAT (a-la C printf)" +//usage: +//usage:#define printf_example_usage +//usage: "$ printf \"Val=%d\\n\" 5\n" +//usage: "Val=5\n" + +#include "libbb.h" + +/* A note on bad input: neither bash 3.2 nor coreutils 6.10 stop on it. + * They report it: + * bash: printf: XXX: invalid number + * printf: XXX: expected a numeric value + * bash: printf: 123XXX: invalid number + * printf: 123XXX: value not completely converted + * but then they use 0 (or partially converted numeric prefix) as a value + * and continue. They exit with 1 in this case. + * Both accept insane field width/precision (e.g. %9999999999.9999999999d). + * Both print error message and assume 0 if %*.*f width/precision is "bad" + * (but negative numbers are not "bad"). + * Both accept negative numbers for %u specifier. + * + * We try to be compatible. + */ + +typedef void FAST_FUNC (*converter)(const char *arg, void *result); + +static int multiconvert(const char *arg, void *result, converter convert) +{ + if (*arg == '"' || *arg == '\'') { + arg = utoa((unsigned char)arg[1]); + } + errno = 0; + convert(arg, result); + if (errno) { + bb_error_msg("invalid number '%s'", arg); + return 1; + } + return 0; +} + +static void FAST_FUNC conv_strtoull(const char *arg, void *result) +{ + /* Allow leading '+' - bb_strtoull() by itself does not allow it, + * and probably shouldn't (other callers might require purely numeric + * inputs to be allowed. + */ + if (arg[0] == '+') + arg++; + *(unsigned long long*)result = bb_strtoull(arg, NULL, 0); + /* both coreutils 6.10 and bash 3.2: + * $ printf '%x\n' -2 + * fffffffffffffffe + * Mimic that: + */ + if (errno) { + *(unsigned long long*)result = bb_strtoll(arg, NULL, 0); + } +} +static void FAST_FUNC conv_strtoll(const char *arg, void *result) +{ + if (arg[0] == '+') + arg++; + *(long long*)result = bb_strtoll(arg, NULL, 0); +} +static void FAST_FUNC conv_strtod(const char *arg, void *result) +{ + char *end; + /* Well, this one allows leading whitespace... so what? */ + /* What I like much less is that "-" accepted too! :( */ +//TODO: needs setlocale(LC_NUMERIC, "C")? + *(double*)result = strtod(arg, &end); + if (end[0]) { + errno = ERANGE; + *(double*)result = 0; + } +} + +/* Callers should check errno to detect errors */ +static unsigned long long my_xstrtoull(const char *arg) +{ + unsigned long long result; + if (multiconvert(arg, &result, conv_strtoull)) + result = 0; + return result; +} +static long long my_xstrtoll(const char *arg) +{ + long long result; + if (multiconvert(arg, &result, conv_strtoll)) + result = 0; + return result; +} +static double my_xstrtod(const char *arg) +{ + double result; + multiconvert(arg, &result, conv_strtod); + return result; +} + +/* Handles %b; return 1 if output is to be short-circuited by \c */ +static int print_esc_string(const char *str) +{ + char c; + while ((c = *str) != '\0') { + str++; + if (c == '\\') { + /* %b also accepts 4-digit octals of the form \0### */ + if (*str == '0') { + if ((unsigned char)(str[1] - '0') < 8) { + /* 2nd char is 0..7: skip leading '0' */ + str++; + } + } + else if (*str == 'c') { + return 1; + } + { + /* optimization: don't force arg to be on-stack, + * use another variable for that. */ + const char *z = str; + c = bb_process_escape_sequence(&z); + str = z; + } + } + putchar(c); + } + + return 0; +} + +static void print_direc(char *format, unsigned fmt_length, + int field_width, int precision, + const char *argument) +{ + long long llv; + double dv; + char saved; + char *have_prec, *have_width; + + saved = format[fmt_length]; + format[fmt_length] = '\0'; + + have_prec = strstr(format, ".*"); + have_width = strchr(format, '*'); + if (have_width - 1 == have_prec) + have_width = NULL; + + /* multiconvert sets errno = 0, but %s needs it cleared */ + errno = 0; + + switch (format[fmt_length - 1]) { + case 'c': + printf(format, *argument); + break; + case 'd': + case 'i': + llv = my_xstrtoll(skip_whitespace(argument)); + print_long: + if (!have_width) { + if (!have_prec) + printf(format, llv); + else + printf(format, precision, llv); + } else { + if (!have_prec) + printf(format, field_width, llv); + else + printf(format, field_width, precision, llv); + } + break; + case 'o': + case 'u': + case 'x': + case 'X': + llv = my_xstrtoull(skip_whitespace(argument)); + /* cheat: unsigned long and long have same width, so... */ + goto print_long; + case 's': + /* Are char* and long long the same? */ + if (sizeof(argument) == sizeof(llv)) { + llv = (long long)(ptrdiff_t)argument; + goto print_long; + } else { + /* Hope compiler will optimize it out by moving call + * instruction after the ifs... */ + if (!have_width) { + if (!have_prec) + printf(format, argument, /*unused:*/ argument, argument); + else + printf(format, precision, argument, /*unused:*/ argument); + } else { + if (!have_prec) + printf(format, field_width, argument, /*unused:*/ argument); + else + printf(format, field_width, precision, argument); + } + break; + } + case 'f': + case 'e': + case 'E': + case 'g': + case 'G': + dv = my_xstrtod(argument); + if (!have_width) { + if (!have_prec) + printf(format, dv); + else + printf(format, precision, dv); + } else { + if (!have_prec) + printf(format, field_width, dv); + else + printf(format, field_width, precision, dv); + } + break; + } /* switch */ + + format[fmt_length] = saved; +} + +/* Handle params for "%*.*f". Negative numbers are ok (compat). */ +static int get_width_prec(const char *str) +{ + int v = bb_strtoi(str, NULL, 10); + if (errno) { + bb_error_msg("invalid number '%s'", str); + v = 0; + } + return v; +} + +/* Print the text in FORMAT, using ARGV for arguments to any '%' directives. + Return advanced ARGV. */ +static char **print_formatted(char *f, char **argv, int *conv_err) +{ + char *direc_start; /* Start of % directive. */ + unsigned direc_length; /* Length of % directive. */ + int field_width; /* Arg to first '*' */ + int precision; /* Arg to second '*' */ + char **saved_argv = argv; + + for (; *f; ++f) { + switch (*f) { + case '%': + direc_start = f++; + direc_length = 1; + field_width = precision = 0; + if (*f == '%') { + bb_putchar('%'); + break; + } + if (*f == 'b') { + if (*argv) { + if (print_esc_string(*argv)) + return saved_argv; /* causes main() to exit */ + ++argv; + } + break; + } + while (*f && strchr("-+ #0", *f)) { + ++f; + ++direc_length; + } + if (*f == '*') { + ++f; + ++direc_length; + if (*argv) + field_width = get_width_prec(*argv++); + } else { + while (isdigit(*f)) { + ++f; + ++direc_length; + } + } + if (*f == '.') { + ++f; + ++direc_length; + if (*f == '*') { + ++f; + ++direc_length; + if (*argv) + precision = get_width_prec(*argv++); + } else { + while (isdigit(*f)) { + ++f; + ++direc_length; + } + } + } + + /* Remove "lLhz" size modifiers, repeatedly. + * bash does not like "%lld", but coreutils + * happily takes even "%Llllhhzhhzd"! + * We are permissive like coreutils */ + while ((*f | 0x20) == 'l' || *f == 'h' || *f == 'z') { + overlapping_strcpy(f, f + 1); + } + /* Add "ll" if integer modifier, then print */ + { + static const char format_chars[] ALIGN1 = "diouxXfeEgGcs"; + char *p = strchr(format_chars, *f); + /* needed - try "printf %" without it */ + if (p == NULL || *f == '\0') { + bb_error_msg("%s: invalid format", direc_start); + /* causes main() to exit with error */ + return saved_argv - 1; + } + ++direc_length; + if (p - format_chars <= 5) { + /* it is one of "diouxX" */ + p = xmalloc(direc_length + 3); + memcpy(p, direc_start, direc_length); + p[direc_length + 1] = p[direc_length - 1]; + p[direc_length - 1] = 'l'; + p[direc_length] = 'l'; + //bb_error_msg("<%s>", p); + direc_length += 2; + direc_start = p; + } else { + p = NULL; + } + if (*argv) { + print_direc(direc_start, direc_length, field_width, + precision, *argv++); + } else { + print_direc(direc_start, direc_length, field_width, + precision, ""); + } + *conv_err |= errno; + free(p); + } + break; + case '\\': + if (*++f == 'c') { + return saved_argv; /* causes main() to exit */ + } + bb_putchar(bb_process_escape_sequence((const char **)&f)); + f--; + break; + default: + putchar(*f); + } + } + + return argv; +} + +int printf_main(int argc UNUSED_PARAM, char **argv) +{ + int conv_err; + char *format; + char **argv2; + + /* We must check that stdout is not closed. + * The reason for this is highly non-obvious. + * printf_main is used from shell. + * Shell must correctly handle 'printf "%s" foo' + * if stdout is closed. With stdio, output gets shoveled into + * stdout buffer, and even fflush cannot clear it out. It seems that + * even if libc receives EBADF on write attempts, it feels determined + * to output data no matter what. So it will try later, + * and possibly will clobber future output. Not good. */ +// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? + if (fcntl(1, F_GETFL) == -1) + return 1; /* match coreutils 6.10 (sans error msg to stderr) */ + //if (dup2(1, 1) != 1) - old way + // return 1; + + /* bash builtin errors out on "printf '-%s-\n' foo", + * coreutils-6.9 works. Both work with "printf -- '-%s-\n' foo". + * We will mimic coreutils. */ + argv = skip_dash_dash(argv); + + if (!argv[0]) { + if ((ENABLE_ASH_PRINTF || ENABLE_HUSH_PRINTF) + && applet_name[0] != 'p' + ) { + bb_simple_error_msg("usage: printf FORMAT [ARGUMENT...]"); + return 2; /* bash compat */ + } + bb_show_usage(); + } + + format = argv[0]; + argv2 = argv + 1; + + conv_err = 0; + do { + argv = argv2; + argv2 = print_formatted(format, argv, &conv_err); + } while (argv2 > argv && *argv2); + + /* coreutils compat (bash doesn't do this): + if (*argv) + fprintf(stderr, "excess args ignored"); + */ + + return (argv2 < argv) /* if true, print_formatted errored out */ + || conv_err; /* print_formatted saw invalid number */ +} diff --git a/busybox-1_37_0/coreutils/pwd.c b/busybox-1_37_0/coreutils/pwd.c new file mode 100644 index 000000000..e62461719 --- /dev/null +++ b/busybox-1_37_0/coreutils/pwd.c @@ -0,0 +1,93 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini pwd implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config PWD +//config: bool "pwd (4 kb)" +//config: default y +//config: help +//config: pwd is used to print the current directory. + +//applet:IF_PWD(APPLET_NOFORK(pwd, pwd, BB_DIR_BIN, BB_SUID_DROP, pwd)) + +//kbuild:lib-$(CONFIG_PWD) += pwd.o + +//usage:#define pwd_trivial_usage +//usage: "" +//usage:#define pwd_full_usage "\n\n" +//usage: "Print the full filename of the current working directory" +//usage: +//usage:#define pwd_example_usage +//usage: "$ pwd\n" +//usage: "/root\n" + +#include "libbb.h" + +static int logical_getcwd(void) +{ + struct stat st1; + struct stat st2; + char *wd; + char *p; + + wd = getenv("PWD"); + if (!wd || wd[0] != '/') + return 0; + + p = wd; + while (*p) { + /* doing strstr(p, "/.") by hand is smaller and faster... */ + if (*p++ != '/') + continue; + if (*p != '.') + continue; + /* we found "/.", skip to next char */ + p++; + if (*p == '.') + p++; /* we found "/.." */ + if (*p == '\0' || *p == '/') + return 0; /* "/./" or "/../" component: bad */ + } + + if (stat(wd, &st1) != 0) + return 0; + if (stat(".", &st2) != 0) + return 0; + if (st1.st_ino != st2.st_ino) + return 0; + if (st1.st_dev != st2.st_dev) + return 0; + + puts(wd); + return 1; +} + +int pwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pwd_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + char *buf; + + if (ENABLE_DESKTOP) { + /* TODO: assume -L if $POSIXLY_CORRECT? (coreutils does that) + * Rationale: + * POSIX requires a default of -L, but most scripts expect -P + */ + unsigned opt = getopt32(argv, "LP"); + if ((opt & 1) && logical_getcwd()) + return fflush_all(); + } + + buf = xrealloc_getcwd_or_warn(NULL); + + if (buf) { + puts(buf); + free(buf); + return fflush_all(); + } + + return EXIT_FAILURE; +} diff --git a/busybox-1_37_0/coreutils/readlink.c b/busybox-1_37_0/coreutils/readlink.c new file mode 100644 index 000000000..9200f4ae0 --- /dev/null +++ b/busybox-1_37_0/coreutils/readlink.c @@ -0,0 +1,94 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini readlink implementation for busybox + * + * Copyright (C) 2000,2001 Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config READLINK +//config: bool "readlink (4.8 kb)" +//config: default y +//config: help +//config: This program reads a symbolic link and returns the name +//config: of the file it points to +//config: +//config:config FEATURE_READLINK_FOLLOW +//config: bool "Enable canonicalization by following all symlinks (-f)" +//config: default y +//config: depends on READLINK +//config: help +//config: Enable the readlink option (-f). + +//applet:IF_READLINK(APPLET_NOFORK(readlink, readlink, BB_DIR_USR_BIN, BB_SUID_DROP, readlink)) + +//kbuild:lib-$(CONFIG_READLINK) += readlink.o + +//usage:#define readlink_trivial_usage +//usage: IF_FEATURE_READLINK_FOLLOW("[-fnv] ") +//usage: IF_NOT_FEATURE_READLINK_FOLLOW("[-n] ") +//usage: "FILE" +//usage:#define readlink_full_usage "\n\n" +//usage: "Display the value of a symlink" "\n" +//usage: "\n -n Don't add newline" +//usage: IF_FEATURE_READLINK_FOLLOW( +//usage: "\n -f Canonicalize by following all symlinks" +//usage: "\n -v Verbose" +//usage: ) + +#include "libbb.h" + +/* + * # readlink --version + * readlink (GNU coreutils) 6.10 + * # readlink --help + * -f, --canonicalize + * canonicalize by following every symlink in + * every component of the given name recursively; + * all but the last component must exist + * -e, --canonicalize-existing + * canonicalize by following every symlink in + * every component of the given name recursively, + * all components must exist + * -m, --canonicalize-missing + * canonicalize by following every symlink in + * every component of the given name recursively, + * without requirements on components existence + * -n, --no-newline do not output the trailing newline + * -q, --quiet, -s, --silent suppress most error messages + * -v, --verbose report error messages + * + * bbox supports: -f (partially) -n -v (fully), -q -s (accepts but ignores) + * Note: we export the -f flag, but our -f behaves like coreutils' -e. + * Unfortunately, there isn't a C lib function we can leverage to get this + * behavior which means we'd have to implement the full stack ourselves :(. + */ + +int readlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int readlink_main(int argc UNUSED_PARAM, char **argv) +{ + char *buf; + unsigned opt; + + /* -n must use bit 0 (see printf below) */ + opt = getopt32(argv, "^" "n" IF_FEATURE_READLINK_FOLLOW("fvsq") + "\0" "=1"); + + /* compat: coreutils readlink reports errors silently via exit code */ + if (!(opt & 4)) /* not -v */ + logmode = LOGMODE_NONE; + + /* NOFORK: only one alloc is allowed; must free */ + if (opt & 2) { /* -f */ + buf = xmalloc_realpath_coreutils(argv[optind]); + } else { + buf = xmalloc_readlink_or_warn(argv[optind]); + } + + if (!buf) + return EXIT_FAILURE; + printf("%s%s", buf, &"\n"[opt & 1]); + free(buf); + + fflush_stdout_and_exit_SUCCESS(); +} diff --git a/busybox-1_37_0/coreutils/realpath.c b/busybox-1_37_0/coreutils/realpath.c new file mode 100644 index 000000000..22820a789 --- /dev/null +++ b/busybox-1_37_0/coreutils/realpath.c @@ -0,0 +1,52 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Now does proper error checking on output and returns a failure exit code + * if one or more paths cannot be resolved. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config REALPATH +//config: bool "realpath (2.5 kb)" +//config: default y +//config: help +//config: Return the canonicalized absolute pathname. +//config: This isn't provided by GNU shellutils, but where else does it belong. + +//applet:IF_REALPATH(APPLET_NOFORK(realpath, realpath, BB_DIR_USR_BIN, BB_SUID_DROP, realpath)) + +//kbuild:lib-$(CONFIG_REALPATH) += realpath.o + +/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */ + +//usage:#define realpath_trivial_usage +//usage: "FILE..." +//usage:#define realpath_full_usage "\n\n" +//usage: "Print absolute pathnames of FILEs" + +#include "libbb.h" + +int realpath_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int realpath_main(int argc UNUSED_PARAM, char **argv) +{ + int retval = EXIT_SUCCESS; + + if (!*++argv) { + bb_show_usage(); + } + + do { + /* NOFORK: only one alloc is allowed; must free */ + char *resolved_path = xmalloc_realpath_coreutils(*argv); + if (resolved_path != NULL) { + puts(resolved_path); + free(resolved_path); + } else { + retval = EXIT_FAILURE; + bb_simple_perror_msg(*argv); + } + } while (*++argv); + + fflush_stdout_and_exit(retval); +} diff --git a/busybox-1_37_0/coreutils/rm.c b/busybox-1_37_0/coreutils/rm.c new file mode 100644 index 000000000..93e01a340 --- /dev/null +++ b/busybox-1_37_0/coreutils/rm.c @@ -0,0 +1,76 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini rm implementation for busybox + * + * Copyright (C) 2001 Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Size reduction. + */ +//config:config RM +//config: bool "rm (5.5 kb)" +//config: default y +//config: help +//config: rm is used to remove files or directories. + +//applet:IF_RM(APPLET_NOEXEC(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) +/* was NOFORK, but then "rm -i FILE" can't be ^C'ed if run by hush */ + +//kbuild:lib-$(CONFIG_RM) += rm.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/rm.html */ + +//usage:#define rm_trivial_usage +//usage: "[-irf] FILE..." +//usage:#define rm_full_usage "\n\n" +//usage: "Remove (unlink) FILEs\n" +//usage: "\n -i Always prompt before removing" +//usage: "\n -f Never prompt" +//usage: "\n -R,-r Recurse" +//usage: +//usage:#define rm_example_usage +//usage: "$ rm -rf /tmp/foo\n" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +int rm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rm_main(int argc UNUSED_PARAM, char **argv) +{ + int status = 0; + int flags = 0; + unsigned opt; + + opt = getopt32(argv, "^" "fiRrv" "\0" "f-i:i-f"); + argv += optind; + if (opt & 1) + flags |= FILEUTILS_FORCE; + if (opt & 2) + flags |= FILEUTILS_INTERACTIVE; + if (opt & (8|4)) + flags |= FILEUTILS_RECUR; + if ((opt & 16) && FILEUTILS_VERBOSE) + flags |= FILEUTILS_VERBOSE; + + if (*argv != NULL) { + do { + const char *base = bb_get_last_path_component_strip(*argv); + + if (DOT_OR_DOTDOT(base)) { + bb_simple_error_msg("can't remove '.' or '..'"); + } else if (remove_file(*argv, flags) >= 0) { + continue; + } + status = 1; + } while (*++argv); + } else if (!(flags & FILEUTILS_FORCE)) { + bb_show_usage(); + } + + return status; +} diff --git a/busybox-1_37_0/coreutils/rmdir.c b/busybox-1_37_0/coreutils/rmdir.c new file mode 100644 index 000000000..96753e009 --- /dev/null +++ b/busybox-1_37_0/coreutils/rmdir.c @@ -0,0 +1,95 @@ +/* vi: set sw=4 ts=4: */ +/* + * rmdir implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config RMDIR +//config: bool "rmdir (3.8 kb)" +//config: default y +//config: help +//config: rmdir is used to remove empty directories. + +//applet:IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) + +//kbuild:lib-$(CONFIG_RMDIR) += rmdir.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */ + +//usage:#define rmdir_trivial_usage +//usage: "[-p] DIRECTORY..." +//usage:#define rmdir_full_usage "\n\n" +//usage: "Remove DIRECTORY if it is empty\n" +//usage: "\n -p Include parents" +//usage: IF_LONG_OPTS( +//usage: "\n --ignore-fail-on-non-empty" +//usage: ) +//usage: +//usage:#define rmdir_example_usage +//usage: "# rmdir /tmp/foo\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + + +#define PARENTS (1 << 0) +#define VERBOSE ((1 << 1) * ENABLE_FEATURE_VERBOSE) +#define IGNORE_NON_EMPTY ((1 << 2) * ENABLE_LONG_OPTS) + +int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rmdir_main(int argc UNUSED_PARAM, char **argv) +{ + int status = EXIT_SUCCESS; + int flags; + char *path; + + flags = getopt32long(argv, "pv", + "parents\0" No_argument "p" + /* Debian etch: many packages fail to be purged or installed + * because they desperately want this option: */ + "ignore-fail-on-non-empty\0" No_argument "\xff" + IF_FEATURE_VERBOSE( + "verbose\0" No_argument "v" + ) + ); + argv += optind; + + if (!*argv) { + bb_show_usage(); + } + + do { + path = *argv; + + while (1) { + if (flags & VERBOSE) { + printf("rmdir: removing directory, '%s'\n", path); + } + + if (rmdir(path) < 0) { +#if ENABLE_LONG_OPTS + if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) + break; +#endif + bb_perror_msg("'%s'", path); /* Match gnu rmdir msg. */ + status = EXIT_FAILURE; + } else if (flags & PARENTS) { + /* Note: path was not "" since rmdir succeeded. */ + path = dirname(path); + /* Path is now just the parent component. Dirname + * returns "." if there are no parents. + */ + if (NOT_LONE_CHAR(path, '.')) { + continue; + } + } + break; + } + } while (*++argv); + + return status; +} diff --git a/busybox-1_37_0/coreutils/seq.c b/busybox-1_37_0/coreutils/seq.c new file mode 100644 index 000000000..094f74e87 --- /dev/null +++ b/busybox-1_37_0/coreutils/seq.c @@ -0,0 +1,142 @@ +/* vi: set sw=4 ts=4: */ +/* + * seq implementation for busybox + * + * Copyright (C) 2004, Glenn McGrath + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config SEQ +//config: bool "seq (4 kb)" +//config: default y +//config: help +//config: print a sequence of numbers + +//applet:IF_SEQ(APPLET_NOEXEC(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) +/* was NOFORK, but then "seq 1 999999999" can't be ^C'ed if run by hush */ + +//kbuild:lib-$(CONFIG_SEQ) += seq.o + +//usage:#define seq_trivial_usage +//usage: "[-w] [-s SEP] [FIRST [INC]] LAST" +//usage:#define seq_full_usage "\n\n" +//usage: "Print numbers from FIRST to LAST, in steps of INC.\n" +//usage: "FIRST, INC default to 1.\n" +//usage: "\n -w Pad with leading zeros" +//usage: "\n -s SEP String separator" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +int seq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int seq_main(int argc, char **argv) +{ + enum { + OPT_w = (1 << 0), + OPT_s = (1 << 1), + }; + double first, last, increment, v; + unsigned n; + unsigned width; + unsigned frac_part; + const char *sep, *opt_s = "\n"; + char *saved; + unsigned opt; + +#if ENABLE_LOCALE_SUPPORT + /* Undo busybox.c: on input, we want to use dot + * as fractional separator, regardless of current locale */ + setlocale(LC_NUMERIC, "C"); +#endif + + /* Cater for negative arguments: if we see one, truncate argv[] on it */ + n = 0; + for (;;) { + char c; + saved = argv[++n]; + if (!saved) + break; + if (saved[0] != '-') { + // break; // "seq -s : -1 1" won't be treated correctly + continue; + } +// "seq -s -1 1 9" is not treated correctly, but such usage +// (delimiter string which looks like negative number) is very unlikely + c = saved[1]; + if (c == '.' || (c >= '0' && c <= '9')) { + argv[n] = NULL; + break; + } + } + opt = getopt32(argv, "+ws:", &opt_s); /* "+": stop at first non-option */ + /* Restore possibly truncated argv[] */ + argv[n] = saved; + + argc -= optind; + argv += optind; + first = increment = 1; + errno = 0; + switch (argc) { + char *pp; + case 3: + increment = strtod(argv[1], &pp); + errno |= *pp; + case 2: + first = strtod(argv[0], &pp); + errno |= *pp; + case 1: + last = strtod(argv[argc-1], &pp); + if (!errno && *pp == '\0') + break; + default: + bb_show_usage(); + } + +#if ENABLE_LOCALE_SUPPORT + setlocale(LC_NUMERIC, ""); +#endif + + /* Last checked to be compatible with: coreutils-6.10 */ + width = 0; + frac_part = 0; + while (1) { + char *dot = strchrnul(*argv, '.'); + int w = (dot - *argv); + int f = strlen(dot); + if (width < w) + width = w; + argv++; + if (!*argv) + break; + /* Why do the above _before_ frac check below? + * Try "seq 1 2.0" and "seq 1.0 2.0": + * coreutils never pay attention to the number + * of fractional digits in last arg. */ + if (frac_part < f) + frac_part = f; + } + if (frac_part) { + frac_part--; + if (frac_part) + width += frac_part + 1; + } + if (!(opt & OPT_w)) + width = 0; + + sep = ""; + v = first; + n = 0; + while (increment >= 0 ? v <= last : v >= last) { + if (printf("%s%0*.*f", sep, width, frac_part, v) < 0) + break; /* I/O error, bail out (yes, this really happens) */ + sep = opt_s; + /* v += increment; - would accumulate floating point errors */ + n++; + v = first + n * increment; + } + if (n) /* if while loop executed at least once */ + bb_putchar('\n'); + + return fflush_all(); +} diff --git a/busybox-1_37_0/coreutils/shred.c b/busybox-1_37_0/coreutils/shred.c new file mode 100644 index 000000000..7c0be612a --- /dev/null +++ b/busybox-1_37_0/coreutils/shred.c @@ -0,0 +1,111 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2017 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config SHRED +//config: bool "shred (5.5 kb)" +//config: default y +//config: help +//config: Overwrite a file to hide its contents, and optionally delete it + +//applet:IF_SHRED(APPLET(shred, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SHRED) += shred.o + +//usage:#define shred_trivial_usage +//usage: "[-fuz] [-n N] [-s SIZE] FILE..." +//usage:#define shred_full_usage "\n\n" +//usage: "Overwrite/delete FILEs\n" +//usage: "\n -f Chmod to ensure writability" +//usage: "\n -s SIZE Size to write" +//usage: "\n -n N Overwrite N times (default 3)" +//usage: "\n -z Final overwrite with zeros" +//usage: "\n -u Remove file" +//-x (exact: don't round up to 4k) and -v (verbose) are accepted but have no effect + +/* shred (GNU coreutils) 8.25: +-f, --force change permissions to allow writing if necessary +-u truncate and remove file after overwriting +-z, --zero add a final overwrite with zeros to hide shredding +-n, --iterations=N overwrite N times instead of the default (3) +-v, --verbose show progress +-x, --exact do not round file sizes up to the next full block; this is the default for non-regular files +--random-source=FILE get random bytes from FILE +-s, --size=N shred this many bytes (suffixes like K, M, G accepted) +--remove[=HOW] like -u but give control on HOW to delete; See below +*/ + +#include "libbb.h" + +int shred_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int shred_main(int argc UNUSED_PARAM, char **argv) +{ + char *opt_s; + int rand_fd = rand_fd; /* for compiler */ + int zero_fd; + unsigned num_iter = 3; + unsigned opt; + enum { + OPT_f = (1 << 0), + OPT_u = (1 << 1), + OPT_z = (1 << 2), + OPT_n = (1 << 3), + OPT_v = (1 << 4), + OPT_x = (1 << 5), + OPT_s = (1 << 6), + }; + + opt = getopt32(argv, "^" "fuzn:+vxs:" "\0" "-1"/*min 1 arg*/, &num_iter, &opt_s); + argv += optind; + + zero_fd = xopen("/dev/zero", O_RDONLY); + if (num_iter != 0) + rand_fd = xopen("/dev/urandom", O_RDONLY); + + for (;;) { + struct stat sb; + const char *fname; + unsigned i; + int fd; + + fname = *argv++; + if (!fname) + break; + fd = -1; + if (opt & OPT_f) { + fd = open(fname, O_WRONLY); + if (fd < 0) + chmod(fname, 0666); + } + if (fd < 0) + fd = xopen(fname, O_WRONLY); + + if (fstat(fd, &sb) == 0 && sb.st_size > 0) { + off_t size = sb.st_size; + + if (opt & OPT_s) { + size = BB_STRTOOFF(opt_s, NULL, 0); /* accepts oct/hex */ + if (errno || size < 0) bb_show_usage(); + } + + for (i = 0; i < num_iter; i++) { + bb_copyfd_size(rand_fd, fd, size); + fdatasync(fd); + xlseek(fd, 0, SEEK_SET); + } + if (opt & OPT_z) { + bb_copyfd_size(zero_fd, fd, size); + fdatasync(fd); + } + } + if (opt & OPT_u) { + ftruncate(fd, 0); + xunlink(fname); + } + xclose(fd); + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/shuf.c b/busybox-1_37_0/coreutils/shuf.c new file mode 100644 index 000000000..0d23382a2 --- /dev/null +++ b/busybox-1_37_0/coreutils/shuf.c @@ -0,0 +1,221 @@ +/* vi: set sw=4 ts=4: */ +/* + * shuf: Write a random permutation of the input lines to standard output. + * + * Copyright (C) 2014 by Bartosz Golaszewski + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SHUF +//config: bool "shuf (6 kb)" +//config: default y +//config: help +//config: Generate random permutations + +//applet:IF_SHUF(APPLET_NOEXEC(shuf, shuf, BB_DIR_USR_BIN, BB_SUID_DROP, shuf)) + +//kbuild:lib-$(CONFIG_SHUF) += shuf.o + +//usage:#define shuf_trivial_usage +//usage: "[-n NUM] [-o FILE] [-z] [FILE | -e [ARG...] | -i L-H]" +//usage:#define shuf_full_usage "\n\n" +//usage: "Randomly permute lines\n" +//usage: "\n -n NUM Output at most NUM lines" +//usage: "\n -o FILE Write to FILE, not standard output" +//usage: "\n -z NUL terminated output" +//usage: "\n -e Treat ARGs as lines" +//usage: "\n -i L-H Treat numbers L-H as lines" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +#define OPT_e (1 << 0) +#define OPT_i (1 << 1) +#define OPT_n (1 << 2) +#define OPT_o (1 << 3) +#define OPT_z (1 << 4) +#define OPT_STR "ei:n:o:z" + +/* + * Use the Fisher-Yates shuffle algorithm on an array of lines. + * If the required number of output lines is less than the total + * we can stop shuffling early. + */ +static void shuffle_lines(char **lines, unsigned numlines, unsigned outlines) +{ + srand(monotonic_us()); + + while (outlines != 0) { + char *tmp; + unsigned r = rand(); + /* RAND_MAX can be as small as 32767 */ + if (numlines > RAND_MAX) + r ^= rand() << 15; + r %= numlines; +//TODO: the above method is seriously non-uniform when numlines is very large. +//For example, with numlines of 0xf0000000, +//values of (r % numlines) in [0, 0x0fffffff] range +//are more likely: e.g. r=1 and r=0xf0000001 both map to 1, +//whereas only one value, r=0xefffffff, maps to 0xefffffff. + numlines--; + tmp = lines[numlines]; + lines[numlines] = lines[r]; + lines[r] = tmp; + outlines--; + } +} + +/* We can handle insanity like this: + * shuf -i 333333333333333333333333333333001-333333333333333333333333333333019 + * but do we want to have +200 bytes of code (~40% code growth)? + */ +#define COMMON_PREFIX_HACK 0 + +int shuf_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int shuf_main(int argc, char **argv) +{ + unsigned opts; + char *opt_i_str, *opt_n_str, *opt_o_str; + char **lines; + unsigned long long lo = lo; + unsigned numlines, outlines; + unsigned i; + char eol; +#if COMMON_PREFIX_HACK + unsigned pfx_len = 0; + unsigned padding_width = padding_width; + const char *pfx = pfx; +#endif + + opts = getopt32(argv, "^" + OPT_STR + "\0" "e--i:i--e"/* mutually exclusive */, + &opt_i_str, &opt_n_str, &opt_o_str + ); + + argc -= optind; + argv += optind; + + /* Prepare lines for shuffling - either: */ + if (opts & OPT_e) { + /* make lines from command-line arguments */ + numlines = argc; + lines = argv; + } else + if (opts & OPT_i) { + /* create a range of numbers */ + unsigned long long hi; + char *dash; + + if (argv[0]) + bb_show_usage(); + + dash = strchr(opt_i_str, '-'); + if (!dash) { + bb_error_msg_and_die("bad range '%s'", opt_i_str); + } + *dash++ = '\0'; +#if COMMON_PREFIX_HACK + { + const char *a = opt_i_str; + const char *b = dash; + /* Skip leading zeros (they may mask that common prefix does exist) */ + while (*a == '0') a++; + while (*b == '0') b++; + /* Do we have a common prefix (long enough to bother)? */ + padding_width = strlen(a); + if (padding_width > 5 && padding_width == strlen(b)) { + /* How long is it? */ + pfx = a; + while (isdigit(*a) && *a == *b + && a[1] /* "111111-111111" case: avoid xatoull("") */ + ) { + a++; + b++; + } + pfx_len = a - pfx; /* can end up being 0 */ + padding_width -= pfx_len; + } else { + /* Undo leading zero 'eating' (think "0-9") */ + a = opt_i_str; + b = dash; + } + lo = xatoull(a); + hi = xatoull(b); + } +#else + lo = xatoull(opt_i_str); + hi = xatoull(dash); +#endif + dash[-1] = '-'; + if (hi < lo) + bb_error_msg_and_die("bad range '%s'", opt_i_str); + hi -= lo; + if (sizeof(size_t) > sizeof(numlines)) { + if (hi >= UINT_MAX) + bb_error_msg_and_die("bad range '%s'", opt_i_str); + } else { + if (hi >= UINT_MAX / sizeof(lines[0])) + bb_error_msg_and_die("bad range '%s'", opt_i_str); + } + + numlines = hi + 1; + lines = xmalloc((size_t)numlines * sizeof(lines[0])); + for (i = 0; i < numlines; i++) { + lines[i] = (char*)(uintptr_t)i; + } + } else { + /* default - read lines from stdin or the input file */ + FILE *fp; + const char *fname = "-"; + + if (argv[0]) { + if (argv[1]) + bb_show_usage(); + fname = argv[0]; + } + + fp = xfopen_stdin(fname); + lines = NULL; + numlines = 0; + for (;;) { + char *line = xmalloc_fgetline(fp); + if (!line) + break; + lines = xrealloc_vector(lines, 6, numlines); + lines[numlines++] = line; + } + fclose_if_not_stdin(fp); + } + + outlines = numlines; + if (opts & OPT_n) { + outlines = xatou(opt_n_str); + if (outlines > numlines) + outlines = numlines; + } + + shuffle_lines(lines, numlines, outlines); + + if (opts & OPT_o) + xmove_fd(xopen(opt_o_str, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO); + + eol = '\n'; + if (opts & OPT_z) + eol = '\0'; + + for (i = numlines - outlines; i < numlines; i++) { + if (opts & OPT_i) { +#if COMMON_PREFIX_HACK + if (pfx_len != 0) + printf("%.*s%0*llu%c", pfx_len, pfx, padding_width, lo + (uintptr_t)lines[i], eol); + else +#endif + printf("%llu%c", lo + (uintptr_t)lines[i], eol); + } else + printf("%s%c", lines[i], eol); + } + + fflush_stdout_and_exit_SUCCESS(); +} diff --git a/busybox-1_37_0/coreutils/sleep.c b/busybox-1_37_0/coreutils/sleep.c new file mode 100644 index 000000000..6fd00f9f1 --- /dev/null +++ b/busybox-1_37_0/coreutils/sleep.c @@ -0,0 +1,103 @@ +/* vi: set sw=4 ts=4: */ +/* + * sleep implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Rewritten to do proper arg and error checking. + * Also, added a 'fancy' configuration to accept multiple args with + * time suffixes for seconds, minutes, hours, and days. + */ +//config:config SLEEP +//config: bool "sleep (2.4 kb)" +//config: default y +//config: help +//config: sleep is used to pause for a specified number of seconds. +//config: It comes in 2 versions: +//config: - small: takes one integer parameter +//config: - fancy: +//config: * takes multiple integer arguments with suffixes: +//config: sleep 1d 2h 3m 15s +//config: * allows fractional numbers: +//config: sleep 2.3s 4.5h sleeps for 16202.3 seconds +//config: fancy is more compatible with coreutils sleep, but it adds around +//config: 1k of code. +//config: +//config:config FEATURE_FANCY_SLEEP +//config: bool "Enable multiple arguments and s/m/h/d suffixes" +//config: default y +//config: depends on SLEEP +//config: help +//config: Allow sleep to pause for specified minutes, hours, and days. + +/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ +//applet:IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SLEEP) += sleep.o +//kbuild:lib-$(CONFIG_ASH_SLEEP) += sleep.o + +/* BB_AUDIT SUSv3 compliant */ +/* BB_AUDIT GNU issues -- fancy version matches except args must be ints. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/sleep.html */ + +//usage:#define sleep_trivial_usage +//usage: IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...") +//usage:#define sleep_full_usage "\n\n" +//usage: IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds") +//usage: IF_FEATURE_FANCY_SLEEP( +//usage: "Pause for a time equal to the total of the args given, where each arg can\n" +//usage: "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays") +//usage: +//usage:#define sleep_example_usage +//usage: "$ sleep 2\n" +//usage: "[2 second delay results]\n" +//usage: IF_FEATURE_FANCY_SLEEP( +//usage: "$ sleep 1d 3h 22m 8s\n" +//usage: "[98528 second delay results]\n") + +#include "libbb.h" + +int sleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sleep_main(int argc UNUSED_PARAM, char **argv) +{ + duration_t duration; + + /* Note: sleep_main may be directly called from ash as a builtin. + * This brings some complications: + * + we can't use xfunc here + * + we can't use bb_show_usage + * + applet_name can be the name of the shell + */ + argv = skip_dash_dash(argv); + if (!argv[0]) { + /* Without this, bare "sleep" in ash shows _ash_ --help */ + /* (ash can be the "sh" applet as well, so check 2nd char) */ + if (ENABLE_ASH_SLEEP && applet_name[1] != 'l') { + bb_simple_error_msg("sleep: missing operand"); + return EXIT_FAILURE; + } + bb_show_usage(); + } + + /* GNU sleep accepts "inf", "INF", "infinity" and "INFINITY" */ + if (strncasecmp(argv[0], "inf", 3) == 0) + for (;;) + sleep(INT_MAX); + +//FIXME: in ash, "sleep 123qwerty" as a builtin aborts the shell +#if ENABLE_FEATURE_FANCY_SLEEP + duration = 0; + do { + duration += parse_duration_str(*argv); + } while (*++argv); + sleep_for_duration(duration); +#else /* simple */ + duration = xatou(*argv); + sleep(duration); +#endif + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/sort.c b/busybox-1_37_0/coreutils/sort.c new file mode 100644 index 000000000..2e952f81c --- /dev/null +++ b/busybox-1_37_0/coreutils/sort.c @@ -0,0 +1,684 @@ +/* vi: set sw=4 ts=4: */ +/* + * SuS3 compliant sort implementation for busybox + * + * Copyright (C) 2004 by Rob Landley + * + * MAINTAINER: Rob Landley + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * See SuS3 sort standard at: + * http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html + */ +//config:config SORT +//config: bool "sort (8.1 kb)" +//config: default y +//config: help +//config: sort is used to sort lines of text in specified files. +//config: +//config:config FEATURE_SORT_BIG +//config: bool "Full SuSv3 compliant sort (support -ktcbdfioghM)" +//config: default y +//config: depends on SORT +//config: help +//config: Without this, sort only supports -rusz, and an integer version +//config: of -n. Selecting this adds sort keys, floating point support, and +//config: more. This adds a little over 3k to a nonstatic build on x86. +//config: +//config: The SuSv3 sort standard is available at: +//config: http://www.opengroup.org/onlinepubs/007904975/utilities/sort.html +//config: +//config:config FEATURE_SORT_OPTIMIZE_MEMORY +//config: bool "Use less memory (but might be slower)" +//config: default n # defaults to N since we are size-paranoid tribe +//config: depends on SORT +//config: help +//config: Attempt to use less memory (by storing only one copy +//config: of duplicated lines, and such). Useful if you work on huge files. + +//applet:IF_SORT(APPLET_NOEXEC(sort, sort, BB_DIR_USR_BIN, BB_SUID_DROP, sort)) + +//kbuild:lib-$(CONFIG_SORT) += sort.o + +//usage:#define sort_trivial_usage +//usage: "[-nru" +//usage: IF_FEATURE_SORT_BIG("ghMcszbdfiokt] [-o FILE] [-k START[.OFS][OPTS][,END[.OFS][OPTS]] [-t CHAR") +//usage: "] [FILE]..." +//usage:#define sort_full_usage "\n\n" +//usage: "Sort lines of text\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -o FILE Output to FILE" +//usage: "\n -c Check whether input is sorted" +//usage: "\n -b Ignore leading blanks" +//usage: "\n -f Ignore case" +//usage: "\n -i Ignore unprintable characters" +//usage: "\n -d Dictionary order (blank or alphanumeric only)" +//usage: ) +//-h, --human-numeric-sort: compare human readable numbers (e.g., 2K 1G) +//usage: "\n -n Sort numbers" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -g General numerical sort" +//usage: "\n -h Sort human readable numbers (2K 1G)" +//usage: "\n -M Sort month" +//usage: "\n -V Sort version" +//usage: "\n -t CHAR Field separator" +//usage: "\n -k N[,M] Sort by Nth field" +//usage: ) +//usage: "\n -r Reverse sort order" +//usage: "\n -s Stable (don't sort ties alphabetically)" +//usage: "\n -u Suppress duplicate lines" +//usage: "\n -z NUL terminated input and output" +///////: "\n -m Ignored for GNU compatibility" +///////: "\n -S BUFSZ Ignored for GNU compatibility" +///////: "\n -T TMPDIR Ignored for GNU compatibility" +//usage: +//usage:#define sort_example_usage +//usage: "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" +//usage: "d\n" +//usage: "e\n" +//usage: "f\n" +//usage: IF_FEATURE_SORT_BIG( +//usage: "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" +//usage: "d 2\n" +//usage: "b 2\n" +//usage: "c 3\n" +//usage: ) +//usage: "" + +#include "libbb.h" + +/* These are sort types */ +enum { + FLAG_n = 1 << 0, /* Numeric sort */ + FLAG_g = 1 << 1, /* Sort using strtod() */ + FLAG_h = 1 << 2, /* Sort using strtod(), plus KMGT suffixes */ + FLAG_M = 1 << 3, /* Sort date */ + FLAG_V = 1 << 4, /* Sort version */ +/* ucsz apply to root level only, not keys. b at root level implies bb */ + FLAG_u = 1 << 5, /* Unique */ + FLAG_c = 1 << 6, /* Check: no output, exit(!ordered) */ + FLAG_s = 1 << 7, /* Stable sort, no ascii fallback at end */ + FLAG_z = 1 << 8, /* Input and output is NUL terminated, not \n */ +/* These can be applied to search keys, the previous four can't */ + FLAG_b = 1 << 9, /* Ignore leading blanks */ + FLAG_r = 1 << 10, /* Reverse */ + FLAG_d = 1 << 11, /* Ignore !(isalnum()|isspace()) */ + FLAG_f = 1 << 12, /* Force uppercase */ + FLAG_i = 1 << 13, /* Ignore !isprint() */ + FLAG_m = 1 << 14, /* ignored: merge already sorted files; do not sort */ + FLAG_S = 1 << 15, /* ignored: -S, --buffer-size=SIZE */ + FLAG_T = 1 << 16, /* ignored: -T, --temporary-directory=DIR */ + FLAG_o = 1 << 17, + FLAG_k = 1 << 18, + FLAG_t = 1 << 19, + FLAG_bb = 0x80000000, /* Ignore trailing blanks */ + FLAG_no_tie_break = 0x40000000, +}; + +static const char sort_opt_str[] ALIGN1 = "^" + "nghMVucszbrdfimS:T:o:k:*t:" + "\0" "o--o:t--t"/*-t, -o: at most one of each*/; +/* + * OPT_STR must not be string literal, needs to have stable address: + * code uses "strchr(OPT_STR,c) - OPT_STR" idiom. + */ +#define OPT_STR (sort_opt_str + 1) + +#if ENABLE_FEATURE_SORT_BIG +static char key_separator; + +static struct sort_key { + struct sort_key *next_key; /* linked list */ + unsigned range[4]; /* start word, start char, end word, end char */ + unsigned flags; +} *key_list; + + +/* This is a NOEXEC applet. Be very careful! */ + + +static char *get_key(char *str, struct sort_key *key, int flags) +{ + int start = start; /* for compiler */ + int end; + int len, j; + unsigned i; + + /* Special case whole string, so we don't have to make a copy */ + if (key->range[0] == 1 && !key->range[1] && !key->range[2] && !key->range[3] + && !(flags & (FLAG_b | FLAG_d | FLAG_f | FLAG_i | FLAG_bb)) + ) { + return str; + } + + /* Find start of key on first pass, end on second pass */ + len = strlen(str); + for (j = 0; j < 2; j++) { + if (!key->range[2*j]) + end = len; + /* Loop through fields */ + else { + unsigned char ch = 0; + + end = 0; + for (i = 1; i < key->range[2*j] + j; i++) { + if (key_separator) { + /* Skip body of key and separator */ + while ((ch = str[end]) != '\0') { + end++; + if (ch == key_separator) + break; + } + } else { + /* Skip leading blanks */ + while (isspace(str[end])) + end++; + /* Skip body of key */ + while (str[end] != '\0') { + if (isspace(str[end])) + break; + end++; + } + } + } + /* Remove last delim: "abc:def:" => "abc:def" */ + if (j && ch) { + //if (str[end-1] != key_separator) + // bb_error_msg(_and_die("BUG! " + // "str[start:%d,end:%d]:'%.*s'", + // start, end, (int)(end-start), &str[start]); + end--; + } + } + if (!j) start = end; + } + /* Strip leading whitespace if necessary */ + if (flags & FLAG_b) + /* not using skip_whitespace() for speed */ + while (isspace(str[start])) start++; + /* Strip trailing whitespace if necessary */ + if (flags & FLAG_bb) + while (end > start && isspace(str[end-1])) end--; + /* -kSTART,N.ENDCHAR: honor ENDCHAR (1-based) */ + if (key->range[3]) { + end = key->range[3]; + if (end > len) end = len; + } + /* -kN.STARTCHAR[,...]: honor STARTCHAR (1-based) */ + if (key->range[1]) { + start += key->range[1] - 1; + if (start > len) start = len; + } + /* Make the copy */ + if (end < start) + end = start; + str = xstrndup(str+start, end-start); + /* Handle -d */ + if (flags & FLAG_d) { + for (start = end = 0; str[end]; end++) + if (isspace(str[end]) || isalnum(str[end])) + str[start++] = str[end]; + str[start] = '\0'; + } + /* Handle -i */ + if (flags & FLAG_i) { + for (start = end = 0; str[end]; end++) + if (isprint_asciionly(str[end])) + str[start++] = str[end]; + str[start] = '\0'; + } + /* Handle -f */ + if (flags & FLAG_f) + for (i = 0; str[i]; i++) + str[i] = toupper(str[i]); + + return str; +} + +static struct sort_key *add_key(void) +{ + struct sort_key **pkey = &key_list; + while (*pkey) + pkey = &((*pkey)->next_key); + return *pkey = xzalloc(sizeof(struct sort_key)); +} + +#define GET_LINE(fp) \ + ((option_mask32 & FLAG_z) \ + ? bb_get_chunk_from_file(fp, NULL) \ + : xmalloc_fgetline(fp)) +#else +#define GET_LINE(fp) xmalloc_fgetline(fp) +#endif + +#if ENABLE_FEATURE_SORT_BIG +static int scale_suffix(const char *tail) +{ + static const char suffix[] ALIGN1 = "kmgtpezy"; + const char *s; + int n; + + if (!tail[0]) + return -1; + s = strchr(suffix, tail[0] | 0x20); + if (!s) + return -1; + n = s - suffix; + if (n != 0 && tail[0] >= 'a') + return -1; /* mg... not accepted, only MG... */ + return n; +} +#endif + +/* Iterate through keys list and perform comparisons */ +static int compare_keys(const void *xarg, const void *yarg) +{ + int flags = option_mask32, retval = 0; + char *x, *y; + +#if ENABLE_FEATURE_SORT_BIG + struct sort_key *key; + + for (key = key_list; !retval && key; key = key->next_key) { + flags = key->flags ? key->flags : option_mask32; + /* Chop out and modify key chunks, handling -dfib */ + x = get_key(*(char **)xarg, key, flags); + y = get_key(*(char **)yarg, key, flags); +#else + /* This curly bracket serves no purpose but to match the nesting + * level of the for () loop we're not using */ + { + x = *(char **)xarg; + y = *(char **)yarg; +#endif + /* Perform actual comparison */ + switch (flags & (FLAG_n | FLAG_g | FLAG_h | FLAG_M | FLAG_V)) { + default: + bb_simple_error_msg_and_die("unknown sort type"); + break; +#if defined(HAVE_STRVERSCMP) && HAVE_STRVERSCMP == 1 + case FLAG_V: + retval = strverscmp(x, y); + break; +#endif + /* Ascii sort */ + case 0: +#if ENABLE_LOCALE_SUPPORT + retval = strcoll(x, y); +#else + retval = strcmp(x, y); +#endif + break; +#if ENABLE_FEATURE_SORT_BIG + case FLAG_g: + case FLAG_h: { + char *xx, *yy; +//TODO: needs setlocale(LC_NUMERIC, "C")? + double dx = strtod(x, &xx); + double dy = strtod(y, &yy); + /* not numbers < NaN < -infinity < numbers < +infinity) */ + if (x == xx) + retval = (y == yy ? 0 : -1); + else if (y == yy) + retval = 1; + /* Check for isnan */ + else if (dx != dx) + retval = (dy != dy) ? 0 : -1; + else if (dy != dy) + retval = 1; + else { + if (flags & FLAG_h) { + int xs = scale_suffix(xx); + int ys = scale_suffix(yy); + if (xs != ys) { + retval = xs - ys; + break; + } + } + /* Check for infinity. Could underflow, but it avoids libm. */ + if (1.0 / dx == 0.0) { + if (dx < 0) + retval = (1.0 / dy == 0.0 && dy < 0) ? 0 : -1; + else + retval = (1.0 / dy == 0.0 && dy > 0) ? 0 : 1; + } else if (1.0 / dy == 0.0) + retval = (dy < 0) ? 1 : -1; + else + retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0); + } + break; + } + case FLAG_M: { + struct tm thyme; + int dx; + char *xx, *yy; + + xx = strptime(skip_whitespace(x), "%b", &thyme); + dx = thyme.tm_mon; + yy = strptime(skip_whitespace(y), "%b", &thyme); + if (!xx) + retval = (!yy) ? 0 : -1; + else if (!yy) + retval = 1; + else + retval = dx - thyme.tm_mon; + break; + } + /* Full floating point version of -n */ + case FLAG_n: { + double dx = atof(x); + double dy = atof(y); + retval = (dx > dy) ? 1 : ((dx < dy) ? -1 : 0); + break; + } + } /* switch */ + /* Free key copies. */ + if (x != *(char **)xarg) free(x); + if (y != *(char **)yarg) free(y); + /* if (retval) break; - done by for () anyway */ +#else + /* Integer version of -n for tiny systems */ + case FLAG_n: + retval = atoi(x) - atoi(y); + break; + } /* switch */ +#endif + } /* for */ + + if (retval == 0) { + /* So far lines are "the same" */ + + if (option_mask32 & FLAG_s) { + /* "Stable sort": later line is "greater than", + * IOW: do not allow qsort() to swap equal lines. + */ + uint32_t *p32; + uint32_t x32, y32; + char *line; + unsigned len; + + line = *(char**)xarg; + len = (strlen(line) + 4) & (~3u); + p32 = (void*)(line + len); + x32 = *p32; + line = *(char**)yarg; + len = (strlen(line) + 4) & (~3u); + p32 = (void*)(line + len); + y32 = *p32; + + /* If x > y, 1, else -1 */ + retval = (x32 > y32) * 2 - 1; + /* Here, -r has no effect! */ + return retval; + } + if (!(option_mask32 & FLAG_no_tie_break)) { + /* fallback sort */ + flags = option_mask32; + retval = strcmp(*(char **)xarg, *(char **)yarg); + } + } + + if (flags & FLAG_r) + return -retval; + + return retval; +} + +#if ENABLE_FEATURE_SORT_BIG +static unsigned str2u(char **str) +{ + unsigned long lu; + if (!isdigit((*str)[0])) + bb_simple_error_msg_and_die("bad field specification"); + lu = strtoul(*str, str, 10); + if ((sizeof(long) > sizeof(int) && lu > INT_MAX) || !lu) + bb_simple_error_msg_and_die("bad field specification"); + return lu; +} +#endif + +int sort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sort_main(int argc UNUSED_PARAM, char **argv) +{ + char **lines; + char *str_ignored, *str_o, *str_t; + llist_t *lst_k = NULL; + int i; + int linecount; + unsigned opts; +#if ENABLE_FEATURE_SORT_OPTIMIZE_MEMORY + bool can_drop_dups; + size_t prev_len = 0; + char *prev_line = (char*) ""; + /* Postpone optimizing if the input is small, < 16k lines: + * even just free()ing duplicate lines takes time. + */ + size_t count_to_optimize_dups = 0x3fff; +#endif + + xfunc_error_retval = 2; + + /* Parse command line options */ + opts = getopt32(argv, + sort_opt_str, + &str_ignored, &str_ignored, &str_o, &lst_k, &str_t + ); +#if ENABLE_FEATURE_SORT_OPTIMIZE_MEMORY + /* Can drop dups only if -u but no "complicating" options, + * IOW: if we do a full line compares. Safe options: + * -o FILE Output to FILE + * -z Lines are terminated by NUL, not newline + * -r Reverse sort order + * -s Stable (don't sort ties alphabetically) + * Not sure about these: + * -b Ignore leading blanks + * -f Ignore case + * -i Ignore unprintable characters + * -d Dictionary order (blank or alphanumeric only) + * -n Sort numbers + * -g General numerical sort + * -M Sort month + */ + can_drop_dups = ((opts & ~(FLAG_o|FLAG_z|FLAG_r|FLAG_s)) == FLAG_u); + /* Stable sort needs every line to be uniquely allocated, + * disable optimization to reuse strings: + */ + if (opts & FLAG_s) + count_to_optimize_dups = (size_t)-1L; +#endif + /* global b strips leading and trailing spaces */ + if (opts & FLAG_b) + option_mask32 |= FLAG_bb; +#if ENABLE_FEATURE_SORT_BIG + if (opts & FLAG_t) { + if (!str_t[0] || str_t[1]) + bb_simple_error_msg_and_die("bad -t parameter"); + key_separator = str_t[0]; + } + /* note: below this point we use option_mask32, not opts, + * since that reduces register pressure and makes code smaller */ + + /* Parse sort key */ + while (lst_k) { + enum { + FLAG_allowed_for_k = + FLAG_n | /* Numeric sort */ + FLAG_g | /* Sort using strtod() */ + FLAG_h | /* Sort using strtod(), plus KMGT suffixes */ + FLAG_M | /* Sort date */ + FLAG_b | /* Ignore leading blanks */ + FLAG_r | /* Reverse */ + FLAG_d | /* Ignore !(isalnum()|isspace()) */ + FLAG_f | /* Force uppercase */ + FLAG_i | /* Ignore !isprint() */ + 0 + }; + struct sort_key *key = add_key(); + char *str_k = llist_pop(&lst_k); + + i = 0; /* i==0 before comma, 1 after (-k3,6) */ + while (*str_k) { + /* Start of range */ + /* Cannot use bb_strtou - suffix can be a letter */ + key->range[2*i] = str2u(&str_k); + if (*str_k == '.') { + str_k++; + key->range[2*i+1] = str2u(&str_k); + } + while (*str_k) { + int flag; + const char *idx; + + if (*str_k == ',' && !i++) { + str_k++; + break; + } /* no else needed: fall through to syntax error + because comma isn't in OPT_STR */ + idx = strchr(OPT_STR, *str_k); + if (!idx) + bb_simple_error_msg_and_die("unknown key option"); + flag = 1 << (idx - OPT_STR); + if (flag & ~FLAG_allowed_for_k) + bb_simple_error_msg_and_die("unknown sort type"); + /* b after ',' means strip _trailing_ space */ + if (i && flag == FLAG_b) + flag = FLAG_bb; + key->flags |= flag; + str_k++; + } + } + } +#endif + + /* Open input files and read data */ + argv += optind; + if (!*argv) + *--argv = (char*)"-"; + linecount = 0; + lines = NULL; + do { + /* coreutils 6.9 compat: abort on first open error, + * do not continue to next file: */ + FILE *fp = xfopen_stdin(*argv); + for (;;) { + char *line = GET_LINE(fp); + if (!line) + break; + +#if ENABLE_FEATURE_SORT_OPTIMIZE_MEMORY + if (count_to_optimize_dups != 0) + count_to_optimize_dups--; + if (count_to_optimize_dups == 0) { + size_t len; + char *new_line; + + /* On kernel/linux/arch/ *.[ch] files, + * this reduces memory usage by 6%. + * yes | head -99999999 | sort + * goes down from 1900Mb to 380 Mb. + */ + len = strlen(line); + if (len <= prev_len) { + new_line = prev_line + (prev_len - len); + if (strcmp(line, new_line) == 0) { + /* it's a tail of the prev line */ + if (can_drop_dups && prev_len == len) { + /* it's identical to prev line */ + free(line); + continue; + } + free(line); + line = new_line; + /* continue using longer prev_line + * for future tail tests. + */ + goto skip; + } + } + prev_len = len; + prev_line = line; + skip: ; + } +#else +//TODO: lighter version which only drops total dups if can_drop_dups == true +#endif + lines = xrealloc_vector(lines, 6, linecount); + lines[linecount++] = line; + } + fclose_if_not_stdin(fp); + } while (*++argv); + +#if ENABLE_FEATURE_SORT_BIG + /* If no key, perform alphabetic sort */ + if (!key_list) + add_key()->range[0] = 1; + /* Handle -c */ + if (option_mask32 & FLAG_c) { + int j = (option_mask32 & FLAG_u) ? -1 : 0; + for (i = 1; i < linecount; i++) { + if (compare_keys(&lines[i-1], &lines[i]) > j) { + fprintf(stderr, "Check line %u\n", i); + return EXIT_FAILURE; + } + } + return EXIT_SUCCESS; + } +#endif + + /* For stable sort, store original line position beyond terminating NUL */ + if (option_mask32 & FLAG_s) { + for (i = 0; i < linecount; i++) { + uint32_t *p32; + char *line; + unsigned len; + + line = lines[i]; + len = (strlen(line) + 4) & (~3u); + lines[i] = line = xrealloc(line, len + 4); + p32 = (void*)(line + len); + *p32 = i; + } + /*option_mask32 |= FLAG_no_tie_break;*/ + /* ^^^redundant: if FLAG_s, compare_keys() does no tie break */ + } + + /* Perform the actual sort */ + qsort(lines, linecount, sizeof(lines[0]), compare_keys); + + /* Handle -u */ + if (option_mask32 & FLAG_u) { + int j = 0; + /* coreutils 6.3 drop lines for which only key is the same: + * - disabling last-resort compare, or else compare_keys() + * will be the same only for completely identical lines + * - disabling -s (same reasons) + */ + option_mask32 = (option_mask32 | FLAG_no_tie_break) & (~FLAG_s); + for (i = 1; i < linecount; i++) { + if (compare_keys(&lines[j], &lines[i]) == 0) + free(lines[i]); + else + lines[++j] = lines[i]; + } + if (linecount) + linecount = j+1; + } + + /* Print it */ +#if ENABLE_FEATURE_SORT_BIG + /* Open output file _after_ we read all input ones */ + if (option_mask32 & FLAG_o) + xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO); +#endif + { + int ch = (option_mask32 & FLAG_z) ? '\0' : '\n'; + for (i = 0; i < linecount; i++) + printf("%s%c", lines[i], ch); + } + + fflush_stdout_and_exit_SUCCESS(); +} diff --git a/busybox-1_37_0/coreutils/split.c b/busybox-1_37_0/coreutils/split.c new file mode 100644 index 000000000..b6d1b9a7b --- /dev/null +++ b/busybox-1_37_0/coreutils/split.c @@ -0,0 +1,179 @@ +/* vi: set sw=4 ts=4: */ +/* + * split - split a file into pieces + * Copyright (c) 2007 Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SPLIT +//config: bool "split (5.2 kb)" +//config: default y +//config: help +//config: Split a file into pieces. +//config: +//config:config FEATURE_SPLIT_FANCY +//config: bool "Fancy extensions" +//config: default y +//config: depends on SPLIT +//config: help +//config: Add support for features not required by SUSv3. +//config: Supports additional suffixes 'b' for 512 bytes, +//config: 'g' for 1GiB for the -b option. + +//applet:IF_SPLIT(APPLET(split, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SPLIT) += split.o + +/* BB_AUDIT: SUSv3 compliant + * SUSv3 requirements: + * http://www.opengroup.org/onlinepubs/009695399/utilities/split.html + */ + +//usage:#define split_trivial_usage +//usage: "[OPTIONS] [INPUT [PREFIX]]" +//usage:#define split_full_usage "\n\n" +//usage: " -b N[k|m] Split by N (kilo|mega)bytes" +//usage: "\n -l N Split by N lines" +//usage: "\n -a N Use N letters as suffix" +//usage: +//usage:#define split_example_usage +//usage: "$ split TODO foo\n" +//usage: "$ cat TODO | split -a 2 -l 2 TODO_\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +#if ENABLE_FEATURE_SPLIT_FANCY +static const struct suffix_mult split_suffixes[] ALIGN_SUFFIX = { + { "b", 512 }, + { "k", 1024 }, + { "m", 1024*1024 }, + { "g", 1024*1024*1024 }, + { "", 0 } +}; +#endif + +/* Increment the suffix part of the filename. + * Returns NULL if we are out of filenames. + */ +static char *next_file(char *old, unsigned suffix_len) +{ + size_t end = strlen(old); + unsigned i = 1; + char *curr; + + while (1) { + curr = old + end - i; + if (*curr < 'z') { + *curr += 1; + break; + } + i++; + if (i > suffix_len) { + return NULL; + } + *curr = 'a'; + } + + return old; +} + +#define read_buffer bb_common_bufsiz1 +enum { READ_BUFFER_SIZE = COMMON_BUFSIZE - 1 }; + +#define SPLIT_OPT_l (1<<0) +#define SPLIT_OPT_b (1<<1) +#define SPLIT_OPT_a (1<<2) + +int split_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int split_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned suffix_len = 2; + char *pfx; + char *count_p; + const char *sfx; + off_t cnt = 1000; + off_t remaining = 0; + unsigned opt; + ssize_t bytes_read, to_write; + char *src; + + setup_common_bufsiz(); + + opt = getopt32(argv, "^" + "l:b:a:+" /* -a N */ + "\0" "?2"/*max 2 args*/, + &count_p, &count_p, &suffix_len + ); + + if (opt & SPLIT_OPT_l) + cnt = XATOOFF(count_p); + if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF + cnt = xatoull_sfx(count_p, + IF_FEATURE_SPLIT_FANCY(split_suffixes) + IF_NOT_FEATURE_SPLIT_FANCY(km_suffixes) + ); + sfx = "x"; + + argv += optind; + if (argv[0]) { + int fd; + if (argv[1]) + sfx = argv[1]; + fd = xopen_stdin(argv[0]); + xmove_fd(fd, STDIN_FILENO); + } else { + argv[0] = (char *) bb_msg_standard_input; + } + + if (NAME_MAX < strlen(sfx) + suffix_len) + bb_simple_error_msg_and_die("suffix too long"); + + { + char *char_p = xzalloc(suffix_len + 1); + memset(char_p, 'a', suffix_len); + pfx = xasprintf("%s%s", sfx, char_p); + if (ENABLE_FEATURE_CLEAN_UP) + free(char_p); + } + + while (1) { + bytes_read = safe_read(STDIN_FILENO, read_buffer, READ_BUFFER_SIZE); + if (!bytes_read) + break; + if (bytes_read < 0) + bb_simple_perror_msg_and_die(argv[0]); + src = read_buffer; + do { + if (!remaining) { + if (!pfx) + bb_simple_error_msg_and_die("suffixes exhausted"); + xmove_fd(xopen(pfx, O_WRONLY | O_CREAT | O_TRUNC), 1); + pfx = next_file(pfx, suffix_len); + remaining = cnt; + } + + if (opt & SPLIT_OPT_b) { + /* split by bytes */ + to_write = (bytes_read < remaining) ? bytes_read : remaining; + remaining -= to_write; + } else { + /* split by lines */ + /* can be sped up by using _memrchr_ + * and writing many lines at once... */ + char *end = memchr(src, '\n', bytes_read); + if (end) { + --remaining; + to_write = end - src + 1; + } else { + to_write = bytes_read; + } + } + + xwrite(STDOUT_FILENO, src, to_write); + bytes_read -= to_write; + src += to_write; + } while (bytes_read); + } + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/stat.c b/busybox-1_37_0/coreutils/stat.c new file mode 100644 index 000000000..2c2909e7e --- /dev/null +++ b/busybox-1_37_0/coreutils/stat.c @@ -0,0 +1,793 @@ +/* vi: set sw=4 ts=4: */ +/* + * stat -- display file or file system status + * + * Copyright (C) 2001, 2002, 2003, 2004, 2005 Free Software Foundation. + * Copyright (C) 2005 by Erik Andersen + * Copyright (C) 2005 by Mike Frysinger + * Copyright (C) 2006 by Yoshinori Sato + * + * Written by Michael Meskes + * Taken from coreutils and turned into a busybox applet by Mike Frysinger + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config STAT +//config: bool "stat (11 kb)" +//config: default y +//config: help +//config: display file or filesystem status. +//config: +//config:config FEATURE_STAT_FORMAT +//config: bool "Enable custom formats (-c)" +//config: default y +//config: depends on STAT +//config: help +//config: Without this, stat will not support the '-c format' option where +//config: users can pass a custom format string for output. This adds about +//config: 7k to a nonstatic build on amd64. +//config: +//config:config FEATURE_STAT_FILESYSTEM +//config: bool "Enable display of filesystem status (-f)" +//config: default y +//config: depends on STAT +//config: help +//config: Without this, stat will not support the '-f' option to display +//config: information about filesystem status. + +//applet:IF_STAT(APPLET_NOEXEC(stat, stat, BB_DIR_BIN, BB_SUID_DROP, stat)) + +//kbuild:lib-$(CONFIG_STAT) += stat.o + +//usage:#define stat_trivial_usage +//usage: "[-lt"IF_FEATURE_STAT_FILESYSTEM("f")"] "IF_FEATURE_STAT_FORMAT("[-c FMT] ")"FILE..." +//usage:#define stat_full_usage "\n\n" +//usage: "Display file" +//usage: IF_FEATURE_STAT_FILESYSTEM(" (default) or filesystem") +//usage: " status\n" +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n -c FMT Use the specified format" +//usage: ) +//usage: IF_FEATURE_STAT_FILESYSTEM( +//usage: "\n -f Display filesystem status" +//usage: ) +//usage: "\n -L Follow links" +//usage: "\n -t Terse display" +//usage: IF_SELINUX( +//usage: "\n -Z Print security context" +//usage: ) +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n\nFMT sequences"IF_FEATURE_STAT_FILESYSTEM(" for files")":\n" +//usage: " %a Access rights in octal\n" +//usage: " %A Access rights in human readable form\n" +//usage: " %b Number of blocks allocated (see %B)\n" +//usage: " %B Size in bytes of each block reported by %b\n" +//usage: " %d Device number in decimal\n" +//usage: " %D Device number in hex\n" +//usage: " %f Raw mode in hex\n" +//usage: " %F File type\n" +//usage: " %g Group ID\n" +//usage: " %G Group name\n" +//usage: " %h Number of hard links\n" +//usage: " %i Inode number\n" +//usage: " %n File name\n" +//usage: " %N File name, with -> TARGET if symlink\n" +//usage: " %o I/O block size\n" +//usage: " %s Total size in bytes\n" +//usage: " %t Major device type in hex\n" +//usage: " %T Minor device type in hex\n" +//usage: " %u User ID\n" +//usage: " %U User name\n" +//usage: " %x Time of last access\n" +//usage: " %X Time of last access as seconds since Epoch\n" +//usage: " %y Time of last modification\n" +//usage: " %Y Time of last modification as seconds since Epoch\n" +//usage: " %z Time of last change\n" +//usage: " %Z Time of last change as seconds since Epoch\n" +//usage: IF_FEATURE_STAT_FILESYSTEM( +//usage: "\nFMT sequences for file systems:\n" +//usage: " %a Free blocks available to non-superuser\n" +//usage: " %b Total data blocks\n" +//usage: " %c Total file nodes\n" +//usage: " %d Free file nodes\n" +//usage: " %f Free blocks\n" +//usage: IF_SELINUX( +//usage: " %C Security context in selinux\n" +//usage: ) +//usage: " %i File System ID in hex\n" +//usage: " %l Maximum length of filenames\n" +//usage: " %n File name\n" +//usage: " %s Block size (for faster transfer)\n" +//usage: " %S Fundamental block size (for block counts)\n" +//usage: " %t Type in hex\n" +//usage: " %T Type in human readable form" +//usage: ) +//usage: ) + +#include "libbb.h" +#include "common_bufsiz.h" + +enum { + OPT_TERSE = (1 << 0), + OPT_DEREFERENCE = (1 << 1), + OPT_FILESYS = (1 << 2) * ENABLE_FEATURE_STAT_FILESYSTEM, + OPT_SELINUX = (1 << (2+ENABLE_FEATURE_STAT_FILESYSTEM)) * ENABLE_SELINUX, +}; + +#if ENABLE_FEATURE_STAT_FORMAT +typedef bool (*statfunc_ptr)(const char *, const char *); +#else +typedef bool (*statfunc_ptr)(const char *); +#endif + +static const char *file_type(const struct stat *st) +{ + /* See POSIX 1003.1-2001 XCU Table 4-8 lines 17093-17107 + * for some of these formats. + * To keep diagnostics grammatical in English, the + * returned string must start with a consonant. + */ + if (S_ISREG(st->st_mode)) return st->st_size == 0 ? "regular empty file" : "regular file"; + if (S_ISDIR(st->st_mode)) return "directory"; + if (S_ISBLK(st->st_mode)) return "block special file"; + if (S_ISCHR(st->st_mode)) return "character special file"; + if (S_ISFIFO(st->st_mode)) return "fifo"; + if (S_ISLNK(st->st_mode)) return "symbolic link"; + if (S_ISSOCK(st->st_mode)) return "socket"; +#ifdef S_TYPEISMQ + if (S_TYPEISMQ(st)) return "message queue"; +#endif +#ifdef S_TYPEISSEM + if (S_TYPEISSEM(st)) return "semaphore"; +#endif +#ifdef S_TYPEISSHM + if (S_TYPEISSHM(st)) return "shared memory object"; +#endif +#ifdef S_TYPEISTMO + if (S_TYPEISTMO(st)) return "typed memory object"; +#endif + return "weird file"; +} + +static const char *human_time(struct timespec *ts) +{ + char fmt[sizeof("%Y-%m-%d %H:%M:%S.123456789 %z") + /*paranoia*/ 8]; + + /* coreutils 6.3 compat */ +#define buf bb_common_bufsiz1 + setup_common_bufsiz(); + + sprintf(stpcpy(fmt, "%Y-%m-%d %H:%M:%S"), ".%09u %%z", (unsigned)ts->tv_nsec); + strftime(buf, COMMON_BUFSIZE, fmt, localtime(&ts->tv_sec)); + return buf; +#undef buf +} + +#if ENABLE_FEATURE_STAT_FILESYSTEM +#define FS_TYPE_LIST \ +FS_TYPE(0xADFF, "affs") \ +FS_TYPE(0x1CD1, "devpts") \ +FS_TYPE(0x137D, "ext") \ +FS_TYPE(0xEF51, "ext2") \ +FS_TYPE(0xEF53, "ext2/ext3") \ +FS_TYPE(0x3153464a, "jfs") \ +FS_TYPE(0x58465342, "xfs") \ +FS_TYPE(0xF995E849, "hpfs") \ +FS_TYPE(0x9660, "isofs") \ +FS_TYPE(0x4000, "isofs") \ +FS_TYPE(0x4004, "isofs") \ +FS_TYPE(0x137F, "minix") \ +FS_TYPE(0x138F, "minix (30 char.)") \ +FS_TYPE(0x2468, "minix v2") \ +FS_TYPE(0x2478, "minix v2 (30 char.)") \ +FS_TYPE(0x4d44, "msdos") \ +FS_TYPE(0x4006, "fat") \ +FS_TYPE(0x564c, "novell") \ +FS_TYPE(0x6969, "nfs") \ +FS_TYPE(0x9fa0, "proc") \ +FS_TYPE(0x517B, "smb") \ +FS_TYPE(0x012FF7B4, "xenix") \ +FS_TYPE(0x012FF7B5, "sysv4") \ +FS_TYPE(0x012FF7B6, "sysv2") \ +FS_TYPE(0x012FF7B7, "coh") \ +FS_TYPE(0x00011954, "ufs") \ +FS_TYPE(0x012FD16D, "xia") \ +FS_TYPE(0x5346544e, "ntfs") \ +FS_TYPE(0x1021994, "tmpfs") \ +FS_TYPE(0x52654973, "reiserfs") \ +FS_TYPE(0x28cd3d45, "cramfs") \ +FS_TYPE(0x7275, "romfs") \ +FS_TYPE(0x858458f6, "ramfs") \ +FS_TYPE(0x73717368, "squashfs") \ +FS_TYPE(0x62656572, "sysfs") +/* Return the type of the specified file system. + * Some systems have statfvs.f_basetype[FSTYPSZ]. (AIX, HP-UX, and Solaris) + * Others have statfs.f_fstypename[MFSNAMELEN]. (NetBSD 1.5.2) + * Still others have neither and have to get by with f_type (Linux). + */ +static const char *human_fstype(uint32_t f_type) +{ +# define FS_TYPE(type, name) type, + static const uint32_t fstype[] ALIGN4 = { + FS_TYPE_LIST + }; +# undef FS_TYPE +# define FS_TYPE(type, name) name"\0" + static const char humanname[] ALIGN1 = + FS_TYPE_LIST + "UNKNOWN"; +# undef FS_TYPE + int i; + + for (i = 0; i < ARRAY_SIZE(fstype); ++i) + if (fstype[i] == f_type) + break; + return nth_string(humanname, i); +} + +/* "man statfs" says that statfsbuf->f_fsid is a mess */ +/* coreutils treats it as an array of ints, most significant first */ +static unsigned long long get_f_fsid(const struct statfs *statfsbuf) +{ + const unsigned *p = (const void*) &statfsbuf->f_fsid; + unsigned sz = sizeof(statfsbuf->f_fsid) / sizeof(unsigned); + unsigned long long r = 0; + + do + r = (r << (sizeof(unsigned)*8)) | *p++; + while (--sz > 0); + return r; +} +#endif /* FEATURE_STAT_FILESYSTEM */ + +#if ENABLE_FEATURE_STAT_FORMAT +static void strcatc(char *str, char c) +{ + int len = strlen(str); + str[len++] = c; + str[len] = '\0'; +} + +static void printfs(char *pformat, const char *msg) +{ + strcatc(pformat, 's'); + printf(pformat, msg); +} + +#if ENABLE_FEATURE_STAT_FILESYSTEM +/* print statfs info */ +static void FAST_FUNC print_statfs(char *pformat, const char m, + const char *const filename, const void *data + IF_SELINUX(, security_context_t scontext)) +{ + const struct statfs *statfsbuf = data; + if (m == 'n') { + printfs(pformat, filename); + } else if (m == 'i') { + strcat(pformat, "llx"); + printf(pformat, get_f_fsid(statfsbuf)); + } else if (m == 'l') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statfsbuf->f_namelen); + } else if (m == 't') { + strcat(pformat, "lx"); + printf(pformat, (unsigned long) statfsbuf->f_type); /* no equiv */ + } else if (m == 'T') { + printfs(pformat, human_fstype(statfsbuf->f_type)); + } else if (m == 'b') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statfsbuf->f_blocks); + } else if (m == 'f') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statfsbuf->f_bfree); + } else if (m == 'a') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statfsbuf->f_bavail); + } else if (m == 's' || m == 'S') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statfsbuf->f_bsize); + } else if (m == 'c') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statfsbuf->f_files); + } else if (m == 'd') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statfsbuf->f_ffree); +# if ENABLE_SELINUX + } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { + printfs(pformat, scontext); +# endif + } else { + strcatc(pformat, 'c'); + printf(pformat, m); + } +} +#endif + +/* print stat info */ +static void FAST_FUNC print_stat(char *pformat, const char m, + const char *const filename, const void *data + IF_SELINUX(, security_context_t scontext)) +{ +#define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) + struct stat *statbuf = (struct stat *) data; + struct passwd *pw_ent; + struct group *gw_ent; + + if (m == 'n') { + printfs(pformat, filename); + } else if (m == 'N') { + strcatc(pformat, 's'); + if (S_ISLNK(statbuf->st_mode)) { + char *linkname = xmalloc_readlink_or_warn(filename); + if (linkname == NULL) + return; + printf("'%s' -> '%s'", filename, linkname); + free(linkname); + } else { + printf(pformat, filename); + } + } else if (m == 'd') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statbuf->st_dev); + } else if (m == 'D') { + strcat(pformat, "llx"); + printf(pformat, (unsigned long long) statbuf->st_dev); + } else if (m == 'i') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statbuf->st_ino); + } else if (m == 'a') { + strcat(pformat, "lo"); + printf(pformat, (unsigned long) (statbuf->st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO))); + } else if (m == 'A') { + char modestr[12]; + printfs(pformat, bb_mode_string(modestr, statbuf->st_mode)); + } else if (m == 'f') { + strcat(pformat, "lx"); + printf(pformat, (unsigned long) statbuf->st_mode); + } else if (m == 'F') { + printfs(pformat, file_type(statbuf)); + } else if (m == 'h') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statbuf->st_nlink); + } else if (m == 'u') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statbuf->st_uid); + } else if (m == 'U') { + pw_ent = getpwuid(statbuf->st_uid); + printfs(pformat, (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN"); + } else if (m == 'g') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statbuf->st_gid); + } else if (m == 'G') { + gw_ent = getgrgid(statbuf->st_gid); + printfs(pformat, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN"); + } else if (m == 't') { + strcat(pformat, "lx"); + printf(pformat, (unsigned long) major(statbuf->st_rdev)); + } else if (m == 'T') { + strcat(pformat, "lx"); + printf(pformat, (unsigned long) minor(statbuf->st_rdev)); + } else if (m == 's') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statbuf->st_size); + } else if (m == 'B') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) 512); //ST_NBLOCKSIZE + } else if (m == 'b') { + strcat(pformat, "llu"); + printf(pformat, (unsigned long long) statbuf->st_blocks); + } else if (m == 'o') { + strcat(pformat, "lu"); + printf(pformat, (unsigned long) statbuf->st_blksize); + } else if (m == 'x') { + printfs(pformat, human_time(&statbuf->st_atim)); + } else if (m == 'X') { + strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); + /* note: (unsigned long) would be wrong: + * imagine (unsigned long64)int32 */ + printf(pformat, (long) statbuf->st_atime); + } else if (m == 'y') { + printfs(pformat, human_time(&statbuf->st_mtim)); + } else if (m == 'Y') { + strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); + printf(pformat, (long) statbuf->st_mtime); + } else if (m == 'z') { + printfs(pformat, human_time(&statbuf->st_ctim)); + } else if (m == 'Z') { + strcat(pformat, TYPE_SIGNED(time_t) ? "ld" : "lu"); + printf(pformat, (long) statbuf->st_ctime); +# if ENABLE_SELINUX + } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { + printfs(pformat, scontext); +# endif + } else { + strcatc(pformat, 'c'); + printf(pformat, m); + } +} + +static void print_it(const char *masterformat, + const char *filename, + void FAST_FUNC (*print_func)(char*, char, const char*, const void* IF_SELINUX(, security_context_t scontext)), + const void *data + IF_SELINUX(, security_context_t scontext)) +{ + /* Create a working copy of the format string */ + char *format = xstrdup(masterformat); + /* Add 2 to accommodate our conversion of the stat '%s' format string + * to the printf '%llu' one. */ + char *dest = xmalloc(strlen(format) + 2 + 1); + char *b; + + b = format; + while (b) { + /* Each iteration finds next %spec, + * prints preceding string and handles found %spec + */ + size_t len; + char *p = strchr(b, '%'); + if (!p) { + /* coreutils 6.3 always prints newline at the end */ + /*fputs(b, stdout);*/ + puts(b); + break; + } + + /* dest = "%" */ + len = 1 + strspn(p + 1, "#-+.I 0123456789"); + memcpy(dest, p, len); + dest[len] = '\0'; + + /* print preceding string */ + *p = '\0'; + fputs_stdout(b); + + p += len; + b = p + 1; + switch (*p) { + case '\0': + b = NULL; + /* fall through */ + case '%': + bb_putchar('%'); + break; + default: + /* Completes "%" with specifier and printfs */ + print_func(dest, *p, filename, data IF_SELINUX(,scontext)); + break; + } + } + + free(format); + free(dest); +} +#endif /* FEATURE_STAT_FORMAT */ + +#if ENABLE_FEATURE_STAT_FILESYSTEM +/* Stat the file system and print what we find. */ +#if !ENABLE_FEATURE_STAT_FORMAT +#define do_statfs(filename, format) do_statfs(filename) +#endif +static bool do_statfs(const char *filename, const char *format) +{ + struct statfs statfsbuf; +#if !ENABLE_FEATURE_STAT_FORMAT + const char *format; +#endif +#if ENABLE_SELINUX + security_context_t scontext = NULL; + + if (option_mask32 & OPT_SELINUX) { + if ((option_mask32 & OPT_DEREFERENCE + ? lgetfilecon(filename, &scontext) + : getfilecon(filename, &scontext) + ) < 0 + ) { + bb_simple_perror_msg(filename); + return 0; + } + } +#endif + if (statfs(filename, &statfsbuf) != 0) { + bb_perror_msg("can't read file system information for '%s'", filename); + return 0; + } + +#if ENABLE_FEATURE_STAT_FORMAT + if (format == NULL) { +# if !ENABLE_SELINUX + format = (option_mask32 & OPT_TERSE + ? "%n %i %l %t %s %b %f %a %c %d" + : " File: \"%n\"\n" + " ID: %-8i Namelen: %-7l Type: %T\n" + "Block size: %-10s\n" + "Blocks: Total: %-10b Free: %-10f Available: %a\n" + "Inodes: Total: %-10c Free: %d"); +# else + format = (option_mask32 & OPT_TERSE + ? (option_mask32 & OPT_SELINUX + ? "%n %i %l %t %s %b %f %a %c %d %C" + : "%n %i %l %t %s %b %f %a %c %d") + : (option_mask32 & OPT_SELINUX + ? " File: \"%n\"\n" + " ID: %-8i Namelen: %-7l Type: %T\n" + "Block size: %-10s\n" + "Blocks: Total: %-10b Free: %-10f Available: %a\n" + "Inodes: Total: %-10c Free: %d" + " S_context: %C" + : " File: \"%n\"\n" + " ID: %-8i Namelen: %-7l Type: %T\n" + "Block size: %-10s\n" + "Blocks: Total: %-10b Free: %-10f Available: %a\n" + "Inodes: Total: %-10c Free: %d") + ); +# endif /* SELINUX */ + } + print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext)); +#else /* !FEATURE_STAT_FORMAT */ + format = (option_mask32 & OPT_TERSE + ? "%s %llx %lu " + : " File: \"%s\"\n" + " ID: %-8llx Namelen: %-7lu "); + printf(format, + filename, + get_f_fsid(&statfsbuf), + statfsbuf.f_namelen); + + if (option_mask32 & OPT_TERSE) + printf("%lx ", (unsigned long) statfsbuf.f_type); + else + printf("Type: %s\n", human_fstype(statfsbuf.f_type)); + +# if !ENABLE_SELINUX + format = (option_mask32 & OPT_TERSE + ? "%lu %llu %llu %llu %llu %llu\n" + : "Block size: %-10lu\n" + "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n" + "Inodes: Total: %-10llu Free: %llu\n"); + printf(format, + (unsigned long) statfsbuf.f_bsize, + (unsigned long long) statfsbuf.f_blocks, + (unsigned long long) statfsbuf.f_bfree, + (unsigned long long) statfsbuf.f_bavail, + (unsigned long long) statfsbuf.f_files, + (unsigned long long) statfsbuf.f_ffree); +# else + format = (option_mask32 & OPT_TERSE + ? (option_mask32 & OPT_SELINUX ? "%lu %llu %llu %llu %llu %llu %C\n" : "%lu %llu %llu %llu %llu %llu\n") + : (option_mask32 & OPT_SELINUX + ? "Block size: %-10lu\n" + "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n" + "Inodes: Total: %-10llu Free: %llu" + "S_context: %C\n" + : "Block size: %-10lu\n" + "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n" + "Inodes: Total: %-10llu Free: %llu\n" + ) + ); + printf(format, + (unsigned long) statfsbuf.f_bsize, + (unsigned long long) statfsbuf.f_blocks, + (unsigned long long) statfsbuf.f_bfree, + (unsigned long long) statfsbuf.f_bavail, + (unsigned long long) statfsbuf.f_files, + (unsigned long long) statfsbuf.f_ffree, + scontext); + + if (scontext) + freecon(scontext); +# endif +#endif /* FEATURE_STAT_FORMAT */ + return 1; +} +#endif /* FEATURE_STAT_FILESYSTEM */ + +/* stat the file and print what we find */ +#if !ENABLE_FEATURE_STAT_FORMAT +#define do_stat(filename, format) do_stat(filename) +#endif +static bool do_stat(const char *filename, const char *format) +{ + struct stat statbuf; +#if ENABLE_SELINUX + security_context_t scontext = NULL; + + if (option_mask32 & OPT_SELINUX) { + if ((option_mask32 & OPT_DEREFERENCE + ? lgetfilecon(filename, &scontext) + : getfilecon(filename, &scontext) + ) < 0 + ) { + bb_simple_perror_msg(filename); + return 0; + } + } +#endif + if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) { + bb_perror_msg("can't stat '%s'", filename); + return 0; + } + +#if ENABLE_FEATURE_STAT_FORMAT + if (format == NULL) { +# if !ENABLE_SELINUX + if (option_mask32 & OPT_TERSE) { + format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; + } else { + if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { + format = + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z"; + } else { + format = + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z"; + } + } +# else + if (option_mask32 & OPT_TERSE) { + format = (option_mask32 & OPT_SELINUX ? + "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n" + : + "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n" + ); + } else { + if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { + format = (option_mask32 & OPT_SELINUX ? + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + " S_Context: %C\n" + "Access: %x\n" "Modify: %y\n" "Change: %z" + : + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z" + ); + } else { + format = (option_mask32 & OPT_SELINUX ? + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "S_Context: %C\n" + "Access: %x\n" "Modify: %y\n" "Change: %z" + : + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z" + ); + } + } +# endif + } + print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext)); +#else /* FEATURE_STAT_FORMAT */ + if (option_mask32 & OPT_TERSE) { + printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu" + IF_NOT_SELINUX("\n"), + filename, + (unsigned long long) statbuf.st_size, + (unsigned long long) statbuf.st_blocks, + (unsigned long) statbuf.st_mode, + (unsigned long) statbuf.st_uid, + (unsigned long) statbuf.st_gid, + (unsigned long long) statbuf.st_dev, + (unsigned long long) statbuf.st_ino, + (unsigned long) statbuf.st_nlink, + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev), + (unsigned long) statbuf.st_atime, + (unsigned long) statbuf.st_mtime, + (unsigned long) statbuf.st_ctime, + (unsigned long) statbuf.st_blksize + ); +# if ENABLE_SELINUX + if (option_mask32 & OPT_SELINUX) + printf(" %s\n", scontext); + else + bb_putchar('\n'); +# endif + } else { + char modestr[12]; + char *linkname = NULL; + struct passwd *pw_ent; + struct group *gw_ent; + + gw_ent = getgrgid(statbuf.st_gid); + pw_ent = getpwuid(statbuf.st_uid); + + if (S_ISLNK(statbuf.st_mode)) + linkname = xmalloc_readlink_or_warn(filename); + if (linkname) { + printf(" File: '%s' -> '%s'\n", filename, linkname); + free(linkname); + } else { + printf(" File: '%s'\n", filename); + } + + printf(" Size: %-10llu\tBlocks: %-10llu IO Block: %-6lu %s\n" + "Device: %llxh/%llud\tInode: %-10llu Links: %-5lu", + (unsigned long long) statbuf.st_size, + (unsigned long long) statbuf.st_blocks, + (unsigned long) statbuf.st_blksize, + file_type(&statbuf), + (unsigned long long) statbuf.st_dev, + (unsigned long long) statbuf.st_dev, + (unsigned long long) statbuf.st_ino, + (unsigned long) statbuf.st_nlink); + if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) + printf(" Device type: %lx,%lx\n", + (unsigned long) major(statbuf.st_rdev), + (unsigned long) minor(statbuf.st_rdev)); + else + bb_putchar('\n'); + printf("Access: (%04lo/%10.10s) Uid: (%5lu/%8s) Gid: (%5lu/%8s)\n", + (unsigned long) (statbuf.st_mode & (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)), + bb_mode_string(modestr, statbuf.st_mode), + (unsigned long) statbuf.st_uid, + (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN", + (unsigned long) statbuf.st_gid, + (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN"); +# if ENABLE_SELINUX + if (option_mask32 & OPT_SELINUX) + printf(" S_Context: %s\n", scontext); +# endif + printf("Access: %s\n", human_time(&statbuf.st_atim)); + printf("Modify: %s\n", human_time(&statbuf.st_mtim)); + printf("Change: %s\n", human_time(&statbuf.st_ctim)); + } +#endif /* FEATURE_STAT_FORMAT */ + return 1; +} + +int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int stat_main(int argc UNUSED_PARAM, char **argv) +{ + IF_FEATURE_STAT_FORMAT(char *format = NULL;) + int i; + int ok; + statfunc_ptr statfunc = do_stat; +#if ENABLE_FEATURE_STAT_FILESYSTEM || ENABLE_SELINUX + unsigned opts; + + opts = +#endif + getopt32(argv, "^" + "tL" + IF_FEATURE_STAT_FILESYSTEM("f") + IF_SELINUX("Z") + IF_FEATURE_STAT_FORMAT("c:") + "\0" "-1" /* min one arg */ + IF_FEATURE_STAT_FORMAT(,&format) + ); +#if ENABLE_FEATURE_STAT_FILESYSTEM + if (opts & OPT_FILESYS) /* -f */ + statfunc = do_statfs; +#endif +#if ENABLE_SELINUX + if (opts & OPT_SELINUX) { + selinux_or_die(); + } +#endif + ok = 1; + argv += optind; + for (i = 0; argv[i]; ++i) + ok &= statfunc(argv[i] IF_FEATURE_STAT_FORMAT(, format)); + + return (ok ? EXIT_SUCCESS : EXIT_FAILURE); +} diff --git a/busybox-1_37_0/coreutils/stty.c b/busybox-1_37_0/coreutils/stty.c new file mode 100644 index 000000000..c88ef07f4 --- /dev/null +++ b/busybox-1_37_0/coreutils/stty.c @@ -0,0 +1,1560 @@ +/* vi: set sw=4 ts=4: */ +/* + * stty -- change and print terminal line settings + * Copyright (C) 1990-1999 Free Software Foundation, Inc. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* David MacKenzie + * + * Special for busybox ported by Vladimir Oleynik 2001 + */ +//config:config STTY +//config: bool "stty (9.2 kb)" +//config: default y +//config: help +//config: stty is used to change and print terminal line settings. + +//applet:IF_STTY(APPLET_NOEXEC(stty, stty, BB_DIR_BIN, BB_SUID_DROP, stty)) + +//kbuild:lib-$(CONFIG_STTY) += stty.o + +//usage:#define stty_trivial_usage +//usage: "[-a|g] [-F DEVICE] [SETTING]..." +//usage:#define stty_full_usage "\n\n" +//usage: "Without arguments, prints baud rate, line discipline,\n" +//usage: "and deviations from stty sane\n" +//usage: "\n -F DEVICE Open device instead of stdin" +//usage: "\n -a Print all current settings in human-readable form" +//usage: "\n -g Print in stty-readable form" +//usage: "\n [SETTING] See manpage" + +/* 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. + */ + +#include "libbb.h" +#include "common_bufsiz.h" + +#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 +/* glibc-2.12.1 uses only VSWTC name */ +#if defined(VSWTC) && !defined(VSWTCH) +# define VSWTCH VSWTC +#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 + +/* Save us from #ifdef forest plague */ +#ifndef BSDLY +# define BSDLY 0 +#endif +#ifndef CIBAUD +# define CIBAUD 0 +#endif +#ifndef CRDLY +# define CRDLY 0 +#endif +#ifndef CMSPAR +# define CMSPAR 0 +#endif +#ifndef CRTSCTS +# define CRTSCTS 0 +#endif +#ifndef ECHOCTL +# define ECHOCTL 0 +#endif +#ifndef ECHOKE +# define ECHOKE 0 +#endif +#ifndef ECHOPRT +# define ECHOPRT 0 +#endif +#ifndef FFDLY +# define FFDLY 0 +#endif +#ifndef IEXTEN +# define IEXTEN 0 +#endif +#ifndef IMAXBEL +# define IMAXBEL 0 +#endif +#ifndef IUCLC +# define IUCLC 0 +#endif +#ifndef IXANY +# define IXANY 0 +#endif +#ifndef NLDLY +# define NLDLY 0 +#endif +#ifndef OCRNL +# define OCRNL 0 +#endif +#ifndef OFDEL +# define OFDEL 0 +#endif +#ifndef OFILL +# define OFILL 0 +#endif +#ifndef OLCUC +# define OLCUC 0 +#endif +#ifndef ONLCR +# define ONLCR 0 +#endif +#ifndef ONLRET +# define ONLRET 0 +#endif +#ifndef ONOCR +# define ONOCR 0 +#endif +#ifndef OXTABS +# define OXTABS 0 +#endif +#ifndef TABDLY +# define TABDLY 0 +#endif +#ifndef TAB1 +# define TAB1 0 +#endif +#ifndef TAB2 +# define TAB2 0 +#endif +#ifndef TOSTOP +# define TOSTOP 0 +#endif +#ifndef VDSUSP +# define VDSUSP 0 +#endif +#ifndef VEOL2 +# define VEOL2 0 +#endif +#ifndef VFLUSHO +# define VFLUSHO 0 +#endif +#ifndef VLNEXT +# define VLNEXT 0 +#endif +#ifndef VREPRINT +# define VREPRINT 0 +#endif +#ifndef VSTATUS +# define VSTATUS 0 +#endif +#ifndef VSWTCH +# define VSWTCH 0 +#endif +#ifndef VTDLY +# define VTDLY 0 +#endif +#ifndef VWERASE +# define VWERASE 0 +#endif +#ifndef XCASE +# define XCASE 0 +#endif +#ifndef IUTF8 +# define IUTF8 0 +#endif + +/* Which speeds to set */ +enum speed_setting { + input_speed, output_speed, both_speeds +}; + +/* Which member(s) of 'struct termios' a mode uses */ +enum { + control, input, output, local, combination +}; +static tcflag_t *get_ptr_to_tcflag(unsigned type, const struct termios *mode) +{ + static const uint8_t tcflag_offsets[] ALIGN1 = { + offsetof(struct termios, c_cflag), /* control */ + offsetof(struct termios, c_iflag), /* input */ + offsetof(struct termios, c_oflag), /* output */ + offsetof(struct termios, c_lflag) /* local */ + }; + if (type <= local) { + return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]); + } + return NULL; +} + +/* 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. + * This structure should be kept as small as humanly possible. + */ +struct mode_info { + const uint8_t type; /* Which structure element to change */ + const uint8_t flags; /* Setting and display options */ + /* only these values are ever used, so... */ +#if (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x100 + const uint8_t mask; +#elif (CSIZE | NLDLY | CRDLY | TABDLY | BSDLY | VTDLY | FFDLY) < 0x10000 + const uint16_t mask; +#else + const tcflag_t mask; /* Other bits to turn off for this mode */ +#endif + /* was using short here, but ppc32 was unhappy */ + const tcflag_t bits; /* Bits to set for this mode */ +}; + +enum { + /* Must match mode_name[] and mode_info[] order! */ + IDX_evenp = 0, + IDX_parity, + IDX_oddp, + IDX_nl, + IDX_ek, + IDX_sane, + IDX_cooked, + IDX_raw, + IDX_pass8, + IDX_litout, + IDX_cbreak, + IDX_crt, + IDX_dec, +#if IXANY + IDX_decctlq, +#endif +#if TABDLY || OXTABS + IDX_tabs, +#endif +#if XCASE && IUCLC && OLCUC + IDX_lcase, + IDX_LCASE, +#endif +}; + +#define MI_ENTRY(N,T,F,B,M) N "\0" + +/* Mode names given on command line */ +static const char mode_name[] ALIGN1 = + MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("ek", combination, OMIT, 0, 0 ) + MI_ENTRY("sane", combination, OMIT, 0, 0 ) + MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("crt", combination, OMIT, 0, 0 ) + MI_ENTRY("dec", combination, OMIT, 0, 0 ) +#if IXANY + MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) +#endif +#if TABDLY || OXTABS + MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) +#endif +#if XCASE && IUCLC && OLCUC + MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) +#endif + MI_ENTRY("parenb", control, REV, PARENB, 0 ) + MI_ENTRY("parodd", control, REV, PARODD, 0 ) +#if CMSPAR + MI_ENTRY("cmspar", control, REV, CMSPAR, 0 ) +#endif + MI_ENTRY("cs5", control, 0, CS5, CSIZE) + MI_ENTRY("cs6", control, 0, CS6, CSIZE) + MI_ENTRY("cs7", control, 0, CS7, CSIZE) + MI_ENTRY("cs8", control, 0, CS8, CSIZE) + MI_ENTRY("hupcl", control, REV, HUPCL, 0 ) + MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ) + MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) + MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) + MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) +#if CRTSCTS + MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) +#endif + MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) + MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ) + MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ) + MI_ENTRY("parmrk", input, REV, PARMRK, 0 ) + MI_ENTRY("inpck", input, REV, INPCK, 0 ) + MI_ENTRY("istrip", input, REV, ISTRIP, 0 ) + MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ) + MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ) + MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) + MI_ENTRY("ixon", input, REV, IXON, 0 ) + MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) +#if IUCLC + MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) +#endif +#if IXANY + MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) +#endif +#if IMAXBEL + MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) +#endif +#if IUTF8 + MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) +#endif + MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) +#if OLCUC + MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) +#endif +#if OCRNL + MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) +#endif +#if ONLCR + MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) +#endif +#if ONOCR + MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) +#endif +#if ONLRET + MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) +#endif +#if OFILL + MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) +#endif +#if OFDEL + MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) +#endif +#if NLDLY + MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) + MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) +#endif +#if CRDLY + MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY) + MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY) + MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY) + MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY) +#endif + +#if TABDLY + MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY) +# if TAB2 + MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY) +# endif +# if TAB1 + MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY) +# endif + MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY) +#else +# if OXTABS + MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) +# endif +#endif + +#if BSDLY + MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) + MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) +#endif +#if VTDLY + MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) + MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) +#endif +#if FFDLY + MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY) + MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY) +#endif + MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ) + MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ) +#if IEXTEN + MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) +#endif + MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) + MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) + MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) + MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) + MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) + MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) +#if XCASE + MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) +#endif +#if TOSTOP + MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) +#endif +#if ECHOPRT + MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) +#endif +#if ECHOCTL + MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) +#endif +#if ECHOKE + MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) +#endif + MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 ) +#ifdef EXTPROC + MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) +#endif + ; + +#undef MI_ENTRY +#define MI_ENTRY(N,T,F,B,M) { T, F, M, B }, + +static const struct mode_info mode_info[] ALIGN4 = { + /* This should be verbatim cut-n-paste copy of the above MI_ENTRYs */ + MI_ENTRY("evenp", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("parity", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("oddp", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("nl", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("ek", combination, OMIT, 0, 0 ) + MI_ENTRY("sane", combination, OMIT, 0, 0 ) + MI_ENTRY("cooked", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("raw", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("pass8", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("litout", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("crt", combination, OMIT, 0, 0 ) + MI_ENTRY("dec", combination, OMIT, 0, 0 ) +#if IXANY + MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) +#endif +#if TABDLY || OXTABS + MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) +#endif +#if XCASE && IUCLC && OLCUC + MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) + MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) +#endif + MI_ENTRY("parenb", control, REV, PARENB, 0 ) + MI_ENTRY("parodd", control, REV, PARODD, 0 ) +#if CMSPAR + MI_ENTRY("cmspar", control, REV, CMSPAR, 0 ) +#endif + MI_ENTRY("cs5", control, 0, CS5, CSIZE) + MI_ENTRY("cs6", control, 0, CS6, CSIZE) + MI_ENTRY("cs7", control, 0, CS7, CSIZE) + MI_ENTRY("cs8", control, 0, CS8, CSIZE) + MI_ENTRY("hupcl", control, REV, HUPCL, 0 ) + MI_ENTRY("hup", control, REV | OMIT, HUPCL, 0 ) + MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) + MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) + MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) +#if CRTSCTS + MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) +#endif + MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) + MI_ENTRY("brkint", input, SANE_SET | REV, BRKINT, 0 ) + MI_ENTRY("ignpar", input, REV, IGNPAR, 0 ) + MI_ENTRY("parmrk", input, REV, PARMRK, 0 ) + MI_ENTRY("inpck", input, REV, INPCK, 0 ) + MI_ENTRY("istrip", input, REV, ISTRIP, 0 ) + MI_ENTRY("inlcr", input, SANE_UNSET | REV, INLCR, 0 ) + MI_ENTRY("igncr", input, SANE_UNSET | REV, IGNCR, 0 ) + MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) + MI_ENTRY("ixon", input, REV, IXON, 0 ) + MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) +#if IUCLC + MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) +#endif +#if IXANY + MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) +#endif +#if IMAXBEL + MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) +#endif +#if IUTF8 + MI_ENTRY("iutf8", input, SANE_UNSET | REV, IUTF8, 0 ) +#endif + MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) +#if OLCUC + MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) +#endif +#if OCRNL + MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) +#endif +#if ONLCR + MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) +#endif +#if ONOCR + MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) +#endif +#if ONLRET + MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) +#endif +#if OFILL + MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) +#endif +#if OFDEL + MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) +#endif +#if NLDLY + MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) + MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) +#endif +#if CRDLY + MI_ENTRY("cr3", output, SANE_UNSET, CR3, CRDLY) + MI_ENTRY("cr2", output, SANE_UNSET, CR2, CRDLY) + MI_ENTRY("cr1", output, SANE_UNSET, CR1, CRDLY) + MI_ENTRY("cr0", output, SANE_SET, CR0, CRDLY) +#endif + +#if TABDLY + MI_ENTRY("tab3", output, SANE_UNSET, TAB3, TABDLY) +# if TAB2 + MI_ENTRY("tab2", output, SANE_UNSET, TAB2, TABDLY) +# endif +# if TAB1 + MI_ENTRY("tab1", output, SANE_UNSET, TAB1, TABDLY) +# endif + MI_ENTRY("tab0", output, SANE_SET, TAB0, TABDLY) +#else +# if OXTABS + MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) +# endif +#endif + +#if BSDLY + MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) + MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) +#endif +#if VTDLY + MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) + MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) +#endif +#if FFDLY + MI_ENTRY("ff1", output, SANE_UNSET, FF1, FFDLY) + MI_ENTRY("ff0", output, SANE_SET, FF0, FFDLY) +#endif + MI_ENTRY("isig", local, SANE_SET | REV, ISIG, 0 ) + MI_ENTRY("icanon", local, SANE_SET | REV, ICANON, 0 ) +#if IEXTEN + MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) +#endif + MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) + MI_ENTRY("echoe", local, SANE_SET | REV, ECHOE, 0 ) + MI_ENTRY("crterase", local, OMIT | REV, ECHOE, 0 ) + MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) + MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) + MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) +#if XCASE + MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) +#endif +#if TOSTOP + MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) +#endif +#if ECHOPRT + MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) +#endif +#if ECHOCTL + MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) +#endif +#if ECHOKE + MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) +#endif + MI_ENTRY("flusho", local, SANE_UNSET | REV, FLUSHO, 0 ) +#ifdef EXTPROC + MI_ENTRY("extproc", local, SANE_UNSET | REV, EXTPROC, 0 ) +#endif +}; + +enum { + NUM_mode_info = ARRAY_SIZE(mode_info) +}; + + +/* Control characters */ +struct control_info { + const uint8_t saneval; /* Value to set for 'stty sane' */ + const uint8_t offset; /* Offset in c_cc */ +}; + +enum { + /* Must match control_name[] and control_info[] order! */ + CIDX_intr = 0, + CIDX_quit, + CIDX_erase, + CIDX_kill, + CIDX_eof, + CIDX_eol, +#if VEOL2 + CIDX_eol2, +#endif +#if VSWTCH + CIDX_swtch, +#endif + CIDX_start, + CIDX_stop, + CIDX_susp, +#if VDSUSP + CIDX_dsusp, +#endif +#if VREPRINT + CIDX_rprnt, +#endif +#if VWERASE + CIDX_werase, +#endif +#if VLNEXT + CIDX_lnext, +#endif +#if VFLUSHO + CIDX_flush, +#endif +#if VSTATUS + CIDX_status, +#endif + CIDX_min, + CIDX_time, +}; + +#define CI_ENTRY(n,s,o) n "\0" + +/* Name given on command line */ +static const char control_name[] ALIGN1 = + CI_ENTRY("intr", CINTR, VINTR ) + CI_ENTRY("quit", CQUIT, VQUIT ) + CI_ENTRY("erase", CERASE, VERASE ) + CI_ENTRY("kill", CKILL, VKILL ) + CI_ENTRY("eof", CEOF, VEOF ) + CI_ENTRY("eol", CEOL, VEOL ) +#if VEOL2 + CI_ENTRY("eol2", CEOL2, VEOL2 ) +#endif +#if VSWTCH + CI_ENTRY("swtch", CSWTCH, VSWTCH ) +#endif + CI_ENTRY("start", CSTART, VSTART ) + CI_ENTRY("stop", CSTOP, VSTOP ) + CI_ENTRY("susp", CSUSP, VSUSP ) +#if VDSUSP + CI_ENTRY("dsusp", CDSUSP, VDSUSP ) +#endif +#if VREPRINT + CI_ENTRY("rprnt", CRPRNT, VREPRINT) +#endif +#if VWERASE + CI_ENTRY("werase", CWERASE, VWERASE ) +#endif +#if VLNEXT + CI_ENTRY("lnext", CLNEXT, VLNEXT ) +#endif +#if VFLUSHO + CI_ENTRY("flush", CFLUSHO, VFLUSHO ) +#endif +#if VSTATUS + CI_ENTRY("status", CSTATUS, VSTATUS ) +#endif + /* These must be last because of the display routines */ + CI_ENTRY("min", 1, VMIN ) + CI_ENTRY("time", 0, VTIME ) + ; + +#undef CI_ENTRY +#define CI_ENTRY(n,s,o) { s, o }, + +static const struct control_info control_info[] ALIGN2 = { + /* This should be verbatim cut-n-paste copy of the above CI_ENTRYs */ + CI_ENTRY("intr", CINTR, VINTR ) + CI_ENTRY("quit", CQUIT, VQUIT ) + CI_ENTRY("erase", CERASE, VERASE ) + CI_ENTRY("kill", CKILL, VKILL ) + CI_ENTRY("eof", CEOF, VEOF ) + CI_ENTRY("eol", CEOL, VEOL ) +#if VEOL2 + CI_ENTRY("eol2", CEOL2, VEOL2 ) +#endif +#if VSWTCH + CI_ENTRY("swtch", CSWTCH, VSWTCH ) +#endif + CI_ENTRY("start", CSTART, VSTART ) + CI_ENTRY("stop", CSTOP, VSTOP ) + CI_ENTRY("susp", CSUSP, VSUSP ) +#if VDSUSP + CI_ENTRY("dsusp", CDSUSP, VDSUSP ) +#endif +#if VREPRINT + CI_ENTRY("rprnt", CRPRNT, VREPRINT) +#endif +#if VWERASE + CI_ENTRY("werase", CWERASE, VWERASE ) +#endif +#if VLNEXT + CI_ENTRY("lnext", CLNEXT, VLNEXT ) +#endif +#if VFLUSHO + CI_ENTRY("flush", CFLUSHO, VFLUSHO ) +#endif +#if VSTATUS + CI_ENTRY("status", CSTATUS, VSTATUS ) +#endif + /* These must be last because of the display routines */ + CI_ENTRY("min", 1, VMIN ) + CI_ENTRY("time", 0, VTIME ) +}; + +enum { + NUM_control_info = ARRAY_SIZE(control_info) +}; + + +struct globals { + const char *device_name; + /* The width of the screen, for output wrapping */ + unsigned max_col; + /* Current position, to know when to wrap */ + unsigned current_col; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + G.device_name = bb_msg_standard_input; \ + G.max_col = 80; \ + G.current_col = 0; /* we are noexec, must clear */ \ +} while (0) + +static void set_speed_or_die(enum speed_setting type, const char *arg, + struct termios *mode) +{ + speed_t baud; + + baud = tty_value_to_baud(xatou(arg)); + + if (type != output_speed) { /* either input or both */ + cfsetispeed(mode, baud); + } + if (type != input_speed) { /* either output or both */ + cfsetospeed(mode, baud); + } +} + +static NORETURN void perror_on_device_and_die(const char *fmt) +{ + bb_perror_msg_and_die(fmt, G.device_name); +} + +static void perror_on_device(const char *fmt) +{ + bb_perror_msg(fmt, G.device_name); +} + +/* Print format string MESSAGE and optional args. + Wrap to next line first if it won't fit. + Print a space first unless MESSAGE will start a new line */ +static void wrapf(const char *message, ...) +{ + char buf[128]; + va_list args; + unsigned buflen; + + va_start(args, message); + buflen = vsnprintf(buf, sizeof(buf), message, args); + va_end(args); + /* We seem to be called only with suitable lengths, but check if + somebody failed to adhere to this assumption just to be sure. */ + if (!buflen || buflen >= sizeof(buf)) return; + + if (G.current_col > 0) { + G.current_col++; + if (buf[0] != '\n') { + if (G.current_col + buflen >= G.max_col) { + G.current_col = 0; + bb_putchar('\n'); + } else { + bb_putchar(' '); + } + } + } + fputs_stdout(buf); + G.current_col += buflen; + if (buf[buflen-1] == '\n') + G.current_col = 0; +} + +static void newline(void) +{ + if (G.current_col != 0) + wrapf("\n"); +} + +#ifdef TIOCGWINSZ +static void set_window_size(int rows, int cols) +{ + struct winsize win = { 0, 0, 0, 0 }; + + if (ioctl(STDIN_FILENO, TIOCGWINSZ, &win)) { + if (errno != EINVAL) { + goto bail; + } + memset(&win, 0, sizeof(win)); + } + + if (rows >= 0) + win.ws_row = rows; + if (cols >= 0) + win.ws_col = cols; + + if (ioctl(STDIN_FILENO, TIOCSWINSZ, (char *) &win)) +bail: + perror_on_device("%s"); +} +#endif + +static void display_window_size(int fancy) +{ + const char *fmt_str = "%s\0%s: no size information for this device"; + unsigned width, height; + + if (get_terminal_width_height(STDIN_FILENO, &width, &height)) { + if ((errno != EINVAL) || ((fmt_str += 2), !fancy)) { + perror_on_device(fmt_str); + } + } else { + wrapf(fancy ? "rows %u; columns %u;" : "%u %u\n", + height, width); + } +} + +static const struct suffix_mult stty_suffixes[] ALIGN_SUFFIX = { + { "b", 512 }, + { "k", 1024 }, + { "B", 1024 }, + { "", 0 } +}; + +static const struct mode_info *find_mode(const char *name) +{ + int i = index_in_strings(mode_name, name); + return i >= 0 ? &mode_info[i] : NULL; +} + +static const struct control_info *find_control(const char *name) +{ + int i = index_in_strings(control_name, name); + return i >= 0 ? &control_info[i] : NULL; +} + +enum { + param_need_arg = 0x80, + param_line = 1 | 0x80, + param_rows = 2 | 0x80, + param_cols = 3 | 0x80, + param_columns = 4 | 0x80, + param_size = 5, + param_speed = 6, + param_ispeed = 7 | 0x80, + param_ospeed = 8 | 0x80, +}; + +static int find_param(const char *name) +{ + static const char params[] ALIGN1 = + "line\0" /* 1 */ + "rows\0" /* 2 */ + "cols\0" /* 3 */ + "columns\0" /* 4 */ + "size\0" /* 5 */ + "speed\0" /* 6 */ + "ispeed\0" + "ospeed\0"; + int i = index_in_strings(params, name) + 1; + if (i == 0) + return 0; + if (i != 5 && i != 6) + i |= 0x80; + return i; +} + +static int recover_mode(const char *arg, struct termios *mode) +{ + int i, n; + unsigned 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; +} + +static void display_recoverable(const struct termios *mode, + int UNUSED_PARAM dummy) +{ + int i; + printf("%lx:%lx:%lx:%lx", + (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag, + (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag); + for (i = 0; i < NCCS; ++i) + printf(":%x", (unsigned int) mode->c_cc[i]); + bb_putchar('\n'); +} + +static void display_speed(const struct termios *mode, int fancy) +{ + //____________________ 01234567 8 9 + const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;"; + unsigned long ispeed, ospeed; + + ispeed = cfgetispeed(mode); + ospeed = cfgetospeed(mode); + if (ispeed == 0 || ispeed == ospeed) { + ispeed = ospeed; /* in case ispeed was 0 */ + //________ 0123 4 5 6 7 8 9 + fmt_str = "%lu\n\0\0\0\0\0speed %lu baud;"; + } + if (fancy) fmt_str += 9; + wrapf(fmt_str, tty_baud_to_value(ispeed), tty_baud_to_value(ospeed)); +} + +static void do_display(const struct termios *mode, int all) +{ + int i; + tcflag_t *bitsp; + unsigned long mask; + int prev_type = control; + + display_speed(mode, 1); + if (all) + display_window_size(1); +#ifdef __linux__ + wrapf("line = %u;\n", mode->c_line); +#else + newline(); +#endif + + for (i = 0; i != CIDX_min; ++i) { + char ch; + char buf10[10]; + + /* If swtch is the same as susp, don't print both */ +#if VSWTCH == VSUSP + if (i == CIDX_swtch) + continue; +#endif + /* If eof uses the same slot as min, only print whichever applies */ +#if VEOF == VMIN + if (!(mode->c_lflag & ICANON) + && (i == CIDX_eof || i == CIDX_eol) + ) { + continue; + } +#endif + ch = mode->c_cc[control_info[i].offset]; + if (ch == _POSIX_VDISABLE) + strcpy(buf10, ""); + else + visible(ch, buf10, 0); + wrapf("%s = %s;", nth_string(control_name, i), buf10); + } +#if VEOF == VMIN + if ((mode->c_lflag & ICANON) == 0) +#endif + wrapf("min = %u; time = %u;", mode->c_cc[VMIN], mode->c_cc[VTIME]); + newline(); + + for (i = 0; i < NUM_mode_info; ++i) { + if (mode_info[i].flags & OMIT) + continue; + if (mode_info[i].type != prev_type) { + newline(); + prev_type = mode_info[i].type; + } + + bitsp = get_ptr_to_tcflag(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 (all || (mode_info[i].flags & SANE_UNSET)) + wrapf("-%s"+1, nth_string(mode_name, i)); + } else { + if ((all && mode_info[i].flags & REV) + || (!all && (mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) + ) { + wrapf("-%s", nth_string(mode_name, i)); + } + } + } + newline(); +} + +static void sane_mode(struct termios *mode) +{ + int i; + + for (i = 0; i < NUM_control_info; ++i) { +#if VMIN == VEOF + if (i == CIDX_min) + break; +#endif + mode->c_cc[control_info[i].offset] = control_info[i].saneval; + } + + for (i = 0; i < NUM_mode_info; ++i) { + tcflag_t val; + tcflag_t *bitsp = get_ptr_to_tcflag(mode_info[i].type, mode); + + if (!bitsp) + continue; + val = *bitsp & ~((unsigned long)mode_info[i].mask); + if (mode_info[i].flags & SANE_SET) { + *bitsp = val | mode_info[i].bits; + } else + if (mode_info[i].flags & SANE_UNSET) { + *bitsp = val & ~mode_info[i].bits; + } + } +} + +static void set_mode(const struct mode_info *info, int reversed, + struct termios *mode) +{ + tcflag_t *bitsp; + + bitsp = get_ptr_to_tcflag(info->type, mode); + + if (bitsp) { + tcflag_t val = *bitsp & ~info->mask; + if (reversed) + *bitsp = val & ~info->bits; + else + *bitsp = val | info->bits; + return; + } + + /* !bitsp - it's a "combination" mode */ + if (info == &mode_info[IDX_evenp] || info == &mode_info[IDX_parity]) { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; + } else if (info == &mode_info[IDX_oddp]) { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; + } else if (info == &mode_info[IDX_nl]) { + if (reversed) { + mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; + mode->c_oflag = (mode->c_oflag | ONLCR) & ~OCRNL & ~ONLRET; + } else { + mode->c_iflag = mode->c_iflag & ~ICRNL; + if (ONLCR) mode->c_oflag = mode->c_oflag & ~ONLCR; + } + } else if (info == &mode_info[IDX_ek]) { + mode->c_cc[VERASE] = CERASE; + mode->c_cc[VKILL] = CKILL; + } else if (info == &mode_info[IDX_sane]) { + sane_mode(mode); + } else if (info == &mode_info[IDX_cbreak]) { + if (reversed) + mode->c_lflag |= ICANON; + else + mode->c_lflag &= ~ICANON; + } else if (info == &mode_info[IDX_pass8]) { + if (reversed) { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + } else { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + } + } else if (info == &mode_info[IDX_litout]) { + if (reversed) { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + mode->c_oflag |= OPOST; + } else { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + mode->c_oflag &= ~OPOST; + } + } else if (info == &mode_info[IDX_raw] || info == &mode_info[IDX_cooked]) { + if ((info == &mode_info[IDX_raw] && reversed) + || (info == &mode_info[IDX_cooked] && !reversed) + ) { + /* Cooked mode */ + mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; + mode->c_oflag |= OPOST; + mode->c_lflag |= ISIG | ICANON; +#if VMIN == VEOF + mode->c_cc[VEOF] = CEOF; +#endif +#if VTIME == VEOL + mode->c_cc[VEOL] = CEOL; +#endif + } else { + /* Raw mode */ + mode->c_iflag = 0; + mode->c_oflag &= ~OPOST; + mode->c_lflag &= ~(ISIG | ICANON | XCASE); + mode->c_cc[VMIN] = 1; + mode->c_cc[VTIME] = 0; + } + } +#if IXANY + else if (info == &mode_info[IDX_decctlq]) { + if (reversed) + mode->c_iflag |= IXANY; + else + mode->c_iflag &= ~IXANY; + } +#endif +#if TABDLY + else if (info == &mode_info[IDX_tabs]) { + if (reversed) + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; + else + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; + } +#endif +#if OXTABS + else if (info == &mode_info[IDX_tabs]) { + if (reversed) + mode->c_oflag |= OXTABS; + else + mode->c_oflag &= ~OXTABS; + } +#endif +#if XCASE && IUCLC && OLCUC + else if (info==&mode_info[IDX_lcase] || info==&mode_info[IDX_LCASE]) { + if (reversed) { + mode->c_lflag &= ~XCASE; + mode->c_iflag &= ~IUCLC; + mode->c_oflag &= ~OLCUC; + } else { + mode->c_lflag |= XCASE; + mode->c_iflag |= IUCLC; + mode->c_oflag |= OLCUC; + } + } +#endif + else if (info == &mode_info[IDX_crt]) { + mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; + } else if (info == &mode_info[IDX_dec]) { + mode->c_cc[VINTR] = 3; /* ^C */ + mode->c_cc[VERASE] = 127; /* DEL */ + mode->c_cc[VKILL] = 21; /* ^U */ + mode->c_lflag |= ECHOE | ECHOCTL | ECHOKE; + if (IXANY) mode->c_iflag &= ~IXANY; + } +} + +static void set_control_char_or_die(const struct control_info *info, + const char *arg, struct termios *mode) +{ + unsigned char value; + + if (info == &control_info[CIDX_min] || info == &control_info[CIDX_time]) + value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); + else if (arg[0] == '\0' || arg[1] == '\0') + value = arg[0]; + else if (strcmp(arg, "^-") == 0 || strcmp(arg, "undef") == 0) + value = _POSIX_VDISABLE; + else if (arg[0] == '^') { /* Ignore any trailing junk (^Cjunk) */ + value = arg[1] & 0x1f; /* Non-letters get weird results */ + if (arg[1] == '?') + value = 127; + } else + value = xatoul_range_sfx(arg, 0, 0xff, stty_suffixes); + mode->c_cc[info->offset] = value; +} + +#define STTY_require_set_attr (1 << 0) +#define STTY_speed_was_set (1 << 1) +#define STTY_verbose_output (1 << 2) +#define STTY_recoverable_output (1 << 3) +#define STTY_noargs (1 << 4) + +int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int stty_main(int argc UNUSED_PARAM, char **argv) +{ + struct termios mode; + void (*output_func)(const struct termios *, int); + const char *file_name = NULL; + int display_all = 0; + int stty_state; + int k; + + INIT_G(); + + stty_state = STTY_noargs; + output_func = do_display; + + /* First pass: only parse/verify command line params */ + k = 0; + while (argv[++k]) { + const struct mode_info *mp; + const struct control_info *cp; + const char *arg = argv[k]; + const char *argnext = argv[k+1]; + int param; + + if (arg[0] == '-') { + int i; + mp = find_mode(arg+1); + if (mp) { + if (!(mp->flags & REV)) + goto invalid_argument; + stty_state &= ~STTY_noargs; + continue; + } + /* It is an option - parse it */ + i = 0; + while (arg[++i]) { + switch (arg[i]) { + case 'a': + stty_state |= STTY_verbose_output; + output_func = do_display; + display_all = 1; + break; + case 'g': + stty_state |= STTY_recoverable_output; + output_func = display_recoverable; + break; + case 'F': + if (file_name) + bb_simple_error_msg_and_die("only one device may be specified"); + file_name = &arg[i+1]; /* "-Fdevice" ? */ + if (!file_name[0]) { /* nope, "-F device" */ + int p = k+1; /* argv[p] is argnext */ + file_name = argnext; + if (!file_name) + bb_error_msg_and_die(bb_msg_requires_arg, "-F"); + /* remove -F param from arg[vc] */ + while (argv[p]) { + argv[p] = argv[p+1]; + ++p; + } + } + goto end_option; + default: + goto invalid_argument; + } + } + end_option: + continue; + } + + mp = find_mode(arg); + if (mp) { + stty_state &= ~STTY_noargs; + continue; + } + + cp = find_control(arg); + if (cp) { + if (!argnext) + bb_error_msg_and_die(bb_msg_requires_arg, arg); + /* called for the side effect of xfunc death only */ + set_control_char_or_die(cp, argnext, &mode); + stty_state &= ~STTY_noargs; + ++k; + continue; + } + + param = find_param(arg); + if (param & param_need_arg) { + if (!argnext) + bb_error_msg_and_die(bb_msg_requires_arg, arg); + ++k; + } + + switch (param) { +#ifdef __linux__ + case param_line: +# ifndef TIOCGWINSZ + xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); + break; +# endif /* else fall-through */ +#endif +#ifdef TIOCGWINSZ + case param_rows: + case param_cols: + case param_columns: + xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); + break; + case param_size: +#endif + case param_speed: + break; + case param_ispeed: + /* called for the side effect of xfunc death only */ + set_speed_or_die(input_speed, argnext, &mode); + break; + case param_ospeed: + /* called for the side effect of xfunc death only */ + set_speed_or_die(output_speed, argnext, &mode); + break; + default: + if (recover_mode(arg, &mode) == 1) break; + if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) break; + invalid_argument: + bb_error_msg_and_die("invalid argument '%s'", arg); + } + stty_state &= ~STTY_noargs; + } + + /* Specifying both -a and -g is an error */ + if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == + (STTY_verbose_output | STTY_recoverable_output) + ) { + bb_simple_error_msg_and_die("-a and -g are mutually exclusive"); + } + /* Specifying -a or -g with non-options is an error */ + if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) + && !(stty_state & STTY_noargs) + ) { + bb_simple_error_msg_and_die("modes may not be set when -a or -g is used"); + } + + /* Now it is safe to start doing things */ + if (file_name) { + G.device_name = file_name; + xmove_fd(xopen_nonblocking(G.device_name), STDIN_FILENO); + ndelay_off(STDIN_FILENO); + } + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure */ + memset(&mode, 0, sizeof(mode)); + if (tcgetattr(STDIN_FILENO, &mode)) + perror_on_device_and_die("%s"); + + if (stty_state & (STTY_verbose_output | STTY_recoverable_output | STTY_noargs)) { + G.max_col = get_terminal_width(STDOUT_FILENO); + output_func(&mode, display_all); + return EXIT_SUCCESS; + } + + /* Second pass: perform actions */ + k = 0; + while (argv[++k]) { + const struct mode_info *mp; + const struct control_info *cp; + const char *arg = argv[k]; + const char *argnext = argv[k+1]; + int param; + + if (arg[0] == '-') { + mp = find_mode(arg+1); + if (mp) { + set_mode(mp, 1 /* reversed */, &mode); + stty_state |= STTY_require_set_attr; + } + /* It is an option - already parsed. Skip it */ + continue; + } + + mp = find_mode(arg); + if (mp) { + set_mode(mp, 0 /* non-reversed */, &mode); + stty_state |= STTY_require_set_attr; + continue; + } + + cp = find_control(arg); + if (cp) { + ++k; + set_control_char_or_die(cp, argnext, &mode); + stty_state |= STTY_require_set_attr; + continue; + } + + param = find_param(arg); + if (param & param_need_arg) { + ++k; + } + + switch (param) { +#ifdef __linux__ + case param_line: + mode.c_line = xatoul_sfx(argnext, stty_suffixes); + stty_state |= STTY_require_set_attr; + break; +#endif +#ifdef TIOCGWINSZ + case param_cols: + case param_columns: + set_window_size(-1, xatoul_sfx(argnext, stty_suffixes)); + break; + case param_size: + display_window_size(0); + break; + case param_rows: + set_window_size(xatoul_sfx(argnext, stty_suffixes), -1); + break; +#endif + case param_speed: + display_speed(&mode, 0); + break; + case param_ispeed: + set_speed_or_die(input_speed, argnext, &mode); + stty_state |= (STTY_require_set_attr | STTY_speed_was_set); + break; + case param_ospeed: + set_speed_or_die(output_speed, argnext, &mode); + stty_state |= (STTY_require_set_attr | STTY_speed_was_set); + break; + default: + if (recover_mode(arg, &mode) == 1) + stty_state |= STTY_require_set_attr; + else /* true: if (tty_value_to_baud(xatou(arg)) != (speed_t) -1) */{ + set_speed_or_die(both_speeds, arg, &mode); + stty_state |= (STTY_require_set_attr | STTY_speed_was_set); + } /* else - impossible (caught in the first pass): + bb_error_msg_and_die("invalid argument '%s'", arg); */ + } + } + + if (stty_state & STTY_require_set_attr) { + struct termios new_mode; + + if (tcsetattr(STDIN_FILENO, TCSADRAIN, &mode)) + perror_on_device_and_die("%s"); + + /* POSIX (according to Zlotnick's book) tcsetattr returns zero if + it performs *any* of the requested operations. This means it + can report 'success' when it has actually failed to perform + some proper subset of the requested operations. To detect + this partial failure, get the current terminal attributes and + compare them to the requested ones */ + + /* Initialize to all zeroes so there is no risk memcmp will report a + spurious difference in an uninitialized portion of the structure */ + memset(&new_mode, 0, sizeof(new_mode)); + if (tcgetattr(STDIN_FILENO, &new_mode)) + perror_on_device_and_die("%s"); + + if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { +/* + * I think the below chunk is not necessary on Linux. + * If you are deleting it, also delete STTY_speed_was_set bit - + * it is only ever checked here. + */ +#if 0 /* was "if CIBAUD" */ + /* SunOS 4.1.3 (at least) has the problem that after this sequence, + tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); + sometimes (m1 != m2). The only difference is in the four bits + of the c_cflag field corresponding to the baud rate. To save + Sun users a little confusion, don't report an error if this + happens. But suppress the error only if we haven't tried to + set the baud rate explicitly -- otherwise we'd never give an + error for a true failure to set the baud rate */ + + new_mode.c_cflag &= (~CIBAUD); + if ((stty_state & STTY_speed_was_set) + || memcmp(&mode, &new_mode, sizeof(mode)) != 0) +#endif + perror_on_device_and_die("%s: cannot perform all requested operations"); + } + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/sum.c b/busybox-1_37_0/coreutils/sum.c new file mode 100644 index 000000000..78e69acc6 --- /dev/null +++ b/busybox-1_37_0/coreutils/sum.c @@ -0,0 +1,118 @@ +/* vi: set sw=4 ts=4: */ +/* + * sum -- checksum and count the blocks in a file + * Like BSD sum or SysV sum -r, except like SysV sum if -s option is given. + * + * Copyright (C) 86, 89, 91, 1995-2002, 2004 Free Software Foundation, Inc. + * Copyright (C) 2005 by Erik Andersen + * Copyright (C) 2005 by Mike Frysinger + * + * Written by Kayvan Aghaiepour and David MacKenzie + * Taken from coreutils and turned into a busybox applet by Mike Frysinger + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SUM +//config: bool "sum (4.2 kb)" +//config: default y +//config: help +//config: checksum and count the blocks in a file + +//applet:IF_SUM(APPLET(sum, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SUM) += sum.o + +//usage:#define sum_trivial_usage +//usage: "[-rs] [FILE]..." +//usage:#define sum_full_usage "\n\n" +//usage: "Checksum and count the blocks in a file\n" +//usage: "\n -r Use BSD sum algorithm (1K blocks)" +//usage: "\n -s Use System V sum algorithm (512byte blocks)" + +#include "libbb.h" +#include "common_bufsiz.h" + +enum { SUM_BSD, PRINT_NAME, SUM_SYSV }; + +/* BSD: calculate and print the rotated checksum and the size in 1K blocks + The checksum varies depending on sizeof (int). */ +/* SYSV: calculate and print the checksum and the size in 512-byte blocks */ +/* Return 1 if successful. */ +static unsigned sum_file(const char *file, unsigned type) +{ + unsigned long long total_bytes = 0; + int fd, r; + /* The sum of all the input bytes, modulo (UINT_MAX + 1). */ + unsigned s = 0; + +#define buf bb_common_bufsiz1 + setup_common_bufsiz(); + + fd = open_or_warn_stdin(file); + if (fd == -1) + return 0; + + while (1) { + size_t bytes_read = safe_read(fd, buf, COMMON_BUFSIZE); + + if ((ssize_t)bytes_read <= 0) { + r = (fd && close(fd) != 0); + if (!bytes_read && !r) + /* no error */ + break; + bb_simple_perror_msg(file); + return 0; + } + + total_bytes += bytes_read; + if (type >= SUM_SYSV) { + do s += buf[--bytes_read]; while (bytes_read); + } else { + r = 0; + do { + s = (s >> 1) + ((s & 1) << 15); + s += buf[r++]; + s &= 0xffff; /* Keep it within bounds. */ + } while (--bytes_read); + } + } + + if (type < PRINT_NAME) + file = ""; + if (type >= SUM_SYSV) { + r = (s & 0xffff) + ((s & 0xffffffff) >> 16); + s = (r & 0xffff) + (r >> 16); + printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); + } else + printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); + return 1; +#undef buf +} + +int sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sum_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned n; + unsigned type = SUM_BSD; + + n = getopt32(argv, "sr"); + argv += optind; + if (n & 1) type = SUM_SYSV; + /* give the bsd priority over sysv func */ + if (n & 2) type = SUM_BSD; + + if (!argv[0]) { + /* Do not print the name */ + n = sum_file("-", type); + } else { + /* Need to print the name if either + * - more than one file given + * - doing sysv */ + type += (argv[1] || type == SUM_SYSV); + n = 1; + do { + n &= sum_file(*argv, type); + } while (*++argv); + } + return !n; +} diff --git a/busybox-1_37_0/coreutils/sync.c b/busybox-1_37_0/coreutils/sync.c new file mode 100644 index 000000000..b6a4a4b70 --- /dev/null +++ b/busybox-1_37_0/coreutils/sync.c @@ -0,0 +1,140 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini sync implementation for busybox + * + * Copyright (C) 1995, 1996 by Bruce Perens . + * Copyright (C) 2015 by Ari Sundholm + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config SYNC +//config: bool "sync (4 kb)" +//config: default y +//config: help +//config: sync is used to flush filesystem buffers. +//config:config FEATURE_SYNC_FANCY +//config: bool "Enable -d and -f flags (requires syncfs(2) in libc)" +//config: default y +//config: depends on SYNC +//config: help +//config: sync -d FILE... executes fdatasync() on each FILE. +//config: sync -f FILE... executes syncfs() on each FILE. + +// APPLET_NOFORK:name main location suid_type help +//applet:IF_SYNC(APPLET_NOFORK(sync, sync, BB_DIR_BIN, BB_SUID_DROP, sync)) + +//kbuild:lib-$(CONFIG_SYNC) += sync.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define sync_trivial_usage +//usage: ""IF_FEATURE_SYNC_FANCY("[-df] [FILE]...") +//usage:#define sync_full_usage "\n\n" +//usage: IF_NOT_FEATURE_SYNC_FANCY( +//usage: "Write all buffered blocks to disk" +//usage: ) +//usage: IF_FEATURE_SYNC_FANCY( +//usage: "Write all buffered blocks (in FILEs) to disk" +//usage: "\n -d Avoid syncing metadata" +//usage: "\n -f Sync filesystems underlying FILEs" +//usage: ) + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +#if ENABLE_FEATURE_SYNC_FANCY || ENABLE_FSYNC +static int sync_common(int opts, char **argv) +{ + int ret; + enum { + OPT_DATASYNC = (1 << 0), + OPT_SYNCFS = (1 << 1), + }; + + ret = EXIT_SUCCESS; + do { + /* GNU "sync FILE" uses O_NONBLOCK open */ + int fd = open_or_warn(*argv, /*O_NOATIME |*/ O_NOCTTY | O_RDONLY | O_NONBLOCK); + /* open(NOATIME) can only be used by owner or root, don't use NOATIME here */ + + if (fd < 0) { + ret = EXIT_FAILURE; + goto next; + } +# if ENABLE_FEATURE_SYNC_FANCY + if (opts & OPT_SYNCFS) { + /* + * syncfs is documented to only fail with EBADF, + * which can't happen here. So, no error checks. + */ + syncfs(fd); + } else +# endif + if (((opts & OPT_DATASYNC) ? fdatasync(fd) : fsync(fd)) != 0) { + bb_simple_perror_msg(*argv); + ret = EXIT_FAILURE; + } + close(fd); + next: + argv++; + } while (*argv); + + return ret; +} +#endif + +#if ENABLE_SYNC +int sync_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sync_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) +{ +# if !ENABLE_FEATURE_SYNC_FANCY + /* coreutils-6.9 compat */ + bb_warn_ignoring_args(argv[1]); + sync(); + return EXIT_SUCCESS; +# else + unsigned opts = getopt32(argv, "^" "df" "\0" "d--f:f--d"); + argv += optind; + if (!argv[0]) { + sync(); + return EXIT_SUCCESS; + } + return sync_common(opts, argv); +# endif +} +#endif + +/* + * Mini fsync implementation for busybox + * + * Copyright (C) 2008 Nokia Corporation. All rights reserved. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config FSYNC +//config: bool "fsync (3.8 kb)" +//config: default y +//config: help +//config: fsync is used to flush file-related cached blocks to disk. + +// APPLET_NOFORK:name main location suid_type help +//applet:IF_FSYNC(APPLET_NOFORK(fsync, fsync, BB_DIR_BIN, BB_SUID_DROP, fsync)) + +//kbuild:lib-$(CONFIG_FSYNC) += sync.o + +//usage:#define fsync_trivial_usage +//usage: "[-d] FILE..." +//usage:#define fsync_full_usage "\n\n" +//usage: "Write all buffered blocks in FILEs to disk\n" +//usage: "\n -d Avoid syncing metadata" + +#if ENABLE_FSYNC +int fsync_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fsync_main(int argc UNUSED_PARAM, char **argv) +{ + int opts = getopt32(argv, "^" "d" "\0" "-1"/*min 1 arg*/); + argv += optind; + return sync_common(opts, argv); +} +#endif diff --git a/busybox-1_37_0/coreutils/tac.c b/busybox-1_37_0/coreutils/tac.c new file mode 100644 index 000000000..6d3ea9c19 --- /dev/null +++ b/busybox-1_37_0/coreutils/tac.c @@ -0,0 +1,117 @@ +/* vi: set sw=4 ts=4: */ +/* + * tac implementation for busybox + * tac - concatenate and print files in reverse + * + * Copyright (C) 2003 Yang Xiaopeng + * Copyright (C) 2007 Natanael Copa + * Copyright (C) 2007 Tito Ragusa + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +/* Based on Yang Xiaopeng's (yxp at hanwang.com.cn) patch + * http://www.uclibc.org/lists/busybox/2003-July/008813.html + */ +//config:config TAC +//config: bool "tac (4.1 kb)" +//config: default y +//config: help +//config: tac is used to concatenate and print files in reverse. + +//applet:IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) + +//kbuild:lib-$(CONFIG_TAC) += tac.o + +//usage:#define tac_trivial_usage +//usage: "[FILE]..." +//usage:#define tac_full_usage "\n\n" +//usage: "Concatenate FILEs and print them in reverse" + +#include "libbb.h" + +/* This is a NOEXEC applet. Be very careful! */ + +struct lstring { + int size; + char buf[1]; +}; + +int tac_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tac_main(int argc UNUSED_PARAM, char **argv) +{ + char **name; + FILE *f; + struct lstring *line = NULL; + llist_t *list = NULL; + int retval = EXIT_SUCCESS; + +#if ENABLE_DESKTOP +/* tac from coreutils 6.9 supports: + -b, --before + attach the separator before instead of after + -r, --regex + interpret the separator as a regular expression + -s, --separator=STRING + use STRING as the separator instead of newline +We support none, but at least we will complain or handle "--": +*/ + getopt32(argv, ""); + argv += optind; +#else + argv++; +#endif + if (!*argv) + *--argv = (char *)"-"; + /* We will read from last file to first */ + name = argv; + while (*name) + name++; + + do { + int ch, i; + + name--; + f = fopen_or_warn_stdin(*name); + if (f == NULL) { + /* error message is printed by fopen_or_warn_stdin */ + retval = EXIT_FAILURE; + continue; + } + + errno = i = 0; + do { + ch = fgetc(f); + if (ch != EOF) { + if (!(i & 0x7f)) + /* Grow on every 128th char */ + line = xrealloc(line, i + 0x7f + sizeof(int) + 1); + line->buf[i++] = ch; + } + if (ch == '\n' || (ch == EOF && i != 0)) { + line = xrealloc(line, i + sizeof(int)); + line->size = i; + llist_add_to(&list, line); + line = NULL; + i = 0; + } + } while (ch != EOF); + /* fgetc sets errno to ENOENT on EOF, we don't want + * to warn on this non-error! */ + if (errno && errno != ENOENT) { + bb_simple_perror_msg(*name); + retval = EXIT_FAILURE; + } + } while (name != argv); + + while (list) { + line = (struct lstring *)list->data; + xwrite(STDOUT_FILENO, line->buf, line->size); + if (ENABLE_FEATURE_CLEAN_UP) { + free(llist_pop(&list)); + } else { + list = list->link; + } + } + + return retval; +} diff --git a/busybox-1_37_0/coreutils/tail.c b/busybox-1_37_0/coreutils/tail.c new file mode 100644 index 000000000..4680295b9 --- /dev/null +++ b/busybox-1_37_0/coreutils/tail.c @@ -0,0 +1,421 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tail implementation for busybox + * + * Copyright (C) 2001 by Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Pretty much rewritten to fix numerous bugs and reduce realloc() calls. + * Bugs fixed (although I may have forgotten one or two... it was pretty bad) + * 1) mixing printf/write without fflush()ing stdout + * 2) no check that any open files are present + * 3) optstring had -q taking an arg + * 4) no error checking on write in some cases, and a warning even then + * 5) q and s interaction bug + * 6) no check for lseek error + * 7) lseek attempted when count==0 even if arg was +0 (from top) + */ +//config:config TAIL +//config: bool "tail (7.2 kb)" +//config: default y +//config: help +//config: tail is used to print the last specified number of lines +//config: from files. +//config: +//config:config FEATURE_FANCY_TAIL +//config: bool "Enable -q, -s, -v, and -F options" +//config: default y +//config: depends on TAIL +//config: help +//config: These options are provided by GNU tail, but +//config: are not specified in the SUSv3 standard: +//config: -q Never output headers giving file names +//config: -s SEC Wait SEC seconds between reads with -f +//config: -v Always output headers giving file names +//config: -F Same as -f, but keep retrying + +//applet:IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TAIL) += tail.o + +/* BB_AUDIT SUSv3 compliant (need fancy for -c) */ +/* BB_AUDIT GNU compatible -c, -q, and -v options in 'fancy' configuration. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/tail.html */ + +//usage:#define tail_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define tail_full_usage "\n\n" +//usage: "Print last 10 lines of FILEs (or stdin) to.\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -c [+]N[bkm] Print last N bytes" +//usage: "\n -n N[bkm] Print last N lines" +//usage: "\n -n +N[bkm] Start on Nth line and print the rest" +//usage: "\n (b:*512 k:*1024 m:*1024^2)" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: ) +//usage: "\n -f Print data as file grows" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -F Same as -f, but keep retrying" +//usage: "\n -s SECONDS Wait SECONDS between reads with -f" +//usage: ) +//usage: +//usage:#define tail_example_usage +//usage: "$ tail -n 1 /etc/resolv.conf\n" +//usage: "nameserver 10.0.0.1\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +struct globals { + bool from_top; + bool exitcode; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { setup_common_bufsiz(); } while (0) + +static void tail_xprint_header(const char *fmt, const char *filename) +{ + if (fdprintf(STDOUT_FILENO, fmt, filename) < 0) + bb_perror_nomsg_and_die(); +} + +static ssize_t tail_read(int fd, char *buf, size_t count) +{ + ssize_t r; + + r = full_read(fd, buf, count); + if (r < 0) { + bb_simple_perror_msg(bb_msg_read_error); + G.exitcode = EXIT_FAILURE; + } + + return r; +} + +#define header_fmt_str "\n==> %s <==\n" + +static unsigned eat_num(const char *p) +{ + if (*p == '-') + p++; + else if (*p == '+') { + p++; + G.from_top = 1; + } + return xatou_sfx(p, bkm_suffixes); +} + +int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tail_main(int argc, char **argv) +{ + unsigned count = 10; + unsigned sleep_period = 1; + const char *str_c, *str_n; + + char *tailbuf; + size_t tailbufsize; + unsigned header_threshold = 1; + unsigned nfiles; + int i, opt; + + int *fds; + const char *fmt; + int prev_fd; + + INIT_G(); + +#if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_TAIL + /* Allow legacy syntax of an initial numeric option without -n. */ + if (argv[1] && (argv[1][0] == '+' || argv[1][0] == '-') + && isdigit(argv[1][1]) + ) { + count = eat_num(argv[1]); + argv++; + argc--; + } +#endif + + /* -s NUM, -F imlies -f */ + opt = getopt32(argv, IF_FEATURE_FANCY_TAIL("^") + "fc:n:"IF_FEATURE_FANCY_TAIL("qs:+vF") + IF_FEATURE_FANCY_TAIL("\0" "Ff"), + &str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period) + ); +#define FOLLOW (opt & 0x1) +#define COUNT_BYTES (opt & 0x2) + //if (opt & 0x1) // -f + if (opt & 0x2) count = eat_num(str_c); // -c + if (opt & 0x4) count = eat_num(str_n); // -n +#if ENABLE_FEATURE_FANCY_TAIL + /* q: make it impossible for nfiles to be > header_threshold */ + if (opt & 0x8) header_threshold = UINT_MAX; // -q + //if (opt & 0x10) // -s + if (opt & 0x20) header_threshold = 0; // -v +# define FOLLOW_RETRY (opt & 0x40) +#else +# define FOLLOW_RETRY 0 +#endif + argc -= optind; + argv += optind; + + /* open all the files */ + fds = xmalloc(sizeof(fds[0]) * (argc + 1)); + if (!argv[0]) { + struct stat statbuf; + + if (fstat(STDIN_FILENO, &statbuf) == 0 + && S_ISFIFO(statbuf.st_mode) + ) { + opt &= ~1; /* clear FOLLOW */ + } + argv[0] = (char *) bb_msg_standard_input; + } + nfiles = i = 0; + do { + int fd = open_or_warn_stdin(argv[i]); + if (fd < 0 && !FOLLOW_RETRY) { + G.exitcode = EXIT_FAILURE; + continue; + } + fds[nfiles] = fd; + argv[nfiles++] = argv[i]; + } while (++i < argc); + + if (!nfiles) + bb_simple_error_msg_and_die("no files"); + + /* prepare the buffer */ + tailbufsize = BUFSIZ; + if (!G.from_top && COUNT_BYTES) { + if (tailbufsize < count + BUFSIZ) { + tailbufsize = count + BUFSIZ; + } + } + /* tail -c1024m REGULAR_FILE doesn't really need 1G mem block. + * (In fact, it doesn't need ANY memory). So delay allocation. + */ + tailbuf = NULL; + + /* tail the files */ + + fmt = header_fmt_str + 1; /* skip leading newline in the header on the first output */ + i = 0; + do { + char *buf; + int taillen; + int newlines_seen; + unsigned seen; + int nread; + int fd = fds[i]; + + if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) + continue; /* may happen with -F */ + + if (nfiles > header_threshold) { + tail_xprint_header(fmt, argv[i]); + fmt = header_fmt_str; + } + + if (!G.from_top) { + off_t current = lseek(fd, 0, SEEK_END); + if (current > 0) { + unsigned off; + if (COUNT_BYTES) { + /* Optimizing count-bytes case if the file is seekable. + * Beware of backing up too far. + * Also we exclude files with size 0 (because of /proc/xxx) */ + if (count == 0) + continue; /* showing zero bytes is easy :) */ + current -= count; + if (current < 0) + current = 0; + xlseek(fd, current, SEEK_SET); + bb_copyfd_size(fd, STDOUT_FILENO, count); + continue; + } +#if 1 /* This is technically incorrect for *LONG* strings, but very useful */ + /* Optimizing count-lines case if the file is seekable. + * We assume the lines are <64k. + * (Users complain that tail takes too long + * on multi-gigabyte files) */ + off = (count | 0xf); /* for small counts, be more paranoid */ + if (off > (INT_MAX / (64*1024))) + off = (INT_MAX / (64*1024)); + current -= off * (64*1024); + if (current < 0) + current = 0; + xlseek(fd, current, SEEK_SET); +#endif + } + } + + if (!tailbuf) + tailbuf = xmalloc(tailbufsize); + + buf = tailbuf; + taillen = 0; + /* "We saw 1st line/byte". + * Used only by +N code ("start from Nth", 1-based): */ + seen = 1; + newlines_seen = 0; + while ((nread = tail_read(fd, buf, tailbufsize - taillen)) > 0) { + if (G.from_top) { + int nwrite = nread; + if (seen < count) { + /* We need to skip a few more bytes/lines */ + if (COUNT_BYTES) { + nwrite -= (count - seen); + seen += nread; + } else { + char *s = buf; + do { + --nwrite; + if (*s++ == '\n' && ++seen == count) { + break; + } + } while (nwrite); + } + } + if (nwrite > 0) + xwrite(STDOUT_FILENO, buf + nread - nwrite, nwrite); + } else if (count) { + if (COUNT_BYTES) { + taillen += nread; + if (taillen > (int)count) { + memmove(tailbuf, tailbuf + taillen - count, count); + taillen = count; + } + } else { + int k = nread; + int newlines_in_buf = 0; + + do { /* count '\n' in last read */ + k--; + if (buf[k] == '\n') { + newlines_in_buf++; + } + } while (k); + + if (newlines_seen + newlines_in_buf < (int)count) { + newlines_seen += newlines_in_buf; + taillen += nread; + } else { + int extra = (buf[nread-1] != '\n'); + char *s; + + k = newlines_seen + newlines_in_buf + extra - count; + s = tailbuf; + while (k) { + if (*s == '\n') { + k--; + } + s++; + } + taillen += nread - (s - tailbuf); + memmove(tailbuf, s, taillen); + newlines_seen = count - extra; + } + if (tailbufsize < (size_t)taillen + BUFSIZ) { + tailbufsize = taillen + BUFSIZ; + tailbuf = xrealloc(tailbuf, tailbufsize); + } + } + buf = tailbuf + taillen; + } + } /* while (tail_read() > 0) */ + if (!G.from_top) { + xwrite(STDOUT_FILENO, tailbuf, taillen); + } + } while (++i < nfiles); + prev_fd = fds[i-1]; + + tailbuf = xrealloc(tailbuf, BUFSIZ); + + fmt = NULL; + + if (FOLLOW) while (1) { + sleep(sleep_period); + + i = 0; + do { + int nread; + const char *filename = argv[i]; + int fd = fds[i]; + int new_fd = -1; + struct stat sbuf; + + if (FOLLOW_RETRY) { + struct stat fsbuf; + + if (fd < 0 + || fstat(fd, &fsbuf) < 0 + || stat(filename, &sbuf) < 0 + || fsbuf.st_dev != sbuf.st_dev + || fsbuf.st_ino != sbuf.st_ino + ) { + /* Looks like file has been created/renamed/deleted */ + new_fd = open(filename, O_RDONLY); + if (new_fd >= 0) { + bb_error_msg("%s has %s; following end of new file", + filename, (fd < 0) ? "appeared" : "been replaced" + ); + if (fd < 0) { + /* No previously open fd for this file, + * start using new_fd immediately. */ + fds[i] = fd = new_fd; + new_fd = -1; + } + } else if (fd >= 0) { + bb_perror_msg("%s has been renamed or deleted", filename); + } + } + } + if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) + continue; + if (nfiles > header_threshold) { + fmt = header_fmt_str; + } + for (;;) { + /* tail -f keeps following files even if they are truncated */ + /* /proc files report zero st_size, don't lseek them */ + if (fstat(fd, &sbuf) == 0 + /* && S_ISREG(sbuf.st_mode) TODO? */ + && sbuf.st_size > 0 + ) { + off_t current = lseek(fd, 0, SEEK_CUR); + if (sbuf.st_size < current) { + //bb_perror_msg("%s: file truncated", filename); - says coreutils 8.32 + xlseek(fd, 0, SEEK_SET); + } + } + + nread = tail_read(fd, tailbuf, BUFSIZ); + if (nread <= 0) { + if (new_fd < 0) + break; + /* Switch to "tail -F"ing the new file */ + xmove_fd(new_fd, fd); + new_fd = -1; + continue; + } + if (fmt && (fd != prev_fd)) { + tail_xprint_header(fmt, filename); + fmt = NULL; + prev_fd = fd; + } + xwrite(STDOUT_FILENO, tailbuf, nread); + } + } while (++i < nfiles); + } /* while (1) */ + + if (ENABLE_FEATURE_CLEAN_UP) { + free(fds); + free(tailbuf); + } + return G.exitcode; +} diff --git a/busybox-1_37_0/coreutils/tee.c b/busybox-1_37_0/coreutils/tee.c new file mode 100644 index 000000000..603fd3ad4 --- /dev/null +++ b/busybox-1_37_0/coreutils/tee.c @@ -0,0 +1,153 @@ +/* vi: set sw=4 ts=4: */ +/* + * tee implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config TEE +//config: bool "tee (4.4 kb)" +//config: default y +//config: help +//config: tee is used to read from standard input and write +//config: to standard output and files. +//config: +//config:config FEATURE_TEE_USE_BLOCK_IO +//config: bool "Enable block I/O (larger/faster) instead of byte I/O" +//config: default y +//config: depends on TEE +//config: help +//config: Enable this option for a faster tee, at expense of size. + +//applet:IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TEE) += tee.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/tee.html */ + +//usage:#define tee_trivial_usage +//usage: "[-ai] [FILE]..." +//usage:#define tee_full_usage "\n\n" +//usage: "Copy stdin to each FILE, and also to stdout\n" +//usage: "\n -a Append to the given FILEs, don't overwrite" +//usage: "\n -i Ignore interrupt signals (SIGINT)" +//usage: +//usage:#define tee_example_usage +//usage: "$ echo \"Hello\" | tee /tmp/foo\n" +//usage: "$ cat /tmp/foo\n" +//usage: "Hello\n" + +// Bare "tee" with no below options does not install SIGPIPE handler - just dies on it. +// TODO: +// --output-error[=MODE] +// 'warn' diagnose errors writing to any output +// 'warn-nopipe' diagnose errors writing to any output not a pipe +// 'exit' exit on error writing to any output +// 'exit-nopipe' exit on error writing to any output not a pipe +// ^^^ all of these should set SIGPIPE to SIG_IGN. +// Because "exit" mode should print error message and exit1(1) - not die on SIGPIPE. +// "exit-nopipe" does not exit on EPIPE and does not set exitcode to 1 too. +// -p diagnose errors writing to non pipes +// ^^^^ this should set SIGPIPE to SIG_IGN. EPIPE is ignored (same as "warn-nopipe") + +#include "libbb.h" +#include "common_bufsiz.h" + +int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tee_main(int argc, char **argv) +{ + const char *mode = "w\0a"; + FILE **files; + FILE **fp; + char **names; + char **np; + char retval; +//TODO: make unconditional +#if ENABLE_FEATURE_TEE_USE_BLOCK_IO + ssize_t c; +# define buf bb_common_bufsiz1 + setup_common_bufsiz(); +#else + int c; +#endif + retval = getopt32(argv, "ia"); /* 'a' must be 2nd */ + argc -= optind; + argv += optind; + + mode += (retval & 2); /* Since 'a' is the 2nd option... */ + + if (retval & 1) { + signal(SIGINT, SIG_IGN); + } + retval = EXIT_SUCCESS; + /* if (opt_p || opt_output_error) + signal(SIGPIPE, SIG_IGN); + */ + + /* Allocate an array of FILE *'s, with one extra for a sentinel. */ + fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); + np = names = argv - 1; + + files[0] = stdout; + goto GOT_NEW_FILE; + + do { + *fp = stdout; + if (NOT_LONE_DASH(*argv)) { + *fp = fopen_or_warn(*argv, mode); + if (*fp == NULL) { + retval = EXIT_FAILURE; + argv++; + continue; + } + } + *np = *argv++; + GOT_NEW_FILE: + setbuf(*fp, NULL); /* tee must not buffer output. */ + fp++; + np++; + } while (*argv); + /* names[0] will be filled later */ + +#if ENABLE_FEATURE_TEE_USE_BLOCK_IO + while ((c = safe_read(STDIN_FILENO, buf, COMMON_BUFSIZE)) > 0) { + fp = files; + do + fwrite(buf, 1, c, *fp); + /* if (opt_p && fwrite() != c && !EPIPE) bb_error_msg("..."); */ + while (*++fp); + } + if (c < 0) { /* Make sure read errors are signaled. */ + retval = EXIT_FAILURE; + } +#else + setvbuf(stdout, NULL, _IONBF, 0); + while ((c = getchar()) != EOF) { + fp = files; + do + putc(c, *fp); + /* if (opt_p && putc() == EOF && !EPIPE) bb_error_msg("..."); */ + while (*++fp); + } +#endif + + /* Now we need to check for i/o errors on stdin and the various + * output files. Since we know that the first entry in the output + * file table is stdout, we can save one "if ferror" test by + * setting the first entry to stdin and checking stdout error + * status with fflush_stdout_and_exit()... although fflush()ing + * is unnecessary here. */ + np = names; + fp = files; + names[0] = (char *) bb_msg_standard_input; + files[0] = stdin; + do { /* Now check for input and output errors. */ + /* Checking ferror should be sufficient, but we may want to fclose. + * If we do, remember not to close stdin! */ + die_if_ferror(*fp++, *np++); + } while (*fp); + + fflush_stdout_and_exit(retval); +} diff --git a/busybox-1_37_0/coreutils/test.c b/busybox-1_37_0/coreutils/test.c new file mode 100644 index 000000000..008d90b25 --- /dev/null +++ b/busybox-1_37_0/coreutils/test.c @@ -0,0 +1,1028 @@ +/* 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. + * modified by Bernhard Reutner-Fischer to be useable (i.e. a bit less bloaty). + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Original copyright notice states: + * "This program is in the Public Domain." + */ +//config:config TEST +//config: bool "test (4.4 kb)" +//config: default y +//config: help +//config: test is used to check file types and compare values, +//config: returning an appropriate exit code. The bash shell +//config: has test built in, ash can build it in optionally. +//config: +//config:config TEST1 +//config: bool "test as [" +//config: default y +//config: help +//config: Provide test command in the "[ EXPR ]" form +//config: +//config:config TEST2 +//config: bool "test as [[" +//config: default y +//config: help +//config: Provide test command in the "[[ EXPR ]]" form +//config: +//config:config FEATURE_TEST_64 +//config: bool "Extend test to 64 bit" +//config: default y +//config: depends on TEST || TEST1 || TEST2 || ASH_TEST || HUSH_TEST +//config: help +//config: Enable 64-bit support in test. + +//applet:IF_TEST(APPLET_NOFORK(test, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +//applet:IF_TEST1(APPLET_NOFORK([, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +//applet:IF_TEST2(APPLET_NOFORK([[, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) + +//kbuild:lib-$(CONFIG_TEST) += test.o test_ptr_hack.o +//kbuild:lib-$(CONFIG_TEST1) += test.o test_ptr_hack.o +//kbuild:lib-$(CONFIG_TEST2) += test.o test_ptr_hack.o + +//kbuild:lib-$(CONFIG_ASH_TEST) += test.o test_ptr_hack.o +//kbuild:lib-$(CONFIG_HUSH_TEST) += test.o test_ptr_hack.o + +/* "test --help" is special-cased to ignore --help */ +//usage:#define test_trivial_usage NOUSAGE_STR +//usage:#define test_full_usage "" +//usage: +//usage:#define test_example_usage +//usage: "$ test 1 -eq 2\n" +//usage: "$ echo $?\n" +//usage: "1\n" +//usage: "$ test 1 -eq 1\n" +//usage: "$ echo $?\n" +//usage: "0\n" +//usage: "$ [ -d /etc ]\n" +//usage: "$ echo $?\n" +//usage: "0\n" +//usage: "$ [ -d /junk ]\n" +//usage: "$ echo $?\n" +//usage: "1\n" + +#include "libbb.h" +#include +#include + +/* This is a NOFORK applet. Be very careful! */ + +/* test_main() is called from shells, and we need to be extra careful here. + * This is true regardless of PREFER_APPLETS and SH_STANDALONE + * state. */ + +/* 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 ::= +*/ + +/* TODO: handle [[ expr ]] bashism bash-compatibly. + * [[ ]] is meant to be a "better [ ]", with less weird syntax + * and without the risk of variables and quoted strings misinterpreted + * as operators. + * This will require support from shells - we need to know quote status + * of each parameter (see below). + * + * Word splitting and pathname expansion should NOT be performed: + * # a="a b"; [[ $a = "a b" ]] && echo YES + * YES + * # [[ /bin/m* ]] && echo YES + * YES + * + * =~ should do regexp match + * = and == should do pattern match against right side: + * # [[ *a* == bab ]] && echo YES + * # [[ bab == *a* ]] && echo YES + * YES + * != does the negated == (i.e., also with pattern matching). + * Pattern matching is quotation-sensitive: + * # [[ bab == "b"a* ]] && echo YES + * YES + * # [[ bab == b"a*" ]] && echo YES + * + * Conditional operators such as -f must be unquoted literals to be recognized: + * # [[ -e /bin ]] && echo YES + * YES + * # [[ '-e' /bin ]] && echo YES + * bash: conditional binary operator expected... + * # A='-e'; [[ $A /bin ]] && echo YES + * bash: conditional binary operator expected... + * + * || and && should work as -o and -a work in [ ] + * -a and -o aren't recognized (&& and || are to be used instead) + * ( and ) do not need to be quoted unlike in [ ]: + * # [[ ( abc ) && '' ]] && echo YES + * # [[ ( abc ) || '' ]] && echo YES + * YES + * # [[ ( abc ) -o '' ]] && echo YES + * bash: syntax error in conditional expression... + * + * Apart from the above, [[ expr ]] should work as [ expr ] + */ + +#define TEST_DEBUG 0 + +#if ENABLE_TEST2 \ + || (ENABLE_ASH_BASH_COMPAT && ENABLE_ASH_TEST) \ + || (ENABLE_HUSH_BASH_COMPAT && ENABLE_HUSH_TEST) +# define BASH_TEST2 1 +#else +# define BASH_TEST2 0 +#endif + +enum token { + EOI, + + FILRD, /* file access */ + FILWR, + FILEX, + + FILEXIST, + + FILREG, /* file type */ + FILDIR, + FILCDEV, + FILBDEV, + FILFIFO, + FILSOCK, + + FILSYM, + FILGZ, + FILTT, + + FILSUID, /* file bit */ + FILSGID, + FILSTCK, + + FILNT, /* file ops */ + FILOT, + FILEQ, + + FILUID, + FILGID, + + STREZ, /* str ops */ + STRNZ, + STREQ, + STRNE, + STRLT, + STRGT, + +#if BASH_TEST2 + REGEX, +#endif + + INTEQ, /* int ops */ + INTNE, + INTGE, + INTGT, + INTLE, + INTLT, + + UNOT, + BAND, + BOR, + LPAREN, + RPAREN, + OPERAND +}; +#define is_int_op(a) (((unsigned char)((a) - INTEQ)) <= 5) +#define is_str_op(a) (((unsigned char)((a) - STREZ)) <= 5) +#define is_file_op(a) (((unsigned char)((a) - FILNT)) <= 2) +#define is_file_access(a) (((unsigned char)((a) - FILRD)) <= 2) +#define is_file_type(a) (((unsigned char)((a) - FILREG)) <= 5) +#define is_file_bit(a) (((unsigned char)((a) - FILSUID)) <= 2) + +#if TEST_DEBUG +int depth; +#define nest_msg(...) do { \ + depth++; \ + fprintf(stderr, "%*s", depth*2, ""); \ + fprintf(stderr, __VA_ARGS__); \ +} while (0) +#define unnest_msg(...) do { \ + fprintf(stderr, "%*s", depth*2, ""); \ + fprintf(stderr, __VA_ARGS__); \ + depth--; \ +} while (0) +#define dbg_msg(...) do { \ + fprintf(stderr, "%*s", depth*2, ""); \ + fprintf(stderr, __VA_ARGS__); \ +} while (0) +#define unnest_msg_and_return(expr, ...) do { \ + number_t __res = (expr); \ + fprintf(stderr, "%*s", depth*2, ""); \ + fprintf(stderr, __VA_ARGS__, res); \ + depth--; \ + return __res; \ +} while (0) +static const char *const TOKSTR[] ALIGN_PTR = { + "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", +#if BASH_TEST2 + "REGEX", +#endif + "INTEQ", + "INTNE", + "INTGE", + "INTGT", + "INTLE", + "INTLT", + "UNOT", + "BAND", + "BOR", + "LPAREN", + "RPAREN", + "OPERAND" +}; +#else +#define nest_msg(...) ((void)0) +#define unnest_msg(...) ((void)0) +#define dbg_msg(...) ((void)0) +#define unnest_msg_and_return(expr, ...) return expr +#endif + +enum { + UNOP, + BINOP, + BUNOP, + BBINOP, + PAREN +}; + +struct operator_t { + unsigned char op_num, op_type; +}; + +static const struct operator_t ops_table[] ALIGN2 = { + { /* "-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 }, + /* "==" is bashism, http://pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html + * lists only "=" as comparison operator. + */ + { /* "==" */ STREQ , BINOP }, + { /* "!=" */ STRNE , BINOP }, + { /* "<" */ STRLT , BINOP }, + { /* ">" */ STRGT , BINOP }, +#if BASH_TEST2 + { /* "=~" */ REGEX , BINOP }, +#endif + { /* "-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 }, +#if BASH_TEST2 + { /* "&&" */ BAND , BBINOP }, + { /* "||" */ BOR , BBINOP }, +#endif + { /* "(" */ LPAREN , PAREN }, + { /* ")" */ RPAREN , PAREN }, +}; +/* Please keep these two tables in sync */ +static const char ops_texts[] ALIGN1 = + "-r" "\0" + "-w" "\0" + "-x" "\0" + "-e" "\0" + "-f" "\0" + "-d" "\0" + "-c" "\0" + "-b" "\0" + "-p" "\0" + "-u" "\0" + "-g" "\0" + "-k" "\0" + "-s" "\0" + "-t" "\0" + "-z" "\0" + "-n" "\0" + "-h" "\0" + + "-O" "\0" + "-G" "\0" + "-L" "\0" + "-S" "\0" + "=" "\0" + /* "==" is bashism */ + "==" "\0" + "!=" "\0" + "<" "\0" + ">" "\0" +#if BASH_TEST2 + "=~" "\0" +#endif + "-eq" "\0" + "-ne" "\0" + "-ge" "\0" + "-gt" "\0" + "-le" "\0" + "-lt" "\0" + "-nt" "\0" + "-ot" "\0" + "-ef" "\0" + "!" "\0" + "-a" "\0" + "-o" "\0" +#if BASH_TEST2 + "&&" "\0" + "||" "\0" +#endif + "(" "\0" + ")" "\0" +; + + +#if ENABLE_FEATURE_TEST_64 +typedef int64_t number_t; +#else +typedef int number_t; +#endif + + +/* We try to minimize both static and stack usage. */ +struct test_statics { + char **args; + /* set only by check_operator(), either to bogus struct + * or points to matching operator_t struct. Never NULL. */ + const struct operator_t *last_operator; + gid_t *group_array; + int ngroups; +#if BASH_TEST2 + bool bash_test2; +#endif + jmp_buf leaving; +}; + +/* See test_ptr_hack.c */ +extern struct test_statics *BB_GLOBAL_CONST test_ptr_to_statics; + +#define S (*test_ptr_to_statics) +#define args (S.args ) +#define last_operator (S.last_operator) +#define group_array (S.group_array ) +#define ngroups (S.ngroups ) +#define bash_test2 (S.bash_test2 ) +#define leaving (S.leaving ) + +#define INIT_S() do { \ + XZALLOC_CONST_PTR(&test_ptr_to_statics, sizeof(S)); \ +} while (0) +#define DEINIT_S() do { \ + free(group_array); \ + free(test_ptr_to_statics); \ +} while (0) + +static number_t primary(enum token n); + +static void syntax(const char *op, const char *msg) NORETURN; +static void syntax(const char *op, const char *msg) +{ + if (op && *op) { + bb_error_msg("%s: %s", op, msg); + } else { + bb_error_msg("%s: %s"+4, msg); + } + longjmp(leaving, 2); +} + +/* atoi with error detection */ +//XXX: FIXME: duplicate of existing libbb function? +static number_t getn(const char *s) +{ + char *p; +#if ENABLE_FEATURE_TEST_64 + long long r; +#else + long r; +#endif + + errno = 0; +#if ENABLE_FEATURE_TEST_64 + r = strtoll(s, &p, 10); +#else + r = strtol(s, &p, 10); +#endif + + if (errno != 0) + syntax(s, "out of range"); + + if (p == s || *(skip_whitespace(p)) != '\0') + syntax(s, "bad number"); + + return r; +} + +/* UNUSED +static int newerf(const char *f1, const char *f2) +{ + struct stat b1, b2; + + return (stat(f1, &b1) == 0 && + stat(f2, &b2) == 0 && b1.st_mtime > b2.st_mtime); +} + +static int olderf(const char *f1, const char *f2) +{ + struct stat b1, b2; + + return (stat(f1, &b1) == 0 && + stat(f2, &b2) == 0 && b1.st_mtime < b2.st_mtime); +} + +static int equalf(const char *f1, const char *f2) +{ + 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); +} +*/ + + +static enum token check_operator(const char *s) +{ + static const struct operator_t no_op = { + .op_num = -1, + .op_type = -1 + }; + int n; + + last_operator = &no_op; + if (s == NULL) + return EOI; + n = index_in_strings(ops_texts, s); + if (n < 0) + return OPERAND; + +#if BASH_TEST2 + if (ops_table[n].op_num == REGEX && !bash_test2) { + /* =~ is only for [[ ]] */ + return OPERAND; + } + if (ops_table[n].op_num == BAND || ops_table[n].op_num == BOR) { + /* [ ] accepts -a and -o but not && and || */ + /* [[ ]] accepts && and || but not -a and -o */ + if (bash_test2 == (s[0] == '-')) + return OPERAND; + } +#endif + + last_operator = &ops_table[n]; + return ops_table[n].op_num; +} + + +static int binop(void) +{ + const char *opnd1, *opnd2; + const struct operator_t *op; + number_t val1, val2; + + opnd1 = *args; + check_operator(*++args); + op = last_operator; + + opnd2 = *++args; + if (opnd2 == NULL) + syntax(args[-1], "argument expected"); + + if (is_int_op(op->op_num)) { + val1 = getn(opnd1); + val2 = getn(opnd2); + if (op->op_num == INTEQ) + return val1 == val2; + if (op->op_num == INTNE) + return val1 != val2; + if (op->op_num == INTGE) + return val1 >= val2; + if (op->op_num == INTGT) + return val1 > val2; + if (op->op_num == INTLE) + return val1 <= val2; + /*if (op->op_num == INTLT)*/ + return val1 < val2; + } +#if BASH_TEST2 + if (bash_test2) { + if (op->op_num == STREQ) { + val1 = fnmatch(opnd2, opnd1, 0); + return val1 == 0; + } + if (op->op_num == STRNE) { + val1 = fnmatch(opnd2, opnd1, 0); + return val1 != 0; + } + if (op->op_num == REGEX) { + regex_t re_buffer; + memset(&re_buffer, 0, sizeof(re_buffer)); + if (regcomp(&re_buffer, opnd2, REG_EXTENDED)) { // REG_NEWLINE? + /* Bad regex */ + longjmp(leaving, 2); /* [[ a =~ * ]]; echo $? - prints 2 (silently, no error msg) */ + } + val1 = regexec(&re_buffer, opnd1, 0, NULL, 0); + regfree(&re_buffer); + return val1 == 0; + } + } +#endif + if (is_str_op(op->op_num)) { + val1 = strcmp(opnd1, opnd2); + if (op->op_num == STREQ) + return val1 == 0; + if (op->op_num == STRNE) + return val1 != 0; + if (op->op_num == STRLT) + return val1 < 0; + /*if (op->op_num == STRGT)*/ + return val1 > 0; + } + /* We are sure that these three are by now the only binops we didn't check + * yet, so we do not check if the class is correct: + */ +/* if (is_file_op(op->op_num)) */ + { + struct stat b1, b2; + + if (stat(opnd1, &b1) || stat(opnd2, &b2)) + return 0; /* false, since at least one stat failed */ + if (op->op_num == FILNT) + return b1.st_mtime > b2.st_mtime; + if (op->op_num == FILOT) + return b1.st_mtime < b2.st_mtime; + /*if (op->op_num == FILEQ)*/ + return b1.st_dev == b2.st_dev && b1.st_ino == b2.st_ino; + } + /*return 1; - NOTREACHED */ +} + +static void initialize_group_array(void) +{ + group_array = bb_getgroups(&ngroups, NULL); +} + +/* Return non-zero if GID is one that we have in our groups list. */ +//XXX: FIXME: duplicate of existing libbb function? +// see toplevel TODO file: +// possible code duplication ingroup() and is_a_group_member() +static int is_a_group_member(gid_t gid) +{ + int i; + + /* Short-circuit if possible, maybe saving a call to getgroups(). */ + if (gid == getgid() || gid == getegid()) + return 1; + + if (ngroups == 0) + initialize_group_array(); + + /* Search through the list looking for GID. */ + for (i = 0; i < ngroups; i++) + if (gid == group_array[i]) + return 1; + + return 0; +} + + +/* 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(struct stat *st, int mode) +{ + unsigned int euid = geteuid(); + + 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 int filstat(char *nm, enum token mode) +{ + struct stat s; + unsigned i = i; /* gcc 3.x thinks it can be used uninitialized */ + + 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; + if (mode == FILEXIST) + return 1; + if (is_file_access(mode)) { + if (mode == FILRD) + i = R_OK; + if (mode == FILWR) + i = W_OK; + if (mode == FILEX) + i = X_OK; + return test_eaccess(&s, i) == 0; + } + if (is_file_type(mode)) { + if (mode == FILREG) + i = S_IFREG; + if (mode == FILDIR) + i = S_IFDIR; + if (mode == FILCDEV) + i = S_IFCHR; + if (mode == FILBDEV) + i = S_IFBLK; + if (mode == FILFIFO) { +#ifdef S_IFIFO + i = S_IFIFO; +#else + return 0; +#endif + } + if (mode == FILSOCK) { +#ifdef S_IFSOCK + i = S_IFSOCK; +#else + return 0; +#endif + } + filetype: + return ((s.st_mode & S_IFMT) == i); + } + if (is_file_bit(mode)) { + if (mode == FILSUID) + i = S_ISUID; + if (mode == FILSGID) + i = S_ISGID; + if (mode == FILSTCK) + i = S_ISVTX; + return ((s.st_mode & i) != 0); + } + if (mode == FILGZ) + return s.st_size > 0L; + if (mode == FILUID) + return s.st_uid == geteuid(); + if (mode == FILGID) + return s.st_gid == getegid(); + return 1; /* NOTREACHED */ +} + + +static number_t nexpr(enum token n) +{ + number_t res; + + nest_msg(">nexpr(%s)\n", TOKSTR[n]); + if (n == UNOT) { + n = check_operator(*++args); + if (n == EOI) { + /* special case: [ ! ], [ a -a ! ] are valid */ + /* IOW, "! ARG" may miss ARG */ + args--; + unnest_msg("aexpr(%s)\n", TOKSTR[n]); + res = nexpr(n); + dbg_msg("aexpr: nexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); + if (check_operator(*++args) == BAND) { + dbg_msg("aexpr: arg is AND, next args:%s(%p)\n", args[1], &args[1]); + res = aexpr(check_operator(*++args)) && res; + unnest_msg("oexpr(%s)\n", TOKSTR[n]); + res = aexpr(n); + dbg_msg("oexpr: aexpr:%lld, next args:%s(%p)\n", res, args[1], &args[1]); + if (check_operator(*++args) == BOR) { + dbg_msg("oexpr: next arg is OR, next args:%s(%p)\n", args[1], &args[1]); + res = oexpr(check_operator(*++args)) || res; + unnest_msg("primary(%s)\n", TOKSTR[n]); + if (n == EOI) { + syntax(NULL, "argument expected"); + } + if (n == LPAREN) { + res = oexpr(check_operator(*++args)); + if (check_operator(*++args) != RPAREN) + syntax(NULL, "closing paren expected"); + unnest_msg("op_type == BINOP) + unnest_msg_and_return(binop(), "op_type == UNOP) { + /* unary expression */ + if (args[1] == NULL) +// syntax(args0_op->op_text, "argument expected"); + goto check_emptiness; + args++; + if (n == STREZ) + unnest_msg_and_return(args[0][0] == '\0', "op_type == BINOP) { + /* args[2] is known to be NULL, isn't it bound to fail? */ + unnest_msg_and_return(binop(), "op_type == BINOP) { + /* "test [!] arg1 arg2" */ + args = argv; + res = (binop() == 0); + ret_special: + /* If there was leading "!" op... */ + res ^= negate; + goto ret; + } + /* """If $1 is '(' and $3 is ')', perform the unary test of $2.""" + * Looks like this works without additional coding. + */ + goto check_negate; + } + /* argv[3] exists (at least 4 args), is it exactly 4 args? */ + if (!argv[4]) { + /* + * """ 4 arguments: + * If $1 is '!', negate the three-argument test of $2, $3, and $4. + * If $1 is '(' and $4 is ')', perform the two-argument test of $2 and $3. + * """ + * Example why code below is necessary: test '(' ! -e ')' + */ + if (LONE_CHAR(argv[0], '(') + && LONE_CHAR(argv[3], ')') + ) { + /* "test [!] ( x y )" */ + argv[3] = NULL; + argv++; + } + } + } + check_negate: + if (LONE_CHAR(argv[0], '!')) { + argv++; + negate ^= 1; + goto again; + } + } + + res = !oexpr(check_operator(*args)); + + if (*args != NULL && *++args != NULL) { + /* Examples: + * test 3 -lt 5 6 + * test -t 1 2 + */ + bb_error_msg("%s: unknown operand", *args); + res = 2; + } + ret: + DEINIT_S(); + return res; +} diff --git a/busybox-1_37_0/coreutils/test_ptr_hack.c b/busybox-1_37_0/coreutils/test_ptr_hack.c new file mode 100644 index 000000000..5ba9dcc68 --- /dev/null +++ b/busybox-1_37_0/coreutils/test_ptr_hack.c @@ -0,0 +1,23 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2008 by Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +struct test_statics; + +#ifndef GCC_COMBINE + +/* We cheat here. It is declared as const ptr in libbb.h, + * but here we make it live in R/W memory */ +struct test_statics *test_ptr_to_statics; + +#else + +/* gcc -combine will see through and complain */ +/* Using alternative method which is more likely to break + * on weird architectures, compilers, linkers and so on */ +struct test_statics *const test_ptr_to_statics __attribute__ ((section (".data"))); + +#endif diff --git a/busybox-1_37_0/coreutils/timeout.c b/busybox-1_37_0/coreutils/timeout.c new file mode 100644 index 000000000..84299a0a5 --- /dev/null +++ b/busybox-1_37_0/coreutils/timeout.c @@ -0,0 +1,158 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * COPYING NOTES + * + * timeout.c -- a timeout handler for shell commands + * + * Copyright (C) 2005-6, Roberto A. Foglietta + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA. + */ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * REVISION NOTES: + * released 17-11-2005 by Roberto A. Foglietta + * talarm 04-12-2005 by Roberto A. Foglietta + * modified 05-12-2005 by Roberto A. Foglietta + * sizerdct 06-12-2005 by Roberto A. Foglietta + * splitszf 12-05-2006 by Roberto A. Foglietta + * rewrite 14-11-2008 vda + */ +//config:config TIMEOUT +//config: bool "timeout (6.5 kb)" +//config: default y +//config: help +//config: Runs a program and watches it. If it does not terminate in +//config: specified number of seconds, it is sent a signal. + +//applet:IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o + +//usage:#define timeout_trivial_usage +//usage: "[-s SIG] [-k KILL_SECS] SECS PROG ARGS" +//usage:#define timeout_full_usage "\n\n" +//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n" +//usage: "Default SIG: TERM." +//usage: "If it still exists in KILL_SECS seconds, send KILL.\n" + +#include "libbb.h" + +static NOINLINE int timeout_wait(duration_t timeout, pid_t pid) +{ + /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ + while (1) { +#if ENABLE_FLOAT_DURATION + if (timeout < 1) + sleep_for_duration(timeout); + else +#endif + sleep1(); + if (--timeout <= 0) + break; + if (kill(pid, 0)) { + /* process is gone */ + return EXIT_SUCCESS; + } + } + return EXIT_FAILURE; +} + +int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int timeout_main(int argc UNUSED_PARAM, char **argv) +{ + int signo; + int status; + int parent = 0; + duration_t timeout; + duration_t kill_timeout; + pid_t pid; +#if !BB_MMU + char *sv1, *sv2; +#endif + const char *opt_s = "TERM"; + char *opt_k = NULL; + + /* -p option is not documented, it is needed to support NOMMU. */ + + /* -t SECONDS; -p PARENT_PID */ + /* '+': stop at first non-option */ + getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); + /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ + + signo = get_signum(opt_s); + if (signo < 0) + bb_error_msg_and_die("unknown signal '%s'", opt_s); + + kill_timeout = 0; + if (opt_k) + kill_timeout = parse_duration_str(opt_k); + + if (!argv[optind]) + bb_show_usage(); + timeout = parse_duration_str(argv[optind++]); + if (!argv[optind]) /* no PROG? */ + bb_show_usage(); + + /* We want to create a grandchild which will watch + * and kill the grandparent. Other methods: + * making parent watch child disrupts parent<->child link + * (example: "tcpsvd 0.0.0.0 1234 timeout service_prog" - + * it's better if service_prog is a child of tcpsvd!), + * making child watch parent results in programs having + * unexpected children. */ + + if (parent) /* we were re-execed, already grandchild */ + goto grandchild; + +#if !BB_MMU + sv1 = argv[optind]; + sv2 = argv[optind + 1]; +#endif + pid = xvfork(); + if (pid == 0) { + /* Child: spawn grandchild and exit */ + parent = getppid(); +#if !BB_MMU + argv[optind] = xasprintf("-p%u", parent); + argv[optind + 1] = NULL; +#endif + /* NB: exits with nonzero on error: */ + bb_daemonize_or_rexec(0, argv); + /* Here we are grandchild. Sleep, then kill grandparent */ + grandchild: + if (timeout_wait(timeout, parent) == EXIT_SUCCESS) + return EXIT_SUCCESS; + kill(parent, signo); + + if (kill_timeout > 0) { + if (timeout_wait(kill_timeout, parent) == EXIT_SUCCESS) + return EXIT_SUCCESS; + kill(parent, SIGKILL); + } + + return EXIT_SUCCESS; + } + + /* Parent */ + wait(&status); /* wait for child to die */ + /* Did intermediate [v]fork or exec fail? */ + if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) + return EXIT_FAILURE; + /* Ok, exec a program as requested */ + argv += optind; +#if !BB_MMU + argv[0] = sv1; + argv[1] = sv2; +#endif + BB_EXECVP_or_die(argv); +} diff --git a/busybox-1_37_0/coreutils/touch.c b/busybox-1_37_0/coreutils/touch.c new file mode 100644 index 000000000..ced596c89 --- /dev/null +++ b/busybox-1_37_0/coreutils/touch.c @@ -0,0 +1,193 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini touch implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Previous version called open() and then utime(). While this will be + * be necessary to implement -r and -t, it currently only makes things bigger. + * Also, exiting on a failure was a bug. All args should be processed. + */ +//config:config TOUCH +//config: bool "touch (6.1 kb)" +//config: default y +//config: help +//config: touch is used to create or change the access and/or +//config: modification timestamp of specified files. +//config: +//config:config FEATURE_TOUCH_SUSV3 +//config: bool "Add support for SUSV3 features (-a -d -m -t -r)" +//config: default y +//config: depends on TOUCH +//config: help +//config: Enable touch to use a reference file or a given date/time argument. + +//applet:IF_TOUCH(APPLET_NOFORK(touch, touch, BB_DIR_BIN, BB_SUID_DROP, touch)) + +//kbuild:lib-$(CONFIG_TOUCH) += touch.o + +//usage:#define touch_trivial_usage +//usage: "[-ch" IF_FEATURE_TOUCH_SUSV3("am") "]" +//usage: IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") +//usage: " FILE..." +//usage:#define touch_full_usage "\n\n" +//usage: "Update mtime of FILEs\n" +//usage: "\n -c Don't create files" +//usage: "\n -h Don't follow links" +//usage: IF_FEATURE_TOUCH_SUSV3( +//usage: "\n -a Change only atime" +//usage: "\n -m Change only mtime" +//usage: "\n -d DT Date/time to use" +//usage: "\n -t DT Date/time to use" +//usage: "\n -r FILE Use FILE's date/time" +//usage: ) +//usage: +//usage:#define touch_example_usage +//usage: "$ ls -l /tmp/foo\n" +//usage: "/bin/ls: /tmp/foo: No such file or directory\n" +//usage: "$ touch /tmp/foo\n" +//usage: "$ ls -l /tmp/foo\n" +//usage: "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" + +/* coreutils implements: + * -a change only the access time + * -c, --no-create + * do not create any files + * -d, --date=STRING + * parse STRING and use it instead of current time + * -f (ignored, BSD compat) + * -m change only the modification time + * -h, --no-dereference + * -r, --reference=FILE + * use this file's times instead of current time + * -t STAMP + * use [[CC]YY]MMDDhhmm[.ss] instead of current time + * --time=WORD + * change the specified time: WORD is access, atime, or use + */ + +#include "libbb.h" + +int touch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int touch_main(int argc UNUSED_PARAM, char **argv) +{ + int fd; + int opts; + exitcode_t status = EXIT_SUCCESS; +#if ENABLE_FEATURE_TOUCH_SUSV3 + char *reference_file; + char *date_str; + /* timebuf[0] is atime, timebuf[1] is mtime */ + struct timespec timebuf[2]; +#else +# define reference_file NULL +# define date_str NULL +# define timebuf ((struct timespec*)NULL) +#endif + + enum { + OPT_c = (1 << 0), + OPT_h = (1 << 1), + OPT_r = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_d = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_t = (1 << 4) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_a = (1 << 5) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_m = (1 << 6) * ENABLE_FEATURE_TOUCH_SUSV3, + }; +#if ENABLE_LONG_OPTS + static const char touch_longopts[] ALIGN1 = + /* name, has_arg, val */ + "no-create\0" No_argument "c" + "no-dereference\0" No_argument "h" + IF_FEATURE_TOUCH_SUSV3("reference\0" Required_argument "r") + IF_FEATURE_TOUCH_SUSV3("date\0" Required_argument "d") + ; +#endif + /* -d and -t both set time. In coreutils, + * accepted data format differs a bit between -d and -t. + * We accept the same formats for both + */ + opts = getopt32long(argv, "^" + "ch" + IF_FEATURE_TOUCH_SUSV3("r:d:t:am") + /*ignored:*/ "f" IF_NOT_FEATURE_TOUCH_SUSV3("am") + "\0" /* opt_complementary: */ + /* at least one arg: */ "-1" + /* coreutils forbids -r and -t at once: */ IF_FEATURE_TOUCH_SUSV3(":r--t:t--r") + /* but allows these combinations: "r--d:d--r:t--d:d--t" */ + , touch_longopts +#if ENABLE_FEATURE_TOUCH_SUSV3 + , &reference_file + , &date_str + , &date_str +#endif + ); + +#if ENABLE_FEATURE_TOUCH_SUSV3 + timebuf[0].tv_nsec = timebuf[1].tv_nsec = UTIME_NOW; + if (opts & OPT_r) { + struct stat stbuf; + xstat(reference_file, &stbuf); + timebuf[0].tv_sec = stbuf.st_atime; + timebuf[1].tv_sec = stbuf.st_mtime; + timebuf[0].tv_nsec = stbuf.st_atim.tv_nsec; + timebuf[1].tv_nsec = stbuf.st_mtim.tv_nsec; + } + if (opts & (OPT_d|OPT_t)) { + struct tm tm_time; + time_t t; + int check_dst; + + //memset(&tm_time, 0, sizeof(tm_time)); + /* Better than memset: makes "HH:MM" dates meaningful */ + time(&t); + localtime_r(&t, &tm_time); + check_dst = parse_datestr(date_str, &tm_time); + + /* Correct any day of week and day of year etc. fields */ + if (check_dst) + tm_time.tm_isdst = -1; /* recheck dst unless date is UTC */ + t = validate_tm_time(date_str, &tm_time); + + timebuf[1].tv_sec = timebuf[0].tv_sec = t; + timebuf[1].tv_nsec = timebuf[0].tv_nsec = 0; + } + /* If both -a and -m specified, both times should be set. + * IOW: set OMIT only if one, not both, of them is given! + */ + if ((opts & (OPT_a|OPT_m)) == OPT_a) + timebuf[1].tv_nsec = UTIME_OMIT; + if ((opts & (OPT_a|OPT_m)) == OPT_m) + timebuf[0].tv_nsec = UTIME_OMIT; +#endif + + argv += optind; + do { + int result = utimensat(AT_FDCWD, *argv, timebuf, + (opts & OPT_h) ? AT_SYMLINK_NOFOLLOW : 0); + if (result != 0) { + if (errno == ENOENT) { /* no such file? */ + if (opts & OPT_c) { + /* Creation is disabled, so ignore */ + continue; + } + /* Try to create the file */ + fd = open(*argv, O_RDWR | O_CREAT, 0666); + if (fd >= 0) { + if (opts & (OPT_r|OPT_d|OPT_t)) + futimens(fd, timebuf); + xclose(fd); + continue; + } + } + status = EXIT_FAILURE; + bb_simple_perror_msg(*argv); + } + } while (*++argv); + + return status; +} diff --git a/busybox-1_37_0/coreutils/tr.c b/busybox-1_37_0/coreutils/tr.c new file mode 100644 index 000000000..8d779d8ea --- /dev/null +++ b/busybox-1_37_0/coreutils/tr.c @@ -0,0 +1,360 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini tr implementation for busybox + * + * Copyright (c) 1987,1997, Prentice Hall All rights reserved. + * + * The name of Prentice Hall may not be used to endorse or promote + * products derived from this software without specific prior + * written permission. + * + * Copyright (c) Michiel Huisjes + * + * This version of tr is adapted from Minix tr and was modified + * by Erik Andersen to be used in busybox. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html + * TODO: graph, print + */ +//config:config TR +//config: bool "tr (5.3 kb)" +//config: default y +//config: help +//config: tr is used to squeeze, and/or delete characters from standard +//config: input, writing to standard output. +//config: +//config:config FEATURE_TR_CLASSES +//config: bool "Enable character classes (such as [:upper:])" +//config: default y +//config: depends on TR +//config: help +//config: Enable character classes, enabling commands such as: +//config: tr [:upper:] [:lower:] to convert input into lowercase. +//config: +//config:config FEATURE_TR_EQUIV +//config: bool "Enable equivalence classes" +//config: default y +//config: depends on TR +//config: help +//config: Enable equivalence classes, which essentially add the enclosed +//config: character to the current set. For instance, tr [=a=] xyz would +//config: replace all instances of 'a' with 'xyz'. This option is mainly +//config: useful for cases when no other way of expressing a character +//config: is possible. + +//applet:IF_TR(APPLET(tr, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TR) += tr.o + +//usage:#define tr_trivial_usage +//usage: "[-cds] STRING1 [STRING2]" +//usage:#define tr_full_usage "\n\n" +//usage: "Translate, squeeze, or delete characters from stdin, writing to stdout\n" +//usage: "\n -c Take complement of STRING1" +//usage: "\n -d Delete input characters coded STRING1" +//usage: "\n -s Squeeze multiple output characters of STRING2 into one character" +//usage: +//usage:#define tr_example_usage +//usage: "$ echo \"gdkkn vnqkc\" | tr [a-y] [b-z]\n" +//usage: "hello world\n" + +#include "libbb.h" + +enum { + ASCII = 256, + /* string buffer needs to be at least as big as the whole "alphabet". + * BUFSIZ == ASCII is ok, but we will realloc in expand + * even for smallest patterns, let's avoid that by using *2: + */ + TR_BUFSIZ = (BUFSIZ > ASCII*2) ? BUFSIZ : ASCII*2, +}; + +static void map(char *pvector, + char *string1, unsigned string1_len, + char *string2, unsigned string2_len) +{ + char last = '0'; + unsigned i, j; + + for (j = 0, i = 0; i < string1_len; i++) { + if (string2_len <= j) + pvector[(unsigned char)(string1[i])] = last; + else + pvector[(unsigned char)(string1[i])] = last = string2[j++]; + } +} + +/* supported constructs: + * Ranges, e.g., 0-9 ==> 0123456789 + * Escapes, e.g., \a ==> Control-G + * Character classes, e.g. [:upper:] ==> A...Z + * Equiv classess, e.g. [=A=] ==> A (hmmmmmmm?) + * not supported: + * [x*N] - repeat char x N times + * [x*] - repeat char x until it fills STRING2: + * # echo qwe123 | /usr/bin/tr 123456789 '[d]' + * qwe[d] + * # echo qwe123 | /usr/bin/tr 123456789 '[d*]' + * qweddd + */ +static unsigned expand(char *arg, char **buffer_p) +{ + char *buffer = *buffer_p; + unsigned pos = 0; + unsigned size = TR_BUFSIZ; + unsigned i; /* can't be unsigned char: must be able to hold 256 */ + unsigned char ac; + + while (*arg) { + if (pos + ASCII > size) { + size += ASCII; + *buffer_p = buffer = xrealloc(buffer, size); + } + if (*arg == '\\') { + const char *z; + arg++; + z = arg; + ac = bb_process_escape_sequence(&z); + arg = (char *)z; + arg--; + *arg = ac; + /* + * fall through, there may be a range. + * If not, current char will be treated anyway. + */ + } + if (arg[1] == '-') { /* "0-9..." */ + ac = arg[2]; + if (ac == '\0') { /* "0-": copy verbatim */ + buffer[pos++] = *arg++; /* copy '0' */ + continue; /* next iter will copy '-' and stop */ + } + i = (unsigned char) *arg; + arg += 3; /* skip 0-9 or 0-\ */ + if (ac == '\\') { + const char *z; + z = arg; + ac = bb_process_escape_sequence(&z); + arg = (char *)z; + } + while (i <= ac) /* ok: i is unsigned _int_ */ + buffer[pos++] = i++; + continue; + } + if ((ENABLE_FEATURE_TR_CLASSES || ENABLE_FEATURE_TR_EQUIV) + && *arg == '[' + ) { + arg++; + i = (unsigned char) *arg++; + /* "[xyz...". i=x, arg points to y */ + if (ENABLE_FEATURE_TR_CLASSES && i == ':') { /* [:class:] */ +#define CLO ":]\0" + static const char classes[] ALIGN1 = + "alpha"CLO "alnum"CLO "digit"CLO + "lower"CLO "upper"CLO "space"CLO + "blank"CLO "punct"CLO "cntrl"CLO + "xdigit"CLO; + enum { + CLASS_invalid = 0, /* we increment the retval */ + CLASS_alpha = 1, + CLASS_alnum = 2, + CLASS_digit = 3, + CLASS_lower = 4, + CLASS_upper = 5, + CLASS_space = 6, + CLASS_blank = 7, + CLASS_punct = 8, + CLASS_cntrl = 9, + CLASS_xdigit = 10, + //CLASS_graph = 11, + //CLASS_print = 12, + }; + smalluint j; + char *tmp; + + /* xdigit needs 8, not 7 */ + i = 7 + (arg[0] == 'x'); + tmp = xstrndup(arg, i); + j = index_in_strings(classes, tmp) + 1; + free(tmp); + + if (j == CLASS_invalid) + goto skip_bracket; + + arg += i; + if (j == CLASS_alnum || j == CLASS_digit || j == CLASS_xdigit) { + for (i = '0'; i <= '9'; i++) + buffer[pos++] = i; + } + if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_upper) { + for (i = 'A'; i <= 'Z'; i++) + buffer[pos++] = i; + } + if (j == CLASS_alpha || j == CLASS_alnum || j == CLASS_lower) { + for (i = 'a'; i <= 'z'; i++) + buffer[pos++] = i; + } + if (j == CLASS_space || j == CLASS_blank) { + buffer[pos++] = '\t'; + if (j == CLASS_space) { + buffer[pos++] = '\n'; + buffer[pos++] = '\v'; + buffer[pos++] = '\f'; + buffer[pos++] = '\r'; + } + buffer[pos++] = ' '; + } + if (j == CLASS_punct || j == CLASS_cntrl) { + for (i = '\0'; i < ASCII; i++) { + if ((j == CLASS_punct && isprint_asciionly(i) && !isalnum(i) && !isspace(i)) + || (j == CLASS_cntrl && iscntrl(i)) + ) { + buffer[pos++] = i; + } + } + } + if (j == CLASS_xdigit) { + for (i = 'A'; i <= 'F'; i++) { + buffer[pos + 6] = i | 0x20; + buffer[pos++] = i; + } + pos += 6; + } + continue; + } + /* "[xyz...", i=x, arg points to y */ + if (ENABLE_FEATURE_TR_EQUIV && i == '=') { /* [=CHAR=] */ + buffer[pos++] = *arg; /* copy CHAR */ + if (!arg[0] || arg[1] != '=' || arg[2] != ']') + bb_show_usage(); + arg += 3; /* skip CHAR=] */ + continue; + } + /* The rest of "[xyz..." cases is treated as normal + * string, "[" has no special meaning here: + * tr "[a-z]" "[A-Z]" can be written as tr "a-z" "A-Z", + * also try tr "[a-z]" "_A-Z+" and you'll see that + * [] is not special here. + */ + skip_bracket: + arg -= 2; /* points to "[" in "[xyz..." */ + } + buffer[pos++] = *arg++; + } + return pos; +} + +/* NB: buffer is guaranteed to be at least TR_BUFSIZE + * (which is >= ASCII) big. + */ +static int complement(char *buffer, int buffer_len) +{ + int len; + char conv[ASCII]; + unsigned char ch; + + len = 0; + ch = '\0'; + while (1) { + if (memchr(buffer, ch, buffer_len) == NULL) + conv[len++] = ch; + if (++ch == '\0') + break; + } + memcpy(buffer, conv, len); + return len; +} + +int tr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tr_main(int argc UNUSED_PARAM, char **argv) +{ + int i; + smalluint opts; + ssize_t read_chars; + size_t in_index, out_index; + unsigned last = UCHAR_MAX + 1; /* not equal to any char */ + unsigned char coded, c; + char *str1 = xmalloc(TR_BUFSIZ); + char *str2 = xmalloc(TR_BUFSIZ); + int str2_length; + int str1_length; + char *vector = xzalloc(ASCII * 3); + char *invec = vector + ASCII; + char *outvec = vector + ASCII * 2; + +#define TR_OPT_complement (3 << 0) +#define TR_OPT_delete (1 << 2) +#define TR_OPT_squeeze_reps (1 << 3) + + for (i = 0; i < ASCII; i++) { + vector[i] = i; + /*invec[i] = outvec[i] = FALSE; - done by xzalloc */ + } + + /* -C/-c difference is that -C complements "characters", + * and -c complements "values" (binary bytes I guess). + * In POSIX locale, these are the same. + */ + + /* '+': stop at first non-option */ + opts = getopt32(argv, "^+" "Ccds" "\0" "-1:?2"); + argv += optind; + + str1_length = expand(*argv++, &str1); + str2_length = 0; + if (opts & TR_OPT_complement) + str1_length = complement(str1, str1_length); + if (*argv) { + if (argv[0][0] == '\0') + bb_simple_error_msg_and_die("STRING2 cannot be empty"); + str2_length = expand(*argv, &str2); + map(vector, str1, str1_length, + str2, str2_length); + } + for (i = 0; i < str1_length; i++) + invec[(unsigned char)(str1[i])] = TRUE; + for (i = 0; i < str2_length; i++) + outvec[(unsigned char)(str2[i])] = TRUE; + + goto start_from; + + /* In this loop, str1 space is reused as input buffer, + * str2 - as output one. */ + for (;;) { + /* If we're out of input, flush output and read more input. */ + if ((ssize_t)in_index == read_chars) { + if (out_index) { + xwrite(STDOUT_FILENO, str2, out_index); + start_from: + out_index = 0; + } + read_chars = safe_read(STDIN_FILENO, str1, TR_BUFSIZ); + if (read_chars <= 0) { + if (read_chars < 0) + bb_simple_perror_msg_and_die(bb_msg_read_error); + break; + } + in_index = 0; + } + c = str1[in_index++]; + if ((opts & TR_OPT_delete) && invec[c]) + continue; + coded = vector[c]; + if ((opts & TR_OPT_squeeze_reps) && last == coded + && (invec[c] || outvec[coded]) + ) { + continue; + } + str2[out_index++] = last = coded; + } + + if (ENABLE_FEATURE_CLEAN_UP) { + free(vector); + free(str2); + free(str1); + } + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/true.c b/busybox-1_37_0/coreutils/true.c new file mode 100644 index 000000000..02e533a0a --- /dev/null +++ b/busybox-1_37_0/coreutils/true.c @@ -0,0 +1,38 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini true implementation for busybox + * + * Copyright (C) 1999-2004 by Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config TRUE +//config: bool "true (311 bytes)" +//config: default y +//config: help +//config: true returns an exit code of TRUE (0). + +//applet:IF_TRUE(APPLET_NOFORK(true, true, BB_DIR_BIN, BB_SUID_DROP, true)) + +//kbuild:lib-$(CONFIG_TRUE) += true.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/true.html */ + +/* "true --help" is special-cased to ignore --help */ +//usage:#define true_trivial_usage NOUSAGE_STR +//usage:#define true_full_usage "" +//usage:#define true_example_usage +//usage: "$ true\n" +//usage: "$ echo $?\n" +//usage: "0\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int true_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int true_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/truncate.c b/busybox-1_37_0/coreutils/truncate.c new file mode 100644 index 000000000..8826e6b4c --- /dev/null +++ b/busybox-1_37_0/coreutils/truncate.c @@ -0,0 +1,86 @@ +/* + * Mini truncate implementation for busybox + * + * Copyright (C) 2015 by Ari Sundholm + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config TRUNCATE +//config: bool "truncate (4.4 kb)" +//config: default y +//config: help +//config: truncate truncates files to a given size. If a file does +//config: not exist, it is created unless told otherwise. + +//applet:IF_TRUNCATE(APPLET_NOFORK(truncate, truncate, BB_DIR_USR_BIN, BB_SUID_DROP, truncate)) + +//kbuild:lib-$(CONFIG_TRUNCATE) += truncate.o + +//usage:#define truncate_trivial_usage +//usage: "[-c] -s SIZE FILE..." +//usage:#define truncate_full_usage "\n\n" +//usage: "Truncate FILEs to SIZE\n" +//usage: "\n -c Do not create files" +//usage: "\n -s SIZE" +//usage: +//usage:#define truncate_example_usage +//usage: "$ truncate -s 1G foo" + +#include "libbb.h" + +#if ENABLE_LFS +# define XATOU_SFX xatoull_sfx +#else +# define XATOU_SFX xatoul_sfx +#endif + +/* This is a NOFORK applet. Be very careful! */ + +int truncate_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int truncate_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + int flags = O_WRONLY | O_NONBLOCK; + int ret = EXIT_SUCCESS; + char *size_str; + off_t size; + + enum { + OPT_NOCREATE = (1 << 0), + OPT_SIZE = (1 << 1), + }; + + opts = getopt32(argv, "^" "cs:" "\0" "s:-1", &size_str); + + if (!(opts & OPT_NOCREATE)) + flags |= O_CREAT; + + // TODO: coreutils 8.17 also support "m" (lowercase) suffix + // with truncate, but not with dd! + // We share kMG_suffixes[], so we can't make both tools + // compatible at once... + size = XATOU_SFX(size_str, kMG_suffixes); + + argv += optind; + while (*argv) { + int fd = open(*argv, flags, 0666); + if (fd < 0) { + if (errno != ENOENT || !(opts & OPT_NOCREATE)) { + bb_perror_msg("%s: open", *argv); + ret = EXIT_FAILURE; + } + /* else: ENOENT && OPT_NOCREATE: + * do not report error, exitcode is also 0. + */ + } else { + if (ftruncate(fd, size) == -1) { + bb_perror_msg("%s: truncate", *argv); + ret = EXIT_FAILURE; + } + xclose(fd); + } + ++argv; + } + + return ret; +} diff --git a/busybox-1_37_0/coreutils/tsort.c b/busybox-1_37_0/coreutils/tsort.c new file mode 100644 index 000000000..e1ee6bcd7 --- /dev/null +++ b/busybox-1_37_0/coreutils/tsort.c @@ -0,0 +1,202 @@ +/* vi: set sw=4 ts=4: */ +/* + * tsort implementation for busybox + * + * public domain -- David Leonard, 2022 + */ +//config:config TSORT +//config: bool "tsort (2.6 kb)" +//config: default y +//config: help +//config: tsort performs a topological sort. + +//applet:IF_TSORT(APPLET(tsort, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_TSORT) += tsort.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/tsort.html */ + +//usage:#define tsort_trivial_usage +//usage: "[FILE]" +//usage:#define tsort_full_usage "\n\n" +//usage: "Topological sort" +//usage:#define tsort_example_usage +//usage: "$ echo -e \"a b\\nb c\" | tsort\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" + +#include "libbb.h" +#include "common_bufsiz.h" + +struct node { + unsigned in_count; + unsigned out_count; + struct node **out; + char name[1]; +}; + +struct globals { + struct node **nodes; + unsigned nodes_len; +}; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ + G.nodes = NULL; \ + G.nodes_len = 0; \ +} while (0) + +static struct node * +get_node(const char *name) +{ + struct node *n; + unsigned a = 0; + unsigned b = G.nodes_len; + + /* Binary search for name */ + while (a != b) { + unsigned m = (a + b) / 2; + int cmp = strcmp(name, G.nodes[m]->name); + if (cmp == 0) + return G.nodes[m]; /* found */ + if (cmp < 0) { + b = m; + } else { + a = m + 1; + } + } + + /* Allocate new node */ + n = xzalloc(sizeof(*n) + strlen(name)); + //n->in_count = 0; + //n->out_count = 0; + //n->out = NULL; + strcpy(n->name, name); + + /* Insert to maintain sort */ + G.nodes = xrealloc(G.nodes, (G.nodes_len + 1) * sizeof(*G.nodes)); + memmove(&G.nodes[a + 1], &G.nodes[a], + (G.nodes_len - a) * sizeof(*G.nodes)); + G.nodes[a] = n; + G.nodes_len++; + return n; +} + +static void +add_edge(struct node *a, struct node *b) +{ + a->out = xrealloc_vector(a->out, 6, a->out_count); + a->out[a->out_count++] = b; + b->in_count++; +} + +int tsort_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tsort_main(int argc UNUSED_PARAM, char **argv) +{ + char *line; + size_t linesz; + ssize_t len; + struct node *a; + int cycles; + unsigned i; +#if ENABLE_FEATURE_CLEAN_UP + unsigned max_len; +#endif + + INIT_G(); + + if (argv[1]) { + if (argv[2]) + bb_show_usage(); + if (NOT_LONE_DASH(argv[1])) { + close(STDIN_FILENO); /* == 0 */ + xopen(argv[1], O_RDONLY); /* fd will be 0 */ + } + } + + /* Read in words separated by s */ + a = NULL; + line = NULL; + linesz = 0; + while ((len = getline(&line, &linesz, stdin)) != -1) { + char *s = line; + while (*(s = skip_whitespace(s)) != '\0') { + struct node *b; + char *word; + + word = s; + s = skip_non_whitespace(s); + if (*s) + *s++ = '\0'; + + /* Create nodes and edges for each word pair */ + b = get_node(word); + if (!a) { + a = b; + } else { + if (a != b) + add_edge(a, b); + a = NULL; + } + } + } +// Most other tools do not check for input read error (treat them as EOF) +// die_if_ferror(in, input_filename); + if (a) + bb_simple_error_msg_and_die("odd input"); + free(line); + + /* + * Kahn's algorithm: + * - find a node that has no incoming edges, print and remove it + * - repeat until the graph is empty + * - if any nodes are left, they form cycles. + */ + cycles = 0; +#if ENABLE_FEATURE_CLEAN_UP + max_len = G.nodes_len; +#endif + while (G.nodes_len) { + struct node *n; + + /* Search for first node with no incoming edges */ + for (i = 0; i < G.nodes_len; i++) { + if (!G.nodes[i]->in_count) + break; + } + if (i == G.nodes_len) { + /* Must be a cycle; arbitraily break it at node 0 */ + cycles++; + i = 0; +#ifndef TINY + bb_error_msg("cycle at %s", G.nodes[i]->name); +#endif + } + + /* Remove the node (need no longer maintain sort) */ + n = G.nodes[i]; + G.nodes[i] = G.nodes[--G.nodes_len]; +#if ENABLE_FEATURE_CLEAN_UP + /* Keep reference to removed node so it can be freed */ + G.nodes[G.nodes_len] = n; +#endif + + /* And remove its outgoing edges */ + for (i = 0; i < n->out_count; i++) + n->out[i]->in_count--; + + puts(n->name); + } +#if ENABLE_FEATURE_CLEAN_UP + for (i = 0; i < max_len; i++) { + free(G.nodes[i]->out); + free(G.nodes[i]); + } + free(G.nodes); +#endif + + fflush_stdout_and_exit(cycles ? 1 : 0); +} diff --git a/busybox-1_37_0/coreutils/tty.c b/busybox-1_37_0/coreutils/tty.c new file mode 100644 index 000000000..8f9a82b0e --- /dev/null +++ b/busybox-1_37_0/coreutils/tty.c @@ -0,0 +1,66 @@ +/* vi: set sw=4 ts=4: */ +/* + * tty implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config TTY +//config: bool "tty (3.9 kb)" +//config: default y +//config: help +//config: tty is used to print the name of the current terminal to +//config: standard output. + +//applet:IF_TTY(APPLET_NOFORK(tty, tty, BB_DIR_USR_BIN, BB_SUID_DROP, tty)) + +//kbuild:lib-$(CONFIG_TTY) += tty.o + +/* BB_AUDIT SUSv4 compliant */ +/* http://www.opengroup.org/onlinepubs/9699919799/utilities/tty.html */ + +//usage:#define tty_trivial_usage +//usage: "" IF_INCLUDE_SUSv2("[-s]") +//usage:#define tty_full_usage "\n\n" +//usage: "Print file name of stdin's terminal" +//usage: IF_INCLUDE_SUSv2( "\n" +//usage: "\n -s Print nothing, only return exit status" +//usage: ) +//usage: +//usage:#define tty_example_usage +//usage: "$ tty\n" +//usage: "/dev/tty2\n" + +#include "libbb.h" + +int tty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tty_main(int argc UNUSED_PARAM, char **argv) +{ + const char *s; + IF_INCLUDE_SUSv2(int silent;) /* Note: No longer relevant in SUSv3. */ + int retval; + + xfunc_error_retval = 2; /* SUSv3 requires > 1 for error. */ + + IF_INCLUDE_SUSv2(silent = getopt32(argv, "s");) + IF_INCLUDE_SUSv2(argv += optind;) + IF_NOT_INCLUDE_SUSv2(argv += 1;) + + /* gnu tty outputs a warning that it is ignoring all args. */ + bb_warn_ignoring_args(argv[0]); + + retval = EXIT_SUCCESS; + + s = xmalloc_ttyname(STDIN_FILENO); + if (s == NULL) { + /* According to SUSv3, ttyname can fail with EBADF or ENOTTY. + * We know the file descriptor is good, so failure means not a tty. */ + s = "not a tty"; + retval = EXIT_FAILURE; + } + IF_INCLUDE_SUSv2(if (!silent) puts(s);) + IF_NOT_INCLUDE_SUSv2(puts(s);) + + fflush_stdout_and_exit(retval); +} diff --git a/busybox-1_37_0/coreutils/uname.c b/busybox-1_37_0/coreutils/uname.c new file mode 100644 index 000000000..e1e7a7660 --- /dev/null +++ b/busybox-1_37_0/coreutils/uname.c @@ -0,0 +1,213 @@ +/* vi: set sw=4 ts=4: */ +/* + * uname -- print system information + * Copyright (C) 1989-1999 Free Software Foundation, Inc. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Option Example + * -s, --sysname SunOS + * -n, --nodename rocky8 + * -r, --release 4.0 + * -v, --version + * -m, --machine sun + * -a, --all SunOS rocky8 4.0 sun + * + * The default behavior is equivalent to '-s'. + * + * David MacKenzie + * + * GNU coreutils 6.10: + * Option: struct Example(s): + * utsname + * field: + * -s, --kernel-name sysname Linux + * -n, --nodename nodename localhost.localdomain + * -r, --kernel-release release 2.6.29 + * -v, --kernel-version version #1 SMP Sun Jan 11 20:52:37 EST 2009 + * -m, --machine machine x86_64 i686 + * -p, --processor (none) x86_64 i686 + * -i, --hardware-platform (none) x86_64 i386 + * NB: vanilla coreutils reports "unknown" -p and -i, + * x86_64 and i686/i386 shown above are Fedora's inventions. + * -o, --operating-system (none) GNU/Linux + * -a, --all: all of the above, in the order shown. + * If -p or -i is not known, don't show them + */ +/* Busyboxed by Erik Andersen + * + * Before 2003: Glenn McGrath and Manuel Novoa III + * Further size reductions. + * Mar 16, 2003: Manuel Novoa III (mjn3@codepoet.org) + * Now does proper error checking on i/o. Plus some further space savings. + * Jan 2009: + * Fix handling of -a to not print "unknown", add -o and -i support. + */ +//config:config UNAME +//config: bool "uname (4.2 kb)" +//config: default y +//config: help +//config: uname is used to print system information. +//config: +//config:config UNAME_OSNAME +//config: string "Operating system name" +//config: default "GNU/Linux" +//config: depends on UNAME +//config: help +//config: Sets the operating system name reported by uname -o. The +//config: default is "GNU/Linux". +//config: +//can't use "ARCH" for this applet, all hell breaks loose in build system :) +//config:config BB_ARCH +//config: bool "arch (1.4 kb)" +//config: default y +//config: help +//config: Same as uname -m. + +// APPLET_NOFORK:name main location suid_type help +//applet:IF_UNAME(APPLET_NOFORK( uname, uname, BB_DIR_BIN, BB_SUID_DROP, uname)) +//applet:IF_BB_ARCH(APPLET_NOFORK(arch, uname, BB_DIR_BIN, BB_SUID_DROP, arch)) + +//kbuild:lib-$(CONFIG_UNAME) += uname.o +//kbuild:lib-$(CONFIG_BB_ARCH) += uname.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/uname.html */ + +//usage:#define uname_trivial_usage +//usage: "[-amnrspvio]" +//usage:#define uname_full_usage "\n\n" +//usage: "Print system information\n" +//usage: "\n -a Print all" +//usage: "\n -m Machine (hardware) type" +//usage: "\n -n Hostname" +//usage: "\n -r Kernel release" +//usage: "\n -s Kernel name (default)" +//usage: "\n -p Processor type" +//usage: "\n -v Kernel version" +//usage: "\n -i Hardware platform" +//usage: "\n -o OS name" +//usage: +//usage:#define uname_example_usage +//usage: "$ uname -a\n" +//usage: "Linux debian 2.4.23 #2 Tue Dec 23 17:09:10 MST 2003 i686 GNU/Linux\n" + +//usage:#define arch_trivial_usage +//usage: "" +//usage:#define arch_full_usage "\n\n" +//usage: "Print system architecture" + +#include "libbb.h" +/* After libbb.h, since it needs sys/types.h on some systems */ +#include + +typedef struct { + struct utsname name; + char processor[sizeof(((struct utsname*)NULL)->machine)]; + char platform[sizeof(((struct utsname*)NULL)->machine)]; + char os[sizeof(CONFIG_UNAME_OSNAME)]; +} uname_info_t; + +#if ENABLE_UNAME +#define options "snrvmpioa" +static const unsigned short utsname_offset[] = { + offsetof(uname_info_t, name.sysname), /* -s */ + offsetof(uname_info_t, name.nodename), /* -n */ + offsetof(uname_info_t, name.release), /* -r */ + offsetof(uname_info_t, name.version), /* -v */ + offsetof(uname_info_t, name.machine), /* -m */ + offsetof(uname_info_t, processor), /* -p */ + offsetof(uname_info_t, platform), /* -i */ + offsetof(uname_info_t, os), /* -o */ +}; +#endif + +int uname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uname_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + uname_info_t uname_info; + IF_UNAME(const char *unknown_str = "unknown";) +#if ENABLE_UNAME + unsigned toprint = (1 << 4); /* "arch" = "uname -m" */ + + if (!ENABLE_BB_ARCH || applet_name[0] == 'u') { +# if ENABLE_LONG_OPTS + static const char uname_longopts[] ALIGN1 = + /* name, has_arg, val */ + "all\0" No_argument "a" + "kernel-name\0" No_argument "s" + "nodename\0" No_argument "n" + "kernel-release\0" No_argument "r" + "release\0" No_argument "r" + "kernel-version\0" No_argument "v" + "machine\0" No_argument "m" + "processor\0" No_argument "p" + "hardware-platform\0" No_argument "i" + "operating-system\0" No_argument "o" + ; +# endif + toprint = getopt32long(argv, options, uname_longopts); + if (argv[optind]) { /* coreutils-6.9 compat */ + bb_show_usage(); + } + if (toprint & (1 << 8)) { /* -a => all opts on */ + toprint = (1 << 8) - 1; + unknown_str = ""; /* -a does not print unknown fields */ + } + if (toprint == 0) { /* no opts => -s (sysname) */ + toprint = 1; + } + } /* if "uname" */ +#endif + + uname(&uname_info.name); /* never fails */ + +#if defined(__sparc__) && defined(__linux__) + { + char *fake_sparc = getenv("FAKE_SPARC"); + if (fake_sparc && (fake_sparc[0] | 0x20) == 'y') { + strcpy(uname_info.name.machine, "sparc"); + } + } +#endif + if (ENABLE_BB_ARCH && (!ENABLE_UNAME || applet_name[0] == 'a')) { + puts(uname_info.name.machine); + } else { +#if ENABLE_UNAME + /* "uname" */ + const char *fmt; + const unsigned short *delta; + + strcpy(uname_info.processor, unknown_str); + strcpy(uname_info.platform, unknown_str); + strcpy(uname_info.os, CONFIG_UNAME_OSNAME); +# if ENABLE_FEDORA_COMPAT + /* Fedora does something like this */ + strcpy(uname_info.processor, uname_info.name.machine); + strcpy(uname_info.platform, uname_info.name.machine); + if (uname_info.platform[0] == 'i' + && uname_info.platform[1] + && uname_info.platform[2] == '8' + && uname_info.platform[3] == '6' + ) { + uname_info.platform[1] = '3'; + } +# endif + delta = utsname_offset; + fmt = " %s" + 1; + do { + if (toprint & 1) { + const char *p = (char *)(&uname_info) + *delta; + if (p[0]) { + printf(fmt, p); + fmt = " %s"; + } + } + ++delta; + } while (toprint >>= 1); + bb_putchar('\n'); +#endif + } + + fflush_stdout_and_exit_SUCCESS(); /* coreutils-6.9 compat */ +} diff --git a/busybox-1_37_0/coreutils/uniq.c b/busybox-1_37_0/coreutils/uniq.c new file mode 100644 index 000000000..2c112dadb --- /dev/null +++ b/busybox-1_37_0/coreutils/uniq.c @@ -0,0 +1,143 @@ +/* vi: set sw=4 ts=4: */ +/* + * uniq implementation for busybox + * + * Copyright (C) 2005 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config UNIQ +//config: bool "uniq (5.1 kb)" +//config: default y +//config: help +//config: uniq is used to remove duplicate lines from a sorted file. + +//applet:IF_UNIQ(APPLET(uniq, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UNIQ) += uniq.o + +/* BB_AUDIT SUSv3 compliant */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ + +//usage:#define uniq_trivial_usage +//usage: "[-cduiz] [-f,s,w N] [FILE [OUTFILE]]" +//usage:#define uniq_full_usage "\n\n" +//usage: "Discard duplicate lines\n" +//usage: "\n -c Prefix lines by the number of occurrences" +//usage: "\n -d Only print duplicate lines" +//usage: "\n -u Only print unique lines" +//usage: "\n -i Ignore case" +//usage: "\n -z NUL terminated output" +//usage: "\n -f N Skip first N fields" +//usage: "\n -s N Skip first N chars (after any skipped fields)" +//usage: "\n -w N Compare N characters in line" +//usage: +//usage:#define uniq_example_usage +//usage: "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" +//usage: "a\n" +//usage: "b\n" +//usage: "c\n" + +#include "libbb.h" + +int uniq_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uniq_main(int argc UNUSED_PARAM, char **argv) +{ + const char *input_filename; + unsigned skip_fields, skip_chars, max_chars; + unsigned opt; + char eol; + char *cur_line; + const char *cur_compare; + + enum { + OPT_c = 1 << 0, + OPT_d = 1 << 1, /* print only dups */ + OPT_u = 1 << 2, /* print only uniq */ + OPT_f = 1 << 3, + OPT_s = 1 << 4, + OPT_w = 1 << 5, + OPT_i = 1 << 6, + OPT_z = 1 << 7, + }; + + skip_fields = skip_chars = 0; + max_chars = INT_MAX; + + opt = getopt32(argv, "cduf:+s:+w:+iz", &skip_fields, &skip_chars, &max_chars); + argv += optind; + + input_filename = argv[0]; + if (input_filename) { + const char *output; + + if (input_filename[0] != '-' || input_filename[1]) { + close(STDIN_FILENO); /* == 0 */ + xopen(input_filename, O_RDONLY); /* fd will be 0 */ + } + output = argv[1]; + if (output) { + if (argv[2]) + bb_show_usage(); + if (output[0] != '-' || output[1]) { + // Won't work with "uniq - FILE" and closed stdin: + //close(STDOUT_FILENO); + //xopen(output, O_WRONLY | O_CREAT | O_TRUNC); + xmove_fd(xopen(output, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); + } + } + } + + cur_compare = cur_line = NULL; /* prime the pump */ + eol = (opt & OPT_z) ? 0 : '\n'; + + do { + unsigned i; + unsigned long dups; + char *old_line; + const char *old_compare; + + old_line = cur_line; + old_compare = cur_compare; + dups = 0; + + /* gnu uniq ignores newlines */ + while ((cur_line = xmalloc_fgetline(stdin)) != NULL) { + cur_compare = cur_line; + for (i = skip_fields; i; i--) { + cur_compare = skip_whitespace(cur_compare); + cur_compare = skip_non_whitespace(cur_compare); + } + for (i = skip_chars; *cur_compare && i; i--) { + ++cur_compare; + } + + if (!old_line) + break; + if ((opt & OPT_i) + ? strncasecmp(old_compare, cur_compare, max_chars) + : strncmp(old_compare, cur_compare, max_chars) + ) { + break; + } + + free(cur_line); + ++dups; /* testing for overflow seems excessive */ + } + + if (old_line) { + if (!(opt & (OPT_d << !!dups))) { /* (if dups, opt & OPT_u) */ + if (opt & OPT_c) { + /* %7lu matches GNU coreutils 6.9 */ + printf("%7lu ", dups + 1); + } + printf("%s%c", old_line, eol); + } + free(old_line); + } + } while (cur_line); + + die_if_ferror(stdin, input_filename); + + fflush_stdout_and_exit_SUCCESS(); +} diff --git a/busybox-1_37_0/coreutils/unlink.c b/busybox-1_37_0/coreutils/unlink.c new file mode 100644 index 000000000..61b108a84 --- /dev/null +++ b/busybox-1_37_0/coreutils/unlink.c @@ -0,0 +1,33 @@ +/* vi: set sw=4 ts=4: */ +/* + * unlink for busybox + * + * Copyright (C) 2014 Isaac Dunham + * + * Licensed under GPLv2, see LICENSE in this source tree + */ +//config:config UNLINK +//config: bool "unlink (3.5 kb)" +//config: default y +//config: help +//config: unlink deletes a file by calling unlink() + +//applet:IF_UNLINK(APPLET_NOFORK(unlink, unlink, BB_DIR_USR_BIN, BB_SUID_DROP, unlink)) + +//kbuild:lib-$(CONFIG_UNLINK) += unlink.o + +//usage:#define unlink_trivial_usage +//usage: "FILE" +//usage:#define unlink_full_usage "\n\n" +//usage: "Delete FILE by calling unlink()" + +#include "libbb.h" + +int unlink_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int unlink_main(int argc UNUSED_PARAM, char **argv) +{ + getopt32(argv, "^" "" "\0" "=1"); + argv += optind; + xunlink(argv[0]); + return 0; +} diff --git a/busybox-1_37_0/coreutils/usleep.c b/busybox-1_37_0/coreutils/usleep.c new file mode 100644 index 000000000..bb619405b --- /dev/null +++ b/busybox-1_37_0/coreutils/usleep.c @@ -0,0 +1,51 @@ +/* vi: set sw=4 ts=4: */ +/* + * usleep implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config USLEEP +//config: bool "usleep (1.6 kb)" +//config: default y +//config: help +//config: usleep is used to pause for a specified number of microseconds. + +//applet:IF_USLEEP(APPLET_NOFORK(usleep, usleep, BB_DIR_BIN, BB_SUID_DROP, usleep)) + +//kbuild:lib-$(CONFIG_USLEEP) += usleep.o + +/* BB_AUDIT SUSv3 N/A -- Apparently a busybox extension. */ + +//usage:#define usleep_trivial_usage +//usage: "N" +//usage:#define usleep_full_usage "\n\n" +//usage: "Pause for N microseconds" +//usage: +//usage:#define usleep_example_usage +//usage: "$ usleep 1000000\n" +//usage: "[pauses for 1 second]\n" + +#include "libbb.h" + +/* This is a NOFORK applet. Be very careful! */ + +int usleep_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int usleep_main(int argc UNUSED_PARAM, char **argv) +{ + if (!argv[1]) { + bb_show_usage(); + } + + /* Safe wrt NOFORK? (noforks are not allowed to run for + * a long time). Try "usleep 99999999" + ^C + "echo $?" + * in hush with FEATURE_SH_NOFORK=y. + * At least on uclibc, usleep() thanslates to nanosleep() + * which returns early on any signal (even caught one), + * and uclibc does not loop back on EINTR. + */ + usleep(xatou(argv[1])); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/uudecode.c b/busybox-1_37_0/coreutils/uudecode.c new file mode 100644 index 000000000..59768f87e --- /dev/null +++ b/busybox-1_37_0/coreutils/uudecode.c @@ -0,0 +1,390 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright 2003, Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * Based on specification from + * http://www.opengroup.org/onlinepubs/007904975/utilities/uuencode.html + * + * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the + * "end" line + */ +//config:config UUDECODE +//config: bool "uudecode (5.9 kb)" +//config: default y +//config: help +//config: uudecode is used to decode a uuencoded file. + +//applet:IF_UUDECODE(APPLET(uudecode, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UUDECODE) += uudecode.o + +//usage:#define uudecode_trivial_usage +//usage: "[-o OUTFILE] [INFILE]" +//usage:#define uudecode_full_usage "\n\n" +//usage: "Uudecode a file\n" +//usage: "Finds OUTFILE in uuencoded source unless -o is given" +//usage: +//usage:#define uudecode_example_usage +//usage: "$ uudecode -o busybox busybox.uu\n" +//usage: "$ ls -l busybox\n" +//usage: "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" + +#include "libbb.h" + +#if ENABLE_UUDECODE +static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags UNUSED_PARAM) +{ + char *line; + + for (;;) { + int encoded_len, str_len; + char *line_ptr, *dst; + size_t line_len; + + line_len = 64 * 1024; + line = xmalloc_fgets_str_len(src_stream, "\n", &line_len); + if (!line) + break; + /* Handle both Unix and MSDOS text. + * Note: space should not be trimmed, some encoders use it instead of "`" + * for padding of last incomplete 4-char block. + */ + str_len = line_len; + while (--str_len >= 0 + && (line[str_len] == '\n' || line[str_len] == '\r') + ) { + line[str_len] = '\0'; + } + + if (strcmp(line, "end") == 0) { + return; /* the only non-error exit */ + } + + line_ptr = line; + while (*line_ptr) { + *line_ptr = (*line_ptr - 0x20) & 0x3f; + line_ptr++; + } + str_len = line_ptr - line; + + encoded_len = line[0] * 4 / 3; + /* Check that line is not too short. (we tolerate + * overly _long_ line to accommodate possible extra "`"). + * Empty line case is also caught here. */ + if (str_len <= encoded_len) { + break; /* go to bb_error_msg_and_die("short file"); */ + } + if (encoded_len <= 0) { + /* Ignore the "`\n" line, why is it even in the encode file ? */ + free(line); + continue; + } + if (encoded_len > 60) { + bb_simple_error_msg_and_die("line too long"); + } + + dst = line; + line_ptr = line + 1; + do { + /* Merge four 6 bit chars to three 8 bit chars */ + *dst++ = line_ptr[0] << 2 | line_ptr[1] >> 4; + encoded_len--; + if (encoded_len == 0) { + break; + } + + *dst++ = line_ptr[1] << 4 | line_ptr[2] >> 2; + encoded_len--; + if (encoded_len == 0) { + break; + } + + *dst++ = line_ptr[2] << 6 | line_ptr[3]; + line_ptr += 4; + encoded_len -= 2; + } while (encoded_len > 0); + fwrite(line, 1, dst - line, dst_stream); + free(line); + } + bb_simple_error_msg_and_die("short file"); +} + +int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uudecode_main(int argc UNUSED_PARAM, char **argv) +{ + FILE *src_stream; + char *outname = NULL; + char *line; + + getopt32(argv, "^" "o:" "\0" "?1"/* 1 arg max*/, &outname); + argv += optind; + + if (!argv[0]) + *--argv = (char*)"-"; + src_stream = xfopen_stdin(argv[0]); + + /* Search for the start of the encoding */ + while ((line = xmalloc_fgetline(src_stream)) != NULL) { + void FAST_FUNC (*decode_fn_ptr)(FILE *src, FILE *dst, int flags); + char *line_ptr; + FILE *dst_stream; + int mode; + + if (is_prefixed_with(line, "begin-base64 ")) { + line_ptr = line + 13; + decode_fn_ptr = read_base64; + } else if (is_prefixed_with(line, "begin ")) { + line_ptr = line + 6; + decode_fn_ptr = read_stduu; + } else { + free(line); + continue; + } + + /* begin line found. decode and exit */ + mode = bb_strtou(line_ptr, NULL, 8); + if (outname == NULL) { + outname = strchr(line_ptr, ' '); + if (!outname) + break; + outname++; + trim(outname); /* remove trailing space (and '\r' for DOS text) */ + if (!outname[0]) + break; + } + dst_stream = stdout; + if (NOT_LONE_DASH(outname) +/* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html + * https://pubs.opengroup.org/onlinepubs/9699919799/utilities/uuencode.html + * The above says that output file name specified in input file + * or overridden by -o OUTFILE can be special "/dev/stdout" string. + * This usually works "implicitly": many systems have /dev/stdout. + * If ENABLE_DESKTOP, support that explicitly: + */ + && (!ENABLE_DESKTOP || strcmp(outname, "/dev/stdout") != 0) + ) { + dst_stream = xfopen_for_write(outname); + fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO)); + } + free(line); + decode_fn_ptr(src_stream, dst_stream, /*flags:*/ BASE64_FLAG_UU_STOP + BASE64_FLAG_NO_STOP_CHAR); + /* fclose_if_not_stdin(src_stream); - redundant */ + return EXIT_SUCCESS; + } + bb_simple_error_msg_and_die("no 'begin' line"); +} +#endif + +//config:config BASE32 +//config: bool "base32 (5.5 kb)" +//config: default y +//config: help +//config: Base32 encode and decode + +//config:config BASE64 +//config: bool "base64 (5.3 kb)" +//config: default y +//config: help +//config: Base64 encode and decode + +//usage:#define base32_trivial_usage +//usage: "[-d] [-w COL] [FILE]" +//usage:#define base32_full_usage "\n\n" +//usage: "Base32 encode or decode FILE to standard output\n" +//usage: "\n -d Decode data" +//usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" +////usage: "\n -i When decoding, ignore non-alphabet characters" + +//usage:#define base64_trivial_usage +//usage: "[-d] [-w COL] [FILE]" +//usage:#define base64_full_usage "\n\n" +//usage: "Base64 encode or decode FILE to standard output\n" +//usage: "\n -d Decode data" +//usage: "\n -w COL Wrap lines at COL (default 76, 0 disables)" +///////: "\n -i When decoding, ignore non-alphabet characters" +// -i is accepted but has no effect: currently, decode_base32/64() functions +// (called via read_base64()) skip invalid chars unconditionally. + +// APPLET_ODDNAME:name main location suid_type help +//applet:IF_BASE32(APPLET_ODDNAME(base32, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base32)) +//applet:IF_BASE64(APPLET_ODDNAME(base64, baseNUM, BB_DIR_BIN, BB_SUID_DROP, base64)) + +//kbuild:lib-$(CONFIG_BASE64) += uudecode.o +//kbuild:lib-$(CONFIG_BASE32) += uudecode.o + +#if ENABLE_BASE32 || ENABLE_BASE64 + +# if ENABLE_BASE32 +static void bb_b32encode(char *p, const void *src, int length) +{ +#define tbl bb_uuenc_tbl_base32 + const unsigned char *s = src; + + /* Transform 5x8 bits to 8x5 bits */ + while (length > 0) { + unsigned cur, next; + + length--; + cur = *s++; + *p++ = tbl[cur >> 3]; // xxxxx--- -------- -------- -------- -------- + cur &= 7; + + next = 0; + if (--length >= 0) + next = *s++; + *p++ = tbl[(cur << 2) + (next >> 6)]; // -----xxx xx------ -------- -------- -------- + cur = next & 0x3f; + + *p++ = tbl[cur >> 1]; // -------- --xxxxx- -------- -------- -------- + cur &= 1; + + next = 0; + if (--length >= 0) + next = *s++; + *p++ = tbl[(cur << 4) + (next >> 4)]; // -------- -------x xxxx---- -------- -------- + cur = next & 0xf; + + next = 0; + if (--length >= 0) + next = *s++; + *p++ = tbl[(cur << 1) + (next >> 7)]; // -------- -------- ----xxxx x------- -------- + cur = next & 0x7f; + + *p++ = tbl[cur >> 2]; // -------- -------- -------- -xxxxx-- -------- + cur &= 3; + + next = 0; + if (--length >= 0) + next = *s++; + *p++ = tbl[(cur << 3) + (next >> 5)]; // -------- -------- -------- ------xx xxx----- + cur = next & 0x1f; + + *p++ = tbl[cur]; // -------- -------- -------- -------- ---xxxxx + } +#undef tbl + /* Zero-terminate */ + *p = '\0'; + /* Pad as necessary */ + length = ((-length) * 3) >> 1; /* -4 => 6 pad chars, -3 => 4, -2 => 3, -1 => 1 */ + while (length--) { + *--p = '='; + } +} +# else +void bb_b32encode(char *p, const void *src, int length); /* undefined */ +# endif + +int baseNUM_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int baseNUM_main(int argc UNUSED_PARAM, char **argv) +{ + FILE *src_stream; + unsigned opts; + unsigned col = 76; + + opts = getopt32(argv, "^" "diw:+" "\0" "?1"/* 1 arg max*/, &col); + argv += optind; + + if (!argv[0]) + *--argv = (char*)"-"; + src_stream = xfopen_stdin(argv[0]); + if (opts & 1) { + /* -d: decode */ + int flags = (unsigned char)EOF; + if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3')) + flags = ((unsigned char)EOF) | BASE64_32; + read_base64(src_stream, stdout, flags); + } else { + enum { + SRC_BUF_SIZE = 3 * 5 * 32, /* this *MUST* be a multiple of 3 and 5 */ + DST_BUF_SIZE = 8 * ((SRC_BUF_SIZE + 4) / 5), /* max growth on encode (base32 case) */ + }; + /* Use one buffer for both input and output: + * encoding reads input "left-to-right", + * it's safe to place source at the end of the buffer and + * overwrite it while encoding, just be careful to have a gap. + */ + char dst_buf[((DST_BUF_SIZE + /*gap:*/ 16) /*round up to 16:*/ | 0xf) + 1]; +#define src_buf (dst_buf + sizeof(dst_buf) - SRC_BUF_SIZE) + int src_fd, rem; + + src_fd = fileno(src_stream); + rem = 0; + while (1) { + size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE); + if ((ssize_t)size < 0) + bb_simple_perror_msg_and_die(bb_msg_read_error); + if (size == 0) { + if (rem != 0) bb_putchar('\n'); + break; + } + + /* Encode the buffer we just read in */ + if (ENABLE_BASE32 && (!ENABLE_BASE64 || applet_name[4] == '3')) { + bb_b32encode(dst_buf, src_buf, size); + size = 8 * ((size + 4) / 5); + } else { + bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); + size = 4 * ((size + 2) / 3); + } + + if (col == 0) { + fputs_stdout(dst_buf); + } else { + char *result = dst_buf; + if (rem == 0) + rem = col; + while (1) { + int out = size < rem ? size : rem; + rem -= out; + printf(rem != 0 ? "%.*s" : "%.*s\n", out, result); + if (rem != 0) + break; + size -= out; + if (size == 0) + break; + result += out; + rem = col; + } + } + } +#undef src_buf + } + + fflush_stdout_and_exit_SUCCESS(); +} +#endif + +/* Test script. +Put this into an empty dir with busybox binary, an run. + +#!/bin/sh +test -x busybox || { echo "No ./busybox?"; exit; } +ln -sf busybox uudecode +ln -sf busybox uuencode +>A_null +echo -n A >A +echo -n AB >AB +echo -n ABC >ABC +echo -n ABCD >ABCD +echo -n ABCDE >ABCDE +echo -n ABCDEF >ABCDEF +cat busybox >A_bbox +for f in A*; do + echo uuencode $f + ./uuencode $f <$f >u_$f + ./uuencode -m $f <$f >m_$f +done +mkdir unpk_u unpk_m 2>/dev/null +for f in u_*; do + ./uudecode <$f -o unpk_u/${f:2} + diff -a ${f:2} unpk_u/${f:2} >/dev/null 2>&1 + echo uudecode $f: $? +done +for f in m_*; do + ./uudecode <$f -o unpk_m/${f:2} + diff -a ${f:2} unpk_m/${f:2} >/dev/null 2>&1 + echo uudecode $f: $? +done +*/ diff --git a/busybox-1_37_0/coreutils/uuencode.c b/busybox-1_37_0/coreutils/uuencode.c new file mode 100644 index 000000000..97ff39ee3 --- /dev/null +++ b/busybox-1_37_0/coreutils/uuencode.c @@ -0,0 +1,82 @@ +/* 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. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config UUENCODE +//config: bool "uuencode (4.7 kb)" +//config: default y +//config: help +//config: uuencode is used to uuencode a file. + +//applet:IF_UUENCODE(APPLET(uuencode, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UUENCODE) += uuencode.o + +//usage:#define uuencode_trivial_usage +//usage: "[-m] [FILE] STORED_FILENAME" +//usage:#define uuencode_full_usage "\n\n" +//usage: "Uuencode FILE (or stdin) to stdout\n" +//usage: "\n -m Use base64 encoding per RFC1521" +//usage: +//usage:#define uuencode_example_usage +//usage: "$ uuencode busybox busybox\n" +//usage: "begin 755 busybox\n" +//usage: "\n" +//usage: "$ uudecode busybox busybox > busybox.uu\n" +//usage: "$\n" + +#include "libbb.h" + +enum { + SRC_BUF_SIZE = 15*3, /* This *MUST* be a multiple of 3 */ + DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), +}; + +int uuencode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int uuencode_main(int argc UNUSED_PARAM, char **argv) +{ + struct stat stat_buf; + int src_fd = STDIN_FILENO; + const char *tbl; + mode_t mode; + char src_buf[SRC_BUF_SIZE]; + char dst_buf[DST_BUF_SIZE + 1]; + + tbl = bb_uuenc_tbl_std; + mode = 0666 & ~umask(0666); + if (getopt32(argv, "^" "m" "\0" "-1:?2"/*must have 1 or 2 args*/)) { + tbl = bb_uuenc_tbl_base64; + } + argv += optind; + if (argv[1]) { + src_fd = xopen(argv[0], O_RDONLY); + fstat(src_fd, &stat_buf); + mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); + argv++; + } + + printf("begin%s %o %s", tbl == bb_uuenc_tbl_std ? "" : "-base64", mode, *argv); + while (1) { + size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE); + if (!size) + break; + if ((ssize_t)size < 0) + bb_simple_perror_msg_and_die(bb_msg_read_error); + /* Encode the buffer we just read in */ + bb_uuencode(dst_buf, src_buf, size, tbl); + bb_putchar('\n'); + if (tbl == bb_uuenc_tbl_std) { + bb_putchar(tbl[size]); + } + fflush(stdout); + xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3)); + } + printf(tbl == bb_uuenc_tbl_std ? "\n`\nend\n" : "\n====\n"); + + fflush_stdout_and_exit_SUCCESS(); +} diff --git a/busybox-1_37_0/coreutils/wc.c b/busybox-1_37_0/coreutils/wc.c new file mode 100644 index 000000000..de75aba72 --- /dev/null +++ b/busybox-1_37_0/coreutils/wc.c @@ -0,0 +1,257 @@ +/* vi: set sw=4 ts=4: */ +/* + * wc implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Rewritten to fix a number of problems and do some size optimizations. + * Problems in the previous busybox implementation (besides bloat) included: + * 1) broken 'wc -c' optimization (read note below) + * 2) broken handling of '-' args + * 3) no checking of ferror on EOF returns + * 4) isprint() wasn't considered when word counting. + * + * NOTES: + * + * The previous busybox wc attempted an optimization using stat for the + * case of counting chars only. I omitted that because it was broken. + * It didn't take into account the possibility of input coming from a + * pipe, or input from a file with file pointer not at the beginning. + * + * To implement such a speed optimization correctly, not only do you + * need the size, but also the file position. Note also that the + * file position may be past the end of file. Consider the example + * (adapted from example in gnu wc.c) + * + * echo hello > /tmp/testfile && + * (dd ibs=1k skip=1 count=0 &> /dev/null; wc -c) < /tmp/testfile + * + * for which 'wc -c' should output '0'. + */ +//config:config WC +//config: bool "wc (4.7 kb)" +//config: default y +//config: help +//config: wc is used to print the number of bytes, words, and lines, +//config: in specified files. +//config: +//config:config FEATURE_WC_LARGE +//config: bool "Support very large counts" +//config: default y +//config: depends on WC +//config: help +//config: Use "unsigned long long" for counter variables. + +//applet:IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_WC) += wc.o + +/* BB_AUDIT SUSv3 compliant. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */ + +#include "libbb.h" +#include "unicode.h" + +#if !ENABLE_LOCALE_SUPPORT +# undef isprint +# undef isspace +# define isprint(c) ((unsigned)((c) - 0x20) <= (0x7e - 0x20)) +# define isspace(c) ((c) == ' ') +#endif + +#if ENABLE_FEATURE_WC_LARGE +# define COUNT_T unsigned long long +# define COUNT_FMT "llu" +#else +# define COUNT_T unsigned +# define COUNT_FMT "u" +#endif + +/* We support -m even when UNICODE_SUPPORT is off, + * we just don't advertise it in help text, + * since it is the same as -c in this case. + */ + +//usage:#define wc_trivial_usage +//usage: "[-c"IF_UNICODE_SUPPORT("m")"lwL] [FILE]..." +//usage: +//usage:#define wc_full_usage "\n\n" +//usage: "Count lines, words, and bytes for FILEs (or stdin)\n" +//usage: "\n -c Count bytes" +//usage: IF_UNICODE_SUPPORT( +//usage: "\n -m Count characters" +//usage: ) +//usage: "\n -l Count newlines" +//usage: "\n -w Count words" +//usage: "\n -L Print longest line length" +//usage: +//usage:#define wc_example_usage +//usage: "$ wc /etc/passwd\n" +//usage: " 31 46 1365 /etc/passwd\n" + +/* Order is important if we want to be compatible with + * column order in "wc -cmlwL" output: + */ +enum { + WC_LINES = 0, /* -l */ + WC_WORDS = 1, /* -w */ + WC_UNICHARS = 2, /* -m */ + WC_BYTES = 3, /* -c */ + WC_LENGTH = 4, /* -L */ + NUM_WCS = 5, +}; + +int wc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int wc_main(int argc UNUSED_PARAM, char **argv) +{ + const char *arg; + const char *start_fmt = " %9"COUNT_FMT + 1; + const char *fname_fmt = " %s\n"; + COUNT_T *pcounts; + COUNT_T counts[NUM_WCS]; + COUNT_T totals[NUM_WCS]; + int num_files; + smallint status = EXIT_SUCCESS; + unsigned print_type; + + init_unicode(); + + print_type = getopt32(argv, "lwmcL"); + + if (print_type == 0) { + print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_BYTES); + } + + argv += optind; + if (!argv[0]) { + *--argv = (char *) bb_msg_standard_input; + fname_fmt = "\n"; + } + if (!argv[1]) { /* zero or one filename? */ + if (!((print_type-1) & print_type)) /* exactly one option? */ + start_fmt = "%"COUNT_FMT; + } + + memset(totals, 0, sizeof(totals)); + + pcounts = counts; + + num_files = 0; + while ((arg = *argv++) != NULL) { + FILE *fp; + const char *s; + unsigned u; + unsigned linepos; + smallint in_word; + + ++num_files; + fp = fopen_or_warn_stdin(arg); + if (!fp) { + status = EXIT_FAILURE; + continue; + } + + memset(counts, 0, sizeof(counts)); + linepos = 0; + in_word = 0; + + while (1) { + int c; + /* Our -w doesn't match GNU wc exactly... oh well */ + + c = getc(fp); + if (c == EOF) { + if (ferror(fp)) { + bb_simple_perror_msg(arg); + status = EXIT_FAILURE; + } + goto DO_EOF; /* Treat an EOF as '\r'. */ + } + + /* Cater for -c and -m */ + ++counts[WC_BYTES]; + if (unicode_status != UNICODE_ON /* every byte is a new char */ + || (c & 0xc0) != 0x80 /* it isn't a 2nd+ byte of a Unicode char */ + ) { + ++counts[WC_UNICHARS]; + } + + if (isprint_asciionly(c)) { /* FIXME: not unicode-aware */ + ++linepos; + if (!isspace(c)) { + in_word = 1; + continue; + } + } else if ((unsigned)(c - 9) <= 4) { + /* \t 9 + * \n 10 + * \v 11 + * \f 12 + * \r 13 + */ + if (c == '\t') { + linepos = (linepos | 7) + 1; + } else { /* '\n', '\r', '\f', or '\v' */ + DO_EOF: + if (linepos > counts[WC_LENGTH]) { + counts[WC_LENGTH] = linepos; + } + if (c == '\n') { + ++counts[WC_LINES]; + } + if (c != '\v') { + linepos = 0; + } + } + } else { + continue; + } + + counts[WC_WORDS] += in_word; + in_word = 0; + if (c == EOF) { + break; + } + } + + fclose_if_not_stdin(fp); + + if (totals[WC_LENGTH] < counts[WC_LENGTH]) { + totals[WC_LENGTH] = counts[WC_LENGTH]; + } + totals[WC_LENGTH] -= counts[WC_LENGTH]; + + OUTPUT: + /* coreutils wc tries hard to print pretty columns + * (saves results for all files, finds max col len etc...) + * we won't try that hard, it will bloat us too much */ + s = start_fmt; + u = 0; + do { + if (print_type & (1 << u)) { + printf(s, pcounts[u]); + s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ + } + totals[u] += pcounts[u]; + } while (++u < NUM_WCS); + printf(fname_fmt, arg); + } + + /* If more than one file was processed, we want the totals. To save some + * space, we set the pcounts ptr to the totals array. This has the side + * effect of trashing the totals array after outputting it, but that's + * irrelavent since we no longer need it. */ + if (num_files > 1) { + num_files = 0; /* Make sure we don't get here again. */ + arg = "total"; + pcounts = totals; + --argv; + goto OUTPUT; + } + + fflush_stdout_and_exit(status); +} diff --git a/busybox-1_37_0/coreutils/who.c b/busybox-1_37_0/coreutils/who.c new file mode 100644 index 000000000..6f96f7243 --- /dev/null +++ b/busybox-1_37_0/coreutils/who.c @@ -0,0 +1,170 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini who is used to display user name, login time, + * idle time and host name. + * + * Author: Da Chen + * + * This is a free document; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation: + * http://www.gnu.org/copyleft/gpl.html + * + * Copyright (c) 2002 AYR Networks, Inc. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config WHO +//config: bool "who (5.6 kb)" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Print users currently logged on. +//config: +// procps-ng has this variation of "who": +//config:config W +//config: bool "w (5.5 kb)" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Print users currently logged on. +//config: +//config:config USERS +//config: bool "users (3.6 kb)" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Print users currently logged on. + +// APPLET_NOEXEC:name main location suid_type help +//applet:IF_USERS(APPLET_NOEXEC(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) +//applet:IF_W( APPLET_NOEXEC(w, who, BB_DIR_USR_BIN, BB_SUID_DROP, w)) +//applet:IF_WHO( APPLET_NOEXEC(who, who, BB_DIR_USR_BIN, BB_SUID_DROP, who)) + +//kbuild:lib-$(CONFIG_USERS) += who.o +//kbuild:lib-$(CONFIG_W) += who.o +//kbuild:lib-$(CONFIG_WHO) += who.o + +/* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */ + +//usage:#define users_trivial_usage +//usage: "" +//usage:#define users_full_usage "\n\n" +//usage: "Print the users currently logged on" + +//usage:#define w_trivial_usage +//usage: "" +//usage:#define w_full_usage "\n\n" +//usage: "Show who is logged on" +// +// procps-ng 3.3.10: +// "\n -h, --no-header" +// "\n -u, --no-current" +// Ignores the username while figuring out the current process +// and cpu times. To demonstrate this, do a "su" and do a "w" and a "w -u". +// "\n -s, --short" +// Short format. Don't print the login time, JCPU or PCPU times. +// "\n -f, --from" +// Toggle printing the from (remote hostname) field. +// The default is for the from field to not be printed +// "\n -i, --ip-addr" +// Display IP address instead of hostname for from field. +// "\n -o, --old-style" +// Old style output. Prints blank space for idle times less than one minute. +// Example output: +// 17:28:00 up 4 days, 22:41, 4 users, load average: 0.84, 0.97, 0.90 +// USER TTY LOGIN@ IDLE JCPU PCPU WHAT +// root tty1 Thu18 4days 4:33m 0.07s /bin/sh /etc/xdg/xfce4/xinitrc -- vt +// root pts/1 Mon13 3:24m 1:01 0.01s w + +//usage:#define who_trivial_usage +//usage: "[-aH]" +//usage:#define who_full_usage "\n\n" +//usage: "Show who is logged on\n" +//usage: "\n -a Show all" +//usage: "\n -H Print column headers" + +#include "libbb.h" + +static void idle_string(char *str6, time_t t) +{ + t = time(NULL) - t; + + /*if (t < 60) { + str6[0] = '.'; + str6[1] = '\0'; + return; + }*/ + if (t >= 0 && t < (24 * 60 * 60)) { + sprintf(str6, "%02d:%02d", + (int) (t / (60 * 60)), + (int) ((t % (60 * 60)) / 60)); + return; + } + strcpy(str6, "old"); +} + +int who_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int who_main(int argc UNUSED_PARAM, char **argv) +{ +#define CNT_APPLET (ENABLE_USERS + ENABLE_W + ENABLE_WHO) + int do_users = (ENABLE_USERS && (CNT_APPLET == 1 || applet_name[0] == 'u')); + int do_w = (ENABLE_W && (CNT_APPLET == 1 || applet_name[1] == '\0')); + int do_who = (ENABLE_WHO && (CNT_APPLET == 1 || applet_name[1] == 'h')); + struct utmpx *ut; + unsigned opt; + const char *fmt = "%s"; + + opt = getopt32(argv, do_who ? "^" "aH" "\0" "=0": "^" "" "\0" "=0"); + if ((opt & 2) || do_w) /* -H or we are w */ + puts("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST"); + + setutxent(); + while ((ut = getutxent()) != NULL) { + if (ut->ut_user[0] + && ((opt & 1) || ut->ut_type == USER_PROCESS) + ) { + if (!do_users) { + char str6[6]; + char name[sizeof("/dev/") + sizeof(ut->ut_line) + 1]; + struct stat st; + time_t seconds; + + str6[0] = '?'; + str6[1] = '\0'; + strcpy(name, "/dev/"); + safe_strncpy(ut->ut_line[0] == '/' ? name : name + sizeof("/dev/")-1, + ut->ut_line, + sizeof(ut->ut_line)+1 + ); + if (stat(name, &st) == 0) + idle_string(str6, st.st_atime); + /* manpages say ut_tv.tv_sec *is* time_t, + * but some systems have it wrong */ + seconds = ut->ut_tv.tv_sec; + /* How wide time field can be? + * "Nov 10 19:33:20": 15 chars + * "2010-11-10 19:33": 16 chars + */ + printf("%-15.*s %-15.*s %-7s %-16.16s %.*s\n", + (int)sizeof(ut->ut_user), ut->ut_user, + (int)sizeof(ut->ut_line), ut->ut_line, + str6, +// TODO: with LANG=en_US.UTF-8, who from coreutils 8.25 shows +// TIME col as "2017-04-06 18:47" (the default format is "Apr 6 18:47"). +// The former format looks saner to me. Switch to it unconditionally? + ctime(&seconds) + 4, + (int)sizeof(ut->ut_host), ut->ut_host + ); + } else { + printf(fmt, ut->ut_user); + fmt = " %s"; + } + } + } + if (do_users) + bb_putchar('\n'); + if (ENABLE_FEATURE_CLEAN_UP) + endutxent(); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/coreutils/whoami.c b/busybox-1_37_0/coreutils/whoami.c new file mode 100644 index 000000000..7e94d51fb --- /dev/null +++ b/busybox-1_37_0/coreutils/whoami.c @@ -0,0 +1,39 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini whoami implementation for busybox + * + * Copyright (C) 2000 Edward Betts . + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config WHOAMI +//config: bool "whoami (3.5 kb)" +//config: default y +//config: help +//config: whoami is used to print the username of the current +//config: user id (same as id -un). + +//applet:IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami)) + +//kbuild:lib-$(CONFIG_WHOAMI) += whoami.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define whoami_trivial_usage +//usage: "" +//usage:#define whoami_full_usage "\n\n" +//usage: "Print the user name associated with the current effective user id" + +#include "libbb.h" + +int whoami_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int whoami_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + if (argv[1]) + bb_show_usage(); + + /* Will complain and die if username not found */ + puts(xuid2uname(geteuid())); + + return fflush_all(); +} diff --git a/busybox-1_37_0/coreutils/yes.c b/busybox-1_37_0/coreutils/yes.c new file mode 100644 index 000000000..e04ad3ac0 --- /dev/null +++ b/busybox-1_37_0/coreutils/yes.c @@ -0,0 +1,54 @@ +/* vi: set sw=4 ts=4: */ +/* + * yes implementation for busybox + * + * Copyright (C) 2003 Manuel Novoa III + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) + * + * Size reductions and removed redundant applet name prefix from error messages. + */ +//config:config YES +//config: bool "yes (1.5 kb)" +//config: default y +//config: help +//config: yes is used to repeatedly output a specific string, or +//config: the default string 'y'. + +//applet:IF_YES(APPLET_NOEXEC(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) +/* was NOFORK, but then yes can't be ^C'ed if run by hush */ + +//kbuild:lib-$(CONFIG_YES) += yes.o + +/* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ + +//usage:#define yes_trivial_usage +//usage: "[STRING]" +//usage:#define yes_full_usage "\n\n" +//usage: "Repeatedly print a line with STRING, or 'y'" + +#include "libbb.h" + +int yes_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int yes_main(int argc UNUSED_PARAM, char **argv) +{ + char **pp; + + argv[0] = (char*)"y"; + if (argv[1]) + ++argv; + + do { + pp = argv; + while (1) { + fputs_stdout(*pp); + if (!*++pp) + break; + putchar(' '); + } + } while (putchar('\n') != EOF); + + bb_perror_nomsg_and_die(); +} diff --git a/busybox-1_37_0/debianutils/Config.src b/busybox-1_37_0/debianutils/Config.src new file mode 100644 index 000000000..17b0d8945 --- /dev/null +++ b/busybox-1_37_0/debianutils/Config.src @@ -0,0 +1,10 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Debian Utilities" + +INSERT + +endmenu diff --git a/busybox-1_37_0/debianutils/Kbuild.src b/busybox-1_37_0/debianutils/Kbuild.src new file mode 100644 index 000000000..6b4fb7470 --- /dev/null +++ b/busybox-1_37_0/debianutils/Kbuild.src @@ -0,0 +1,9 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +lib-y:= + +INSERT diff --git a/busybox-1_37_0/debianutils/pipe_progress.c b/busybox-1_37_0/debianutils/pipe_progress.c new file mode 100644 index 000000000..acd7402d7 --- /dev/null +++ b/busybox-1_37_0/debianutils/pipe_progress.c @@ -0,0 +1,48 @@ +/* vi: set sw=4 ts=4: */ +/* + * Monitor a pipe with a simple progress display. + * + * Copyright (C) 2003 by Rob Landley , Joey Hess + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config PIPE_PROGRESS +//config: bool "pipe_progress (576 bytes)" +//config: default y +//config: help +//config: Display a dot to indicate pipe activity. + +//applet:IF_PIPE_PROGRESS(APPLET(pipe_progress, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PIPE_PROGRESS) += pipe_progress.o + +//usage:#define pipe_progress_trivial_usage NOUSAGE_STR +//usage:#define pipe_progress_full_usage "" + +#include "libbb.h" + +#define PIPE_PROGRESS_SIZE 4096 + +/* Read a block of data from stdin, write it to stdout. + * Activity is indicated by a '.' to stderr + */ +int pipe_progress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pipe_progress_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + char buf[PIPE_PROGRESS_SIZE]; + time_t t = time(NULL); + int len; + + while ((len = safe_read(STDIN_FILENO, buf, PIPE_PROGRESS_SIZE)) > 0) { + time_t new_time = time(NULL); + if (new_time != t) { + t = new_time; + bb_putchar_stderr('.'); + } + full_write(STDOUT_FILENO, buf, len); + } + + bb_putchar_stderr('\n'); + + return 0; +} diff --git a/busybox-1_37_0/debianutils/run_parts.c b/busybox-1_37_0/debianutils/run_parts.c new file mode 100644 index 000000000..780df3e96 --- /dev/null +++ b/busybox-1_37_0/debianutils/run_parts.c @@ -0,0 +1,246 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini run-parts implementation for busybox + * + * Copyright (C) 2007 Bernhard Reutner-Fischer + * + * Based on a older version that was in busybox which was 1k big. + * Copyright (C) 2001 by Emanuele Aina + * + * Based on the Debian run-parts program, version 1.15 + * Copyright (C) 1996 Jeff Noxon , + * Copyright (C) 1996-1999 Guy Maor + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* This is my first attempt to write a program in C (well, this is my first + * attempt to write a program! :-) . */ + +/* This piece of code is heavily based on the original version of run-parts, + * taken from debian-utils. I've only removed the long options and the + * report mode. As the original run-parts support only long options, I've + * broken compatibility because the BusyBox policy doesn't allow them. + */ +//config:config RUN_PARTS +//config: bool "run-parts (6.2 kb)" +//config: default y +//config: help +//config: run-parts is a utility designed to run all the scripts in a directory. +//config: +//config: It is useful to set up a directory like cron.daily, where you need to +//config: execute all the scripts in that directory. +//config: +//config: In this implementation of run-parts some features (such as report +//config: mode) are not implemented. +//config: +//config: Unless you know that run-parts is used in some of your scripts +//config: you can safely say N here. +//config: +//config:config FEATURE_RUN_PARTS_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on RUN_PARTS && LONG_OPTS +//config: +//config:config FEATURE_RUN_PARTS_FANCY +//config: bool "Support additional arguments" +//config: default y +//config: depends on RUN_PARTS +//config: help +//config: Support additional options: +//config: -l --list print the names of the all matching files (not +//config: limited to executables), but don't actually run them. + +//applet:IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts)) + +//kbuild:lib-$(CONFIG_RUN_PARTS) += run_parts.o + +//usage:#define run_parts_trivial_usage +//usage: "[-a ARG]... [-u UMASK] " +//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS("[--reverse] [--test] [--exit-on-error] "IF_FEATURE_RUN_PARTS_FANCY("[--list] ")) +//usage: "DIRECTORY" +//usage:#define run_parts_full_usage "\n\n" +//usage: "Run a bunch of scripts in DIRECTORY\n" +//usage: "\n -a ARG Pass ARG as argument to scripts" +//usage: "\n -u UMASK Set UMASK before running scripts" +//usage: IF_FEATURE_RUN_PARTS_LONG_OPTIONS( +//usage: "\n --reverse Reverse execution order" +//usage: "\n --test Dry run" +//usage: "\n --exit-on-error Exit if a script exits with non-zero" +//usage: IF_FEATURE_RUN_PARTS_FANCY( +//usage: "\n --list Print names of matching files even if they are not executable" +//usage: ) +//usage: ) +//usage: +//usage:#define run_parts_example_usage +//usage: "$ run-parts -a start /etc/init.d\n" +//usage: "$ run-parts -a stop=now /etc/init.d\n\n" +//usage: "Let's assume you have a script foo/dosomething:\n" +//usage: "#!/bin/sh\n" +//usage: "for i in $*; do eval $i; done; unset i\n" +//usage: "case \"$1\" in\n" +//usage: "start*) echo starting something;;\n" +//usage: "stop*) set -x; shutdown -h $stop;;\n" +//usage: "esac\n\n" +//usage: "Running this yields:\n" +//usage: "$run-parts -a stop=+4m foo/\n" +//usage: "+ shutdown -h +4m" + +#include "libbb.h" +#include "common_bufsiz.h" + +struct globals { + char **names; + int cur; + char *cmd[2 /* using 1 provokes compiler warning */]; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define names (G.names) +#define cur (G.cur ) +#define cmd (G.cmd ) +#define INIT_G() do { setup_common_bufsiz(); } while (0) + +enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; + +enum { + OPT_a = (1 << 0), + OPT_u = (1 << 1), + OPT_r = (1 << 2) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_t = (1 << 3) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_e = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS, + OPT_l = (1 << 5) * ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS + * ENABLE_FEATURE_RUN_PARTS_FANCY, +}; + +/* Is this a valid filename (upper/lower alpha, digits, + * underscores, hyphens, and non-leading dots only?) + */ +static bool invalid_name(const char *c) +{ + c = bb_basename(c); + + if (*c == '.') + return *c; + + /* Debian run-parts 4.8.3, manpage: + * "...the names must consist entirely of ASCII letters, + * ASCII digits, ASCII underscores, and ASCII minus-hyphens. + * However, the name must not begin with a period." + * The last sentence is a giveaway that something is fishy + * (why mention leading dot if dots are not allowed anyway?). + * Yes, you guessed it right: in fact non-leading dots ARE allowed. + */ + while (isalnum(*c) || *c == '_' || *c == '-' || *c == '.') + c++; + + return *c; /* TRUE (!0) if terminating NUL is not reached */ +} + +static int bb_alphasort(const void *p1, const void *p2) +{ + int r = strcmp(*(char **) p1, *(char **) p2); + return (option_mask32 & OPT_r) ? -r : r; +} + +static int FAST_FUNC act(struct recursive_state *state, + const char *file, struct stat *statbuf) +{ + if (state->depth == 0) + return TRUE; + + if (state->depth == 1 + && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) + || invalid_name(file) + || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) + ) { + return SKIP; + } + + names = xrealloc_vector(names, 4, cur); + names[cur++] = xstrdup(file); + /*names[cur] = NULL; - xrealloc_vector did it */ + + return TRUE; +} + +#if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS +static const char runparts_longopts[] ALIGN1 = + "arg\0" Required_argument "a" + "umask\0" Required_argument "u" +//TODO: "verbose\0" No_argument "v" + "reverse\0" No_argument "\xf0" + "test\0" No_argument "\xf1" + "exit-on-error\0" No_argument "\xf2" +# if ENABLE_FEATURE_RUN_PARTS_FANCY + "list\0" No_argument "\xf3" +# endif + ; +# define GETOPT32 getopt32long +# define LONGOPTS ,runparts_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS +#endif + +int run_parts_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int run_parts_main(int argc UNUSED_PARAM, char **argv) +{ + const char *umask_p = "22"; + llist_t *arg_list = NULL; + unsigned n; + int ret; + + INIT_G(); + + /* We require exactly one argument: the directory name */ + GETOPT32(argv, "^" "a:*u:" "\0" "=1" LONGOPTS, + &arg_list, &umask_p + ); + + umask(xstrtou_range(umask_p, 8, 0, 07777)); + + n = 1; + while (arg_list && n < NUM_CMD) { + cmd[n++] = llist_pop(&arg_list); + } + /* cmd[n] = NULL; - is already zeroed out */ + + /* run-parts has to sort executables by name before running them */ + + recursive_action(argv[optind], + ACTION_RECURSE|ACTION_FOLLOWLINKS, + act, /* file action */ + act, /* dir action */ + NULL /* user data */ + ); + + if (!names) + return 0; + + qsort(names, cur, sizeof(char *), bb_alphasort); + + n = 0; + while (1) { + char *name = *names++; + if (!name) + break; + if (option_mask32 & (OPT_t | OPT_l)) { + puts(name); + continue; + } + cmd[0] = name; + ret = spawn_and_wait(cmd); + if (ret == 0) + continue; + n = 1; + if (ret < 0) + bb_perror_msg("can't execute '%s'", name); + else /* ret > 0 */ + bb_error_msg("%s: exit status %u", name, ret & 0xff); + + if (option_mask32 & OPT_e) + xfunc_die(); + } + + return n; +} diff --git a/busybox-1_37_0/debianutils/start_stop_daemon.c b/busybox-1_37_0/debianutils/start_stop_daemon.c new file mode 100644 index 000000000..271bc4edf --- /dev/null +++ b/busybox-1_37_0/debianutils/start_stop_daemon.c @@ -0,0 +1,634 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini start-stop-daemon implementation(s) for busybox + * + * Written by Marek Michalkiewicz , + * Adapted for busybox David Kimdon + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* +This is how it is supposed to work: + +start-stop-daemon [OPTIONS] [--start|--stop] [[--] ARGS] + +One (only) of these must be given: + -S,--start Start + -K,--stop Stop + -T,--status Check for the existence of a process, return exitcode (since version 1.16.1) + 0 - program is running + 1 - program is not running and the pid file exists + 3 - program is not running + 4 - can't determine program status + +Search for matching processes. +If --stop is given, stop all matching processes (by sending a signal). +If --start is given, start a new process unless a matching process was found. + +Options controlling process matching +(if multiple conditions are specified, all must match): + -u,--user USERNAME|UID Only consider this user's processes + -n,--name PROCESS_NAME Look for processes by matching PROCESS_NAME + with comm field in /proc/$PID/stat. + Only basename is compared: + "ntpd" == "./ntpd" == "/path/to/ntpd". +[TODO: can PROCESS_NAME be a full pathname? Should we require full match then +with /proc/$PID/exe or argv[0] (comm can't be matched, it never contains path)] + -x,--exec EXECUTABLE Look for processes that were started with this + command in /proc/$PID/exe and /proc/$PID/cmdline + (/proc/$PID/cmdline is a bbox extension) + Unlike -n, we match against the full path: + "ntpd" != "./ntpd" != "/path/to/ntpd" + -p,--pidfile PID_FILE Look for processes with PID from this file + --pid PID Look for process with this pid (since version 1.17.6) + --ppid PPID Look for processes with parent pid (since version 1.17.7) + +Options which are valid for --start only: + -x,--exec EXECUTABLE Program to run (1st arg of execvp). + If no -x, EXECUTABLE is taken from ARGS[0] + -a,--startas NAME argv[0] (defaults to EXECUTABLE) + -b,--background Put process into background + -O,--output FILE Redirect stdout and stderr to FILE when forcing the + daemon into the background (since version 1.20.6). + Requires --background and absolute pathname (tested with 1.21.22). + Uses O_CREAT|O_APPEND! + If execv fails, error message goes to FILE. + -N,--nicelevel N Add N to process' nice level + -c,--chuid USER[:[GRP]] Change to specified user [and group] + -m,--make-pidfile Write PID to the pidfile + (both -m and -p must be given!) + -P,--procsched policy:priority + This alters the process scheduler policy and priority of the + process before starting it (since version 1.15.0). The + priority can be optionally specified by appending a : + followed by the value. The default priority is 0. The + currently supported policy values are other, fifo and rr. + -r,--chroot DIR Change directory and chroot to DIR before starting the + process. Please note that the pidfile is also written after + the chroot. + -d,--chdir DIR Change directory to DIR before starting the process. This is + done after the chroot if the -r|--chroot option is set. + When not specified, start-stop-daemon will change directory to the + root directory before starting the process. + ^^^^ Gentoo does not have the default chdir("/"). Debian does. + Tested -S with 1.21.22: + "start-stop-daemon -S -x /bin/pwd" is the minimum needed to run pwd. + "start-stop-daemon -S -a /bin/pwd -n pwd" works too. + "start-stop-daemon -S -a /bin/pwd" does NOT work. + Earlier versions were less picky (which? Or is it only Gentoo's clone?) + +Options which are valid for --stop only: + -s,--signal SIG Signal to send (default:TERM) + -t,--test Exit with status 0 if process is found + (we don't actually start or stop daemons) + --remove-pidfile Used when stopping a program that does not remove its own pid + file (since version 1.17.19). Requires -p PIDFILE? + +Misc options: + -o,--oknodo Exit with status 0 if nothing is done + -q,--quiet Quiet + -v,--verbose Verbose +*/ +//config:config START_STOP_DAEMON +//config: bool "start-stop-daemon (12 kb)" +//config: default y +//config: help +//config: start-stop-daemon is used to control the creation and +//config: termination of system-level processes, usually the ones +//config: started during the startup of the system. +//config: +//config:config FEATURE_START_STOP_DAEMON_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on START_STOP_DAEMON && LONG_OPTS +//config: +//config:config FEATURE_START_STOP_DAEMON_FANCY +//config: bool "Support additional arguments" +//config: default y +//config: depends on START_STOP_DAEMON +//config: help +//config: -o|--oknodo ignored since we exit with 0 anyway +//config: -v|--verbose +//config: -N|--nicelevel N + +//applet:IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) +/* not NOEXEC: uses bb_common_bufsiz1 */ + +//kbuild:lib-$(CONFIG_START_STOP_DAEMON) += start_stop_daemon.o + +//usage:#define start_stop_daemon_trivial_usage +//usage: "-S|-K [OPTIONS] [-- ARGS]" +//usage:#define start_stop_daemon_full_usage "\n\n" +//usage: "Search for matching processes, and then\n" +//usage: "-S: start a process unless a matching process is found\n" +//usage: "-K: stop all matching processes\n" +//usage: "\nProcess matching:" +//usage: "\n -u USERNAME|UID Match only this user's processes" +//usage: "\n -n NAME Match processes with NAME" +//usage: "\n in comm field in /proc/PID/stat" +//usage: "\n -x EXECUTABLE Match processes with this command" +//usage: "\n in /proc/PID/cmdline" +//usage: "\n -p FILE Match a process with PID from FILE" +//usage: "\n All specified conditions must match" +//usage: "\n-S only:" +//usage: "\n -x EXECUTABLE Program to run" +//usage: "\n -a NAME Zeroth argument" +//usage: "\n -b Background" +//usage: "\n -O FILE Append stdout and stderr to FILE" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -N N Change nice level" +//usage: ) +//usage: "\n -c USER[:[GRP]] Change user/group" +//usage: "\n -d DIR Change to DIR" +//usage: "\n -m Write PID to pidfile specified by -p" +//usage: "\n-K only:" +//usage: "\n -s SIG Signal to send" +//usage: "\n -t Match only, exit with 0 if found" +//usage: "\nOther:" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -o Exit with status 0 if nothing is done" +//usage: "\n -v Verbose" +//usage: "\n -q Quiet" +//usage: ) + +/* Override ENABLE_FEATURE_PIDFILE */ +#define WANT_PIDFILE 1 +#include "libbb.h" +#include "common_bufsiz.h" + +struct pid_list { + struct pid_list *next; + pid_t pid; +}; + +enum { + CTX_STOP = (1 << 0), + CTX_START = (1 << 1), + OPT_BACKGROUND = (1 << 2), // -b + OPT_QUIET = (1 << 3), // -q + OPT_TEST = (1 << 4), // -t + OPT_MAKEPID = (1 << 5), // -m + OPT_a = (1 << 6), // -a + OPT_n = (1 << 7), // -n + OPT_s = (1 << 8), // -s + OPT_u = (1 << 9), // -u + OPT_c = (1 << 10), // -c + OPT_d = (1 << 11), // -d + OPT_x = (1 << 12), // -x + OPT_p = (1 << 13), // -p + OPT_OUTPUT = (1 << 14), // -O + OPT_OKNODO = (1 << 15) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -o + OPT_VERBOSE = (1 << 16) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -v + OPT_NICELEVEL = (1 << 17) * ENABLE_FEATURE_START_STOP_DAEMON_FANCY, // -N +}; +#define QUIET (option_mask32 & OPT_QUIET) +#define TEST (option_mask32 & OPT_TEST) + +struct globals { + struct pid_list *found_procs; + const char *userspec; + const char *cmdname; + const char *execname; + const char *pidfile; + char *execname_cmpbuf; + unsigned execname_sizeof; + int user_id; + smallint signal_nr; +#ifdef OLDER_VERSION_OF_X + struct stat execstat; +#endif +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define userspec (G.userspec ) +#define cmdname (G.cmdname ) +#define execname (G.execname ) +#define pidfile (G.pidfile ) +#define user_id (G.user_id ) +#define signal_nr (G.signal_nr ) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + user_id = -1; \ + signal_nr = 15; \ +} while (0) + +#ifdef OLDER_VERSION_OF_X +/* -x,--exec EXECUTABLE + * Look for processes with matching /proc/$PID/exe. + * Match is performed using device+inode. + */ +static int pid_is_exec(pid_t pid) +{ + struct stat st; + char buf[sizeof("/proc/%u/exe") + sizeof(int)*3]; + + sprintf(buf, "/proc/%u/exe", (unsigned)pid); + if (stat(buf, &st) < 0) + return 0; + if (st.st_dev == G.execstat.st_dev + && st.st_ino == G.execstat.st_ino) + return 1; + return 0; +} +#else +static int pid_is_exec(pid_t pid) +{ + ssize_t bytes; + char buf[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; + char *procname, *exelink; + int match; + + procname = buf + sprintf(buf, "/proc/%u/exe", (unsigned)pid) - 3; + + exelink = xmalloc_readlink(buf); + match = (exelink && strcmp(execname, exelink) == 0); + free(exelink); + if (match) + return match; + + strcpy(procname, "cmdline"); + bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof); + if (bytes > 0) { + G.execname_cmpbuf[bytes] = '\0'; + return strcmp(execname, G.execname_cmpbuf) == 0; + } + return 0; +} +#endif + +static int pid_is_name(pid_t pid) +{ + /* /proc/PID/stat is "PID (comm_15_bytes_max) ..." */ + char buf[32]; /* should be enough */ + char *p, *pe; + + sprintf(buf, "/proc/%u/stat", (unsigned)pid); + if (open_read_close(buf, buf, sizeof(buf) - 1) < 0) + return 0; + buf[sizeof(buf) - 1] = '\0'; /* paranoia */ + p = strchr(buf, '('); + if (!p) + return 0; + pe = strrchr(++p, ')'); + if (!pe) + return 0; + *pe = '\0'; + /* we require comm to match and to not be truncated */ + /* in Linux, if comm is 15 chars, it may be a truncated + * name, so we don't allow that to match */ + if (strlen(p) >= COMM_LEN - 1) /* COMM_LEN is 16 */ + return 0; + return strcmp(p, cmdname) == 0; +} + +static int pid_is_user(int pid) +{ + struct stat sb; + char buf[sizeof("/proc/") + sizeof(int)*3]; + + sprintf(buf, "/proc/%u", (unsigned)pid); + if (stat(buf, &sb) != 0) + return 0; + return (sb.st_uid == (uid_t)user_id); +} + +static void check(int pid) +{ + struct pid_list *p; + + if (execname && !pid_is_exec(pid)) { + return; + } + if (cmdname && !pid_is_name(pid)) { + return; + } + if (userspec && !pid_is_user(pid)) { + return; + } + p = xmalloc(sizeof(*p)); + p->next = G.found_procs; + p->pid = pid; + G.found_procs = p; +} + +static void do_pidfile(void) +{ + FILE *f; + unsigned pid; + + f = fopen_for_read(pidfile); + if (f) { + if (fscanf(f, "%u", &pid) == 1) + check(pid); + fclose(f); + } else if (errno != ENOENT) + bb_perror_msg_and_die("open pidfile %s", pidfile); +} + +static void do_procinit(void) +{ + DIR *procdir; + struct dirent *entry; + int pid; + + if (pidfile) { + do_pidfile(); + return; + } + + procdir = xopendir("/proc"); + + pid = 0; + while (1) { + errno = 0; /* clear any previous error */ + entry = readdir(procdir); +// TODO: this check is too generic, it's better +// to check for exact errno(s) which mean that we got stale entry + if (errno) /* Stale entry, process has died after opendir */ + continue; + if (!entry) /* EOF, no more entries */ + break; + pid = bb_strtou(entry->d_name, NULL, 10); + if (errno) /* NaN */ + continue; + check(pid); + } + closedir(procdir); + if (!pid) + bb_simple_error_msg_and_die("nothing in /proc - not mounted?"); +} + +static int do_stop(void) +{ + const char *what; + struct pid_list *p; + int killed = 0; + + if (cmdname) { + if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(cmdname); + if (!ENABLE_FEATURE_CLEAN_UP) what = cmdname; + } else if (execname) { + if (ENABLE_FEATURE_CLEAN_UP) what = xstrdup(execname); + if (!ENABLE_FEATURE_CLEAN_UP) what = execname; + } else if (pidfile) { + what = xasprintf("process in pidfile '%s'", pidfile); + } else if (userspec) { + what = xasprintf("process(es) owned by '%s'", userspec); + } else { + bb_simple_error_msg_and_die("internal error, please report"); + } + + if (!G.found_procs) { + if (!QUIET) + printf("no %s found; none killed\n", what); + killed = -1; + goto ret; + } + for (p = G.found_procs; p; p = p->next) { + if (kill(p->pid, TEST ? 0 : signal_nr) == 0) { + killed++; + } else { + bb_perror_msg("warning: killing process %u", (unsigned)p->pid); + p->pid = 0; + if (TEST) { + /* Example: -K --test --pidfile PIDFILE detected + * that PIDFILE's pid doesn't exist */ + killed = -1; + goto ret; + } + } + } + if (!QUIET && killed) { + printf("stopped %s (pid", what); + for (p = G.found_procs; p; p = p->next) + if (p->pid) + printf(" %u", (unsigned)p->pid); + puts(")"); + } + ret: + if (ENABLE_FEATURE_CLEAN_UP) + free((char *)what); + return killed; +} + +#if ENABLE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS +static const char start_stop_daemon_longopts[] ALIGN1 = + "stop\0" No_argument "K" + "start\0" No_argument "S" + "background\0" No_argument "b" + "quiet\0" No_argument "q" + "test\0" No_argument "t" + "make-pidfile\0" No_argument "m" + "output\0" Required_argument "O" +# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + "oknodo\0" No_argument "o" + "verbose\0" No_argument "v" + "nicelevel\0" Required_argument "N" +# endif + "startas\0" Required_argument "a" + "name\0" Required_argument "n" + "signal\0" Required_argument "s" + "user\0" Required_argument "u" + "chuid\0" Required_argument "c" + "chdir\0" Required_argument "d" + "exec\0" Required_argument "x" + "pidfile\0" Required_argument "p" +# if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + "retry\0" Required_argument "R" +# endif + ; +# define GETOPT32 getopt32long +# define LONGOPTS start_stop_daemon_longopts, +#else +# define GETOPT32 getopt32 +# define LONGOPTS +#endif + +int start_stop_daemon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opt; + const char *signame; + const char *startas = NULL; + char *chuid; + const char *chdir; + const char *output = NULL; +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +// const char *retry_arg = NULL; +// int retries = -1; + const char *opt_N; +#endif + + INIT_G(); + + opt = GETOPT32(argv, "^" + "KSbqtma:n:s:u:c:d:x:p:O:" + IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:") + "\0" + "K:S:K--S:S--K" + /* -K or -S is required; they are mutually exclusive */ + ":m?p" /* -p is required if -m is given */ + ":K?xpun" /* -xpun (at least one) is required if -K is given */ + /* (the above does not seem to be enforced by Gentoo, it does nothing + * if no matching is specified with -K, and it ignores ARGS + * - does not take ARGS[0] as program name to kill) + */ +// ":S?xa" /* -xa (at least one) is required if -S is given */ +//Gentoo clone: "start-stop-daemon -S -- sleep 5" is a valid invocation + IF_FEATURE_START_STOP_DAEMON_FANCY(":q-v") /* -q turns off -v */ + , + LONGOPTS + &startas, &cmdname, &signame, &userspec, &chuid, &chdir, &execname, &pidfile, &output + IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N) + /* We accept and ignore -R / --retry */ + IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL) + ); + +//-O requires --background and absolute pathname (tested with 1.21.22). +//We don't bother requiring that (smaller code): +//#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY +// if ((opt & OPT_OUTPUT) && !(opt & OPT_BACKGROUND)) +// bb_show_usage(); +//#endif + + if (opt & OPT_s) { + signal_nr = get_signum(signame); + if (signal_nr < 0) bb_show_usage(); + } + + //argc -= optind; + argv += optind; +// ARGS contains zeroth arg if -x/-a is not given, else it starts with 1st arg. +// These will try to execute "[/bin/]sleep 5": +// "start-stop-daemon -S -- sleep 5" +// "start-stop-daemon -S -x /bin/sleep -- 5" +// "start-stop-daemon -S -a sleep -- 5" +// NB: -n option does _not_ behave in this way: this will try to execute "5": +// "start-stop-daemon -S -n sleep -- 5" + if (opt & CTX_START) { + if (!execname) { /* -x is not given */ + execname = startas; + if (!execname) { /* neither -x nor -a is given */ + execname = argv[0]; + if (!execname) + bb_show_usage(); + argv++; + } + } + if (!startas) /* -a is not given: use -x EXECUTABLE or argv[0] */ + startas = execname; + *--argv = (char *)startas; + } + if (execname) { + G.execname_sizeof = strlen(execname) + 1; + G.execname_cmpbuf = xmalloc(G.execname_sizeof + 1); + } +// IF_FEATURE_START_STOP_DAEMON_FANCY( +// if (retry_arg) +// retries = xatoi_positive(retry_arg); +// ) + if (userspec) { + user_id = bb_strtou(userspec, NULL, 10); + if (errno) + user_id = xuname2uid(userspec); + } + + /* Both start and stop need to know current processes */ + do_procinit(); + + if (opt & CTX_STOP) { + int i = do_stop(); + return (opt & OPT_OKNODO) ? 0 : (i <= 0); + } + + /* else: CTX_START (-S). execname can't be NULL. */ + + if (G.found_procs) { + if (!QUIET) + printf("%s is already running\n", execname); + return !(opt & OPT_OKNODO); + } + +#ifdef OLDER_VERSION_OF_X + if (execname) + xstat(execname, &G.execstat); +#endif + + if (opt & OPT_BACKGROUND) { + /* Daemons usually call bb_daemonize_or_rexec(), but SSD can do + * without: SSD is not itself a daemon, it _execs_ a daemon. + * The usual NOMMU problem of "child can't run indefinitely, + * it must exec" does not bite us: we exec anyway. + * + * bb_daemonize(DAEMON_DEVNULL_STDIO | DAEMON_CLOSE_EXTRA_FDS | DAEMON_DOUBLE_FORK) + * can be used on MMU systems, but use of vfork() + * is preferable since we want to create pidfile + * _before_ parent returns, and vfork() on Linux + * ensures that (by blocking parent until exec in the child). + */ + pid_t pid = xvfork(); + if (pid != 0) { + /* Parent */ + /* why _exit? the child may have changed the stack, + * so "return 0" may do bad things + */ + _exit_SUCCESS(); + } + /* Child */ + setsid(); /* detach from controlling tty */ + /* Redirect stdin to /dev/null, close extra FDs */ + /* Testcase: "start-stop-daemon -Sb -d /does/not/exist usleep 1" should not eat error message */ + bb_daemon_helper(DAEMON_DEVNULL_STDIN + DAEMON_CLOSE_EXTRA_FDS); + if (!output) + output = bb_dev_null; /* redirect output just before execv */ + /* On Linux, session leader can acquire ctty + * unknowingly, by opening a tty. + * Prevent this: stop being a session leader. + */ + pid = xvfork(); + if (pid != 0) + _exit_SUCCESS(); /* Parent */ + } + if (opt & OPT_MAKEPID) { + /* User wants _us_ to make the pidfile */ + write_pidfile(pidfile); + } +#if ENABLE_FEATURE_START_STOP_DAEMON_FANCY + if (opt & OPT_NICELEVEL) { + /* Set process priority (must be before OPT_c) */ + int prio = getpriority(PRIO_PROCESS, 0) + xatoi_range(opt_N, INT_MIN/2, INT_MAX/2); + if (setpriority(PRIO_PROCESS, 0, prio) < 0) { + bb_perror_msg_and_die("setpriority(%d)", prio); + } + } +#endif + if (opt & OPT_c) { + struct bb_uidgid_t ugid; + parse_chown_usergroup_or_die(&ugid, chuid); + if (ugid.uid != (uid_t) -1L) { + struct passwd *pw = xgetpwuid(ugid.uid); + if (ugid.gid != (gid_t) -1L) + pw->pw_gid = ugid.gid; + /* initgroups, setgid, setuid: */ + change_identity(pw); + } else if (ugid.gid != (gid_t) -1L) { + xsetgid(ugid.gid); + setgroups(1, &ugid.gid); + } + } + if (opt & OPT_d) { + xchdir(chdir); + } + if (output) { + int outfd = xopen(output, O_WRONLY | O_CREAT | O_APPEND); + xmove_fd(outfd, STDOUT_FILENO); + xdup2(STDOUT_FILENO, STDERR_FILENO); + /* on execv error, the message goes to -O file. This is intended */ + } + /* Try: + * strace -oLOG start-stop-daemon -S -x /bin/usleep -a qwerty 500000 + * should exec "/bin/usleep", but argv[0] should be "qwerty": + */ + execvp(execname, argv); + bb_perror_msg_and_die("can't execute '%s'", startas); +} diff --git a/busybox-1_37_0/debianutils/which.c b/busybox-1_37_0/debianutils/which.c new file mode 100644 index 000000000..1f547919f --- /dev/null +++ b/busybox-1_37_0/debianutils/which.c @@ -0,0 +1,74 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 1999-2004 by Erik Andersen + * Copyright (C) 2006 Gabriel Somlo + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config WHICH +//config: bool "which (4 kb)" +//config: default y +//config: help +//config: which is used to find programs in your PATH and +//config: print out their pathnames. + +//applet:IF_WHICH(APPLET_NOFORK(which, which, BB_DIR_USR_BIN, BB_SUID_DROP, which)) + +//kbuild:lib-$(CONFIG_WHICH) += which.o + +//usage:#define which_trivial_usage +//usage: "[-a] COMMAND..." +//usage:#define which_full_usage "\n\n" +//usage: "Locate COMMAND\n" +//usage: "\n -a Show all matches" +//usage: +//usage:#define which_example_usage +//usage: "$ which login\n" +//usage: "/bin/login\n" + +#include "libbb.h" + +int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int which_main(int argc UNUSED_PARAM, char **argv) +{ + char *env_path; + int status = 0; + /* This sizeof(): bb_default_root_path is shorter than BB_PATH_ROOT_PATH */ + char buf[sizeof(BB_PATH_ROOT_PATH)]; + + env_path = getenv("PATH"); + if (!env_path) + /* env_path must be writable, and must not alloc, so... */ + env_path = strcpy(buf, bb_default_root_path); + + getopt32(argv, "^" "a" "\0" "-1"/*at least one arg*/); + argv += optind; + + do { + int missing = 1; + + /* If file contains a slash don't use PATH */ + if (strchr(*argv, '/')) { + if (file_is_executable(*argv)) { + missing = 0; + puts(*argv); + } + } else { + char *path; + char *p; + + path = env_path; + /* NOFORK NB: xmalloc inside find_executable(), must have no allocs above! */ + while ((p = find_executable(*argv, &path)) != NULL) { + missing = 0; + puts(p); + free(p); + if (!option_mask32) /* -a not set */ + break; + } + } + status |= missing; + } while (*++argv); + + return status; +} diff --git a/busybox-1_37_0/docs/.gitignore b/busybox-1_37_0/docs/.gitignore new file mode 100644 index 000000000..3d1c5bd8a --- /dev/null +++ b/busybox-1_37_0/docs/.gitignore @@ -0,0 +1,5 @@ +/busybox.1 +/BusyBox.html +/busybox.net +/BusyBox.txt +/busybox.pod diff --git a/busybox-1_37_0/docs/Kconfig-language.txt b/busybox-1_37_0/docs/Kconfig-language.txt new file mode 100644 index 000000000..0ba8932ba --- /dev/null +++ b/busybox-1_37_0/docs/Kconfig-language.txt @@ -0,0 +1,255 @@ +Introduction +------------ + +The configuration database is collection of configuration options +organized in a tree structure: + + +- Code maturity level options + | +- Prompt for development and/or incomplete code/drivers + +- General setup + | +- Networking support + | +- System V IPC + | +- BSD Process Accounting + | +- Sysctl support + +- Loadable module support + | +- Enable loadable module support + | +- Set version information on all module symbols + | +- Kernel module loader + +- ... + +Every entry has its own dependencies. These dependencies are used +to determine the visible of an entry. Any child entry is only +visible if its parent entry is also visible. + +Menu entries +------------ + +Most entries define a config option, all other entries help to organize +them. A single configuration option is defined like this: + +config MODVERSIONS + bool "Set version information on all module symbols" + depends MODULES + help + Usually, modules have to be recompiled whenever you switch to a new + kernel. ... + +Every line starts with a key word and can be followed by multiple +arguments. "config" starts a new config entry. The following lines +define attributes for this config option. Attributes can be the type of +the config option, input prompt, dependencies, help text and default +values. A config option can be defined multiple times with the same +name, but every definition can have only a single input prompt and the +type must not conflict. + +Menu attributes +--------------- + +A menu entry can have a number of attributes. Not all of them are +applicable everywhere (see syntax). + +- type definition: "bool"/"tristate"/"string"/"hex"/"integer" + Every config option must have a type. There are only two basic types: + tristate and string, the other types base on these two. The type + definition optionally accepts an input prompt, so these two examples + are equivalent: + + bool "Networking support" + and + bool + prompt "Networking support" + +- input prompt: "prompt" ["if" ] + Every menu entry can have at most one prompt, which is used to display + to the user. Optionally dependencies only for this prompt can be added + with "if". + +- default value: "default" ["if" ] + A config option can have any number of default values. If multiple + default values are visible, only the first defined one is active. + Default values are not limited to the menu entry, where they are + defined, this means the default can be defined somewhere else or be + overridden by an earlier definition. + The default value is only assigned to the config symbol if no other + value was set by the user (via the input prompt above). If an input + prompt is visible the default value is presented to the user and can + be overridden by him. + Optionally dependencies only for this default value can be added with + "if". + +- dependencies: "depends on"/"requires" + This defines a dependency for this menu entry. If multiple + dependencies are defined they are connected with '&&'. Dependencies + are applied to all other options within this menu entry (which also + accept "if" expression), so these two examples are equivalent: + + bool "foo" if BAR + default y if BAR + and + depends on BAR + bool "foo" + default y + +- help text: "help" + This defines a help text. The end of the help text is determined by + the level indentation, this means it ends at the first line which has + a smaller indentation than the first line of the help text. + + +Menu dependencies +----------------- + +Dependencies define the visibility of a menu entry and can also reduce +the input range of tristate symbols. The tristate logic used in the +expressions uses one more state than normal boolean logic to express the +module state. Dependency expressions have the following syntax: + + ::= (1) + '=' (2) + '!=' (3) + '(' ')' (4) + '!' (5) + '||' (6) + '&&' (7) + +Expressions are listed in decreasing order of precedence. + +(1) Convert the symbol into an expression. Boolean and tristate symbols + are simply converted into the respective expression values. All + other symbol types result in 'n'. +(2) If the values of both symbols are equal, it returns 'y', + otherwise 'n'. +(3) If the values of both symbols are equal, it returns 'n', + otherwise 'y'. +(4) Returns the value of the expression. Used to override precedence. +(5) Returns the result of (2-/expr/). +(6) Returns the result of min(/expr/, /expr/). +(7) Returns the result of max(/expr/, /expr/). + +An expression can have a value of 'n', 'm' or 'y' (or 0, 1, 2 +respectively for calculations). A menu entry becomes visible when it's +expression evaluates to 'm' or 'y'. + +There are two type of symbols: constant and nonconstant symbols. +Nonconstant symbols are the most common ones and are defined with the +'config' statement. Nonconstant symbols consist entirely of alphanumeric +characters or underscores. +Constant symbols are only part of expressions. Constant symbols are +always surrounded by single or double quotes. Within the quote any +other character is allowed and the quotes can be escaped using '\'. + +Menu structure +-------------- + +The position of a menu entry in the tree is determined in two ways. First +it can be specified explicitely: + +menu "Network device support" + depends NET + +config NETDEVICES + ... + +endmenu + +All entries within the "menu" ... "endmenu" block become a submenu of +"Network device support". All subentries inherit the dependencies from +the menu entry, e.g. this means the dependency "NET" is added to the +dependency list of the config option NETDEVICES. + +The other way to generate the menu structure is done by analyzing the +dependencies. If a menu entry somehow depends on the previous entry, it +can be made a submenu of it. First the the previous (parent) symbol must +be part of the dependency list and then one of these two condititions +must be true: +- the child entry must become invisible, if the parent is set to 'n' +- the child entry must only be visible, if the parent is visible + +config MODULES + bool "Enable loadable module support" + +config MODVERSIONS + bool "Set version information on all module symbols" + depends MODULES + +comment "module support disabled" + depends !MODULES + +MODVERSIONS directly depends on MODULES, this means it's only visible if +MODULES is different from 'n'. The comment on the other hand is always +visible when MODULES it's visible (the (empty) dependency of MODULES is +also part of the comment dependencies). + + +Kconfig syntax +-------------- + +The configuration file describes a series of menu entries, where every +line starts with a keyword (except help texts). The following keywords +end a menu entry: +- config +- choice/endchoice +- comment +- menu/endmenu +- if/endif +- source +The first four also start the definition of a menu entry. + +config: + + "config" + + +This defines a config symbol and accepts any of above +attributes as options. + +choices: + + "choice" + + + "endchoice" + +This defines a choice group and accepts any of above attributes as +options. A choice can only be of type bool or tristate, while a boolean +choice only allows a single config entry to be selected, a tristate +choice also allows any number of config entries to be set to 'm'. This +can be used if multiple drivers for a single hardware exists and only a +single driver can be compiled/loaded into the kernel, but all drivers +can be compiled as modules. +A choice accepts another option "optional", which allows to set the +choice to 'n' and no entry needs to be selected. + +comment: + + "comment" + + +This defines a comment which is displayed to the user during the +configuration process and is also echoed to the output files. The only +possible options are dependencies. + +menu: + + "menu" + + + "endmenu" + +This defines a menu block, see "Menu structure" above for more +information. The only possible options are dependencies. + +if: + + "if" + + "endif" + +This defines an if block. The dependency expression is appended +to all enclosed menu entries. + +source: + + "source" + +This reads the specified configuration file. This file is always parsed. diff --git a/busybox-1_37_0/docs/Serial-Programming-HOWTO.txt b/busybox-1_37_0/docs/Serial-Programming-HOWTO.txt new file mode 100644 index 000000000..8a3954b09 --- /dev/null +++ b/busybox-1_37_0/docs/Serial-Programming-HOWTO.txt @@ -0,0 +1,424 @@ +Downloaded from http://www.lafn.org/~dave/linux/Serial-Programming-HOWTO.txt +Seems to be somewhat old, but contains useful bits for getty.c hacking +============================================================================ + + The Linux Serial Programming HOWTO, Part 1 of 2 + By Vernon C. Hoxie + v2.0 10 September 1999 + + This document describes how to program communications with devices + over a serial port on a Linux box. + ______________________________________________________________________ + + Table of Contents + + 1. Copyright + + 2. Introduction + + 3. Opening + + 4. Commands + + 5. Changing Baud Rates + + 6. Additional Control Calls + + 6.1 Sending a "break". + 6.2 Hardware flow control. + 6.3 Flushing I/O buffers. + + 7. Modem control + + 8. Process Groups + + 8.1 Sessions + 8.2 Process Groups + 8.3 Controlling Terminal + 8.3.1 Get the foreground group process id. + 8.3.2 Set the foreground process group id of a terminal. + 8.3.3 Get process group id. + + 9. Lockfiles + + 10. Additional Information + + 11. Feedback + + ______________________________________________________________________ + + 1. Copyright + + The Linux Serial-Programming-HOWTO is copyright (C) 1997 by Vernon + Hoxie. Linux HOWTO documents may be reproduced and distributed in + whole or in part, in any medium physical or electronic, as long as + this copyright notice is retained on all copies. Commercial + redistribution is allowed and encouraged; however, the author would + like to be notified of any such distributions. + + All translations, derivative works, or aggregate works incorporating + this Linux HOWTO document must be covered under this copyright notice. + That is, you may not produce a derivative work from this HOWTO and + impose additional restrictions on its distribution. + + This version is a complete rewrite of the previous Serial-Programming- + HOWTO by Peter H. Baumann, + + 2. Introduction + + This HOWTO will attempt to give hints about how to write a program + which needs to access a serial port. Its principal focus will be on + the Linux implementation and what the meaning of the various library + functions available. + + Someone asked about which of several sequences of operations was + right. There is no absolute right way to accomplish an outcome. The + options available are too numerous. If your sequences produces the + desired results, then that is the right way for you. Another + programmer may select another set of options and get the same results. + His method is right for him. + + Neither of these methods may operate properly with some other + implementation of UNIX. It is strange that many of the concepts which + were implemented in the SYSV version have been dumped. Because UNIX + was developed by AT&T and much code has been generated on those + concepts, the AT&T version should be the standard to which others + should emulate. + + Now the standard is POSIX. + + It was once stated that the popularity of UNIX and C was that they + were created by programmers for programmers. Not by scholars who + insist on purity of style in deference to results and simplicity of + use. Not by committees with people who have diverse personal or + proprietary agenda. Now ANSI and POSIX have strayed from those + original clear and simply concepts. + + 3. Opening + + The various serial devices are opened just as any other file. + Although, the fopen(3) command may be used, the plain open(2) is + preferred. This call returns the file descriptor which is required + for the various commands that configure the interface. + + Open(2) has the format: + + #include + int open(char *path, int flags, [int mode]); + + In addition to the obvious O_RDWR, O_WRONLY and O_RDONLY, two + additional flags are available. These are O_NONBLOCK and O_NOCTTY. + Other flags listed in the open(2) manual page are not applicable to + serial devices. + + Normally, a serial device opens in "blocking" mode. This means that + the open() will not return until the Carrier Detect line from the port + is active, e.g. modem, is active. When opened with the O_NONBLOCK + flag set, the open() will return immediately regardless of the status + of the DCD line. The "blocking" mode also affects the read() call. + + The fcntl(2) command can be used to change the O_NONBLOCK flag anytime + after the device has been opened. + + The device driver and the data passing through it are controlled + according to settings in the struct termios. This structure is + defined in "/usr/include/termios.h". In the Linux tree, further + reference is made to "/usr/include/asm/termbits.h". + In blocking mode, a read(2) will block until data is available or a + signal is received. It is still subject to state of the ICANON flag. + + When the termios.c_lflag ICANON bit is set, input data is collected + into strings until a NL, EOF or EOL character is received. You can + define these in the termios.c_cc[] array. Also, ERASE and KILL + characters will operate on the incoming data before it is delivered to + the user. + + In non-canonical mode, incoming data is quantified by use of the + c_cc[VMIN and c_cc[VTIME] values in termios.c_cc[]. + + Some programmers use the select() call to detect the completion of a + read(). This is not the best way of checking for incoming data. + Select() is part of the SOCKETS scheme and too complex for most + applications. + + A full explanation of the fields of the termios structure is contained + in termios(7) of the Users Manual. A version is included in Part 2 of + this HOWTO document. + + 4. Commands + + Changes to the struct termios are made by retrieving the current + settings, making the desired changes and transmitting the modified + structure back to the kernel. + + The historic means of communicating with the kernel was by use of the + ioctl(fd, COMMAND, arg) system call. Then the purists in the + computer industry decided that this was not genetically consistent. + Their argument was that the argument changed its stripes. Sometimes + it was an int, sometimes it was a pointer to int and other times it + was a pointer to struct termios. Then there were those times it was + empty or NULL. These variations are dependent upon the COMMAND. + + As a alternative, the tc* series of functions were concocted. + + These are: + + int tcgetattr(int filedes, struct termios *termios_p); + int tcsetattr(int filedes, int optional_actions, + const struct termios *termios_p); + + instead of: + + int ioctl(int filedes, int command, + struct termios *termios_p); + + where command is TCGETS or one of TCSETS, TCSETSW or TCSETSF. + + The TCSETS command is comparable to the TCSANOW optional_action for + the tc* version. These direct the kernel to adopt the changes + immediately. Other pairs are: + + command optional_action Meaning + TCSETSW TCSADRAIN Change after all output has drained. + TCSETSF TCSAFLUSH Change after all output has drained + then discard any input characters + not read. + + Since the return code from either the ioctl(2) or the tcsetattr(2) + commands only indicate that the command was processed by the kernel. + These do not indicate whether or not the changes were actually + accomplished. Either of these commands should be followed by a call + to: + + ioctl(fd, TCGETS, &new_termios); + + or: + + tcgetattr(fd, &new_termios); + + A user function which makes changes to the termios structure should + define two struct termios variables. One of these variables should + contain the desired configuration. The other should contain a copy of + the kernels version. Then after the desired configuration has been + sent to the kernel, another call should be made to retrieve the + kernels version. Then the two compared. + + Here is an example of how to add RTS/CTS flow control: + + struct termios my_termios; + struct termios new_termios; + + tcgetattr(fd, &my_termios); + my_termios.c_flag |= CRTSCTS; + tcsetattr(fd, TCSANOW, &my_termios); + tcgetattr(fd, &new_termios); + if (memcmp(my_termios, new_termios, + sizeof(my_termios)) != 0) { + /* do some error handling */ + } + + 5. Changing Baud Rates + + With Linux, the baud rate can be changed using a technique similar to + add/delete RTS/CTS. + + struct termios my_termios; + struct termios new_termios; + + tcgetattr(fd, &my_termios); + my_termios.c_flag &= ~CBAUD; + my_termios.c_flag |= B19200; + tcsetattr(fd, TCSANOW, &my_termios); + tcgetattr(fd, &new_termios); + if (memcmp(my_termios, new_termios, + sizeof(my_termios)) != 0) { + /* do some error handling */ + } + + POSIX adds another method. They define: + + speed_t cfgetispeed(const struct termios *termios_p); + speed_t cfgetospeed(const struct termios *termios_p); + + library calls to extract the current input or output speed from the + struct termios pointed to with *termio_p. This is a variable defined + in the calling process. In practice, the data contained in this + termios, should be obtained by the tcgetattr() call or an ioctl() call + using the TCGETS command. + + The companion library calls are: + + int cfsetispeed(struct termios *termios_p, speed_t speed); + int cfsetospeed(struct termios *termios_p, speed_t speed); + + which are used to change the value of the baud rate in the locally + defined *termios_p. Following either of these calls, either a call to + tcsetattr() or ioctl() with one of TCSETS, TCSETSW or TCSETSF as the + command to transmit the change to the kernel. + + The cf* commands are preferred for portability. Some weird Unices use + a considerably different format of termios. + + Most implementations of Linux use only the input speed for both input + and output. These functions are defined in the application program by + reference to . In reality, they are in + /usr/include/asm/termbits.h. + + 6. Additional Control Calls + + 6.1. Sending a "break". + + int ioctl(fd, TCSBRK, int arg); + int tcsendbreak(fd, int arg); + + Send a break: Here the action differs between the conventional + ioctl() call and the POSIX call. For the conventional call, an arg of + '0' sets the break control line of the UART for 0.25 seconds. For the + POSIX command, the break line is set for arg times 0.1 seconds. + + 6.2. Hardware flow control. + + int ioctl(fd, TCXONC, int action); + int tcflow(fd, int action); + + The action flags are: + + o TCOOFF 0 suspend output + + o TCOON 1 restart output + + o TCIOFF 2 transmit STOP character to suspend input + + o TCION 3 transmit START character to restart input + + 6.3. Flushing I/O buffers. + + int ioctl(fd, TCFLSH, queue_selector); + int tcflush(fd, queue_selector); + + The queue_selector flags are: + + o TCIFLUSH 0 flush any data not yet read from the input buffer + + o TCOFLUSH 1 flush any data written to the output buffer but not + yet transmitted + + o TCIOFLUSH 2 flush both buffers + + 7. Modem control + + The hardware modem control lines can be monitored or modified by the + ioctl(2) system call. A set of comparable tc* calls apparently do not + exist. The form of this call is: + + int ioctl(fd, COMMAND, (int *)flags); + + The COMMANDS and their action are: + + o TIOCMBIS turn on control lines depending upon which bits are set + in flags. + + o TIOCMBIC turn off control lines depending upon which bits are + unset in flags. + o TIOCMGET the appropriate bits are set in flags according to the + current status + + o TIOCMSET the state of the UART is changed according to which bits + are set/unset in 'flags' + + The bit pattern of flags refer to the following control lines: + + o TIOCM_LE Line enable + + o TIOCM_DTR Data Terminal Ready + + o TIOCM_RTS Request to send + + o TIOCM_ST Secondary transmit + + o TIOCM_SR Secondary receive + + o TIOCM_CTS Clear to send + + o TIOCM_CAR Carrier detect + + o TIOCM_RNG Ring + + o TIOCM_DSR Data set ready + + It should be noted that some of these bits are controlled by the modem + and the UART cannot change them but their status can be sensed by + TIOCMGET. Also, most Personal Computers do not provide hardware for + secondary transmit and receive. + + There are also a pair of ioctl() to monitor these lines. They are + undocumented as far as I have learned. The commands are TIOCMIWAIT + and TCIOGICOUNT. They also differ between versions of the Linux + kernel. + + See the lines.c file in my "serial_suite" for an example of how these + can be used see + + 8. Process Groups + + 8.1. Sessions + + 8.2. Process Groups + + Any newly created process inherits the Process Group of its creator. + The Process Group leader has the same PID as PGID. + + 8.3. Controlling Terminal + + There are a series of ioctl(2) and tc*(2) calls which can be used to + monitor or to change the process group to which the device is + attached. + + 8.3.1. Get the foreground group process id. + + If there is no foreground group, a number not representing an existing + process group is returned. On error, a -1 is returned and errno is + set. + + int ioctl(fd, TIOCGPGRP, (pid_t *)pid); + int tcgetpgrp(fd, (pid_t *)pid); + + 8.3.2. Set the foreground process group id of a terminal. + + The fd must be the controlling terminal and be associated with the + session of the calling process. + + int ioctl(fd, TIOCSPGRP, (pid_t *)pid); + int tcsetpgrp(fd, (pid_t *)pid); + + 8.3.3. Get process group id. + + int ioctl(fd, TIOCGPGRP, &(pid_t)pid); + int tcgetpgrp(fd, &(pid_t)pid); + + 9. Lockfiles + + Any process which accesses a serial device should first check for the + existence of lock file for the desired device. If such a lock lock + file exists, this means that the device may be in use by another + process. + + Check my "libdevlocks-x.x.tgz" at + for an example of how these lock + files should be utilized. + + 10. Additional Information + + Check out my "serial_suite.tgz" for more information about programming + the serial ports at . There some + examples and some blurbs about setting up modems and comments about + some general considerations. + + 11. Feedback + + Please send me any corrections, questions, comments, suggestions, or + additional material. I would like to improve this HOWTO! Tell me + exactly what you don't understand, or what could be clearer. You can + reach me at via email. Please + include the version number of the Serial-Programming-HOWTO when + writing. diff --git a/busybox-1_37_0/docs/busybox_footer.pod b/busybox-1_37_0/docs/busybox_footer.pod new file mode 100644 index 000000000..0f4810bd3 --- /dev/null +++ b/busybox-1_37_0/docs/busybox_footer.pod @@ -0,0 +1,284 @@ +=head1 LIBC NSS + +GNU Libc (glibc) 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. This is implemented +using an /etc/nsswitch.conf configuration file, and using one or more of the +/lib/libnss_* libraries. BusyBox tries to avoid using any libc calls that make +use of NSS. Some applets however, such as login and su, will use libc functions +that require NSS. + +If you enable CONFIG_USE_BB_PWD_GRP, BusyBox will use internal functions to +directly access the /etc/passwd, /etc/group, and /etc/shadow files without +using NSS. This may allow you to run your system without the need for +installing any of the NSS configuration files and libraries. + +When used with glibc, the BusyBox 'networking' applets will similarly require +that you install at least some of the glibc NSS stuff (in particular, +/etc/nsswitch.conf, /lib/libnss_dns*, /lib/libnss_files*, and /lib/libresolv*). + +Shameless Plug: As an alternative, one could use a C library such as uClibc. In +addition to making your system significantly smaller, uClibc does not require the +use of any NSS support files or libraries. + +=head1 MAINTAINER + +Denis Vlasenko + +=head1 AUTHORS + +The following people have contributed code to BusyBox whether they know it or +not. If you have written code included in BusyBox, you should probably be +listed here so you can obtain your bit of eternal glory. If you should be +listed here, or the description of what you have done needs more detail, or is +incorrect, please send in an update. + + +=for html
+ +Emanuele Aina + + run-parts + +=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. + Lots of tedious effort writing these boring docs that + nobody is going to actually read. + +=for html
+ +Laurence Anderson + + rpm2cpio, unzip, get_header_cpio, read_gz interface, rpm + +=for html
+ +Jeff Angielski + + ftpput, ftpget + +=for html
+ +Edward Betts + + expr, hostid, logname, whoami + +=for html
+ +John Beppu + + du, nslookup, sort + +=for html
+ +Brian Candler + + tiny-ls(ls) + +=for html
+ +Randolph Chung + + fbset, ping, hostname + +=for html
+ +Dave Cinege + + more(v2), makedevs, dutmp, modularization, auto links file, + various fixes, Linux Router Project maintenance + +=for html
+ +Jordan Crouse + + ipcalc + +=for html
+ +Magnus Damm + + tftp client insmod powerpc support + +=for html
+ +Larry Doolittle + + pristine source directory compilation, lots of patches and fixes. + +=for html
+ +Glenn Engel + + httpd + +=for html
+ +Gennady Feldman + + Sysklogd (single threaded syslogd, IPC Circular buffer support, + logread), various fixes. + +=for html
+ +Karl M. Hegbloom + + cp_mv.c, the test suite, various fixes to utility.c, &c. + +=for html
+ +Daniel Jacobowitz + + mktemp.c + +=for html
+ +Matt Kraai + + documentation, bugfixes, test suite + +=for html
+ +Stephan Linz + + ipcalc, Red Hat equivalence + +=for html
+ +John Lombardo + + tr + +=for html
+ +Glenn McGrath + + Common unarchiving code and unarchiving applets, ifupdown, ftpgetput, + nameif, sed, patch, fold, install, uudecode. + Various bugfixes, review and apply numerous patches. + +=for html
+ +Manuel Novoa III + + cat, head, mkfifo, mknod, rmdir, sleep, tee, tty, uniq, usleep, wc, yes, + mesg, vconfig, make_directory, parse_mode, dirname, mode_string, + get_last_path_component, simplify_path, and a number trivial libbb routines + + also bug fixes, partial rewrites, and size optimizations in + ash, basename, cal, cmp, cp, df, du, echo, env, ln, logname, md5sum, mkdir, + mv, realpath, rm, sort, tail, touch, uname, watch, arith, human_readable, + interface, dutmp, ifconfig, route + +=for html
+ +Vladimir Oleynik + + cmdedit; xargs(current), httpd(current); + ports: ash, crond, fdisk, inetd, stty, traceroute, top; + locale, various fixes + and irreconcilable critic of everything not perfect. + +=for html
+ +Bruce Perens + + Original author of BusyBox in 1995, 1996. Some of his code can + still be found hiding here and there... + +=for html
+ +Tim Riker + + bug fixes, member of fan club + +=for html
+ +Kent Robotti + + reset, tons and tons of bug reports and patches. + +=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 + + grep, sed, cut, xargs(previous), + style-guide, new-applet-HOWTO, bug fixes, etc. + +=for html
+ +Charles P. Wright + + gzip, mini-netcat(nc) + +=for html
+ +Enrique Zanardi + + tarcat (since removed), loadkmap, various fixes, Debian maintenance + +=for html
+ +Tito Ragusa + + devfsd and size optimizations in strings, openvt and deallocvt. + +=for html
+ +Paul Fox + + vi editing mode for ash, various other patches/fixes + +=for html
+ +Roberto A. Foglietta + + port: dnsd + +=for html
+ +Bernhard Reutner-Fischer + + misc + +=for html
+ +Mike Frysinger + + initial e2fsprogs, printenv, setarch, sum, misc + +=for html
+ +Jie Zhang + + fixed two bugs in msh and hush (exitcode of killed processes) + +=cut diff --git a/busybox-1_37_0/docs/busybox_header.pod b/busybox-1_37_0/docs/busybox_header.pod new file mode 100644 index 000000000..85a173e82 --- /dev/null +++ b/busybox-1_37_0/docs/busybox_header.pod @@ -0,0 +1,82 @@ +# 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 GNU coreutils, util-linux, 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 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 Linux kernel. +BusyBox provides a fairly complete POSIX environment for any small or embedded +system. + +BusyBox is extremely configurable. This allows you to include only the +components you need, thereby reducing binary size. Run 'make config' or 'make +menuconfig' to select the functionality that you wish to enable. Then run +'make' to compile BusyBox using your configuration. + +After the compile has finished, you should use 'make install' to install +BusyBox. This will install the 'bin/busybox' binary, in the target directory +specified by CONFIG_PREFIX. CONFIG_PREFIX can be set when configuring BusyBox, +or you can specify an alternative location at install time (i.e., with a +command line like 'make CONFIG_PREFIX=/tmp/foo install'). If you enabled +any applet installation scheme (either as symlinks or hardlinks), these will +also be installed in the location pointed to by CONFIG_PREFIX. + +=head1 USAGE + +BusyBox is a multi-call binary. A multi-call binary is an executable program +that performs the same job as more than one utility program. That means there +is just a single BusyBox binary, but that single binary acts like a large +number of utilities. This allows BusyBox to be smaller since all the built-in +utility programs (we call them applets) can share code for many common +operations. + +You can also invoke BusyBox by issuing a command as an argument on the +command line. For example, entering + + /bin/busybox ls + +will also cause BusyBox to behave as 'ls'. + +Of course, adding '/bin/busybox' into every command would be painful. So most +people will invoke BusyBox using links to the BusyBox binary. + +For example, entering + + ln -s /bin/busybox ls + ./ls + +will cause BusyBox to behave as 'ls' (if the 'ls' command has been compiled +into BusyBox). Generally speaking, you should never need to make all these +links yourself, as the BusyBox build system will do this for you when you run +the 'make install' command. + +If you invoke BusyBox with no arguments, it will provide you with a list of the +applets that have been compiled into your BusyBox binary. + +=head1 COMMON OPTIONS + +Most BusyBox applets support the B<--help> argument to provide a terse runtime +description of their behavior. If the CONFIG_FEATURE_VERBOSE_USAGE option has +been enabled, more detailed usage information will also be available. + +=head1 COMMANDS + +Currently available applets include: diff --git a/busybox-1_37_0/docs/cgi/cl.html b/busybox-1_37_0/docs/cgi/cl.html new file mode 100644 index 000000000..4f8faae9f --- /dev/null +++ b/busybox-1_37_0/docs/cgi/cl.html @@ -0,0 +1,46 @@ +CGI Command line options

CGI Command line options

+

+ +

Specification

+ +The command line is only used in the case of an ISINDEX query. It is +not used in the case of an HTML form or any as yet undefined query +type. The server should search the query information (the QUERY_STRING environment variable) for a non-encoded += character to determine if the command line is to be used, if it +finds one, the command line is not to be used. This trusts the clients +to encode the = sign in ISINDEX queries, a practice which was +considered safe at the time of the design of this specification.

+ +For example, use the finger script and the ISINDEX interface to look up "httpd". You will see that the script will call itself with /cgi-bin/finger?httpd and will actually execute "finger httpd" on the command line and output the results to you. +

+If the server does find a "=" in the QUERY_STRING, +then the command line will not be used, and no decoding will be +performed. The query then remains intact for processing by an +appropriate FORM submission decoder. +Again, as an example, use this hyperlink to submit "httpd=name" to the finger script. Since this QUERY_STRING +contained an unencoded "=", nothing was decoded, the script didn't know +it was being submitted a valid query, and just gave you the default +finger form. +

+If the server finds that it cannot send the string due to internal +limitations (such as exec() or /bin/sh command line restrictions) the +server should include NO command line information and provide the +non-decoded query information in the environment +variable QUERY_STRING.

+


+

Examples

+ +Examples of the command line usage are much better demonstrated than explained. For these +examples, pay close attention to the script output which says what +argc and argv are.

+ +


+ +[Back]Return to the +interface specification

+ +CGI - Common Gateway Interface +

cgi@ncsa.uiuc.edu
+ + + diff --git a/busybox-1_37_0/docs/cgi/env.html b/busybox-1_37_0/docs/cgi/env.html new file mode 100644 index 000000000..66a548b46 --- /dev/null +++ b/busybox-1_37_0/docs/cgi/env.html @@ -0,0 +1,149 @@ +CGI Environment Variables

CGI Environment Variables

+
+ +

+ +In order to pass data about the information request from the server to +the script, the server uses command line arguments as well as +environment variables. These environment variables are set when the +server executes the gateway program.

+ +


+

Specification

+ +

+The following environment variables are not request-specific and are +set for all requests:

+ +

    +
  • SERVER_SOFTWARE

    + + The name and version of the information server software answering + the request (and running the gateway). Format: name/version

    + +

  • SERVER_NAME

    + The server's hostname, DNS alias, or IP address as it would appear + in self-referencing URLs.

    + +

  • GATEWAY_INTERFACE

    + The revision of the CGI specification to which this server + complies. Format: CGI/revision

    + +

+ +
+ +The following environment variables are specific to the request being +fulfilled by the gateway program:

+ +

    +
  • SERVER_PROTOCOL

    + The name and revision of the information protocol this request came + in with. Format: protocol/revision

    + +

  • SERVER_PORT

    + The port number to which the request was sent.

    + +

  • REQUEST_METHOD

    + The method with which the request was made. For HTTP, this is + "GET", "HEAD", "POST", etc.

    + +

  • PATH_INFO

    + The extra path information, as given by the client. In other + words, scripts can be accessed by their virtual pathname, followed + by extra information at the end of this path. The extra + information is sent as PATH_INFO. This information should be + decoded by the server if it comes from a URL before it is passed + to the CGI script.

    + +

  • PATH_TRANSLATED

    + The server provides a translated version of PATH_INFO, which takes + the path and does any virtual-to-physical mapping to it.

    + +

  • SCRIPT_NAME

    + A virtual path to the script being executed, used for + self-referencing URLs.

    + +

  • QUERY_STRING

    + The information which follows the ? in the URL + which referenced this script. This is the query information. It + should not be decoded in any fashion. This variable should always + be set when there is query information, regardless of command line decoding.

    + +

  • REMOTE_HOST

    + The hostname making the request. If the server does not have this + information, it should set REMOTE_ADDR and leave this unset.

    + +

  • REMOTE_ADDR

    + The IP address of the remote host making the request.

    + +

  • AUTH_TYPE

    + If the server supports user authentication, and the script is + protects, this is the protocol-specific authentication method used + to validate the user.

    + +

  • REMOTE_USER

    + If the server supports user authentication, and the script is + protected, this is the username they have authenticated as.

    +

  • REMOTE_IDENT

    + If the HTTP server supports RFC 931 identification, then this + variable will be set to the remote user name retrieved from the + server. Usage of this variable should be limited to logging only. +

    + +

  • CONTENT_TYPE

    + For queries which have attached information, such as HTTP POST and + PUT, this is the content type of the data.

    + +

  • CONTENT_LENGTH

    + The length of the said content as given by the client.

    + +

+ + +
+ +In addition to these, the header lines received from the client, if +any, are placed into the environment with the prefix HTTP_ followed by +the header name. Any - characters in the header name are changed to _ +characters. The server may exclude any headers which it has already +processed, such as Authorization, Content-type, and Content-length. If +necessary, the server may choose to exclude any or all of these +headers if including them would exceed any system environment +limits.

+ +An example of this is the HTTP_ACCEPT variable which was defined in +CGI/1.0. Another example is the header User-Agent.

+ +

    +
  • HTTP_ACCEPT

    + The MIME types which the client will accept, as given by HTTP + headers. Other protocols may need to get this information from + elsewhere. Each item in this list should be separated by commas as + per the HTTP spec.

    + + Format: type/subtype, type/subtype

    + + +

  • HTTP_USER_AGENT

    + + The browser the client is using to send the request. General +format: software/version library/version.

    + +

+ +
+

Examples

+ +Examples of the setting of environment variables are really much better +demonstrated than explained.

+ +


+ +[Back]Return to the +interface specification

+ +CGI - Common Gateway Interface +

cgi@ncsa.uiuc.edu
+ + diff --git a/busybox-1_37_0/docs/cgi/in.html b/busybox-1_37_0/docs/cgi/in.html new file mode 100644 index 000000000..7ee5fe601 --- /dev/null +++ b/busybox-1_37_0/docs/cgi/in.html @@ -0,0 +1,33 @@ +CGI Script input

CGI Script Input

+
+ +

Specification

+ +For requests which have information attached after the header, such as +HTTP POST or PUT, the information will be sent to the script on stdin. +

+ +The server will send CONTENT_LENGTH bytes on +this file descriptor. Remember that it will give the CONTENT_TYPE of the data as well. The server is +in no way obligated to send end-of-file after the script reads +CONTENT_LENGTH bytes.

+


+

Example

+ +Let's take a form with METHOD="POST" as an example. Let's say the form +results are 7 bytes encoded, and look like a=b&b=c. +

+ +In this case, the server will set CONTENT_LENGTH to 7 and CONTENT_TYPE +to application/x-www-form-urlencoded. The first byte on the script's +standard input will be "a", followed by the rest of the encoded string.

+ +


+ +[Back]Return to the +interface specification

+ +CGI - Common Gateway Interface +

cgi@ncsa.uiuc.edu
+ + diff --git a/busybox-1_37_0/docs/cgi/interface.html b/busybox-1_37_0/docs/cgi/interface.html new file mode 100644 index 000000000..0be016b4c --- /dev/null +++ b/busybox-1_37_0/docs/cgi/interface.html @@ -0,0 +1,29 @@ +The Common Gateway Interface Specification +[http://hoohoo.ncsa.uiuc.edu/cgi/interface.html] +

The CGI Specification

+ +
+ +This is the specification for CGI version 1.1, or CGI/1.1. Further +revisions of this protocol are guaranteed to be backward compatible. +

+ +The server and the CGI script communicate in four major ways. Each of +the following is a hotlink to graphic detail.

+ +

+
+ + +[Back]Return to the overview

+ + + +CGI - Common Gateway Interface +

cgi@ncsa.uiuc.edu
+ diff --git a/busybox-1_37_0/docs/cgi/out.html b/busybox-1_37_0/docs/cgi/out.html new file mode 100644 index 000000000..5266985b5 --- /dev/null +++ b/busybox-1_37_0/docs/cgi/out.html @@ -0,0 +1,126 @@ +CGI Script output

CGI Script Output

+
+ +

Script output

+ +The script sends its output to stdout. This output can either be a +document generated by the script, or instructions to the server for +retrieving the desired output.

+


+ +

Script naming conventions

+ +Normally, scripts produce output which is interpreted and sent back to +the client. An advantage of this is that the scripts do not need to +send a full HTTP/1.0 header for every request.

+ +Some scripts may want to avoid the extra overhead of the server +parsing their output, and talk directly to the client. In order to +distinguish these scripts from the other scripts, CGI requires that +the script name begins with nph- if a script does not want the server +to parse its header. In this case, it is the script's responsibility +to return a valid HTTP/1.0 (or HTTP/0.9) response to the client.

+ +


+

Parsed headers

+ +The output of scripts begins with a small header. This header consists +of text lines, in the same format as an +HTTP header, terminated by a blank line (a line with only a +linefeed or CR/LF).

+ +Any headers which are not server directives are sent directly back to +the client. Currently, this specification defines three server +directives:

+ +

    +
  • Content-type

    + + This is the MIME type of the document you are returning.

    + +

  • Location

    + + This is used to specify to the server that you are returning a + reference to a document rather than an actual document.

    + + If the argument to this is a URL, the server will issue a redirect + to the client.

    + + If the argument to this is a virtual path, the server will + retrieve the document specified as if the client had requested + that document originally. ? directives will work in here, but # + directives must be redirected back to the client.

    + + +

  • Status

    + + This is used to give the server an HTTP/1.0 status +line to send to the client. The format is nnn xxxxx, +where nnn is the 3-digit status code, and +xxxxx is the reason string, such as "Forbidden".

    + +

+ +
+

Examples

+ +Let's say I have a fromgratz to HTML converter. When my converter is +finished with its work, it will output the following on stdout (note +that the lines beginning and ending with --- are just for illustration +and would not be output):

+ +

--- start of output ---
+Content-type: text/html
+
+--- end of output ---
+
+ +Note the blank line after Content-type.

+ +Now, let's say I have a script which, in certain instances, wants to +return the document /path/doc.txt from this server just +as if the user had actually requested +http://server:port/path/doc.txt to begin with. In this +case, the script would output:

+

--- start of output ---
+Location: /path/doc.txt
+
+--- end of output ---
+
+ +The server would then perform the request and send it to the client. +

+ +Let's say that I have a script which wants to reference our gopher +server. In this case, if the script wanted to refer the user to +gopher://gopher.ncsa.uiuc.edu/, it would output:

+ +

--- start of output ---
+Location: gopher://gopher.ncsa.uiuc.edu/
+
+--- end of output ---
+
+ +Finally, I have a script which wants to talk to the client directly. +In this case, if the script is referenced with SERVER_PROTOCOL of HTTP/1.0, +the script would output the following HTTP/1.0 response:

+ +

--- start of output ---
+HTTP/1.0 200 OK
+Server: NCSA/1.0a6
+Content-type: text/plain
+
+This is a plaintext document generated on the fly just for you.
+
+--- end of output ---
+
+ + +
+ +[Back]Return to the +interface specification

+ +CGI - Common Gateway Interface +

cgi@ncsa.uiuc.edu
+ diff --git a/busybox-1_37_0/docs/contributing.txt b/busybox-1_37_0/docs/contributing.txt new file mode 100644 index 000000000..e3289fd49 --- /dev/null +++ b/busybox-1_37_0/docs/contributing.txt @@ -0,0 +1,439 @@ +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.net/ + + + +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 +~~~~~~~~~~~~~~~~~~~~~~~~ + +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 development tree, please look at the +following links: + + http://busybox.net/source.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://busybox.net/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://busybox.net/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 +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. Rationale: bugs in these tools can destroy + vast amounts of data. Keeping up with filesystem format development + is impractical (especially in the area of keeping fsck tool safe + and up-to-date). + + - 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. + + +Bug Reporting +~~~~~~~~~~~~~ + +If you find bugs, please submit a detailed bug report to the busybox mailing +list at busybox@busybox.net. 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: + + To: busybox@busybox.net + From: diligent@testing.linux.org + Subject: /bin/date doesn't work + + Package: busybox + Version: 1.00 + + When I execute Busybox 'date' it produces unexpected results. + With GNU date I get the following output: + + $ date + Wed Mar 21 14:19:41 MST 2001 + + But when I use BusyBox date I get this instead: + + $ date + Illegal instruction + + I am using Debian unstable, kernel version 2.4.19-rmk1 on an Netwinder, + and the latest uClibc from CVS. + + -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 never be fixed... Thanks for understanding. + + + +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 find -name '*.[ch]'|xargs grep $i; 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. + + +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. + + - Security audits: + http://www.securityfocus.com/popups/forums/secprog/intro.shtml + + - 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 function 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://www.lysator.liu.se/c/ten-commandments.html + +Other useful links: + + - the comp.lang.c FAQ: http://home.datacomm.ch/t_wolf/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 Git access set up, making a patch is simple. Just make +sure you're in the busybox/ directory and type: + + git diff -b -w > 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 -p1 < 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 push a change to Git. 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 busybox +mailing list 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: v1.01pre (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. + + + +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 Git. 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. + + + +Pushing Changes to Git +---------------------- + +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 push +changes directly to Git. This is nice because you don't have to wait for +someone else to push your change for you, you can just do it yourself. + +But note that this is a privilege that comes with some responsibilities. You +should test your changes before you push 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. + +For more information on Git push access, see: + + http://busybox.net/developer.html + + +When To Push +~~~~~~~~~~~~ + +Generally, you should feel free to push 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 push a change +directly to Git. + + +When Not To Push +~~~~~~~~~~~~~~~~ + +Even if you have push access, 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 pushing. + + + +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-1_37_0/docs/ctty.htm b/busybox-1_37_0/docs/ctty.htm new file mode 100644 index 000000000..3cb2dd2bd --- /dev/null +++ b/busybox-1_37_0/docs/ctty.htm @@ -0,0 +1,479 @@ + + + + The Linux kernel: Processes + + +
+

10. Processes

+ +

Before looking at the Linux implementation, first a general Unix +description of threads, processes, process groups and sessions. +

+(See also General Terminal Interface) +

A session contains a number of process groups, and a process group +contains a number of processes, and a process contains a number +of threads. +

A session can have a controlling tty. +At most one process group in a session can be a foreground process group. +An interrupt character typed on a tty ("Teletype", i.e., terminal) +causes a signal to be sent to all members of the foreground process group +in the session (if any) that has that tty as controlling tty. +

All these objects have numbers, and we have thread IDs, process IDs, +process group IDs and session IDs. +

+

10.1 Processes +

+ +

+

Creation

+ +

A new process is traditionally started using the fork() +system call: +

+
pid_t p;
+
+p = fork();
+if (p == (pid_t) -1)
+        /* ERROR */
+else if (p == 0)
+        /* CHILD */
+else
+        /* PARENT */
+
+
+

This creates a child as a duplicate of its parent. +Parent and child are identical in almost all respects. +In the code they are distinguished by the fact that the parent +learns the process ID of its child, while fork() +returns 0 in the child. (It can find the process ID of its +parent using the getppid() system call.) +

+

Termination

+ +

Normal termination is when the process does +

+
exit(n);
+
+
+ +or +
+
return n;
+
+
+ +from its main() procedure. It returns the single byte n +to its parent. +

Abnormal termination is usually caused by a signal. +

+

Collecting the exit code. Zombies

+ +

The parent does +

+
pid_t p;
+int status;
+
+p = wait(&status);
+
+
+ +and collects two bytes: +

+

+ + + +

A process that has terminated but has not yet been waited for +is a zombie. It need only store these two bytes: +exit code and reason for termination. +

On the other hand, if the parent dies first, init (process 1) +inherits the child and becomes its parent. +

+

Signals

+ +

+

Stopping

+ +

Some signals cause a process to stop: +SIGSTOP (stop!), +SIGTSTP (stop from tty: probably ^Z was typed), +SIGTTIN (tty input asked by background process), +SIGTTOU (tty output sent by background process, and this was +disallowed by stty tostop). +

Apart from ^Z there also is ^Y. The former stops the process +when it is typed, the latter stops it when it is read. +

Signals generated by typing the corresponding character on some tty +are sent to all processes that are in the foreground process group +of the session that has that tty as controlling tty. (Details below.) +

If a process is being traced, every signal will stop it. +

+

Continuing

+ +

SIGCONT: continue a stopped process. +

+

Terminating

+ +

SIGKILL (die! now!), +SIGTERM (please, go away), +SIGHUP (modem hangup), +SIGINT (^C), +SIGQUIT (^\), etc. +Many signals have as default action to kill the target. +(Sometimes with an additional core dump, when such is +allowed by rlimit.) +The signals SIGCHLD and SIGWINCH +are ignored by default. +All except SIGKILL and SIGSTOP can be +caught or ignored or blocked. +For details, see signal(7). +

+

10.2 Process groups +

+ +

Every process is member of a unique process group, +identified by its process group ID. +(When the process is created, it becomes a member of the process group +of its parent.) +By convention, the process group ID of a process group +equals the process ID of the first member of the process group, +called the process group leader. +A process finds the ID of its process group using the system call +getpgrp(), or, equivalently, getpgid(0). +One finds the process group ID of process p using +getpgid(p). +

One may use the command ps j to see PPID (parent process ID), +PID (process ID), PGID (process group ID) and SID (session ID) +of processes. With a shell that does not know about job control, +like ash, each of its children will be in the same session +and have the same process group as the shell. With a shell that knows +about job control, like bash, the processes of one pipeline, like +

+
% cat paper | ideal | pic | tbl | eqn | ditroff > out
+
+
+ +form a single process group. +

+

Creation

+ +

A process pid is put into the process group pgid by +

+
setpgid(pid, pgid);
+
+
+ +If pgid == pid or pgid == 0 then this creates +a new process group with process group leader pid. +Otherwise, this puts pid into the already existing +process group pgid. +A zero pid refers to the current process. +The call setpgrp() is equivalent to setpgid(0,0). +

+

Restrictions on setpgid()

+ +

The calling process must be pid itself, or its parent, +and the parent can only do this before pid has done +exec(), and only when both belong to the same session. +It is an error if process pid is a session leader +(and this call would change its pgid). +

+

Typical sequence

+ +

+

+
p = fork();
+if (p == (pid_t) -1) {
+        /* ERROR */
+} else if (p == 0) {    /* CHILD */
+        setpgid(0, pgid);
+        ...
+} else {                /* PARENT */
+        setpgid(p, pgid);
+        ...
+}
+
+
+ +This ensures that regardless of whether parent or child is scheduled +first, the process group setting is as expected by both. +

+

Signalling and waiting

+ +

One can signal all members of a process group: +

+
killpg(pgrp, sig);
+
+
+

One can wait for children in ones own process group: +

+
waitpid(0, &status, ...);
+
+
+ +or in a specified process group: +
+
waitpid(-pgrp, &status, ...);
+
+
+

+

Foreground process group

+ +

Among the process groups in a session at most one can be +the foreground process group of that session. +The tty input and tty signals (signals generated by ^C, ^Z, etc.) +go to processes in this foreground process group. +

A process can determine the foreground process group in its session +using tcgetpgrp(fd), where fd refers to its +controlling tty. If there is none, this returns a random value +larger than 1 that is not a process group ID. +

A process can set the foreground process group in its session +using tcsetpgrp(fd,pgrp), where fd refers to its +controlling tty, and pgrp is a process group in +its session, and this session still is associated to the controlling +tty of the calling process. +

How does one get fd? By definition, /dev/tty +refers to the controlling tty, entirely independent of redirects +of standard input and output. (There is also the function +ctermid() to get the name of the controlling terminal. +On a POSIX standard system it will return /dev/tty.) +Opening the name of the +controlling tty gives a file descriptor fd. +

+

Background process groups

+ +

All process groups in a session that are not foreground +process group are background process groups. +Since the user at the keyboard is interacting with foreground +processes, background processes should stay away from it. +When a background process reads from the terminal it gets +a SIGTTIN signal. Normally, that will stop it, the job control shell +notices and tells the user, who can say fg to continue +this background process as a foreground process, and then this +process can read from the terminal. But if the background process +ignores or blocks the SIGTTIN signal, or if its process group +is orphaned (see below), then the read() returns an EIO error, +and no signal is sent. (Indeed, the idea is to tell the process +that reading from the terminal is not allowed right now. +If it wouldn't see the signal, then it will see the error return.) +

When a background process writes to the terminal, it may get +a SIGTTOU signal. May: namely, when the flag that this must happen +is set (it is off by default). One can set the flag by +

+
% stty tostop
+
+
+ +and clear it again by +
+
% stty -tostop
+
+
+ +and inspect it by +
+
% stty -a
+
+
+ +Again, if TOSTOP is set but the background process ignores or blocks +the SIGTTOU signal, or if its process group is orphaned (see below), +then the write() returns an EIO error, and no signal is sent. +[vda: correction. SUS says that if SIGTTOU is blocked/ignored, write succeeds. ] +

+

Orphaned process groups

+ +

The process group leader is the first member of the process group. +It may terminate before the others, and then the process group is +without leader. +

A process group is called orphaned when the +parent of every member is either in the process group +or outside the session. +In particular, the process group of the session leader +is always orphaned. +

If termination of a process causes a process group to become +orphaned, and some member is stopped, then all are sent first SIGHUP +and then SIGCONT. +

The idea is that perhaps the parent of the process group leader +is a job control shell. (In the same session but a different +process group.) As long as this parent is alive, it can +handle the stopping and starting of members in the process group. +When it dies, there may be nobody to continue stopped processes. +Therefore, these stopped processes are sent SIGHUP, so that they +die unless they catch or ignore it, and then SIGCONT to continue them. +

Note that the process group of the session leader is already +orphaned, so no signals are sent when the session leader dies. +

Note also that a process group can become orphaned in two ways +by termination of a process: either it was a parent and not itself +in the process group, or it was the last element of the process group +with a parent outside but in the same session. +Furthermore, that a process group can become orphaned +other than by termination of a process, namely when some +member is moved to a different process group. +

+

10.3 Sessions +

+ +

Every process group is in a unique session. +(When the process is created, it becomes a member of the session +of its parent.) +By convention, the session ID of a session +equals the process ID of the first member of the session, +called the session leader. +A process finds the ID of its session using the system call +getsid(). +

Every session may have a controlling tty, +that then also is called the controlling tty of each of +its member processes. +A file descriptor for the controlling tty is obtained by +opening /dev/tty. (And when that fails, there was no +controlling tty.) Given a file descriptor for the controlling tty, +one may obtain the SID using tcgetsid(fd). +

A session is often set up by a login process. The terminal +on which one is logged in then becomes the controlling tty +of the session. All processes that are descendants of the +login process will in general be members of the session. +

+

Creation

+ +

A new session is created by +

+
pid = setsid();
+
+
+ +This is allowed only when the current process is not a process group leader. +In order to be sure of that we fork first: +
+
p = fork();
+if (p) exit(0);
+pid = setsid();
+
+
+ +The result is that the current process (with process ID pid) +becomes session leader of a new session with session ID pid. +Moreover, it becomes process group leader of a new process group. +Both session and process group contain only the single process pid. +Furthermore, this process has no controlling tty. +

The restriction that the current process must not be a process group leader +is needed: otherwise its PID serves as PGID of some existing process group +and cannot be used as the PGID of a new process group. +

+

Getting a controlling tty

+ +

How does one get a controlling terminal? Nobody knows, +this is a great mystery. +

The System V approach is that the first tty opened by the process +becomes its controlling tty. +

The BSD approach is that one has to explicitly call +

+
ioctl(fd, TIOCSCTTY, 0/1);
+
+
+ +to get a controlling tty. +

Linux tries to be compatible with both, as always, and this +results in a very obscure complex of conditions. Roughly: +

The TIOCSCTTY ioctl will give us a controlling tty, +provided that (i) the current process is a session leader, +and (ii) it does not yet have a controlling tty, and +(iii) maybe the tty should not already control some other session; +if it does it is an error if we aren't root, or we steal the tty +if we are all-powerful. +[vda: correction: third parameter controls this: if 1, we steal tty from +any such session, if 0, we don't steal] +

Opening some terminal will give us a controlling tty, +provided that (i) the current process is a session leader, and +(ii) it does not yet have a controlling tty, and +(iii) the tty does not already control some other session, and +(iv) the open did not have the O_NOCTTY flag, and +(v) the tty is not the foreground VT, and +(vi) the tty is not the console, and +(vii) maybe the tty should not be master or slave pty. +

+

Getting rid of a controlling tty

+ +

If a process wants to continue as a daemon, it must detach itself +from its controlling tty. Above we saw that setsid() +will remove the controlling tty. Also the ioctl TIOCNOTTY does this. +Moreover, in order not to get a controlling tty again as soon as it +opens a tty, the process has to fork once more, to assure that it +is not a session leader. Typical code fragment: +

+

        if ((fork()) != 0)
+                exit(0);
+        setsid();
+        if ((fork()) != 0)
+                exit(0);
+
+

See also daemon(3). +

+

Disconnect

+ +

If the terminal goes away by modem hangup, and the line was not local, +then a SIGHUP is sent to the session leader. +Any further reads from the gone terminal return EOF. +(Or possibly -1 with errno set to EIO.) +

If the terminal is the slave side of a pseudotty, and the master side +is closed (for the last time), then a SIGHUP is sent to the foreground +process group of the slave side. +

When the session leader dies, a SIGHUP is sent to all processes +in the foreground process group. Moreover, the terminal stops being +the controlling terminal of this session (so that it can become +the controlling terminal of another session). +

Thus, if the terminal goes away and the session leader is +a job control shell, then it can handle things for its descendants, +e.g. by sending them again a SIGHUP. +If on the other hand the session leader is an innocent process +that does not catch SIGHUP, it will die, and all foreground processes +get a SIGHUP. +

+

10.4 Threads +

+ +

A process can have several threads. New threads (with the same PID +as the parent thread) are started using the clone system +call using the CLONE_THREAD flag. Threads are distinguished +by a thread ID (TID). An ordinary process has a single thread +with TID equal to PID. The system call gettid() returns the +TID. The system call tkill() sends a signal to a single thread. +

Example: a process with two threads. Both only print PID and TID and exit. +(Linux 2.4.19 or later.) +

% cat << EOF > gettid-demo.c
+#include <unistd.h>
+#include <sys/types.h>
+#define CLONE_SIGHAND   0x00000800
+#define CLONE_THREAD    0x00010000
+#include <linux/unistd.h>
+#include <errno.h>
+_syscall0(pid_t,gettid)
+
+int thread(void *p) {
+        printf("thread: %d %d\n", gettid(), getpid());
+}
+
+main() {
+        unsigned char stack[4096];
+        int i;
+
+        i = clone(thread, stack+2048, CLONE_THREAD | CLONE_SIGHAND, NULL);
+        if (i == -1)
+                perror("clone");
+        else
+                printf("clone returns %d\n", i);
+        printf("parent: %d %d\n", gettid(), getpid());
+}
+EOF
+% cc -o gettid-demo gettid-demo.c
+% ./gettid-demo
+clone returns 21826
+parent: 21825 21825
+thread: 21826 21825
+%
+
+

+

+


+ + diff --git a/busybox-1_37_0/docs/draft-coar-cgi-v11-03-clean.html b/busybox-1_37_0/docs/draft-coar-cgi-v11-03-clean.html new file mode 100644 index 000000000..d52c9b842 --- /dev/null +++ b/busybox-1_37_0/docs/draft-coar-cgi-v11-03-clean.html @@ -0,0 +1,2674 @@ + + + + Common Gateway Interface - 1.1 *Draft 03* [http://cgi-spec.golux.com/draft-coar-cgi-v11-03-clean.html] + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + +
+ INTERNET-DRAFT                                 + +           Ken A L Coar +
+ draft-coar-cgi-v11-03.{html,txt}              + +         IBM Corporation +
+                                                 + +       D.R.T. Robinson +
+                                                 + +       E*TRADE UK Ltd. +
+                                                 + +         25 June 1999 +
+
+ +

+ The WWW Common Gateway Interface +
+ Version 1.1 +

+ + + +

+ + Abstract + +

+

+ The Common Gateway Interface (CGI) is a simple interface for running + external programs, software or gateways under an information server + in a platform-independent manner. Currently, the supported information + servers are HTTP servers. +

+

+ The interface has been in use by the World-Wide Web since 1993. This + specification defines the + "current practice" parameters of the + 'CGI/1.1' interface developed and documented at the U.S. National + Centre for Supercomputing Applications [NCSA-CGI]. + This document also defines the use of the CGI/1.1 interface + on the Unix and AmigaDOS(tm) systems. +

+

+ Discussion of this draft occurs on the CGI-WG mailing list; see the + project Web page at + <URL:http://CGI-Spec.Golux.Com/> + for details on the mailing list and the status of the project. +

+ + +

+ Revision History +

+

+ The revision history of this draft is being maintained using Web-based + GUI notation, such as struck-through characters and colour-coded + sections. The following legend describes how to determine the origin + of a particular revision according to the colour of the text: +

+
+
Black +
+
Revision 00, released 28 May 1998 +
+
Green +
+
Revision 01, released 28 December 1998 +
+ Major structure change: Section 4, "Request Metadata (Meta-Variables)" + was moved entirely under Section 7, "Data Input to the + CGI Script." + Due to the size of this change, it is noted here and the text in its + former location does not appear as struckthrough. This has + caused major sections 5 and following to decrement + by one. Other + large text movements are likewise not marked up. References to RFC + 1738 were changed to 2396 (1738's replacement). +
+
Red +
+
Revision 02, released 2 April, 1999 +
+ Added text to section 8.3 defining correct handling + of HTTP/1.1 + requests using "chunked" Transfer-Encoding. Labelled metavariable + names in section 8 with the appropriate detail section + numbers. + Clarified allowed usage of Status and + Location response header fields. Included new + Internet-Draft language. +
+
Fuchsia +
+
Revision 03, released 25 June 1999 +
+ Changed references from "HTTP" to "Protocol-Specific" for the listing of + things like HTTP_ACCEPT. Changed 'entity-body' and 'content-body' to + 'message-body.' Added a note that response headers must comply with + requirements of the protocol level in use. Added a lot of stuff about + security (section 11). Clarified a bunch of productions. Pointed out + that zero-length and omitted values are indistinguishable in this + specification. Clarified production describing order of fields in + script response header. Clarified issues surrounding encoding of + data. Acknowledged additional contributors, and changed one of + the authors' addresses. +
+
+ + +

+ + Table of Contents + +

+
+
+  1 Introduction..............................................TBD
+   1.1 Purpose................................................TBD
+   1.2 Requirements...........................................TBD
+   1.3 Specifications.........................................TBD
+   1.4 Terminology............................................TBD
+  2 Notational Conventions and Generic Grammar................TBD
+   2.1 Augmented BNF..........................................TBD
+   2.2 Basic Rules............................................TBD
+  3 Protocol Parameters.......................................TBD
+   3.1 URL Encoding...........................................TBD
+   3.2 The Script-URI.........................................TBD
+  4 Invoking the Script.......................................TBD
+  5 The CGI Script Command Line...............................TBD
+  6 Data Input to the CGI Script..............................TBD
+   6.1 Request Metadata (Metavariables).......................TBD
+    6.1.1 AUTH_TYPE...........................................TBD
+    6.1.2 CONTENT_LENGTH......................................TBD
+    6.1.3 CONTENT_TYPE........................................TBD
+    6.1.4 GATEWAY_INTERFACE...................................TBD
+    6.1.5 Protocol-Specific Metavariables.....................TBD
+    6.1.6 PATH_INFO...........................................TBD
+    6.1.7 PATH_TRANSLATED.....................................TBD
+    6.1.8 QUERY_STRING........................................TBD
+    6.1.9 REMOTE_ADDR.........................................TBD
+    6.1.10 REMOTE_HOST........................................TBD
+    6.1.11 REMOTE_IDENT.......................................TBD
+    6.1.12 REMOTE_USER........................................TBD
+    6.1.13 REQUEST_METHOD.....................................TBD
+    6.1.14 SCRIPT_NAME........................................TBD
+    6.1.15 SERVER_NAME........................................TBD
+    6.1.16 SERVER_PORT........................................TBD
+    6.1.17 SERVER_PROTOCOL....................................TBD
+    6.1.18 SERVER_SOFTWARE....................................TBD
+    6.2 Request Message-Bodies................................TBD
+  7 Data Output from the CGI Script...........................TBD
+   7.1 Non-Parsed Header Output...............................TBD
+   7.2 Parsed Header Output...................................TBD
+    7.2.1 CGI header fields...................................TBD
+     7.2.1.1 Content-Type.....................................TBD
+     7.2.1.2 Location.........................................TBD
+     7.2.1.3 Status...........................................TBD
+     7.2.1.4 Extension header fields..........................TBD
+    7.2.2 HTTP header fields..................................TBD
+  8 Server Implementation.....................................TBD
+   8.1 Requirements for Servers...............................TBD
+    8.1.1 Script-URI..........................................TBD
+    8.1.2 Request Message-body Handling.......................TBD
+    8.1.3 Required Metavariables..............................TBD
+    8.1.4 Response Compliance.................................TBD
+   8.2 Recommendations for Servers............................TBD
+   8.3 Summary of Metavariables...............................TBD
+  9 Script Implementation.....................................TBD
+   9.1 Requirements for Scripts...............................TBD
+   9.2 Recommendations for Scripts............................TBD
+  10 System Specifications....................................TBD
+   10.1 AmigaDOS..............................................TBD
+   10.2 Unix..................................................TBD
+  11 Security Considerations..................................TBD
+   11.1 Safe Methods..........................................TBD
+   11.2 HTTP Header Fields Containing Sensitive Information...TBD
+   11.3 Script Interference with the Server...................TBD
+   11.4 Data Length and Buffering Considerations..............TBD
+   11.5 Stateless Processing..................................TBD
+  12 Acknowledgments..........................................TBD
+  13 References...............................................TBD
+  14 Authors' Addresses.......................................TBD
+     
+
+ +

+ + 1. Introduction + +

+ +

+ + 1.1. Purpose + +

+

+ Together the HTTP [3,8] server + and the CGI script are responsible + for servicing a client + request by sending back responses. The client + request comprises a Universal Resource Identifier (URI) + [1], a + request method, and various ancillary + information about the request + provided by the transport mechanism. +

+

+ The CGI defines the abstract parameters, known as + metavariables, + which describe the client's + request. Together with a + concrete programmer interface this specifies a platform-independent + interface between the script and the HTTP server. +

+ +

+ + 1.2. Requirements + +

+

+ This specification uses the same words as RFC 1123 + [5] to define the + significance of each particular requirement. These are: +

+

+
+
MUST +
+
+

+ This word or the adjective 'required' means that the item is an + absolute requirement of the specification. +

+
+
SHOULD +
+
+

+ This word or the adjective 'recommended' means that there may + exist valid reasons in particular circumstances to ignore this + item, but the full implications should be understood and the case + carefully weighed before choosing a different course. +

+
+
MAY +
+
+

+ This word or the adjective 'optional' means that this item is + truly optional. One vendor may choose to include the item because + a particular marketplace requires it or because it enhances the + product, for example; another vendor may omit the same item. +

+
+
+

+ An implementation is not compliant if it fails to satisfy one or more + of the 'must' requirements for the protocols it implements. An + implementation that satisfies all of the 'must' and all of the + 'should' requirements for its features is said to be 'unconditionally + compliant'; one that satisfies all of the 'must' requirements but not + all of the 'should' requirements for its features is said to be + 'conditionally compliant.' +

+ +

+ + 1.3. Specifications + +

+

+ Not all of the functions and features of the CGI are defined in the + main part of this specification. The following phrases are used to + describe the features which are not specified: +

+
+
system defined +
+
+

+ The feature may differ between systems, but must be the same for + different implementations using the same system. A system will + usually identify a class of operating-systems. Some systems are + defined in + section 10 of this document. + New systems may be defined + by new specifications without revision of this document. +

+
+
implementation defined +
+
+

+ The behaviour of the feature may vary from implementation to + implementation, but a particular implementation must document its + behaviour. +

+
+
+ +

+ + 1.4. Terminology + +

+

+ This specification uses many terms defined in the HTTP/1.1 + specification [8]; however, the following terms are + used here in a + sense which may not accord with their definitions in that document, + or with their common meaning. +

+ +
+
metavariable +
+
+

+ A named parameter that carries information from the server to the + script. It is not necessarily a variable in the operating-system's + environment, although that is the most common implementation. +

+
+ +
script +
+
+

+ The software which is invoked by the server via this + interface. It + need not be a standalone program, but could be a + dynamically-loaded or shared library, or even a subroutine in the + server. It may be a set of statements + interpreted at run-time, as the term 'script' is frequently + understood, but that is not a requirement and within the context + of this specification the term has the broader definition stated. +

+
+
server +
+
+

+ The application program which invokes the script in order to service + requests. +

+
+
+ +

+ + 2. Notational Conventions and Generic Grammar + +

+ +

+ + 2.1. Augmented BNF + +

+

+ All of the mechanisms specified in this document are described in + both prose and an augmented Backus-Naur Form (BNF) similar to that + used by RFC 822 [6]. This augmented BNF contains + the following constructs: +

+
+
name = definition +
+
+

+ The + definition by the equal character ("="). Whitespace is only + significant in that continuation lines of a definition are + indented. +

+
+
"literal" +
+
+

+ Quotation marks (") surround literal text, except for a literal + quotation mark, which is surrounded by angle-brackets ("<" and ">"). + Unless stated otherwise, the text is case-sensitive. +

+
+
rule1 | rule2 +
+
+

+ Alternative rules are separated by a vertical bar ("|"). +

+
+
(rule1 rule2 rule3) +
+
+

+ Elements enclosed in parentheses are treated as a single element. +

+
+
*rule +
+
+

+ A rule preceded by an asterisk ("*") may have zero or more + occurrences. A rule preceded by an integer followed by an asterisk + must occur at least the specified number of times. +

+
+
[rule] +
+
+

+ An element enclosed in square + brackets ("[" and "]") is optional. +

+
+
+ +

+ + 2.2. Basic Rules + +

+

+ The following rules are used throughout this specification to + describe basic parsing constructs. +

+

+
+    alpha         = lowalpha | hialpha
+    alphanum      = alpha | digit
+    lowalpha      = "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"
+    hialpha       = "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"
+    digit         = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7"
+                    | "8" | "9"
+    hex           = digit | "A" | "B" | "C" | "D" | "E" | "F" | "a"
+                    | "b" | "c" | "d" | "e" | "f"
+    escaped       = "%" hex hex
+    OCTET         = <any 8-bit sequence of data>
+    CHAR          = <any US-ASCII character (octets 0 - 127)>
+    CTL           = <any US-ASCII control character
+                    (octets 0 - 31) and DEL (127)>
+    CR            = <US-ASCII CR, carriage return (13)>
+    LF            = <US-ASCII LF, linefeed (10)>
+    SP            = <US-ASCII SP, space (32)>
+    HT            = <US-ASCII HT, horizontal tab (9)>
+    NL            = CR | LF
+    LWSP          = SP | HT | NL
+    tspecial      = "(" | ")" | "@" | "," | ";" | ":" | "\" | <">
+                    | "/" | "[" | "]" | "?" | "<" | ">" | "{" | "}"
+                    | SP | HT | NL
+    token         = 1*<any CHAR except CTLs or tspecials>
+    quoted-string = ( <"> *qdtext <"> ) | ( "<" *qatext ">")
+    qdtext        = <any CHAR except <"> and CTLs but including LWSP>
+    qatext        = <any CHAR except "<", ">" and CTLs but
+                    including LWSP>
+    mark          = "-" | "_" | "." | "!" | "~" | "*" | "'" | "(" | ")"
+    unreserved    = alphanum | mark
+    reserved      = ";" | "/" | "?" | ":" | "@" | "&" | "=" |
+                    "$" | ","
+    uric          = reserved | unreserved | escaped
+  
+

+ Note that newline (NL) need not be a single character, but can be a + character sequence. +

+ +

+ + 3. Protocol Parameters + +

+ +

+ + 3.1. URL Encoding + +

+

+ Some variables and constructs used here are described as being + 'URL-encoded'. This encoding is described in section + 2 of RFC + 2396 + [4]. +

+

+ An alternate "shortcut" encoding for representing the space + character exists and is in common use. Scripts MUST be prepared to + recognise both '+' and '%20' as an encoded space in a + URL-encoded value. +

+

+ Note that some unsafe characters may have different semantics if + they are encoded. The definition of which characters are unsafe + depends on the context. + For example, the following two URLs do not + necessarily refer to the same resource: +

+

+
+    http://somehost.com/somedir%2Fvalue
+    http://somehost.com/somedir/value
+  
+

+ See section + 2 of RFC + 2396 [4] + for authoritative treatment of this issue. +

+ +

+ + 3.2. The Script-URI + +

+

+ The 'Script-URI' is defined as the URI of the resource identified + by the metavariables. Often, + this URI will be the same as + the URI requested by the client (the 'Client-URI'); however, it need + not be. Instead, it could be a URI invented by the server, and so it + can only be used in the context of the server and its CGI interface. +

+

+ The Script-URI has the syntax of generic-RL as defined in section 2.1 + of RFC 1808 [7], with the exception that object + parameters and + fragment identifiers are not permitted: +

+

+
+    <scheme>://<host><port>/<path>?<query>
+  
+

+ The various components of the + Script-URI + are defined by some of the + metavariables (see + section 4 + below); +

+

+
+    script-uri = protocol "://" SERVER_NAME ":" SERVER_PORT enc-script
+                 enc-path-info "?" QUERY_STRING
+  
+

+ where 'protocol' is obtained + from SERVER_PROTOCOL, 'enc-script' is a + URL-encoded version of SCRIPT_NAME and 'enc-path-info' is a + URL-encoded version of PATH_INFO. See + section 4.6 for more information about the PATH_INFO + metavariable. +

+

+ Note that the scheme and the protocol are not identical; + for instance, a resource accessed via an SSL mechanism + may have a Client-URI with a scheme of "https" + rather than "http". CGI/1.1 provides no means + for the script to reconstruct this, and therefore + the Script-URI includes the base protocol used. +

+ +

+ + 4. Invoking the Script + +

+

+ The + script is invoked in a system defined manner. Unless specified + otherwise, the file containing the script will be invoked as an + executable program. +

+ +

+ + 5. The CGI Script Command Line + +

+

+ Some systems support a method for supplying an array of strings to + the CGI script. This is only used in the case of an 'indexed' query. + This is identified by a "GET" or "HEAD" HTTP request with a URL + query + string not containing any unencoded "=" characters. For such a + request, + servers SHOULD parse the search string + into words, using the following rules: +

+

+
+    search-string = search-word *( "+" search-word )
+    search-word   = 1*schar
+    schar         = xunreserved | escaped | xreserved
+    xunreserved   = alpha | digit | xsafe | extra
+    xsafe         = "$" | "-" | "_" | "."
+    xreserved     = ";" | "/" | "?" | ":" | "@" | "&"
+  
+

+ After parsing, each word is URL-decoded, optionally encoded in a + system defined manner, + and then the argument list is set to the list + of words. +

+

+ If the server cannot create any part of the argument list, then the + server SHOULD NOT generate any command line information. For example, the + number of arguments may be greater than operating system or server + limitations permit, or one of the words may not be representable as an + argument. +

+

+ Scripts SHOULD check to see if the QUERY_STRING value contains an + unencoded "=" character, and SHOULD NOT use the command line arguments + if it does. +

+ +

+ + 6. Data Input to the CGI Script + +

+

+ Information about a request comes from two different sources: the + request header, and any associated + message-body. + Servers MUST + make portions of this information available to + scripts. +

+ +

+ + 6.1. Request Metadata + (Metavariables) + +

+

+ Each CGI server + implementation MUST define a mechanism + to pass data about the request from + the server to the script. + The metavariables containing these + data + are accessed by the script in a system + defined manner. + The + representation of the characters in the + metavariables is + system defined. +

+

+ This specification does not distinguish between the representation of + null values and missing ones. Whether null or missing values + (such as a query component of "?" or "", respectively) are represented + by undefined metavariables or by metavariables with values of "" is + implementation-defined. +

+

+ Case is not significant in the + metavariable + names, in that there cannot be two + different variables + whose names differ in case only. Here they are + shown using a canonical representation of capitals plus underscore + ("_"). The actual representation of the names is system defined; for + a particular system the representation MAY be defined differently + than this. +

+

+ Metavariable + values MUST be + considered case-sensitive except as noted + otherwise. +

+

+ The canonical + metavariables + defined by this specification are: +

+

+
+    AUTH_TYPE
+    CONTENT_LENGTH
+    CONTENT_TYPE
+    GATEWAY_INTERFACE
+    PATH_INFO
+    PATH_TRANSLATED
+    QUERY_STRING
+    REMOTE_ADDR
+    REMOTE_HOST
+    REMOTE_IDENT
+    REMOTE_USER
+    REQUEST_METHOD
+    SCRIPT_NAME
+    SERVER_NAME
+    SERVER_PORT
+    SERVER_PROTOCOL
+    SERVER_SOFTWARE
+  
+

+ Metavariables with names beginning with the protocol name (e.g., + "HTTP_ACCEPT") are also canonical in their description of request header + fields. The number and meaning of these fields may change independently + of this specification. (See also section 6.1.5.) +

+ +

+ + 6.1.1. AUTH_TYPE + +

+

+ This variable is specific to requests made + via the + "http" + scheme. +

+

+ If the Script-URI + required access authentication for external + access, then the server + MUST set + the value of + this variable + from the 'auth-scheme' token in + the request's "Authorization" header + field. + Otherwise + it is + set to NULL. +

+

+
+    AUTH_TYPE   = "" | auth-scheme
+    auth-scheme = "Basic" | "Digest" | token
+  
+

+ HTTP access authentication schemes are described in section 11 of the + HTTP/1.1 specification [8]. The auth-scheme is + not case-sensitive. +

+

+ Servers + MUST + provide this metavariable + to scripts if the request + header included an "Authorization" field + that was authenticated. +

+ +

+ + 6.1.2. CONTENT_LENGTH + +

+

+ This + metavariable + is set to the + size of the message-body + entity attached to the request, if any, in decimal + number of octets. If no data are attached, then this + metavariable + is either NULL or not + defined. The syntax is + the same as for + the HTTP "Content-Length" header field (section 14.14, HTTP/1.1 + specification [8]). +

+

+
+    CONTENT_LENGTH = "" | 1*digit
+  
+

+ Servers MUST provide this metavariable + to scripts if the request + was accompanied by a + message-body entity. +

+ +

+ + 6.1.3. CONTENT_TYPE + +

+

+ If the request includes a + message-body, + CONTENT_TYPE is set + to + the Internet Media Type + [9] of the attached + entity if the type was provided via + a "Content-type" field in the + request header, or if the server can determine it in the absence + of a supplied "Content-type" field. The syntax is the + same as for the HTTP + "Content-Type" header field. +

+

+
+    CONTENT_TYPE = "" | media-type
+    media-type   = type "/" subtype *( ";" parameter)
+    type         = token
+    subtype      = token
+    parameter    = attribute "=" value
+    attribute    = token
+    value        = token | quoted-string
+  
+

+ The type, subtype, + and parameter attribute names are not + case-sensitive. Parameter values MAY be case sensitive. + Media types and their use in HTTP are described + in section 3.7 of the + HTTP/1.1 specification [8]. +

+

+ Example: +

+

+
+    application/x-www-form-urlencoded
+  
+

+ There is no default value for this variable. If and only if it is + unset, then the script MAY attempt to determine the media type from + the data received. If the type remains unknown, then + the script MAY choose to either assume a + content-type of + application/octet-stream + or reject the request with a 415 ("Unsupported Media Type") + error. See section 7.2.1.3 + for more information about returning error status values. +

+

+ Servers MUST provide this metavariable + to scripts if + a "Content-Type" field was present + in the original request header. If the server receives a request + with an attached entity but no "Content-Type" + header field, it MAY attempt to + determine the correct datatype, or it MAY omit this + metavariable when + communicating the request information to the script. +

+ +

+ + 6.1.4. GATEWAY_INTERFACE + +

+

+ This + metavariable + is set to + the dialect of CGI being used + by the server to communicate with the script. + Syntax: +

+

+
+    GATEWAY_INTERFACE = "CGI" "/" major "." minor
+    major             = 1*digit
+    minor             = 1*digit
+  
+

+ Note that the major and minor numbers are treated as separate + integers and hence each may be + more than a single + digit. Thus CGI/2.4 is a lower version than CGI/2.13 which in turn + is lower than CGI/12.3. Leading zeros in either + the major or the minor number MUST be ignored by scripts and + SHOULD NOT be generated by servers. +

+

+ This document defines the 1.1 version of the CGI interface + ("CGI/1.1"). +

+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.5. Protocol-Specific Metavariables + +

+

+ These metavariables are specific to + the protocol + via which the request is made. + Interpretation of these variables depends on the value of + the + SERVER_PROTOCOL + metavariable + (see + section 6.1.17). +

+

+ Metavariables + with names beginning with "HTTP_" contain + values from the request header, if the + scheme used was HTTP. + Each + HTTP header field name is converted to upper case, has all occurrences of + "-" replaced with "_", + and has "HTTP_" prepended to form + the metavariable name. + Similar transformations are applied for other + protocols. + The header data MAY be presented as sent + by the client, or MAY be rewritten in ways which do not change its + semantics. If multiple header fields with the same field-name are received + then the server + MUST rewrite them as though they + had been received as a single header field having the same + semantics before being represented in a + metavariable. + Similarly, a header field that is received on more than one line + MUST be merged into a single line. The server MUST, if necessary, + change the representation of the data (for example, the character + set) to be appropriate for a CGI + metavariable. + +

+

+ Servers are + not required to create + metavariables for all + the request + header fields that they + receive. In particular, + they MAY + decline to make available any + header fields carrying authentication information, such as + "Authorization", or + which are available to the script + via other metavariables, + such as "Content-Length" and "Content-Type". +

+ +

+ + 6.1.6. PATH_INFO + +

+

+ The PATH_INFO + metavariable + specifies + a path to be interpreted by the CGI script. It identifies the + resource or sub-resource to be returned + by the CGI + script, and it is derived from the portion + of the URI path following the script name but preceding + any query data. + The syntax + and semantics are similar to a decoded HTTP URL + 'path' token + (defined in + RFC 2396 + [4]), with the exception + that a PATH_INFO of "/" + represents a single void path segment. +

+

+
+    PATH_INFO = "" | ( "/" path )
+    path      = segment *( "/" segment )
+    segment   = *pchar
+    pchar     = <any CHAR except "/">
+  
+

+ The PATH_INFO string is the trailing part of the <path> component of + the Script-URI + (see section 3.2) + that follows the SCRIPT_NAME + portion of the path. +

+

+ Servers MAY impose their own restrictions and + limitations on what values they will accept for PATH_INFO, and MAY + reject or edit any values they + consider objectionable before passing + them to the script. +

+

+ Servers MUST make this URI component available + to CGI scripts. The PATH_INFO + value is case-sensitive, and the + server MUST preserve the case of the PATH_INFO element of the URI + when making it available to scripts. +

+ +

+ + 6.1.7. PATH_TRANSLATED + +

+

+ PATH_TRANSLATED is derived by taking any path-info component of the + request URI (see + section 6.1.6), decoding it + (see section 3.1), parsing it as a URI in its own + right, and performing any virtual-to-physical + translation appropriate to map it onto the + server's document repository structure. + If the request URI includes no path-info + component, the PATH_TRANSLATED metavariable SHOULD NOT be defined. +

+

+
+    PATH_TRANSLATED = *CHAR
+  
+

+ For a request such as the following: +

+

+
+    http://somehost.com/cgi-bin/somescript/this%2eis%2epath%2einfo
+  
+

+ the PATH_INFO component would be decoded, and the result + parsed as though it were a request for the following: +

+

+
+    http://somehost.com/this.is.the.path.info
+  
+

+ This would then be translated to a + location in the server's document repository, + perhaps a filesystem path something + like this: +

+

+
+    /usr/local/www/htdocs/this.is.the.path.info
+  
+

+ The result of the translation is the value of PATH_TRANSLATED. +

+

+ The value of PATH_TRANSLATED may or may not map to a valid + repository + location. + Servers MUST preserve the case of the path-info + segment if and only if the underlying + repository + supports case-sensitive + names. If the + repository + is only case-aware, case-preserving, or case-blind + with regard to + document names, + servers are not required to preserve the + case of the original segment through the translation. +

+

+ The + translation + algorithm the server uses to derive PATH_TRANSLATED is + implementation defined; CGI scripts which use this variable may + suffer limited portability. +

+

+ Servers SHOULD provide this metavariable + to scripts if and only if the request URI includes a + path-info component. +

+ +

+ + 6.1.8. QUERY_STRING + +

+

+ A URL-encoded + string; the <query> part of the + Script-URI. + (See + section 3.2.) +

+

+
+    QUERY_STRING = query-string
+    query-string = *uric
+  
+

+ The URL syntax for a query + string is described in + section 3 of + RFC 2396 + [4]. +

+

+ Servers MUST supply this value to scripts. + The QUERY_STRING value is case-sensitive. + If the Script-URI does not include a query component, + the QUERY_STRING metavariable MUST be defined as an empty string (""). +

+ +

+ + 6.1.9. REMOTE_ADDR + +

+

+ The IP address of the client + sending the request to the server. This + is not necessarily that of the user + agent + (such as if the request came through a proxy). +

+

+
+    REMOTE_ADDR  = hostnumber
+    hostnumber   = ipv4-address | ipv6-address
+  
+

+ The definitions of ipv4-address and ipv6-address + are provided in Appendix B of RFC 2373 [13]. +

+

+ Servers MUST supply this value to scripts. +

+ +

+ + 6.1.10. REMOTE_HOST + +

+

+ The fully qualified domain name of the + client sending the request to + the server, if available, otherwise NULL. + (See section 6.1.9.) + Fully qualified domain names take the form as described in + section 3.5 of RFC 1034 [10] and section 2.1 of + RFC 1123 [5]. Domain names are not case sensitive. +

+

+ Servers SHOULD provide this information to + scripts. +

+ +

+ + 6.1.11. REMOTE_IDENT + +

+

+ The identity information reported about the connection by a + RFC 1413 [11] request to the remote agent, if + available. Servers + MAY choose not + to support this feature, or not to request the data + for efficiency reasons. +

+

+
+    REMOTE_IDENT = *CHAR
+  
+

+ The data returned + may be used for authentication purposes, but the level + of trust reposed in them should be minimal. +

+

+ Servers MAY supply this information to scripts if the + RFC1413 [11] lookup is performed. +

+ +

+ + 6.1.12. REMOTE_USER + +

+

+ If the request required authentication using the "Basic" + mechanism (i.e., the AUTH_TYPE + metavariable is set + to "Basic"), then the value of the REMOTE_USER + metavariable is set to the + user-ID supplied. In all other cases + the value of this metavariable + is undefined. +

+

+
+    REMOTE_USER = *OCTET
+  
+

+ This variable is specific to requests made via the + HTTP protocol. +

+

+ Servers SHOULD provide this metavariable + to scripts. +

+ +

+ + 6.1.13. REQUEST_METHOD + +

+

+ The REQUEST_METHOD + metavariable + is set to the + method with which the request was made, as described in section + 5.1.1 of the HTTP/1.0 specification [3] and + section 5.1.1 of the + HTTP/1.1 specification [8]. +

+

+
+    REQUEST_METHOD   = http-method
+    http-method      = "GET" | "HEAD" | "POST" | "PUT" | "DELETE"
+                       | "OPTIONS" | "TRACE" | extension-method
+    extension-method = token
+  
+

+ The method is case sensitive. + CGI/1.1 servers MAY choose to process some methods + directly rather than passing them to scripts. +

+

+ This variable is specific to requests made with HTTP. +

+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.14. SCRIPT_NAME + +

+

+ The SCRIPT_NAME + metavariable + is + set to a URL path that could identify the CGI script (rather than the + script's + output). The syntax and semantics are identical to a + decoded HTTP URL 'path' token + (see RFC 2396 + [4]). +

+

+
+    SCRIPT_NAME = "" | ( "/" [ path ] )
+  
+

+ The SCRIPT_NAME string is some leading part of the <path> component + of the Script-URI derived in some + implementation defined manner. + No PATH_INFO or QUERY_STRING segments + (see sections 6.1.6 and + 6.1.8) are included + in the SCRIPT_NAME value. +

+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.15. SERVER_NAME + +

+

+ The SERVER_NAME + metavariable + is set to the + name of the + server, as + derived from the <host> part of the + Script-URI + (see section 3.2). +

+

+
+    SERVER_NAME = hostname | hostnumber
+  
+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.16. SERVER_PORT + +

+

+ The SERVER_PORT + metavariable + is set to the + port on which the + request was received, as used in the <port> + part of the Script-URI. +

+

+
+    SERVER_PORT = 1*digit
+  
+

+ If the <port> portion of the script-URI is blank, the actual + port number upon which the request was received MUST be supplied. +

+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.17. SERVER_PROTOCOL + +

+

+ The SERVER_PROTOCOL + metavariable + is set to + the + name and revision of the information protocol with which + the + request + arrived. This is not necessarily the same as the protocol version used by + the server in its response to the client. +

+

+
+    SERVER_PROTOCOL   = HTTP-Version | extension-version
+                        | extension-token
+    HTTP-Version      = "HTTP" "/" 1*digit "." 1*digit
+    extension-version = protocol "/" 1*digit "." 1*digit
+    protocol          = 1*( alpha | digit | "+" | "-" | "." )
+    extension-token   = token
+  
+

+ 'protocol' is a version of the <scheme> part of the + Script-URI, but is + not identical to it. For example, the scheme of a request may be + "https" while the protocol remains "http". + The protocol is not case sensitive, but + by convention, 'protocol' is in + upper case. +

+

+ A well-known extension token value is "INCLUDED", + which signals that the current document is being included as part of + a composite document, rather than being the direct target of the + client request. +

+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.1.18. SERVER_SOFTWARE + +

+

+ The SERVER_SOFTWARE + metavariable + is set to the + name and version of the information server software answering the + request (and running the gateway). +

+

+
+    SERVER_SOFTWARE = 1*product
+    product         = token [ "/" product-version ]
+    product-version = token
+  
+

+ Servers MUST provide this metavariable + to scripts. +

+ +

+ + 6.2. Request Message-Bodies + +

+

+ As there may be a data entity attached to the request, there MUST be + a system defined method for the script to read + these data. Unless + defined otherwise, this will be via the 'standard input' file + descriptor. +

+

+ If the CONTENT_LENGTH value (see section 6.1.2) + is non-NULL, the server MUST supply at least that many bytes to + scripts on the standard input stream. + Scripts are + not obliged to read the data. + Servers MAY signal an EOF condition after CONTENT_LENGTH bytes have been + read, but are + not obligated to do so. Therefore, scripts + MUST NOT + attempt to read more than CONTENT_LENGTH bytes, even if more data + are available. +

+

+ For non-parsed header (NPH) scripts (see + section 7.1 + below), + servers SHOULD + attempt to ensure that the data + supplied to the script are precisely + as supplied by the client and unaltered by + the server. +

+

+ Section 8.1.2 describes the requirements of + servers with regard to requests that include + message-bodies. +

+ +

+ + 7. Data Output from the CGI Script + +

+

+ There MUST be a system defined method for the script to send data + back to the server or client; a script MUST always return some data. + Unless defined otherwise, this will be via the 'standard + output' file descriptor. +

+

+ There are two forms of output that scripts can supply to servers: non-parsed + header (NPH) output, and parsed header output. + Servers MUST support parsed header + output and MAY support NPH output. The method of + distinguishing between the two + types of output (or scripts) is implementation defined. +

+

+ Servers MAY implement a timeout period within which data must be + received from scripts. If a server implementation defines such + a timeout and receives no data from a script within the timeout + period, the server MAY terminate the script process and SHOULD + abort the client request with + either a + '504 Gateway Timed Out' or a + '500 Internal Server Error' response. +

+ +

+ + 7.1. Non-Parsed Header Output + +

+

+ Scripts using the NPH output form + MUST return a complete HTTP response message, as described + in Section 6 of the HTTP specifications + [3,8]. + NPH scripts + MUST use the SERVER_PROTOCOL variable to determine the appropriate format + for a response. +

+

+ Servers + SHOULD attempt to ensure that the script output is sent + directly to the client, with minimal + internal and no transport-visible + buffering. +

+ +

+ + 7.2. Parsed Header Output + +

+

+ Scripts using the parsed header output form MUST supply + a CGI response message to the server + as follows: +

+

+
+    CGI-Response   = *optional-field CGI-Field *optional-field NL [ Message-Body ]
+    optional-field = ( CGI-Field | HTTP-Field )
+    CGI-Field      = Content-type
+                   | Location
+                   | Status
+                   | extension-header
+  
+

+ The response comprises a header and a body, separated by a blank line. + The body may be NULL. + The header fields are either CGI header fields to be interpreted by + the server, or HTTP header fields + to be included in the response returned + to the client + if the request method is HTTP. At least one + CGI-Field MUST be + supplied, but no CGI field name may be used more than once + in a response. + If a body is supplied, then a "Content-type" + header field MUST be + supplied by the script, + otherwise the script MUST send a "Location" + or "Status" header field. If a + Location CGI-Field + is returned, then the script MUST NOT supply + any HTTP-Fields. +

+

+ Each header field in a CGI-Response MUST be specified on a single line; + CGI/1.1 does not support continuation lines. +

+ +

+ + 7.2.1. CGI header fields + +

+

+ The CGI header fields have the generic syntax: +

+

+
+    generic-field  = field-name ":" [ field-value ] NL
+    field-name     = token
+    field-value    = *( field-content | LWSP )
+    field-content  = *( token | tspecial | quoted-string )
+  
+

+ The field-name is not case sensitive; a NULL field value is + equivalent to the header field not being sent. +

+ +

+ + 7.2.1.1. Content-Type + +

+

+ The Internet Media Type [9] of the entity + body, which is to be sent unmodified to the client. +

+

+
+    Content-Type = "Content-Type" ":" media-type NL
+  
+

+ This is actually an HTTP-Field + rather than a CGI-Field, but + it is listed here because of its importance in the CGI dialogue as + a member of the "one of these is required" set of header + fields. +

+ +

+ + 7.2.1.2. Location + +

+

+ This is used to specify to the server that the script is returning a + reference to a document rather than an actual document. +

+

+
+    Location         = "Location" ":"
+                       ( fragment-URI | rel-URL-abs-path ) NL
+    fragment-URI     = URI [ # fragmentid ]
+    URI              = scheme ":" *qchar
+    fragmentid       = *qchar
+    rel-URL-abs-path = "/" [ hpath ] [ "?" query-string ]
+    hpath            = fpsegment *( "/" psegment )
+    fpsegment        = 1*hchar
+    psegment         = *hchar
+    hchar            = alpha | digit | safe | extra
+                       | ":" | "@" | "& | "="
+  
+

+ The Location + value is either an absolute URI with optional fragment, + as defined in RFC 1630 [1], or an absolute path + within the server's URI space (i.e., + omitting the scheme and network-related fields) and optional + query-string. If an absolute URI is returned by the script, + then the + server MUST generate a + '302 redirect' HTTP response + message unless the script has supplied an + explicit Status response header field. + Scripts returning an absolute URI MAY choose to + provide a message-body. Servers MUST make any appropriate modifications + to the script's output to ensure the response to the user-agent complies + with the response protocol version. + If the Location value is a path, then the server + MUST generate + the response that it would have produced in response to a request + containing the URL +

+

+
+    scheme "://" SERVER_NAME ":" SERVER_PORT rel-URL-abs-path
+  
+

+ Note: If the request was accompanied by a + message-body + (such as for a POST request), and the script + redirects the request with a Location field, the + message-body + may not be + available to the resource that is the target of the redirect. +

+ +

+ + 7.2.1.3. Status + +

+

+ The "Status" header field is used to indicate to the server what + status code the server MUST use in the response message. +

+

+
+    Status        = "Status" ":" digit digit digit SP reason-phrase NL
+    reason-phrase = *<CHAR, excluding CTLs, NL>
+  
+

+ The valid status codes are listed in section 6.1.1 of the HTTP/1.0 + specifications [3]. If the SERVER_PROTOCOL is + "HTTP/1.1", then the status codes defined in the HTTP/1.1 + specification [8] may + be used. If the script does not return a "Status" header + field, then "200 OK" SHOULD be assumed by the server. +

+

+ If a script is being used to handle a particular error or condition + encountered by the server, such as a '404 Not Found' error, the script + SHOULD use the "Status" CGI header field to propagate the error + condition back to the client. E.g., in the example mentioned it + SHOULD include a "Status: 404 Not Found" in the + header data returned to the server. +

+ +

+ + 7.2.1.4. Extension header fields + +

+

+ Scripts MAY include in their CGI response header additional fields + not defined in this or the HTTP specification. + These are called "extension" fields, + and have the syntax of a generic-field as defined in + section 7.2.1. The name of an extension field + MUST NOT conflict with a field name defined in this or any other + specification; extension field names SHOULD begin with "X-CGI-" + to ensure uniqueness. +

+ +

+ + 7.2.2. HTTP header fields + +

+

+ The script MAY return any other header fields defined by the + specification + for the SERVER_PROTOCOL (HTTP/1.0 [3] or HTTP/1.1 + [8]). + Servers MUST resolve conflicts beteen CGI header + and HTTP header formats or names (see section 8). +

+ +

+ + 8. Server Implementation + +

+

+ This section defines the requirements that must be met by HTTP + servers in order to provide a coherent and correct CGI/1.1 + environment in which scripts may function. It is intended + primarily for server implementors, but it is useful for + script authors to be familiar with the information as well. +

+ +

+ + 8.1. Requirements for Servers + +

+

+ In order to be considered CGI/1.1-compliant, a server must meet + certain basic criteria and provide certain minimal functionality. + The details of these requirements are described in the following sections. +

+ +

+ + 8.1.1. Script-URI + +

+

+ Servers MUST support the standard mechanism (described below) which + allows + script authors to determine + what URL to use in documents + which reference the script; + specifically, what URL to use in order to + achieve particular settings of the + metavariables. This + mechanism is as follows: +

+

+ The server + MUST translate the header data from the CGI header field syntax to + the HTTP + header field syntax if these differ. For example, the character + sequence for + newline (such as Unix's ASCII NL) used by CGI scripts may not be the + same as that used by HTTP (ASCII CR followed by LF). The server MUST + also resolve any conflicts between header fields returned by the script + and header fields that it would otherwise send itself. +

+ +

+ + 8.1.2. Request Message-body Handling + +

+

+ These are the requirements for server handling of message-bodies directed + to CGI/1.1 resources: +

+
    +
  1. The message-body the server provides to the CGI script MUST + have any transfer encodings removed. +
  2. +
  3. The server MUST derive and provide a value for the CONTENT_LENGTH + metavariable that reflects the length of the message-body after any + transfer decoding. +
  4. +
  5. The server MUST leave intact any content-encodings of the message-body. +
  6. +
+ +

+ + 8.1.3. Required Metavariables + +

+

+ Servers MUST provide scripts with certain information and + metavariables + as described in section 8.3. +

+ +

+ + 8.1.4. Response Compliance + +

+

+ Servers MUST ensure that responses sent to the user-agent meet all + requirements of the protocol level in effect. This may involve + modifying, deleting, or augmenting any header + fields and/or message-body supplied by the script. +

+ +

+ + 8.2. Recommendations for Servers + +

+

+ Servers SHOULD provide the "query" component of the script-URI + as command-line arguments to scripts if it does not + contain any unencoded '=' characters and the command-line arguments can + be generated in an unambiguous manner. + (See section 5.) +

+

+ Servers SHOULD set the AUTH_TYPE + metavariable to the value of the + 'auth-scheme' token of the "Authorization" + field if it was supplied as part of the request header. + (See section 6.1.1.) +

+

+ Where applicable, servers SHOULD set the current working directory + to the directory in which the script is located before invoking + it. +

+

+ Servers MAY reject with error '404 Not Found' + any requests that would result in + an encoded "/" being decoded into PATH_INFO or SCRIPT_NAME, as this + might represent a loss of information to the script. +

+

+ Although the server and the CGI script need not be consistent in + their handling of URL paths (client URLs and the PATH_INFO data, + respectively), server authors may wish to impose consistency. + So the server implementation SHOULD define its behaviour for the + following cases: +

+
    +
  1. define any restrictions on allowed characters, in particular + whether ASCII NUL is permitted; +
  2. +
  3. define any restrictions on allowed path segments, in particular + whether non-terminal NULL segments are permitted; +
  4. +
  5. define the behaviour for "." or ".." path + segments; i.e., whether they are prohibited, treated as + ordinary path + segments or interpreted in accordance with the relative URL + specification [7]; +
  6. +
  7. define any limits of the implementation, including limits on path or + search string lengths, and limits on the volume of header data the server + will parse. +
  8. +
+

+ Servers MAY generate the + Script-URI in + any way from the client URI, + or from any other data (but the behaviour SHOULD be documented). +

+

+ For non-parsed header (NPH) scripts (see + section 7.1), servers SHOULD + attempt to ensure that the script input comes directly from the + client, with minimal buffering. For all scripts the data will be + as supplied by the client. +

+ +

+ + 8.3. Summary of + MetaVariables + +

+

+ Servers MUST provide the following + metavariables to + scripts. See the individual descriptions for exceptions and semantics. +

+

+
+    CONTENT_LENGTH (section 6.1.2)
+    CONTENT_TYPE (section 6.1.3)
+    GATEWAY_INTERFACE (section 6.1.4)
+    PATH_INFO (section 6.1.6)
+    QUERY_STRING (section 6.1.8)
+    REMOTE_ADDR (section 6.1.9)
+    REQUEST_METHOD (section 6.1.13)
+    SCRIPT_NAME (section 6.1.14)
+    SERVER_NAME (section 6.1.15)
+    SERVER_PORT (section 6.1.16)
+    SERVER_PROTOCOL (section 6.1.17)
+    SERVER_SOFTWARE (section 6.1.18)
+  
+

+ Servers SHOULD define the following + metavariables for scripts. + See the individual descriptions for exceptions and semantics. +

+

+
+    AUTH_TYPE (section 6.1.1)
+    REMOTE_HOST (section 6.1.10)
+  
+

+ In addition, servers SHOULD provide + metavariables for all fields present + in the HTTP request header, with the exception of those involved with + access control. Servers MAY at their discretion provide + metavariables + for access control fields. +

+

+ Servers MAY define the following + metavariables. See the individual + descriptions for exceptions and semantics. +

+

+
+    PATH_TRANSLATED (section 6.1.7)
+    REMOTE_IDENT (section 6.1.11)
+    REMOTE_USER (section 6.1.12)
+  
+

+ Servers MAY + at their discretion define additional implementation-specific + extension metavariables + provided their names do not + conflict with defined header field names. Implementation-specific + metavariable names SHOULD + be prefixed with "X_" (e.g., + "X_DBA") to avoid the potential for such conflicts. +

+ +

+ + 9. + Script Implementation + +

+

+ This section defines the requirements and recommendations for scripts + that are intended to function in a CGI/1.1 environment. It is intended + primarily as a reference for script authors, but server implementors + should be familiar with these issues as well. +

+ +

+ + 9.1. Requirements for Scripts + +

+

+ Scripts using the parsed-header method to communicate with servers + MUST supply a response header to the server. + (See section 7.) +

+

+ Scripts using the NPH method to communicate with servers MUST + provide complete HTTP responses, and MUST use the value of the + SERVER_PROTOCOL metavariable + to determine the appropriate format. + (See section 7.1.) +

+

+ Scripts MUST check the value of the REQUEST_METHOD + metavariable in order + to provide an appropriate response. + (See section 6.1.13.) +

+

+ Scripts MUST be prepared to handled URL-encoded values in + metavariables. + In addition, they MUST recognise both "+" and "%20" in URL-encoded + quantities as representing the space character. + (See section 3.1.) +

+

+ Scripts MUST ignore leading zeros in the major and minor version numbers + in the GATEWAY_INTERFACE + metavariable value. (See + section 6.1.4.) +

+

+ When processing requests that include a + message-body, scripts + MUST NOT read more than CONTENT_LENGTH bytes from the input stream. + (See sections 6.1.2 and 6.2.) +

+ +

+ + 9.2. Recommendations for Scripts + +

+

+ Servers may interrupt or terminate script execution at any time + and without warning, so scripts SHOULD be prepared to deal with + abnormal termination. +

+

+ Scripts MUST + reject with + error '405 Method Not + Allowed' requests + made using methods that they do not support. If the script does + not intend + processing the PATH_INFO data, then it SHOULD reject the request with + '404 Not + Found' if PATH_INFO is not NULL. +

+

+ If a script is processing the output of a form, it SHOULD + verify that the CONTENT_TYPE + is "application/x-www-form-urlencoded" [2] + or whatever other media type is expected. +

+

+ Scripts parsing PATH_INFO, + PATH_TRANSLATED, or SCRIPT_NAME + SHOULD be careful + of void path segments ("//") and special path segments + ("." and + ".."). They SHOULD either be removed from the path before + use in OS + system calls, or the request SHOULD be rejected with + '404 Not Found'. +

+

+ As it is impossible for + scripts to determine the client URI that + initiated a + request without knowledge of the specific server in + use, the script SHOULD NOT return "text/html" + documents containing + relative URL links without including a "<BASE>" + tag in the document. +

+

+ When returning header fields, + scripts SHOULD try to send the CGI + header fields (see section + 7.2) as soon as possible, and + SHOULD send them + before any HTTP header fields. This may + help reduce the server's memory requirements. +

+ +

+ + 10. System Specifications + +

+ +

+ + 10.1. AmigaDOS + +

+

+ The implementation of the CGI on an AmigaDOS operating system platform + SHOULD use environment variables as the mechanism of providing + request metadata to CGI scripts. +

+
+
Environment variables +
+
+

+ These are accessed by the DOS library routine GetVar. The + flags argument SHOULD be 0. Case is ignored, but upper case is + recommended for compatibility with case-sensitive systems. +

+
+
The current working directory +
+
+

+ The current working directory for the script is set to the directory + containing the script. +

+
+
Character set +
+
+

+ The US-ASCII character set is used for the definition of environment + variable names and header + field names; the newline (NL) sequence is LF; + servers SHOULD also accept CR LF as a newline. +

+
+
+ +

+ + 10.2. Unix + +

+

+ The implementation of the CGI on a UNIX operating system platform + SHOULD use environment variables as the mechanism of providing + request metadata to CGI scripts. +

+

+ For Unix compatible operating systems, the following are defined: +

+
+
Environment variables +
+
+

+ These are accessed by the C library routine getenv. +

+
+
The command line +
+
+

+ This is accessed using the + argc and argv + arguments to main(). The words have any characters + that + are 'active' in the Bourne shell escaped with a backslash. + If the value of the QUERY_STRING + metavariable + contains an unencoded equals-sign '=', then the command line + SHOULD NOT be used by the script. +

+
+
The current working directory +
+
+

+ The current working directory for the script + SHOULD be set to the directory + containing the script. +

+
+
Character set +
+
+

+ The US-ASCII character set is used for the definition of environment + variable names and header field names; the newline (NL) sequence is LF; + servers SHOULD also accept CR LF as a newline. +

+
+
+ +

+ + 11. Security Considerations + +

+ +

+ + 11.1. Safe Methods + +

+

+ As discussed in the security considerations of the HTTP + specifications [3,8], the + convention has been established that the + GET and HEAD methods should be 'safe'; they should cause no + side-effects and only have the significance of resource retrieval. +

+

+ CGI scripts are responsible for enforcing any HTTP security considerations + [3,8] + with respect to the protocol version level of the request and + any side effects generated by the scripts on behalf of + the server. Primary + among these + are the considerations of safe and idempotent methods. Idempotent + requests are those that may be repeated an arbitrary number of times + and produce side effects identical to a single request. +

+ +

+ + 11.2. HTTP Header + Fields Containing Sensitive Information + +

+

+ Some HTTP header fields may carry sensitive information which the server + SHOULD NOT pass on to the script unless explicitly configured to do + so. For example, if the server protects the script using the + "Basic" + authentication scheme, then the client will send an + "Authorization" + header field containing a username and password. If the server, rather + than the script, validates this information then the password SHOULD + NOT be passed on to the script via the HTTP_AUTHORIZATION + metavariable + without careful consideration. + This also applies to the + Proxy-Authorization header field and the corresponding + HTTP_PROXY_AUTHORIZATION + metavariable. +

+ +

+ + 11.3. Script + Interference with the Server + +

+

+ The most common implementation of CGI invokes the script as a child + process using the same user and group as the server process. It + SHOULD therefore be ensured that the script cannot interfere with the + server process, its configuration, or documents. +

+

+ If the script is executed by calling a function linked in to the + server software (either at compile-time or run-time) then precautions + SHOULD be taken to protect the core memory of the server, or to + ensure that untrusted code cannot be executed. +

+ +

+ + 11.4. Data Length and Buffering Considerations + +

+

+ This specification places no limits on the length of message-bodies + presented to the script. Scripts should not assume that statically + allocated buffers of any size are sufficient to contain the entire + submission at one time. Use of a fixed length buffer without careful + overflow checking may result in an attacker exploiting 'stack-smashing' + or 'stack-overflow' vulnerabilities of the operating system. + Scripts may spool large submissions to disk or other buffering media, + but a rapid succession of large submissions may result in denial of + service conditions. If the CONTENT_LENGTH of a message-body is larger + than resource considerations allow, scripts should respond with an + error status appropriate for the protocol version; potentially applicable + status codes include '503 Service Unavailable' (HTTP/1.0 and HTTP/1.1), + '413 Request Entity Too Large' (HTTP/1.1), and + '414 Request-URI Too Long' (HTTP/1.1). +

+ +

+ + 11.5. Stateless Processing + +

+

+ The stateless nature of the Web makes each script execution and resource + retrieval independent of all others even when multiple requests constitute a + single conceptual Web transaction. Because of this, a script should not + make any assumptions about the context of the user-agent submitting a + request. In particular, scripts should examine data obtained from the client + and verify that they are valid, both in form and content, before allowing + them to be used for sensitive purposes such as input to other + applications, commands, or operating system services. These uses + include, but are not + limited to: system call arguments, database writes, dynamically evaluated + source code, and input to billing or other secure processes. It is important + that applications be protected from invalid input regardless of whether + the invalidity is the result of user error, logic error, or malicious action. +

+

+ Authors of scripts involved in multi-request transactions should be + particularly cautios about validating the state information; + undesirable effects may result from the substitution of dangerous + values for portions of the submission which might otherwise be + presumed safe. Subversion of this type occurs when alterations + are made to data from a prior stage of the transaction that were + not meant to be controlled by the client (e.g., hidden + HTML form elements, cookies, embedded URLs, etc.). +

+ +

+ + 12. Acknowledgements + +

+

+ This work is based on a draft published in 1997 by David R. Robinson, + which in turn was based on the original CGI interface that arose out of + discussions on the www-talk mailing list. In particular, + Rob McCool, John Franks, Ari Luotonen, + George Phillips and + Tony Sanders deserve special recognition for their efforts in + defining and implementing the early versions of this interface. +

+

+ This document has also greatly benefited from the comments and + suggestions made by Chris Adie, Dave Kristol, + Mike Meyer, David Morris, Jeremy Madea, + Patrick McManus, Adam Donahue, + Ross Patterson, and Harald Alvestrand. +

+ +

+ + 13. References + +

+
+
[1] +
+
Berners-Lee, T., 'Universal Resource Identifiers in WWW: A + Unifying Syntax for the Expression of Names and Addresses of + Objects on the Network as used in the World-Wide Web', RFC 1630, + CERN, June 1994. +

+

+
+
[2] +
+
Berners-Lee, T. and Connolly, D., 'Hypertext Markup Language - + 2.0', RFC 1866, MIT/W3C, November 1995. +

+

+
+
[3] +
+
Berners-Lee, T., Fielding, R. T. and Frystyk, H., + 'Hypertext Transfer Protocol -- HTTP/1.0', RFC 1945, MIT/LCS, + UC Irvine, May 1996. +

+

+
+ +
[4] +
+
Berners-Lee, T., Fielding, R., and Masinter, L., Editors, + 'Uniform Resource Identifiers (URI): Generic Syntax', RFC 2396, + MIT, U.C. Irvine, Xerox Corporation, August 1996. +

+

+
+ +
[5] +
+
Braden, R., Editor, 'Requirements for Internet Hosts -- + Application and Support', STD 3, RFC 1123, IETF, October 1989. +

+

+
+
[6] +
+
Crocker, D.H., 'Standard for the Format of ARPA Internet Text + Messages', STD 11, RFC 822, University of Delaware, August 1982. +

+

+
+
[7] +
+
Fielding, R., 'Relative Uniform Resource Locators', RFC 1808, + UC Irvine, June 1995. +

+

+
+
[8] +
+
Fielding, R., Gettys, J., Mogul, J., Frystyk, H. and + Berners-Lee, T., 'Hypertext Transfer Protocol -- HTTP/1.1', + RFC 2068, UC Irvine, DEC, + MIT/LCS, January 1997. +

+

+
+
[9] +
+
Freed, N. and Borenstein N., 'Multipurpose Internet Mail + Extensions (MIME) Part Two: Media Types', RFC 2046, Innosoft, + First Virtual, November 1996. +

+

+
+
[10] +
+
Mockapetris, P., 'Domain Names - Concepts and Facilities', + STD 13, RFC 1034, ISI, November 1987. +

+

+
+
[11] +
+
St. Johns, M., 'Identification Protocol', RFC 1431, US + Department of Defense, February 1993. +

+

+
+
[12] +
+
'Coded Character Set -- 7-bit American Standard Code for + Information Interchange', ANSI X3.4-1986. +

+

+
+
[13] +
+
Hinden, R. and Deering, S., + 'IP Version 6 Addressing Architecture', RFC 2373, + Nokia, Cisco Systems, + July 1998. +

+

+
+
+ +

+ + 14. Authors' Addresses + +

+
+

+ Ken A L Coar +
+ MeepZor Consulting +
+ 7824 Mayfaire Crest Lane, Suite 202 +
+ Raleigh, NC 27615-4875 +
+ U.S.A. +

+

+ Tel: +1 (919) 254.4237 +
+ Fax: +1 (919) 254.5250 +
+ Email: + Ken.Coar@Golux.Com +

+
+
+

+ David Robinson +
+ E*TRADE UK Ltd +
+ Mount Pleasant House +
+ 2 Mount Pleasant +
+ Huntingdon Road +
+ Cambridge CB3 0RN +
+ UK +

+

+ Tel: +44 (1223) 566926 +
+ Fax: +44 (1223) 506288 +
+ Email: + drtr@etrade.co.uk +

+ + + diff --git a/busybox-1_37_0/docs/embedded-scripts.txt b/busybox-1_37_0/docs/embedded-scripts.txt new file mode 100644 index 000000000..f6f107d4e --- /dev/null +++ b/busybox-1_37_0/docs/embedded-scripts.txt @@ -0,0 +1,111 @@ +Embedded Shell Scripts in BusyBox +================================= + +BusyBox allows applets to be implemented as shell scripts. Since +this obviously requires a shell to interpret the scripts the feature +depends on having a shell built into the binary. Either ash or hush +will do. If both are present ash will be used. Support for embedded +scripts also has to be enabled. + +It's unlikely that your applet will be implemented as a pure shell +script: it will probably need some external commands. If these are +to be provided by BusyBox you'll need to ensure they're enabled too. + +There are two ways to include scripts in BusyBox: the quick-and-dirty +custom script and the full-featured scripted applet. + +Custom Scripts +-------------- + +When embedded script support is enabled the BusyBox build process +assumes that any files in the directory 'embed' at the top level of +the source tree are scripts to be embedded. + +The embed directory isn't present in the BusyBox source tree and +BusyBox itself will never put anything there: it's entirely for the +use of third parties. + +Adding a custom script is as simple as running the following sequence +of commands in the BusyBox source directory: + + mkdir embed + echo 'echo foo' >embed/foo + make defconfig + make + +The resulting binary includes the new applet foo! + +Custom scripts have limited opportunities for configuration: the only +control developers have is to put them in the embed directory, or not. +Everything else takes default values. For more control you need the +additional features provided by scripted applets. + +Scripted Applets +---------------- + +Suppose we want to make a shell script version of the sample applet +from the New Applet HOWTO. First we'd have to write a script (vaguely) +equivalent to the C code: + + return $(($RANDOM%256)) + +This should be placed in the file applets_sh/mu in the source tree. + +Next we need the configuration data. This is very similar to the example +code for the native applet: + +//config:config MU +//config: bool "MU" +//config: default y +//config: help +//config: Returns an indeterminate value. + +//applet:IF_MU(APPLET_SCRIPTED(mu, scripted, BB_DIR_USR_BIN, BB_SUID_DROP, mu)) + +//usage:#define mu_trivial_usage +//usage: "[-abcde] FILE..." +//usage:#define mu_full_usage +//usage: "Returns an indeterminate value\n" +//usage: "\n -a First function" +//usage: "\n -b Second function" + +The only difference is that the applet is specified as being of type +APPLET_SCRIPTED. It would also be useful to include details of any +dependencies the script has. No external commands are used by our mu +script, but it does depend on optional shell features. We can ensure +these are selected by adding this to the configuration: + +//config:config MU_DEPENDENCIES +//config: bool "Enable dependencies for mu" +//config: default y +//config: depends on MU +//config: select ASH_RANDOM_SUPPORT +//config: select FEATURE_SH_MATH +//config: help +//config: mu is implemented as a shell script. It requires support +//config: for $RANDOM and arithmetic. + +The configuration data should be placed in a C file in an appropriate +subdirectory. There isn't any C code, though! In this case the file +could be miscutils/mu.c. + +Scripted applets are just as configurable as applets written in C. +They can be enabled or disabled using the configuration menu; their +install directory can be specified and their usage messages are stored +along with those of all other applets. + +Additional Notes +---------------- + +The source for embedded scripts can be displayed by running: + + busybox --show SCRIPT + +This can be disabled by turning off FEATURE_SHOW_SCRIPT in the +configuration, though it won't prevent a determined user from +extracting the source code. + +It can be argued that embedded scripts are linked into the BusyBox +binary and are therefore not subject to the 'mere aggregation' +exception in the GPL. If this is the case embedded scripts should +have a licence compatible with BusyBox's GPL v2-only licence. diff --git a/busybox-1_37_0/docs/ifupdown_design.txt b/busybox-1_37_0/docs/ifupdown_design.txt new file mode 100644 index 000000000..39e28a9f4 --- /dev/null +++ b/busybox-1_37_0/docs/ifupdown_design.txt @@ -0,0 +1,44 @@ +This document is meant to convince you to not use ifup/ifdown. + + +The general problem with ifupdown is that it is "copulated in vertical +fashion" by design. It tries to do the job of shell script in C, +and this is invariably doomed to fail. You need ifup/ifdown +to be adaptable by local admins, and C is an extremely poor choice +for that. + +We are doomed to have problems with ifup/ifdown. Just look as this code: + +static const struct dhcp_client_t ext_dhcp_clients[] = { + { "dhcpcd", "", "" }, + { "dhclient", ........ }, + { "pump", ........ }, + { "udhcpc", ........ }, +}; + +static int dhcp_down(struct interface_defn_t *ifd, execfn *exec) +{ +#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP + int i ; + for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { + if (executable_exists(ext_dhcp_clients[i].name)) + return execute(ext_dhcp_clients[i].stopcmd, ifd, exec); + } + bb_error_msg("no dhcp clients found, using static interface shutdown"); + return static_down(ifd, exec); +#elif ENABLE_UDHCPC + return execute("kill " + "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); +#else + return 0; /* no dhcp support */ +#endif +} + +How the hell it is supposed to work reliably this way? Just imagine that +admin is using pump and ifup/ifdown. It works. Then, for whatever reason, +admin installs dhclient, but does NOT use it. ifdown will STOP WORKING, +just because it will see installed dhclient binary in e.g. /usr/bin/dhclient! +This is stupid. + +I seriously urge people to not use ifup/ifdown. +Use something less brain damaged. diff --git a/busybox-1_37_0/docs/keep_data_small.txt b/busybox-1_37_0/docs/keep_data_small.txt new file mode 100644 index 000000000..218d4f2ee --- /dev/null +++ b/busybox-1_37_0/docs/keep_data_small.txt @@ -0,0 +1,265 @@ + Keeping data small + +When many applets are compiled into busybox, all rw data and +bss for each applet are concatenated. Including those from libc, +if static busybox is built. When busybox is started, _all_ this data +is allocated, not just that one part for selected applet. + +What "allocated" exactly means, depends on arch. +On NOMMU it's probably bites the most, actually using real +RAM for rwdata and bss. On i386, bss is lazily allocated +by COWed zero pages. Not sure about rwdata - also COW? + +In order to keep busybox NOMMU and small-mem systems friendly +we should avoid large global data in our applets, and should +minimize usage of libc functions which implicitly use +such structures. + +Small experiment to measure "parasitic" bbox memory consumption: +here we start 1000 "busybox sleep 10" in parallel. +busybox binary is practically allyesconfig static one, +built against uclibc. Run on x86-64 machine with 64-bit kernel: + +bash-3.2# nmeter '%t %c %m %p %[pn]' +23:17:28 .......... 168M 0 147 +23:17:29 .......... 168M 0 147 +23:17:30 U......... 168M 1 147 +23:17:31 SU........ 181M 244 391 +23:17:32 SSSSUUU... 223M 757 1147 +23:17:33 UUU....... 223M 0 1147 +23:17:34 U......... 223M 1 1147 +23:17:35 .......... 223M 0 1147 +23:17:36 .......... 223M 0 1147 +23:17:37 S......... 223M 0 1147 +23:17:38 .......... 223M 1 1147 +23:17:39 .......... 223M 0 1147 +23:17:40 .......... 223M 0 1147 +23:17:41 .......... 210M 0 906 +23:17:42 .......... 168M 1 147 +23:17:43 .......... 168M 0 147 + +This requires 55M of memory. Thus 1 trivial busybox applet +takes 55k of memory on 64-bit x86 kernel. + +On 32-bit kernel we need ~26k per applet. + +Script: + +i=1000; while test $i != 0; do + echo -n . + busybox sleep 30 & + i=$((i - 1)) +done +echo +wait + +(Data from NOMMU arches are sought. Provide 'size busybox' output too) + + + Example 1 + +One example how to reduce global data usage is in +archival/libarchive/decompress_gunzip.c: + +/* This is somewhat complex-looking arrangement, but it allows + * to place decompressor state either in bss or in + * malloc'ed space simply by changing #defines below. + * Sizes on i386: + * text data bss dec hex + * 5256 0 108 5364 14f4 - bss + * 4915 0 0 4915 1333 - malloc + */ +#define STATE_IN_BSS 0 +#define STATE_IN_MALLOC 1 + +(see the rest of the file to get the idea) + +This example completely eliminates globals in that module. +Required memory is allocated in unpack_gz_stream() [its main module] +and then passed down to all subroutines which need to access 'globals' +as a parameter. + + + Example 2 + +In case you don't want to pass this additional parameter everywhere, +take a look at archival/gzip.c. Here all global data is replaced by +single global pointer (ptr_to_globals) to allocated storage. + +In order to not duplicate ptr_to_globals in every applet, you can +reuse single common one. It is defined in libbb/ptr_to_globals.c +as struct globals *const ptr_to_globals, but the struct globals is +NOT defined in libbb.h. You first define your own struct: + +struct globals { int a; char buf[1000]; }; + +and then declare that ptr_to_globals is a pointer to it: + +#define G (*ptr_to_globals) + +ptr_to_globals is declared as constant pointer. +This helps gcc understand that it won't change, resulting in noticeably +smaller code. In order to assign it, use SET_PTR_TO_GLOBALS macro: + + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); + +Typically it is done in _main(). Another variation is +to use stack: + +int _main(...) +{ +#undef G + struct globals G; + memset(&G, 0, sizeof(G)); + SET_PTR_TO_GLOBALS(&G); + +Now you can reference "globals" by G.a, G.buf and so on, in any function. + + + bb_common_bufsiz1 + +There is one big common buffer in bss - bb_common_bufsiz1. It is a much +earlier mechanism to reduce bss usage. Each applet can use it for +its needs. Library functions are prohibited from using it. + +'G.' trick can be done using bb_common_bufsiz1 instead of malloced buffer: + +#define G (*(struct globals*)&bb_common_bufsiz1) + +Be careful, though, and use it only if globals fit into bb_common_bufsiz1. +Since bb_common_bufsiz1 is BUFSIZ + 1 bytes long and BUFSIZ can change +from one libc to another, you have to add compile-time check for it: + +if (sizeof(struct globals) > sizeof(bb_common_bufsiz1)) + BUG__globals_too_big(); + + + Drawbacks + +You have to initialize it by hand. xzalloc() can be helpful in clearing +allocated storage to 0, but anything more must be done by hand. + +All global variables are prefixed by 'G.' now. If this makes code +less readable, use #defines: + +#define dev_fd (G.dev_fd) +#define sector (G.sector) + + + Finding non-shared duplicated strings + +strings busybox | sort | uniq -c | sort -nr + + + gcc's data alignment problem + +The following attribute added in vi.c: + +static int tabstop; +static struct termios term_orig __attribute__ ((aligned (4))); +static struct termios term_vi __attribute__ ((aligned (4))); + +reduces bss size by 32 bytes, because gcc sometimes aligns structures to +ridiculously large values. asm output diff for above example: + + tabstop: + .zero 4 + .section .bss.term_orig,"aw",@nobits +- .align 32 ++ .align 4 + .type term_orig, @object + .size term_orig, 60 + term_orig: + .zero 60 + .section .bss.term_vi,"aw",@nobits +- .align 32 ++ .align 4 + .type term_vi, @object + .size term_vi, 60 + +gcc doesn't seem to have options for altering this behaviour. + +gcc 3.4.3 and 4.1.1 tested: +char c = 1; +// gcc aligns to 32 bytes if sizeof(struct) >= 32 +struct { + int a,b,c,d; + int i1,i2,i3; +} s28 = { 1 }; // struct will be aligned to 4 bytes +struct { + int a,b,c,d; + int i1,i2,i3,i4; +} s32 = { 1 }; // struct will be aligned to 32 bytes +// same for arrays +char vc31[31] = { 1 }; // unaligned +char vc32[32] = { 1 }; // aligned to 32 bytes + +-fpack-struct=1 reduces alignment of s28 to 1 (but probably +will break layout of many libc structs) but s32 and vc32 +are still aligned to 32 bytes. + +I will try to cook up a patch to add a gcc option for disabling it. +Meanwhile, this is where it can be disabled in gcc source: + +gcc/config/i386/i386.c +int +ix86_data_alignment (tree type, int align) +{ +#if 0 + if (AGGREGATE_TYPE_P (type) + && TYPE_SIZE (type) + && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST + && (TREE_INT_CST_LOW (TYPE_SIZE (type)) >= 256 + || TREE_INT_CST_HIGH (TYPE_SIZE (type))) && align < 256) + return 256; +#endif + +Result (non-static busybox built against glibc): + +# size /usr/srcdevel/bbox/fix/busybox.t0/busybox busybox + text data bss dec hex filename + 634416 2736 23856 661008 a1610 busybox + 632580 2672 22944 658196 a0b14 busybox_noalign + + + + Keeping code small + +Use scripts/bloat-o-meter to check whether introduced changes +didn't generate unnecessary bloat. This script needs unstripped binaries +to generate a detailed report. To automate this, just use +"make bloatcheck". It requires busybox_old binary to be present, +use "make baseline" to generate it from unmodified source, or +copy busybox_unstripped to busybox_old before modifying sources +and rebuilding. + +Set CONFIG_EXTRA_CFLAGS="-fno-inline-functions-called-once", +produce "make bloatcheck", see the biggest auto-inlined functions. +Now, set CONFIG_EXTRA_CFLAGS back to "", but add NOINLINE +to some of these functions. In 1.16.x timeframe, the results were +(annotated "make bloatcheck" output): + +function old new delta +expand_vars_to_list - 1712 +1712 win +lzo1x_optimize - 1429 +1429 win +arith_apply - 1326 +1326 win +read_interfaces - 1163 +1163 loss, leave w/o NOINLINE +logdir_open - 1148 +1148 win +check_deps - 1148 +1148 loss +rewrite - 1039 +1039 win +run_pipe 358 1396 +1038 win +write_status_file - 1029 +1029 almost the same, leave w/o NOINLINE +dump_identity - 987 +987 win +mainQSort3 - 921 +921 win +parse_one_line - 916 +916 loss +summarize - 897 +897 almost the same +do_shm - 884 +884 win +cpio_o - 863 +863 win +subCommand - 841 +841 loss +receive - 834 +834 loss + +855 bytes saved in total. + +scripts/mkdiff_obj_bloat may be useful to automate this process: run +"scripts/mkdiff_obj_bloat NORMALLY_BUILT_TREE FORCED_NOINLINE_TREE" +and select modules which shrank. diff --git a/busybox-1_37_0/docs/logging_and_backgrounding.txt b/busybox-1_37_0/docs/logging_and_backgrounding.txt new file mode 100644 index 000000000..c76cd3653 --- /dev/null +++ b/busybox-1_37_0/docs/logging_and_backgrounding.txt @@ -0,0 +1,98 @@ + Logging and backgrounding + +By default, bb_[p]error_msg[_and_die] messages go to stderr, +and of course, usually applets do not auto-background. :) + +Historically, daemons and inetd services are different. + +Busybox is trying to provide compatible behavior, thus if an applet +is emulating an existing utility, it should mimic it. If utility +auto-backgrounds itself, busybox applet should do the same. +If utility normally logs to syslog, busybox applet should do +the same too. + +However, busybox should not needlessly restrict the freedom +of the users. And users have different needs and different preferences. +Some might like logging everything from daemons to syslog. +Others prefer running stuff under runsv/svlogd and thus would like +logging to stderr and no daemonization. + +To help with that, busybox applets should have options to override +default behavior, whatever that is for a given applet. + + +Current situation is a bit of a mess: + +acpid - auto-backgrounds unless -d +crond - auto-backgrounds unless -f, logs to syslog unless -d or -L. + option -d logs to stderr, -L FILE logs to FILE +devfsd - (obsolete) +dnsd - option -d makes it background and log to syslog +fakeidentd - inetd service. Auto-backgrounds and logs to syslog + if no -f and no -i and no -w (-i is "inetd service" flag, + -w is "inetd-wait service" flag) +ftpd - inetd service. Logs to syslog with -S, with -v logs to strerr too +httpd - auto-backgrounds unless -f or -i (-i is "inetd service" flag) +inetd - auto-backgrounds unless -f, logs to syslog unless -e +klogd - auto-backgrounds unless -n +syslogd - auto-backgrounds unless -n +telnetd - auto-backgrounds unless -f or -i (-i is "inetd service" flag) +udhcpc - auto-backgrounds unless -f after lease is obtained, + option -b makes it background sooner (when lease attempt + fails and retries start), + after backgrounding it stops logging to stderr; + logs to stderr, but option -S makes it log *also* to syslog +udhcpd - auto-backgrounds and do not log to stderr unless -f, + otherwise logs to stderr, but option -S makes it log *also* to syslog +zcip - auto-backgrounds and logs *also* to syslog unless -f + behaviour can be overridden with experimental LOGGING env.var + (can be set to either "none" or "syslog") + +Total: 13 applets (+1 obsolete), + 4 log to syslog by default (crond fakeidentd inetd zcip), + 5 never log to syslog (acpid httpd telnetd klogd syslogd, last two + - for obviously correct reasons), + there are no daemons which always log to syslog, + 12 auto-background if not run as inetd services (all except dnsd. + Note that there is no "standard" dnsd AFAIKS). But see below + for daemons (tcpsvd etc) which don't auto-background. + +miscutils/crond.c: logmode = LOGMODE_SYSLOG; +networking/dnsd.c: logmode = LOGMODE_SYSLOG; +networking/ftpd.c: logmode = LOGMODE_NONE; +networking/ftpd.c: logmode |= LOGMODE_SYSLOG; +networking/inetd.c: logmode = LOGMODE_SYSLOG; +networking/isrv_identd.c: logmode = LOGMODE_SYSLOG; +networking/telnetd.c: logmode = LOGMODE_SYSLOG; +networking/udhcp/dhcpc.c: logmode = LOGMODE_NONE; +networking/udhcp/dhcpc.c: logmode |= LOGMODE_SYSLOG; +networking/udhcp/dhcpc.c: logmode &= ~LOGMODE_STDIO; +networking/udhcp/dhcpd.c: logmode = LOGMODE_NONE; +networking/udhcp/dhcpd.c: logmode |= LOGMODE_SYSLOG; +networking/zcip.c: logmode |= LOGMODE_SYSLOG; + + +These daemons never auto-background and never log to syslog: + +lpd - inetd service. Has nothing to log so far, though +dhcprelay - standard behavior +inotifyd - standard behavior +runsv - standard behavior +runsvdir - standard behavior +svlogd - standard behavior +tcpsvd, udpsvd - standard behavior +tftpd - standard behavior + + +Non-daemons (seems to be use syslog for a good reason): + +networking/nameif.c: logmode |= LOGMODE_SYSLOG; +loginutils/chpasswd.c: logmode = LOGMODE_BOTH; +loginutils/chpasswd.c: logmode = LOGMODE_STDIO; +loginutils/getty.c: logmode = LOGMODE_BOTH; +loginutils/getty.c: logmode = LOGMODE_NONE; +loginutils/passwd.c: logmode = LOGMODE_STDIO; +loginutils/passwd.c: logmode = LOGMODE_BOTH; +loginutils/sulogin.c: logmode = LOGMODE_SYSLOG; (used if stdio isn't a tty) +loginutils/sulogin.c: logmode = LOGMODE_BOTH; +util-linux/mount.c: logmode = LOGMODE_SYSLOG; (used in a backgrounded NFS mount helper) diff --git a/busybox-1_37_0/docs/mdev.txt b/busybox-1_37_0/docs/mdev.txt new file mode 100644 index 000000000..b13a0bb93 --- /dev/null +++ b/busybox-1_37_0/docs/mdev.txt @@ -0,0 +1,151 @@ +------------- + MDEV Primer +------------- + +For those of us who know how to use mdev, a primer might seem lame. For +everyone else, mdev is a weird black box that they hear is awesome, but can't +seem to get their head around how it works. Thus, a primer. + +----------- + Basic Use +----------- + +Mdev has two primary uses: initial population and dynamic updates. Both +require sysfs support in the kernel and have it mounted at /sys. For dynamic +updates, you also need to have hotplugging enabled in your kernel. + +Here's a typical code snippet from the init script: +[0] mount -t proc proc /proc +[1] mount -t sysfs sysfs /sys +[2] echo /sbin/mdev > /proc/sys/kernel/hotplug +[3] mdev -s + +Alternatively, without procfs the above becomes: +[1] mount -t sysfs sysfs /sys +[2] sysctl -w kernel.hotplug=/sbin/mdev +[3] mdev -s + + +Of course, a more "full" setup would entail executing this before the previous +code snippet: +[4] mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev +[5] mkdir /dev/pts +[6] mount -t devpts devpts /dev/pts + +The simple explanation here is that [1] you need to have /sys mounted before +executing mdev. Then you [2] instruct the kernel to execute /sbin/mdev whenever +a device is added or removed so that the device node can be created or +destroyed. Then you [3] seed /dev with all the device nodes that were created +while the system was booting. + +For the "full" setup, you want to [4] make sure /dev is a tmpfs filesystem +(assuming you're running out of flash). Then you want to [5] create the +/dev/pts mount point and finally [6] mount the devpts filesystem on it. + +------------- + MDEV Config (/etc/mdev.conf) +------------- + +Mdev has an optional config file for controlling ownership/permissions of +device nodes if your system needs something more than the default root/root +660 permissions. + +The file has the format: + [-][envmatch] : +or + [envmatch]@ : +or + $envvar= : + +For example: + hd[a-z][0-9]* 0:3 660 + +The config file parsing stops at the first matching line unless this line +starts with "-". If no line is matched, then the default of 0:0 660 is used. +To set your own default, simply create your own total match like so: + + .* 1:1 777 + +You can rename/move device nodes by using the next optional field. + + : [=path] + +So if you want to place the device node into a subdirectory, make sure the path +has a trailing /. If you want to rename the device node, just place the name. + hda 0:3 660 =drives/ +This will move "hda" into the drives/ subdirectory. + hdb 0:3 660 =cdrom +This will rename "hdb" to "cdrom". + +Similarly, ">path" renames/moves the device but it also creates +a direct symlink /dev/DEVNAME to the renamed/moved device. + +You can also prevent creation of device nodes with the 4th field as "!": + tty[a-z]. 0:0 660 ! + pty[a-z]. 0:0 660 ! + +If you also enable support for executing your own commands, then the file has +the format: + : [=path] [@|$|*] + or + : [>path] [@|$|*] + or + : [!] [@|$|*] + +For example: +---8<--- +# block devices +([hs]d[a-z]) root:disk 660 >disk/%1/0 +([hs]d[a-z])([0-9]+) root:disk 660 >disk/%1/%2 +mmcblk([0-9]+) root:disk 660 >disk/mmc/%1/0 +mmcblk([0-9]+)p([0-9]+) root:disk 660 >disk/mmc/%1/%2 +# network devices +(tun|tap) root:network 660 >net/%1 +---8<--- + +The special characters have the meaning: + @ Run after creating the device. + $ Run before removing the device. + * Run both after creating and before removing the device. + +The command is executed via the system() function (which means you're giving a +command to the shell), so make sure you have a shell installed at /bin/sh. You +should also keep in mind that the kernel executes hotplug helpers with stdin, +stdout, and stderr connected to /dev/null. + +For your convenience, the shell env var $MDEV is set to the device name. So if +the device "hdc" was matched, MDEV would be set to "hdc". + +---------- + FIRMWARE +---------- + +Some kernel device drivers need to request firmware at runtime in order to +properly initialize a device. Place all such firmware files into the +/lib/firmware/ directory. At runtime, the kernel will invoke mdev with the +filename of the firmware which mdev will load out of /lib/firmware/ and into +the kernel via the sysfs interface. The exact filename is hardcoded in the +kernel, so look there if you need to know how to name the file in userspace. + +------------ + SEQUENCING +------------ + +Kernel does not serialize hotplug events. It increments SEQNUM environmental +variable for each successive hotplug invocation. Normally, mdev doesn't care. +This may reorder hotplug and hot-unplug events, with typical symptoms of +device nodes sometimes not created as expected. + +However, if /dev/mdev.seq file is found, mdev will compare its +contents with SEQNUM. It will retry up to two seconds, waiting for them +to match. If they match exactly (not even trailing '\n' is allowed), +or if two seconds pass, mdev runs as usual, then it rewrites /dev/mdev.seq +with SEQNUM+1. + +IOW: this will serialize concurrent mdev invocations. + +If you want to activate this feature, execute "echo >/dev/mdev.seq" prior to +setting mdev to be the hotplug handler. This writes single '\n' to the file. +NB: mdev recognizes /dev/mdev.seq consisting of single '\n' character +as a special case. IOW: this will not make your first hotplug event +to stall for two seconds. diff --git a/busybox-1_37_0/docs/new-applet-HOWTO.txt b/busybox-1_37_0/docs/new-applet-HOWTO.txt new file mode 100644 index 000000000..619d47fb8 --- /dev/null +++ b/busybox-1_37_0/docs/new-applet-HOWTO.txt @@ -0,0 +1,207 @@ +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 +Thomas Lundquist - trying to keep it updated + +When doing this you should consider using the latest git HEAD. +This is a good thing if you plan to getting it committed into mainline. + +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 and Config.in/Kbuild/usage/applet.h snippets (more on that below +in this document). Be sure to name the main function _main instead +of main. And be sure to put it in .c. Make sure to #include "libbb.h" +as the first include file in your applet. + +For a new applet mu, here is the code that would go in mu.c: + +(libbb.h already includes most usual header files. You do not need +#include etc...) + + +----begin example code------ + +/* vi: set sw=4 ts=4: */ +/* + * Mini mu implementation for busybox + * + * Copyright (C) [YEAR] by [YOUR NAME] + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "other.h" + +//config:config MU +//config: bool "MU" +//config: default y +//config: help +//config: Returns an indeterminate value. + +//kbuild:lib-$(CONFIG_MU) += mu.o +//applet:IF_MU(APPLET(mu, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//usage:#define mu_trivial_usage +//usage: "[-abcde] FILE..." +//usage:#define mu_full_usage +//usage: "Returns an indeterminate value\n" +//usage: "\n -a First function" +//usage: "\n -b Second function" + +int mu_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mu_main(int argc, char **argv) +{ + int fd; + ssize_t n; + char mu; + + fd = xopen("/dev/random", O_RDONLY); + + if ((n = safe_read(fd, &mu, 1)) < 1) + bb_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 +applet that could be useful in other applets, consider putting them in libbb. + +And it may be possible that some of the other applets uses functions you +could use. If so, you have to rip the function out of the applet and make +a libbb function out of it. + +Adding a libbb function: +------------------------ + +Make a new file named .c + +----start example code------ + +#include "libbb.h" +#include "other.h" + +//kbuild:lib-y += function.o + +int function(char *a) +{ + return *a; +} + +----end example code------ + +Remember about the kbuild snippet. + +You should also try to find a suitable place in include/libbb.h for +the function declaration. If not, add it somewhere anyway, with or without +ifdefs to include or not. + +You can look at libbb/Config.src and try to find out if the function is +tunable and add it there if it is. + + +Kbuild/Config.in/usage/applets.h snippets in .c files +----------------------------------------------------- + +The old way of adding new applets was to put all the information needed by the +configuration and build system into appropriate files (namely: Kbuild.src and +Config.src in new applet's directory) and to add the applet declaration and +usage info text to include/applets.src.h and include/usage.src.h respectively. + +Since the scripts/gen_build_files.sh script had been introduced, the preferred +way is to have all these declarations contained within the applet .c files. + +Every line intended to be processed by gen_build_files.sh should start as a +comment without any preceding whitespaces and be followed by an appropriate +keyword - kbuild, config, usage or applet - and a colon, just like shown in the +first example above. + + +Placement / Directory +--------------------- + +Find the appropriate directory for your new applet. + +Add the config snippet to the .c file: + +//config:config MU +//config: bool "MU" +//config: default y +//config: help +//config: Returns an indeterminate value. + +Add the kbuild snippet to the .c file: + +//kbuild:lib-$(CONFIG_MU) += mu.o + + +Usage String(s) +--------------- + +Next, add usage information for your applet to the .c file. +This should look like the following: + +//usage:#define mu_trivial_usage +//usage: "[-abcde] FILE..." +//usage:#define mu_full_usage "\n\n" +//usage: "Returns an indeterminate value" +//usage: "\n" +//usage: "\n -a First function" +//usage: "\n -b Second function" +//usage: ... + +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. + + +Header Files +------------ + +Finally add the applet declaration snippet. Be sure to read the top of +applets.src.h before adding your applet - it contains important info +on applet macros and conventions. + +//applet:IF_MU(APPLET(mu, BB_DIR_USR_BIN, BB_SUID_DROP)) + + +The Grand Announcement +---------------------- + +Then create a diff by adding the new files to git (remember your libbb files) + git add /mu.c +eventually also: + git add libbb/function.c +then + git commit + git format-patch HEAD^ +and send it to the mailing list: + busybox@busybox.net + http://busybox.net/mailman/listinfo/busybox + +Sending patches as attachments is preferred, but not required. diff --git a/busybox-1_37_0/docs/nofork_noexec.txt b/busybox-1_37_0/docs/nofork_noexec.txt new file mode 100644 index 000000000..9d210a1c9 --- /dev/null +++ b/busybox-1_37_0/docs/nofork_noexec.txt @@ -0,0 +1,143 @@ + NOEXEC and NOFORK applets. + +Unix shells traditionally execute some commands internally in the attempt +to dramatically speed up execution. It will be slow as hell if for every +"echo blah" shell will fork and exec /bin/echo. To this end, shells +have to _reimplement_ these commands internally. + +Busybox is unique in this regard because it already is a collection +of reimplemented Unix commands, and we can do the same trick +for speeding up busybox shells, and more. NOEXEC and NOFORK applets +are exactly those applets which are eligible for these tricks. + +Applet will be subject to NOFORK/NOEXEC tricks only if it is marked +as such in applets.src.h or in their inline "//applet:" directives. + +In C, if you want to call a program and wait for it, use +spawn_and_wait(argv), BB_EXECVP(prog,argv) or BB_EXECLP(prog,argv0,...). +They check whether program name is an applet name and optionally +do NOFORK/NOEXEC thing depending on configuration. + + + Relevant CONFIG options + +FEATURE_PREFER_APPLETS + Globally enables NOFORK/NOEXEC tricks for such programs as xargs + and find: + BB_EXECVP(cmd, argv) will try to exec /proc/self/exe + if command's name matches some applet name; + spawn_and_wait(argv) will do NOFORK/NOEXEC tricks + +//TODO: the above two things probably should have separate options? + +FEATURE_SH_STANDALONE + shells will try to exec /proc/self/exe if command's name matches + some applet name; shells will do NOEXEC trick on NOEXEC applets + +//TODO: split (same as for PREFER_APPLETS) + +FEATURE_SH_NOFORK + shells will do NOFORK trick on NOFORK applets + +NB: shell builtins use these tricks regardless of FEATURE_SH_STANDALONE, +FEATURE_PREFER_APPLETS or FEATURE_SH_NOFORK. In effect, builtins +are "always NOFORK". + + + NOEXEC + +NOEXEC applet should work correctly if another applet forks and then +executes exit(_main(argc,argv)) in the child. The rules +roughly are: + +* do not expect shared global variables/buffers to be in their + "initialized" state. Examples: xfunc_error_retval can be != 1, + bb_common_bufsiz1 can be scribbled over, ... + (although usually xfunc_error_retval's state is not a problem). +* do not expect that stdio wasn't used before. Calling set[v]buf() + can be disastrous. +* ... + +NOEXEC applets save only one half of fork+exec overhead. +NOEXEC trick is disabled for NOMMU build. + + + NOFORK + +NOFORK applet should work correctly if another applet simply runs +_main(argc,argv) and then continues with its business. +xargs, find, shells do it (grep for "spawn_and_wait" and +"run_nofork_applet" to find more users). + +This poses much more serious limitations on what applet can do: + +* all NOEXEC limitations apply. +* do not run for a long time or wait for user input: + hush shell only handles signals (like ^C) after you return + from APPLET_main(). +* do not ever exit() or exec(). + - xfuncs are okay. They are using special trick to return + to the caller applet instead of dying when they detect "x" condition. + - you may "exit" to caller applet by calling xfunc_die(). Return value + is taken from xfunc_error_retval. + - fflush_stdout_and_exit(n) is ok to use. +* do not use shared global data, or save/restore shared global data + (e.g. bb_common_bufsiz1) prior to returning. + - getopt32() is ok to use. You do not need to save/restore option_mask32, + xfunc_error_retval, and logmode - it is already done by core code. +* if you allocate memory, you can use xmalloc() only on the very first + allocation. All other allocations should use malloc[_or_warn](). + After first allocation, you cannot use any xfuncs. + Otherwise, failing xfunc will return to caller applet + without freeing malloced data! +* the same applies to other resources, such as open fds: no xfuncs after + acquiring them! +* All allocated data, opened files, signal handlers, termios settings + etc should be freed/closed/restored prior to return. + +Currently, ash shell signal handling is implemented in a way that signals +have non-SA_RESTARTed handlers. This means that system calls can +return EINTR. An example of such problem is "yes" applet: +it is implemented so that it has a writing loop, this loop is exited on +any write error, and in the case of user pressing ^C the error was EINTR. +The problem is, the error causes stdout FILE* object to get into error +state, needing clearerr() - or else subsequent shell output will also +not work. ("yes" has been downgraded to NOEXEC, since hush signal handling +does not have this problem - which makes "yes" to not exit on ^C (bug). +But stray EINTRs can be seen in any NOFORK under ash, until ash is fixed). + +NOFORK applets give the most of speed advantage, but are trickiest +to implement. In order to minimize amount of bugs and maintenance, +prime candidates for NOFORK-ification are those applets which +are small and easy to audit, and those which are more likely to be +frequently executed from shell/find/xargs, particularly in shell +script loops. Applets which mess with signal handlers, termios etc +are probably not worth the effort. + +Applets which must be interruptible by ^C in shells can not be NOFORKs. + +Any NOFORK applet is also a NOEXEC applet. + + + Calling NOFORK applets + +API to call NOFORK applets is two functions: + + run_nofork_applet(appno, argv) + spawn_and_wait(argv) // only if FEATURE_PREFER_APPLETS=y + +First one is directly used by shells if FEATURE_SH_NOFORK=y. +Second one is used by many applets, but main users are xargs and find. +It itself calls run_nofork_applet(), if argv[0] is a name +of a NOFORK applet. + +run_nofork_applet() saves/inits/restores option parsing, xfunc_error_retval, +logmode, applet_name. Thus, for example, caller does not need to worry about +option_mask32 getting trashed. + + + Calling NOEXEC applets + +It's the same trusty spawn_and_wait(argv). If FEATURE_PREFER_APPLETS=y, +it does NOEXEC trick. It resets xfunc_error_retval = 1 and +logmode = LOGMODE_STDIO in the child. diff --git a/busybox-1_37_0/docs/posix_conformance.txt b/busybox-1_37_0/docs/posix_conformance.txt new file mode 100644 index 000000000..8edbe3e15 --- /dev/null +++ b/busybox-1_37_0/docs/posix_conformance.txt @@ -0,0 +1,751 @@ + +Busybox POSIX conformance table + +See POSIX documentation (1003.1-2008) here: +http://www.opengroup.org/onlinepubs/9699919799/ +And the complete list of all utilities that POSIX covers: +http://www.opengroup.org/onlinepubs/9699919799/idx/utilities.html + +This listing is a work in progress, and currently only covers +tool options (not operands, environment variables, return codes, etc..). +For each option it is set if it (a) exists and (b) compliant to POSIX 2008. +Some options exist but there is no value in the 'compliant' column: that +means no one has yet bothered to make sure that the option does what it is +required to do. + +----------------------------------------------- + +POSIX Tools supported only as shell built-ins (ash shell): + alias, bg, cd, fg, getopts, hash, jobs, read, type, umask, ulimit, + unalias, wait, write + +POSIX Tools not supported: + asa, at, batch, bc, c99, command, compress, csplit, ex, fc, file, + gencat, getconf, iconv, join, link, locale, localedef, lp, m4, + mailx, newgrp, nl, pathchk, pax, pr, qalter, qdel, qhold, qmove, + qmsg, qrerun, qrls, qselect, qsig, qstat, qsub, tabs, talk, tput, + unlink, uucp, uustat, uux + +POSIX Tools not supported (DEVELOPMENT): + admin, cflow, ctags, cxref, delta, fort77, get, lex, make, nm, prs, rmdel, + sact, sccs, strip, unget, val, what, yacc + + +POSIX Tools supported: + +Note: echo, printf, kill, pwd documented here as stand-alone applets, + not as ash built-ins. + + +ar POSIX options ********************* Failed to recognize zip & tar (did not compare to regular ar) + option | exists | compliant | remarks + -C | no | no | + -T | no | no | + -a | no | no | + -b | no | no | + -c | no | no | + -d | no | no | + -i | no | no | + -m | no | no | + -p | yes | | + -q | no | no | + -r | no | no | + -s | no | no | + -t | yes | | + -u | no | no | + -v | yes | | + -x | yes | | +ar Busybox specific options: + -o + +awk POSIX options + option | exists | compliant | remarks + -F ERE | yes | | + -f progfile | yes | | + -v assignment | yes | | +awk Busybox specific options: None + +basename POSIX options: None +basename Busybox specific options: None + +cal POSIX options: None +cal Busybox specific options: + -y, -j + +cat POSIX options + option | exists | compliant | remarks + -u | yes | no | option is ignored +cat Busybox specific options: None + +chgrp POSIX options + option | exists | compliant | remarks + -H | yes | | + -L | yes | | + -P | yes | | + -R | yes | | + -h | yes | | +chgrp Busybox specific options: + -f, -c, -v + +chmod POSIX options + option | exists | compliant | remarks + -R | yes | yes | +chmod Busybox specific options: + -f, -v, -c + +chown POSIX options ********************************************* + option | exists | compliant | remarks + -H | yes | | It seems like all flags are supported (according to printout), but + -L | yes | | it fails to work on my machine + -P | yes | | + -R | yes | | + -h | yes | | +chown Busybox specific options: + -f, -c, -v + +cksum POSIX options: None +cksum Busybox specific options: None + +cmp POSIX options + option | exists | compliant | remarks + -l | yes | yes | + -s | yes | yes | +cmp Busybox specific options: + + +comm POSIX options + option | exists | compliant | remarks + -1 | yes | yes | + -2 | yes | yes | + -3 | yes | yes | +comm Busybox specific options: None + +cp POSIX options + option | exists | compliant | remarks + -H | yes | yes | + -L | yes | yes | + -P | yes | yes | + -R | yes | yes | + -f | yes | yes | + -i | yes | yes | + -p | yes | yes | +cp Busybox specific options: + -d, -a, -s, -c, -r, -l + +crontab POSIX options + option | exists | compliant | remarks + -e | yes | | + -l | yes | | + -r | yes | | +crontab Busybox specific options: + -u, -c + +cut POSIX options + option | exists | compliant | remarks + -b list | yes | yes | + -c list | yes | yes | + -d delim | yes | yes | + -f list | yes | yes | + -n | yes | yes | + -s | yes | yes | +cut Busybox specific options: None + +date POSIX options + option | exists | compliant | remarks + -u | yes | yes | +date Busybox specific options: + -I[SPEC], -d TIME, -r FILE, -R, -D FMT + +dd POSIX options: + option | exists | compliant | remarks + if | yes | | + of | yes | | + ibs | yes | | + obs | yes | | + bs | yes | | + cbs | no | no | + skip | yes | | + seek | yes | | + count | yes | | + conv=ascii | no | no | + conv=ebcdic | no | no | + conv=ibm | no | no | + conv=block | no | no | + conv=unblock | no | no | + conv=lcase | no | no | + conv=ucase | no | no | + conv=swap | no | no | + conv=noerror | yes | | + conv=notrunc | yes | | + conv=sync | yes | | +dd compatibility options: + conv=fsync | yes | | + iflag=skip_bytes| yes | | + iflag=fullblock | yes | | + oflag=seek_bytes| yes | | + oflag=append | yes | | + +df POSIX options + option | exists | compliant | remarks + -P | yes | yes | + -k | yes | yes | + -t | no | no | +df Busybox specific options: + -a, -m, -B SIZE, -i, -h +Remark: +- It seems that GNU df does not round percents up in its output (thus its results are a bit different) + +diff POSIX options + option | exists | compliant | remarks + -C n | no | no | + -U n | yes | | + -b | yes | | + -c | no | no | + -e | no | no | + -f | no | no | + -r | yes | | + -u | no | no | +diff Busybox specific options: + -d, -a, -s, -t, -L, -N, -i, -T, -w, -q, -S + +dirname POSIX options: None +dirname Busybox specific options: None + +du POSIX options + option | exists | compliant | remarks + -H | yes | | + -L | yes | | + -a | yes | | + -k | yes | | + -s | yes | | + -x | yes | | +du Busybox specific options: + -c, -m, -h, -d N, -l + + +echo POSIX options: None + option | exists | compliant | remarks + -n | yes | yes | The result of -n is "implementation-defined" +echo Busybox specific options: + -e, -E + +ed POSIX options + option | exists | compliant | remarks + -p string | no | no | + -s | no | no | +ed Busybox specific options: None + +env POSIX options + option | exists | compliant | remarks + -i | no | no | +env Busybox specific options: + -u, -, -i + +expand POSIX options + option | exists | compliant | remarks + -t tablist | yes | yes | +expand Busybox specific options: + --tabs=N, -i, --initial + +expr POSIX operations: + option | exists | compliant | remarks + | | yes | yes | + & | yes | yes | + = | yes | yes | + > | yes | yes | + >= | yes | yes | + <= | yes | yes | + < | yes | yes | + != | yes | yes | + + | yes | yes | + - | yes | yes | + * | yes | yes | + / | yes | yes | + % | yes | yes | + : | yes | yes | + (expr) | yes | yes | + integer | yes | yes | + string | yes | yes | +expr Busybox specific operations: + match, substr, index, length, quote + +false POSIX options: None +false Busybox specific options: None + +find POSIX options + option | exists | compliant | remarks + -H | no | no | + -L | no | no | +find Busybox specific options: + -group NAME, -mtime DAYS, -print, -maxdepth N, -exec CMD ARG ;, -newer FILE, -context, -iname PATTERN, -follow, -depth, -xdev, -inum N, -type X, -print0, -mindepth N, -mmin MINS, -regex PATTERN, -prune, -path PATTERN, -user NAME, -delete, -perm NNN, -name PATTERN, -size N[bck] + +fold POSIX options + option | exists | compliant | remarks + -b | yes | yes | + -s | yes | yes | + -w width | yes | yes | +fold Busybox specific options: None + +fuser POSIX options + option | exists | compliant | remarks + -c | no | no | + -f | no | no | + -u | no | no | +fuser Busybox specific options: + -m, -k, -4, -SIGNAL, -6, -s + +grep POSIX options + option | exists | compliant | remarks + -E | yes | | + -F | yes | | + -c | yes | | + -e pattern_list | yes | | + -f pattern_file | yes | | + -i | yes | | + -l | yes | | + -n | yes | | + -q | yes | | + -s | yes | | + -v | yes | | + -x | no | no | +grep Busybox specific options: + -A, -C, -B, -L, -H, -o, -h, -w, -r, -z, -m MAX + +head POSIX options + option | exists | compliant | remarks + -n number | yes | yes | +head Busybox specific options: + -v, -c NUM, -q + +id POSIX options + option | exists | compliant | remarks + -G | yes | yes | + -g | yes | yes | + -n | yes | yes | + -r | yes | yes | + -u | yes | yes | +id Busybox specific options: + -Z + +ipcrm POSIX options + option | exists | compliant | remarks + -M shmkey | no | no | + -Q msgkey | no | no | + -S semkey | no | no | + -m shmid | no | no | + -q msgid | no | no | + -s semid | no | no | +ipcrm Busybox specific options: + -mM, -qQ, -sS + +ipcs POSIX options + option | exists | compliant | remarks + -a | yes | | + -b | no | no | + -c | yes | | + -m | yes | | + -o | no | no | + -p | yes | | + -q | yes | | + -s | yes | | + -t | yes | | +ipcs Busybox specific options: + -l, -i, -u + +kill POSIX options + option | exists | compliant | remarks + -l | yes | yes | + -s signal_name | yes | yes | + -signal_name | yes | yes | + -signal_number | yes | yes | +kill Busybox specific options: + -q, -o + +ln POSIX options + option | exists | compliant | remarks + -L | no | no | + -P | no | no | + -f | yes | yes | + -s | yes | yes | +ln Busybox specific options: + -S suf, -n, -b + +logger POSIX options: None +logger Busybox specific options: + -p PRIO, -t TAG, -s + +logname POSIX options: None +logname Busybox specific options: None + +ls POSIX options + option | exists | compliant | remarks + -1 | yes | yes | + -A | yes | yes | + -C | yes | yes | + -F | yes | yes | And more: '=' for sockets (not defined by POSIX) + -H | no | no | + -L | yes | yes | But coloring may be wrong (at least POSIX does not require correct colors :) ) + -R | yes | yes | + -S | yes | yes | + -a | yes | yes | + -c | yes | no | Sorts output with '-l' (should only show ctime with '-l', and sort only with '-t') + -d | yes | no | When invoked together with '-L' should read symbolic links, and doesn't + -f | no | no | + -g | no | no | + -i | yes | yes | + -k | yes | no | Does something completely unrelated! (Lists security context instead of specifying block size) + -l | yes | yes | + -m | no | no | + -n | yes | no | Works correctly only together with '-l' (but POSIX requires '-l' to be implicitly assumed) + -o | no | no | + -p | yes | yes | + -q | no | no | + -r | yes | yes | + -s | yes | yes | + -t | yes | yes | + -u | yes | yes | + -x | yes | yes | +ls Busybox specific options: + --color, -T NUM, -K, -X, -Z, -e, -h, -v, -w NUM + +man POSIX options + option | exists | compliant | remarks + -k | no | no | +man Busybox specific options: + -a Display all pages + + +mesg POSIX options: None +mesg Busybox specific options: None + +mkdir POSIX options + option | exists | compliant | remarks + -m mode | yes | yes | + -p | yes | yes | +mkdir Busybox specific options: + -Z + +mkfifo POSIX options + option | exists | compliant | remarks + -m mode | yes | yes | +mkfifo Busybox specific options: + -Z + +more POSIX options + option | exists | compliant | remarks + -c | no | no | + -e | no | no | + -i | no | no | + -n number | no | no | + -p command | no | no | + -s | no | no | + -t tagstring | no | no | + -u | no | no | +more Busybox specific options: None + +mv POSIX options + option | exists | compliant | remarks + -f | yes | yes | + -i | yes | yes | +mv Busybox specific options: None + +nice POSIX options + option | exists | compliant | remarks + -n increment | yes | yes | +nice Busybox specific options: None + +nohup POSIX options: None +nohup Busybox specific options: None + +od POSIX options + option | exists | compliant | remarks + -A address_base | no | no | + -N count | no | no | + -b | no | no | + -c | no | no | + -d | no | no | + -j skip | no | no | + -o | no | no | + -s | no | no | + -t type_string | no | no | + -v | no | no | + -x | no | no | +od Busybox specific options: None + +paste POSIX options + option | exists | compliant | remarks + -d list | yes | yes | + -s | yes | yes | +paste Busybox specific options: None + +patch POSIX options + option | exists | compliant | remarks + -D define | no | no | + -N | no | no | + -R | yes | yes | + -b | no | no | + -c | no | no | + -d dir | no | no | + -e | no | no | + -i patchfile | yes | yes | + -l | no | no | + -n | no | no | + -o outfile | no | no | + -p num | yes | yes | + -r rejectfile | no | no | + -u | no | no | +patch Busybox specific options: None + +printf POSIX options: None +printf Busybox specific options: None + +ps POSIX options + option | exists | compliant | remarks + -A | no | no | + -G grouplist | no | no | + -U userlist | no | no | + -a | no | no | + -d | no | no | + -e | no | no | + -f | no | no | + -g grouplist | no | no | + -l | no | no | + -n namelist | no | no | + -o format | yes | no | not supported: ruser, group, rgroup, pcpu + -p proclist | no | no | + -t termlist | no | no | + -u userlist | no | no | +ps Busybox specific options: None + +pwd POSIX options + option | exists | compliant | remarks + -L | no | no | + -P | no | no | +pwd Busybox specific options: None + +renice POSIX options + option | exists | compliant | remarks + -g | yes | yes | + -n increment | yes | yes | Note POSIX allows only to run with this option (busybox also allows to run without '-n' and set niceness directly) + -p | yes | yes | + -u | yes | yes | +renice Busybox specific options: None + +rm POSIX options + option | exists | compliant | remarks + -R | yes | yes | + -f | yes | yes | + -i | yes | yes | + -r | yes | yes | +rm Busybox specific options: None + +rmdir POSIX options + option | exists | compliant | remarks + -p | yes | yes | +rmdir Busybox specific options: + --parents + +sed POSIX options + option | exists | compliant | remarks + -e script | yes | | + -f script_file | yes | | + -n | yes | | +sed Busybox specific options: + -i, -r + +sh POSIX options + option | exists | compliant | remarks + -c | no | no | + -i | no | no | + -s | no | no | +sh Busybox specific options: None + +sleep POSIX options: None +sleep Busybox specific options: None + +sort POSIX options + option | exists | compliant | remarks + -C | no | no | + -b | yes | yes | + -c | yes | yes | + -d | yes | yes | + -f | yes | yes | + -i | yes | yes | But is not like GNU sort, which isn't! (try to sort 'a\nA\nB\nb' with and without -f) + -k keydef | yes | | + -m | no | no | + -n | yes | yes | + -o output | yes | yes | + -r | yes | yes | + -t char | yes | | + -u | yes | yes | +sort Busybox specific options: + -mST, -g, -M, -s, -z + +split POSIX options + option | exists | compliant | remarks + -a suffix_length | yes | yes | + -b n | yes | yes | + -b nk | yes | yes | + -b nm | yes | yes | + -l line_count | yes | yes | +split Busybox specific options: None + +strings POSIX options + option | exists | compliant | remarks + -a | yes | yes | + -n number | yes | yes | + -t format | no | no | +strings Busybox specific options: + -o, -f + +stty POSIX options + option | exists | compliant | remarks + -a | yes | yes | + -g | yes | yes | +stty Busybox specific options: + -F DEVICE + +tail POSIX options + option | exists | compliant | remarks + -c number | yes | yes | + -f | yes | yes | + -n number | yes | yes | +tail Busybox specific options: + -v, -q, -s SEC + +tee POSIX options + option | exists | compliant | remarks + -a | yes | yes | + -i | yes | yes | +tee Busybox specific options: None + +test POSIX options: None +test Busybox specific options: None + +time POSIX options + option | exists | compliant | remarks + -p | no | no | +time Busybox specific options: + -v + +touch POSIX options + option | exists | compliant | remarks + -a | no | no | + -c | yes | yes | + -d date_time | no | no | + -m | no | no | + -r ref_file | no | no | + -t time | no | no | +touch Busybox specific options: None + +tr POSIX options + option | exists | compliant | remarks + -C | no | no | + -c | yes | yes | + -d | yes | yes | + -s | yes | yes | +tr Busybox specific options: None + +true POSIX options: None +true Busybox specific options: None + +tty POSIX options: None +tty Busybox specific options: + -s + +uname POSIX options + option | exists | compliant | remarks + -a | yes | yes | + -m | yes | yes | + -n | yes | yes | + -r | yes | yes | + -s | yes | yes | + -v | yes | yes | +uname Busybox specific options: + -p + +uncompress POSIX options + option | exists | compliant | remarks + -c | yes | yes | + -f | yes | yes | + -v | no | no | +uncompress Busybox specific options: None + +unexpand POSIX options + option | exists | compliant | remarks + -a | yes | no | POSIX requires converting two or more spaces to tabs, busybox converts one or more spaces + -t tablist | yes | yes | +unexpand Busybox specific options: + --tabs=N, -f, --first-only, --all + +uniq POSIX options + option | exists | compliant | remarks + -c | yes | yes | + -d | yes | yes | + -f fields | yes | yes | + -s chars | yes | yes | + -u | yes | yes | +uniq Busybox specific options: + -w N + +uudecode POSIX options + option | exists | compliant | remarks + -o outfile | yes | no | +uudecode Busybox specific options: None + +uuencode POSIX options + option | exists | compliant | remarks + -m | yes | yes | +uuencode Busybox specific options: None + +vi POSIX options + option | exists | compliant | remarks + -R | yes | | + -c command | yes | | + -r | no | no | + -t tagstring | no | no | + -w size | no | no | +vi Busybox specific options: + -H + +wc POSIX options + option | exists | compliant | remarks + -c | yes | yes | + -l | yes | yes | + -m | no | no | + -w | yes | yes | +wc Busybox specific options: + -L + +who POSIX options + option | exists | compliant | remarks + -H | no | no | + -T | no | no | + -a | yes | no | just shows all + -b | no | no | + -d | no | no | + -l | no | no | + -m | no | no | + -p | no | no | + -q | no | no | + -r | no | no | + -s | no | no | + -t | no | no | + -u | no | no | +who Busybox specific options: None + +xargs POSIX options + option | exists | compliant | remarks + -E eofstr | no | no | + -I replstr | no | no | + -L number | no | no | + -n number | yes | yes | + -p | yes | yes | + -s size | yes | yes | + -t | yes | yes | + -x | yes | yes | +xargs Busybox specific options: + -e[STR], -0, -r + +zcat POSIX options: None +zcat Busybox specific options: None diff --git a/busybox-1_37_0/docs/sigint.htm b/busybox-1_37_0/docs/sigint.htm new file mode 100644 index 000000000..d656aeb8c --- /dev/null +++ b/busybox-1_37_0/docs/sigint.htm @@ -0,0 +1,627 @@ + + + +Proper handling of SIGINT/SIGQUIT [http://www.cons.org/cracauer/sigint.html] + + +

Proper handling of SIGINT/SIGQUIT

+ +

+ + + + + +
Abstract: +In UNIX terminal sessions, you usually have a key like +C-c (Control-C) to immediately end whatever program you +have running in the foreground. This should work even when the program +you called has called other programs in turn. Everything should be +aborted, giving you your command prompt back, no matter how deep the +call stack is. + +

Basically, it's trivial. But the existence of interactive +applications that use SIGINT and/or SIGQUIT for other purposes than a +complete immediate abort make matters complicated, and - as was to +expect - left us with several ways to solve the problems. Of course, +existing shells and applications follow different ways. + +

This Web pages outlines different ways to solve the problem and +argues that only one of them can do everything right, although it +means that we have to fix some existing software. + + + +

Intended audience: Programmers who implement programs that catch SIGINT/SIGQUIT. +
Programmers who implements shells or shell-like programs that +execute batches of programs. + +

Users who have problems problems getting rid of runaway shell +scripts using Control-C. Or have interactive applications +that don't behave right when sending SIGINT. Examples are emacs'es +that die on Control-g or shellscript statements that sometimes are +executed and sometimes not, apparently not determined by the user's +intention. + + +

Required knowledge: You have to know what it means to catch SIGINT or SIGQUIT and how +processes are waiting for other processes (children) they spawned. + + +
+ + + +

Basic concepts

+ +What technically happens when you press Control-C is that all programs +running in the foreground in your current terminal (or virtual +terminal) get the signal SIGINT sent. + +

You may change the key that triggers the signal using +stty and running programs may remap the SIGINT-sending +key at any time they like, without your intervention and without +asking you first. + +

The usual reaction of a running program to SIGINT is to exit. +However, not all program do an exit on SIGINT, programs are free to +use the signal for other actions or to ignore it at all. + +

All programs running in the foreground receive the signal. This may +be a nested "stack" of programs: You started a program that started +another and the outer is waiting for the inner to exit. This nesting +may be arbitrarily deep. + +

The innermost program is the one that decides what to do on SIGINT. +It may exit, do something else or do nothing. Still, when the user hit +SIGINT, all the outer programs are awaken, get the signal and may +react on it. + +

What we try to achieve

+ +The problem is with shell scripts (or similar programs that call +several subprograms one after another). + +

Let us consider the most basic script: +

+#! /bin/sh
+program1
+program2
+
+and the usual run looks like this: +
+$ sh myscript
+[output of program1]
+[output of program2]
+$
+
+ +

Let us assume that both programs do nothing special on SIGINT, they +just exit. + +

Now imagine the user hits C-c while a shellscript is executing its +first program. The following programs receive SIGINT: program1 and +also the shell executing the script. program1 exits. + +

But what should the shell do? If we say that it is only the +innermost's programs business to react on SIGINT, the shell will do +nothing special (not exit) and it will continue the execution of the +script and run program2. But this is wrong: The user's intention in +hitting C-c is to abort the whole script, to get his prompt back. If +he hits C-c while the first program is running, he does not want +program2 to be even started. + +

here is what would happen if the shell doesn't do anything: +

+$ sh myscript
+[first half of program1's output]
+C-c   [users presses C-c]
+[second half of program1's output will not be displayed]
+[output of program2 will appear]
+
+ + +

Consider a more annoying example: +

+#! /bin/sh
+# let's assume there are 300 *.dat files
+for file in *.dat ; do
+	dat2ascii $dat
+done
+
+ +If your shell wouldn't end if the user hits C-c, +C-c would just end one dat2ascii run and +the script would continue. Thus, you had to hit C-c up to +300 times to end this script. + +

Alternatives to do so

+ +

There are several ways to handle abortion of shell scripts when +SIGINT is received while a foreground child runs: + +

+ +
  • As just outlined, the shellscript may just continue, ignoring the +fact that the user hit C-c. That way, your shellscript - +including any loops - would continue and you had no chance of aborting +it except using the kill command after finding out the outermost +shell's PID. This "solution" will not be discussed further, as it is +obviously not desirable. + +

  • The shell itself exits immediately when it receives SIGINT. Not +only the program called will exit, but the calling (the +script-executing) shell. The first variant is to exit the shell (and +therefore discontinuing execution of the script) immediately, while +the background program may still be executing (remember that although +the shell is just waiting for the called program to exit, it is woken +up and may act). I will call the way of doing things the "IUE" (for +"immediate unconditional exit") for the rest of this document. + +

  • As a variant of the former, when the shell receives SIGINT +while it is waiting for a child to exit, the shell does not exit +immediately. but it remembers the fact that a SIGINT happened. After +the called program exits and the shell's wait ends, the shell will +exit itself and hence discontinue the script. I will call the way of +doing things the "WUE" (for "wait and unconditional exit") for the +rest of this document. + +

  • There is also a way that the calling shell can tell whether the +called program exited on SIGINT and if it ignored SIGINT (or used it +for other purposes). As in the WUE way, the shell waits for +the child to complete. It figures whether the program was ended on +SIGINT and if so, it discontinue the script. If the program did any +other exit, the script will be continued. I will call the way of doing +things the "WCE" (for "wait and cooperative exit") for the rest of +this document. + +
  • + +

    The problem

    + +On first sight, all three solutions (IUE, WUE and WCE) all seem to do +what we want: If C-c is hit while the first program of the shell +script runs, the script is discontinued. The user gets his prompt back +immediately. So what are the difference between these way of handling +SIGINT? + +

    There are programs that use the signal SIGINT for other purposes +than exiting. They use it as a normal keystroke. The user is expected +to use the key that sends SIGINT during a perfectly normal program +run. As a result, the user sends SIGINT in situations where he/she +does not want the program or the script to end. + +

    The primary example is the emacs editor: C-g does what ESC does in +other applications: It cancels a partially executed or prepared +operation. Technically, emacs remaps the key that sends SIGINT from +C-c to C-g and catches SIGINT. + +

    Remember that the SIGINT is sent to all programs running in the +foreground. If emacs is executing from a shell script, both emacs and +the shell get SIGINT. emacs is the program that decides what to do: +Exit on SIGINT or not. emacs decides not to exit. The problem arises +when the shell draws its own conclusions from receiving SIGINT without +consulting emacs for its opinion. + +

    Consider this script: +

    +#! /bin/sh
    +emacs /tmp/foo
    +cp /tmp/foo /home/user/mail/sent
    +
    + +

    If C-g is used in emacs, both the shell and emacs will received +SIGINT. Emacs will not exit, the user used C-g as a normal editing +keystroke, he/she does not want the script to be aborted on C-g. + +

    The central problem is that the second command (cp) may +unintentionally be killed when the shell draws its own conclusion +about the user's intention. The innermost program is the only one to +judge. + +

    One more example

    + +

    Imagine a mail session using a curses mailer in a tty. You called +your mailer and started to compose a message. Your mailer calls emacs. +C-g is a normal editing key in emacs. Technically it +sends SIGINT (it was C-c, but emacs remapped the key) to +

    +
  • emacs +
  • the shell between your mailer and emacs, the one from your mailers + system("emacs /tmp/bla.44") command +
  • the mailer itself +
  • possibly another shell if your mailer was called by a shell script +or from another application using system(3) +
  • your interactive shell (which ignores it since it is interactive +and hence is not relevant to this discussion) +
  • + +

    If everyone just exits on SIGINT, you will be left with nothing but +your login shell, without asking. + +

    But for sure you don't want to be dropped out of your editor and +out of your mailer back to the commandline, having your edited data +and mailer status deleted. + +

    Understand the difference: While C-g is used an a kind +of abort key in emacs, it isn't the major "abort everything" key. When +you use C-g in emacs, you want to end some internal emacs +command. You don't want your whole emacs and mailer session to end. + +

    So, if the shell exits immediately if the user sends SIGINT (the +second of the four ways shown above), the parent of emacs would die, +leaving emacs without the controlling tty. The user will lose it's +editing session immediately and unrecoverable. If the "main" shell of +the operating system defaults to this behavior, every editor session +that is spawned from a mailer or such will break (because it is +usually executed by system(3), which calls /bin/sh). This was the case +in FreeBSD before I and Bruce Evans changed it in 1998. + +

    If the shell recognized that SIGINT was sent and exits after the +current foreground process exited (the third way of the four), the +editor session will not be disturbed, but things will still not work +right. + +

    A further look at the alternatives

    + +

    Still considering this script to examine the shell's actions in the +IUE, WUE and ICE way of handling SIGINT: +

    +#! /bin/sh
    +emacs /tmp/foo
    +cp /tmp/foo /home/user/mail/sent
    +
    + +

    The IUE ("immediate unconditional exit") way does not work at all: +emacs wants to survive the SIGINT (it's a normal editing key for +emacs), but its parent shell unconditionally thinks "We received +SIGINT. Abort everything. Now.". The shell will exit even before emacs +exits. But this will leave emacs in an unusable state, since the death +of its calling shell will leave it without required resources (file +descriptors). This way does not work at all for shellscripts that call +programs that use SIGINT for other purposes than immediate exit. Even +for programs that exit on SIGINT, but want to do some cleanup between +the signal and the exit, may fail before they complete their cleanup. + +

    It should be noted that this way has one advantage: If a child +blocks SIGINT and does not exit at all, this way will get control back +to the user's terminal. Since such programs should be banned from your +system anyway, I don't think that weighs against the disadvantages. + +

    WUE ("wait and unconditional exit") is a little more clever: If C-g +was used in emacs, the shell will get SIGINT. It will not immediately +exit, but remember the fact that a SIGINT happened. When emacs ends +(maybe a long time after the SIGINT), it will say "Ok, a SIGINT +happened sometime while the child was executing, the user wants the +script to be discontinued". It will then exit. The cp will not be +executed. But that's bad. The "cp" will be executed when the emacs +session ended without the C-g key ever used, but it will not be +executed when the user used C-g at least one time. That is clearly not +desired. Since C-g is a normal editing key in emacs, the user expects +the rest of the script to behave identically no matter what keys he +used. + +

    As a result, the "WUE" way is better than the "IUE" way in that it +does not break SIGINT-using programs completely. The emacs session +will end undisturbed. But it still does not support scripts where +other actions should be performed after a program that use SIGINT for +non-exit purposes. Since the behavior is basically undeterminable for +the user, this can lead to nasty surprises. + +

    The "WCE" way fixes this by "asking" the called program whether it +exited on SIGINT or not. While emacs receives SIGINT, it does not exit +on it and a calling shell waiting for its exit will not be told that +it exited on SIGINT. (Although it receives SIGINT at some point in +time, the system does not enforce that emacs will exit with +"I-exited-on-SIGINT" status. This is under emacs' control, see below). + +

    this still work for the normal script without SIGINT-using +programs:

    +
    +#! /bin/sh
    +program1
    +program2
    +
    + +Unless program1 and program2 mess around with signal handling, the +system will tell the calling shell whether the programs exited +normally or as a result of SIGINT. + +

    The "WCE" way then has an easy way to things right: When one called +program exited with "I-exited-on-SIGINT" status, it will discontinue +the script after this program. If the program ends without this +status, the next command in the script is started. + +

    It is important to understand that a shell in "WCE" modus does not +need to listen to the SIGINT signal at all. Both in the +"emacs-then-cp" script and in the "several-normal-programs" script, it +will be woken up and receive SIGINT when the user hits the +corresponding key. But the shell does not need to react on this event +and it doesn't need to remember the event of any SIGINT, either. +Telling whether the user wants to end a script is done by asking that +program that has to decide, that program that interprets keystrokes +from the user, the innermost program. + +

    So everything is well with WCE?

    + +Well, almost. + +

    The problem with the "WCE" modus is that there are broken programs +that do not properly communicate the required information up to the +calling program. + +

    Unless a program messes with signal handling, the system does this +automatically. + +

    There are programs that want to exit on SIGINT, but they don't let +the system do the automatic exit, because they want to do some +cleanup. To do so, they catch SIGINT, do the cleanup and then exit by +themselves. + +

    And here is where the problem arises: Once they catch the signal, +the system will no longer communicate the "I-exited-on-SIGINT" status +to the calling program automatically. Even if the program exit +immediately in the signal handler of SIGINT. Once it catches the +signal, it has to take care of communicating the signal status +itself. + +

    Some programs don't do this. On SIGINT, they do cleanup and exit +immediately, but the calling shell isn't told about the non-normal exit +and it will call the next program in the script. + +

    As a result, the user hits SIGINT and while one program exits, the +shellscript continues. To him/her it looks like the shell fails to +obey to his abortion command. + +

    Both IUE or WUE shell would not have this problem, since they +discontinue the script on their own. But as I said, they don't support +programs using SIGINT for non-exiting purposes, no matter whether +these programs properly communicate their signal status to the calling +shell or not. + +

    Since some shell in wide use implement the WUE way (and some even +IUE), there is a considerable number of broken programs out there that +break WCE shells. The programmers just don't recognize it if their +shell isn't WCE. + +

    How to be a proper program

    + +

    (Short note in advance: What you need to achieve is that +WIFSIGNALED(status) is true in the calling program and that +WTERMSIG(status) returns SIGINT.) + +

    If you don't catch SIGINT, the system automatically does the right +thing for you: Your program exits and the calling program gets the +right "I-exited-on-SIGINT" status after waiting for your exit. + +

    But once you catch SIGINT, you have to act. + +

    Decide whether the SIGINT is used for exit/abort purposes and hence +a shellscript calling this program should discontinue. This is +hopefully obvious. If you just need to do some cleanup on SIGINT, but +then exit immediately, the answer is "yes". + +

    If so, you have to tell the calling program about it by exiting +with the "I-exited-on-SIGINT" status. + +

    There is no other way of doing this than to kill yourself with a +SIGINT signal. Do it by resetting the SIGINT handler to SIG_DFL, then +send yourself the signal. + +

    +void sigint_handler(int sig)
    +{
    +	
    +	signal(SIGINT, SIG_DFL);
    +	kill(getpid(), SIGINT);
    +}
    +
    + +Notes: + + + +
  • You cannot "fake" the proper exit status by an exit(3) with a +special numeric value. People often assume this since the manuals for +shells often list some return value for exactly this. But this is just +a convention for your shell script. It does not work from one UNIX API +program to another. + +

    All that happens is that the shell sets the "$?" variable to a +special numeric value for the convenience of your script, because your +script does not have access to the lower-lever UNIX status evaluation +functions. This is just an agreement between your script and the +executing shell, it does not have any meaning in other contexts. + +

  • Do not use kill(0, SIGINT) without consulting the manul for +your OS implementation. I.e. on BSD, this would not send the signal to +the current process, but to all processes in the group. + +

  • POSIX 1003.1 allows all these calls to appear in signal +handlers, so it is portable. + +
  • + +

    In a bourne shell script, you can catch signals using the +trap command. Here, the same as for C programs apply. If +the intention of SIGINT is to end your program, you have to exit in a +way that the calling programs "sees" that you have been killed. If +you don't catch SIGINT, this happened automatically, but of you catch +SIGINT, i.e. to do cleanup work, you have to end the program by +killing yourself, not by calling exit. + +

    Consider this example from FreeBSD's mkdep, which is a +bourne shell script. + +

    +TMP=_mkdep$$
    +trap 'rm -f $TMP ; trap 2 ; kill -2 $$' 1 2 3 13 15
    +
    + +Yes, you have to do it the hard way. It's even more annoying in shell +scripts than in C programs since you can't "pre-delete" temporary +files (which isn't really portable in C, though). + +

    All this applies to programs in all languages, not only C and +bourne shell. Every language implementation that lets you catch SIGINT +should also give you the option to reset the signal and kill yourself. + +

    It is always desirable to exit the right way, even if you don't +expect your usual callers to depend on it, some unusual one will come +along. This proper exit status will be needed for WCE and will not +hurt when the calling shell uses IUE or WUE. + +

    How to be a proper shell

    + +All this applies only for the script-executing case. Most shells will +also have interactive modes where things are different. + + + +
  • Do nothing special when SIGINT appears while you wait for a child. +You don't even have to remember that one happened. + +

  • Wait for child to exit, get the exit status. Do not truncate it +to type char. + +

  • Look at WIFSIGNALED(status) and WTERMSIG(status) to tell +whether the child says "I exited on SIGINT: in my opinion the user +wants the shellscript to be discontinued". + +

  • If the latter applies, discontinue the script. + +

  • Exit. But since a shellscript may in turn be called by a +shellscript, you need to make sure that you properly communicate the +discontinue intention to the calling program. As in any other program +(see above), do + +
    +	signal(SIGINT, SIG_DFL);
    +	kill(getpid(), SIGINT);
    +
    + +
  • + +

    Other remarks

    + +Although this web page talks about SIGINT only, almost the same issues +apply to SIGQUIT, including proper exiting by killing yourself after +catching the signal and proper reaction on the WIFSIGNALED(status) +value. One notable difference for SIGQUIT is that you have to make +sure that not the whole call tree dumps core. + +

    What to fight

    + +Make sure all programs really kill themselves if they react +to SIGINT or SIGQUIT and intend to abort their operation as a result +of this signal. Programs that don't use SIGINT/SIGQUIT as a +termination trigger - but as part of normal operation - don't kill +themselves, but do a normal exit instead. + +

    Make sure people understand why you can't fake an exit-on-signal by +doing exit(...) using any numerical status. + +

    Make sure you use a shell that behaves right. Especially if you +develop programs, since it will help seeing problems. + +

    Concrete examples how to fix programs:

    +
      + +
    • The fix for FreeBSD's +time(1). This fix is the best example, it's quite short and clear and +it fixes a case where someone tried to fake signal exit status by a +numerical value. And the complete program is small. + +

    • Fix for FreeBSD's +truss(1). + +

    • The fix for FreeBSD's +mkdep(1), a shell script. + + +

    • Fix for FreeBSD's make(1), part 1, +part 2. + +
    + +

    Testsuite for shells

    + +I have a collection of shellscripts that test shells for the +behavior. See my download dir to get the newest +"sh-interrupt" files, either as a tarfile or as individual file for +online browsing. This isn't really documented, besides from the +comments the scripts echo. + +

    Appendix 1 - table of implementation choices

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Method signDoes what?Example shells that implement it:What happens when a shellscript called emacs, the user used +C-g and the script has additional commands in it?What happens when a shellscript called emacs, the user did not use +C-c and the script has additional commands in it?What happens if a non-interactive child catches SIGINT?To behave properly, children must do what?
    IUEThe shell executing a script exits immediately if it receives +SIGINT.4.4BSD ash (ash), NetBSD, FreeBSD prior to 3.0/22.8The editor session is lost and subsequent commands are not +executed.The editor continues as normal and the subsequent commands are +executed. The scripts ends immediately, returning to the caller even before +the current foreground child of the shell exits. It doesn't matter what the child does or how it exits, even if the +child continues to operate, the shell returns.
    WUEIf the shell executing a script received SIGINT while a foreground +process was running, it will exit after that child's exit.pdksh (OpenBSD /bin/sh)The editor continues as normal, but subsequent commands from the +script are not executed.The editor continues as normal and subsequent commands are +executed. The scripts returns to its caller after the current foreground +child exits, no matter how the child exited. It doesn't matter how the child exits (signal status or not), but +if it doesn't return at all, the shell will not return. In no case +will further commands from the script be executed.
    WCEThe shell exits if a child signaled that it was killed on a +signal (either it had the default handler for SIGINT or it killed +itself). bash (Linux /bin/sh), most commercial /bin/sh, FreeBSD /bin/sh +from 3.0/2.2.8.The editor continues as normal and subsequent commands are +executed. The editor continues as normal and subsequent commands are +executed. The scripts returns to its caller after the current foreground +child exits, but only if the child exited with signal status. If +the child did a normal exit (even if it received SIGINT, but catches +it), the script will continue. The child must be implemented right, or the user will not be able +to break shell scripts reliably.
    + +

     +
    ©2005 Martin Cracauer <cracauer @ cons.org> +http://www.cons.org/cracauer/ +
    Last changed: $Date: 2005/02/11 21:44:43 $ + diff --git a/busybox-1_37_0/docs/smallint.txt b/busybox-1_37_0/docs/smallint.txt new file mode 100644 index 000000000..b57dfd775 --- /dev/null +++ b/busybox-1_37_0/docs/smallint.txt @@ -0,0 +1,39 @@ + smalluint i = index_in_str_array(params, name) + 1; + if (i == 0) + return 0; + if (!(i == 4 || i == 5)) + i |= 0x80; + + return i; + +I think that this optimization is wrong. +index_in_str_array returns int. At best, compiler will use it as-is. +At worst, compiler will try to make sure that it is properly cast +into a byte, which probably results in "n = n & 0xff" on many architectures. + +You save nothing on space here because i is not stored on-stack, +gcc will keep it in register. And even if it *is* stored, +it is *stack* storage, which is cheap (unlike data/bss). + +small[u]ints are useful _mostly_ for: + +(a) flag variables + (a1) global flag variables - make data/bss smaller + (a2) local flag variables - "a = 5", "a |= 0x40" are smaller + for bytes than for full integers. + Example: + on i386, there is no widening constant store instruction + for some types of address modes, thus + movl $0x0,(%eax) is "c7 00 00 00 00 00" + movb $0x0,(%eax) is "c6 00 00" +(b) small integer structure members, when you have many such + structures allocated, + or when these are global objects of this structure type + +small[u]ints are *NOT* useful for: + +(a) function parameters and return values - + they are pushed on-stack or stored in registers, bytes here are *harder* + to deal with than ints +(b) "computational" variables - "a++", "a = b*3 + 7" may take more code to do + on bytes than on ints on some architectires. diff --git a/busybox-1_37_0/docs/style-guide.txt b/busybox-1_37_0/docs/style-guide.txt new file mode 100644 index 000000000..9eed7f125 --- /dev/null +++ b/busybox-1_37_0/docs/style-guide.txt @@ -0,0 +1,713 @@ +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 preferred 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 { + +If you have long logic statements that need to be wrapped, then uncuddling +the bracket to improve readability is allowed. Generally, this style makes +it easier for reader to notice that 2nd and following lines are still +inside 'if': + + if (some_really_long_checks && some_other_really_long_checks + && some_more_really_long_checks + && even_more_of_long_checks + ) { + do_foo_now; + +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... + } + + +Labels +~~~~~~ + +Labels should start at the beginning of the line, not indented to the block +level (because they do not "belong" to block scope, only to whole function). + + if (foo) { + stmt; + label: + stmt2; + stmt; + } + +(Putting label at position 1 prevents diff -p from confusing label for function +name, but it's not a policy of busybox project to enforce such a minor detail). + + + +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 separated by underscores (i.e. FIFO_TYPE, + 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 'examples/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 'examples/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 CONST 80 + + Do this instead, when the variable is in a header file and will be used in + several source files: + + enum { CONST = 80 }; + +Although enum may look ugly to some people, it is better for code size. +With "const int" compiler may fail to optimize it out and will reserve +a real storage in rodata for it! (Hopefully, newer gcc will get better +at it...). With "define", you have slight risk of polluting namespace +(#define doesn't allow you to redefine the name in the inner scopes), +and complex "define" are evaluated each time they used, not once +at declarations like enums. Also, the preprocessor does _no_ type checking +whatsoever, making it much more error prone. + + +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 CONFIG_FEATURE_FUNKY + maybe_do_funky_stuff(bar, baz); + #endif + + Do this instead: + + (in .h header file) + + #if ENABLE_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 string 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 safe_strncpy +strncpy may fail to 0-terminate dst safe_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_CONFIG_BUFFER(buffer, BUFSIZ); + +and the right thing will happen, based on your configuration. + +Another relatively new trick of similar nature is explained +in keep_data_small.txt. + + + +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 amount 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 = xmalloc_fgets(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 getopt32() 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, if you need to parse long options: + + #include + +Then have long options defined: + + static const char _longopts[] ALIGN1 = + "list\0" No_argument "t" + "extract\0" No_argument "x" + ; + +And a code block similar to the following near the top of your applet_main() +routine: + + char *str_b; + + opt_complementary = "cryptic_string"; + applet_long_options = _longopts; /* if you have them */ + opt = getopt32(argc, argv, "ab:c", &str_b); + if (opt & 1) { + handle_option_a(); + } + if (opt & 2) { + handle_option_b(str_b); + } + if (opt & 4) { + handle_option_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. + +For more info and examples, examine getopt32.c, tar.c, wget.c etc. diff --git a/busybox-1_37_0/docs/syslog.conf.txt b/busybox-1_37_0/docs/syslog.conf.txt new file mode 100644 index 000000000..6d9c4a173 --- /dev/null +++ b/busybox-1_37_0/docs/syslog.conf.txt @@ -0,0 +1,28 @@ +If syslogd applet compiled with FEATURE_SYSLOGD_CFG=y, then it supports restricted syslog.conf. +The config resembles rsyslog.conf in RULES part: + +LINE = DELIM [RULE | COMMENT] +COMMENT = #.* +DELIM = SPACE TAB +RULE = SELECTOR [;SELECTOR]* DELIM* ACTION DELIM* +SELECTOR = FACILITY [,FACILITY]* .[[!]=] PRIORITY +FACILITY = * | kern | user ... (see syslog.h) +PRIORITY = * | emerg | alert ... (see syslog.h) +ACTION = FILE + +"mark" facility is NOT supported. +"none" priority is supported. +In FACILITY and PRIORITY "*" stands for "any". +FILE is a regular file or tty device. + +Here is an example: + +#syslog.conf +kern,user.* /var/log/messages #all messages of kern and user facilities +kern.!err /var/log/critical #all messages of kern facility with priorities lower than err (warn, notice ...) +*.*;auth,authpriv.none /var/log/noauth #all messages except ones with auth and authpriv facilities +kern,user.*;kern.!=notice;*.err;syslog.none /var/log/OMG #some whicked rule just as an example =) +*.* /dev/null #this prevents from logging to default log file (-O FILE or /var/log/messages) + +Even in the case of match with some rule another rules will be tried too. +If there was no match with any of the rules, logging to default log file or shared memory will be performed. diff --git a/busybox-1_37_0/docs/tar_pax.txt b/busybox-1_37_0/docs/tar_pax.txt new file mode 100644 index 000000000..e56c27b16 --- /dev/null +++ b/busybox-1_37_0/docs/tar_pax.txt @@ -0,0 +1,239 @@ +'pax headers' is POSIX 2003 (iirc) addition designed to fix +tar format limitations - older tar format has fixed fields +for everything (filename, uid, filesize etc) which can overflow. + +pax Header Block + +The pax header block shall be identical to the ustar header block +described in ustar Interchange Format, except that two additional +typeflag values are defined: + +x + Represents extended header records for the following file in +the archive (which shall have its own ustar header block). + +g + Represents global extended header records for the following +files in the archive. Each value shall affect all subsequent files +that do not override that value in their own extended header +record and until another global extended header record is reached +that provides another value for the same field. The typeflag g +global headers should not be used with interchange media that +could suffer partial data loss in transporting the archive. + +For both of these types, the size field shall be the size of the +extended header records in octets. The other fields in the header +block are not meaningful to this version of the pax utility. +However, if this archive is read by a pax utility conforming to +the ISO POSIX-2:1993 standard, the header block fields are used to +create a regular file that contains the extended header records as +data. Therefore, header block field values should be selected to +provide reasonable file access to this regular file. + +A further difference from the ustar header block is that data +blocks for files of typeflag 1 (the digit one) (hard link) may be +included, which means that the size field may be greater than +zero. + +pax Extended Header + +An extended header shall consist of one or more records, each +constructed as follows: + +"%d %s=%s\n", , , + +The field shall be the decimal length of the extended +header record in octets, including length string itself and the +trailing . + +[skip] + +atime + The file access time for the following file(s), equivalent to +the value of the st_atime member of the stat structure for a file, +as described by the stat() function. The access time shall be +restored if the process has the appropriate privilege required to +do so. The format of the shall be as described in pax +Extended Header File Times. + +charset + The name of the character set used to encode the data in the +following file(s). + + The encoding is included in an extended header for information +only; when pax is used as described in IEEE Std 1003.1-2001, it +shall not translate the file data into any other encoding. The +BINARY entry indicates unencoded binary data. + + When used in write or copy mode, it is implementation-defined +whether pax includes a charset extended header record for a file. + +comment + A series of characters used as a comment. All characters in +the field shall be ignored by pax. + +gid + The group ID of the group that owns the file, expressed as a +decimal number using digits from the ISO/IEC 646:1991 standard. +This record shall override the gid field in the following header +block(s). When used in write or copy mode, pax shall include a gid +extended header record for each file whose group ID is greater +than 2097151 (octal 7777777). + +gname + The group of the file(s), formatted as a group name in the +group database. This record shall override the gid and gname +fields in the following header block(s), and any gid extended +header record. When used in read, copy, or list mode, pax shall +translate the name from the UTF-8 encoding in the header record to +the character set appropriate for the group database on the +receiving system. If any of the UTF-8 characters cannot be +translated, and if the -o invalid= UTF-8 option is not specified, +the results are implementation-defined. When used in write or copy +mode, pax shall include a gname extended header record for each +file whose group name cannot be represented entirely with the +letters and digits of the portable character set. + +linkpath + The pathname of a link being created to another file, of any +type, previously archived. This record shall override the linkname +field in the following ustar header block(s). The following ustar +header block shall determine the type of link created. If typeflag +of the following header block is 1, it shall be a hard link. If +typeflag is 2, it shall be a symbolic link and the linkpath value +shall be the contents of the symbolic link. The pax utility shall +translate the name of the link (contents of the symbolic link) +from the UTF-8 encoding to the character set appropriate for the +local file system. When used in write or copy mode, pax shall +include a linkpath extended header record for each link whose +pathname cannot be represented entirely with the members of the +portable character set other than NUL. + +mtime + The file modification time of the following file(s), +equivalent to the value of the st_mtime member of the stat +structure for a file, as described in the stat() function. This +record shall override the mtime field in the following header +block(s). The modification time shall be restored if the process +has the appropriate privilege required to do so. The format of the + shall be as described in pax Extended Header File Times. + +path + The pathname of the following file(s). This record shall +override the name and prefix fields in the following header +block(s). The pax utility shall translate the pathname of the file +from the UTF-8 encoding to the character set appropriate for the +local file system. + + When used in write or copy mode, pax shall include a path +extended header record for each file whose pathname cannot be +represented entirely with the members of the portable character +set other than NUL. + +realtime.any + The keywords prefixed by "realtime." are reserved for future +standardization. + +security.any + The keywords prefixed by "security." are reserved for future +standardization. + +size + The size of the file in octets, expressed as a decimal number +using digits from the ISO/IEC 646:1991 standard. This record shall +override the size field in the following header block(s). When +used in write or copy mode, pax shall include a size extended +header record for each file with a size value greater than +8589934591 (octal 77777777777). + +uid + The user ID of the file owner, expressed as a decimal number +using digits from the ISO/IEC 646:1991 standard. This record shall +override the uid field in the following header block(s). When used +in write or copy mode, pax shall include a uid extended header +record for each file whose owner ID is greater than 2097151 (octal +7777777). + +uname + The owner of the following file(s), formatted as a user name +in the user database. This record shall override the uid and uname +fields in the following header block(s), and any uid extended +header record. When used in read, copy, or list mode, pax shall +translate the name from the UTF-8 encoding in the header record to +the character set appropriate for the user database on the +receiving system. If any of the UTF-8 characters cannot be +translated, and if the -o invalid= UTF-8 option is not specified, +the results are implementation-defined. When used in write or copy +mode, pax shall include a uname extended header record for each +file whose user name cannot be represented entirely with the +letters and digits of the portable character set. + +If the field is zero length, it shall delete any header +block field, previously entered extended header value, or global +extended header value of the same name. + +If a keyword in an extended header record (or in a -o +option-argument) overrides or deletes a corresponding field in the +ustar header block, pax shall ignore the contents of that header +block field. + +Unlike the ustar header block fields, NULs shall not delimit +s; all characters within the field shall be +considered data for the field. None of the length limitations of +the ustar header block fields in ustar Header Block shall apply to +the extended header records. + +pax Extended Header File Times + +Time records shall be formatted as a decimal representation of the +time in seconds since the Epoch. If a period ( '.' ) decimal point +character is present, the digits to the right of the point shall +represent the units of a subsecond timing granularity. In read or +copy mode, the pax utility shall truncate the time of a file to +the greatest value that is not greater than the input header +file time. In write or copy mode, the pax utility shall output a +time exactly if it can be represented exactly as a decimal number, +and otherwise shall generate only enough digits so that the same +time shall be recovered if the file is extracted on a system whose +underlying implementation supports the same time granularity. + +Example from Linux kernel archive tarball: + +00000000 70 61 78 5f 67 6c 6f 62 61 6c 5f 68 65 61 64 65 |pax_global_heade| +00000010 72 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |r...............| +00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000060 00 00 00 00 30 30 30 30 36 36 36 00 30 30 30 30 |....0000666.0000| +00000070 30 30 30 00 30 30 30 30 30 30 30 00 30 30 30 30 |000.0000000.0000| +00000080 30 30 30 30 30 36 34 00 30 30 30 30 30 30 30 30 |0000064.00000000| +00000090 30 30 30 00 30 30 31 34 30 35 33 00 67 00 00 00 |000.0014053.g...| +000000a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000000b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000100 00 75 73 74 61 72 00 30 30 67 69 74 00 00 00 00 |.ustar.00git....| +00000110 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000120 00 00 00 00 00 00 00 00 00 67 69 74 00 00 00 00 |.........git....| +00000130 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000140 00 00 00 00 00 00 00 00 00 30 30 30 30 30 30 30 |.........0000000| +00000150 00 30 30 30 30 30 30 30 00 00 00 00 00 00 00 00 |.0000000........| +00000160 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000170 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000180 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000190 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001a0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001b0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +00000200 35 32 20 63 6f 6d 6d 65 6e 74 3d 62 31 30 35 30 |52 comment=b1050| +00000210 32 62 32 32 61 31 32 30 39 64 36 62 34 37 36 33 |2b22a1209d6b4763| +00000220 39 64 38 38 62 38 31 32 62 32 31 66 62 35 39 34 |9d88b812b21fb594| +00000230 39 65 34 0a 00 00 00 00 00 00 00 00 00 00 00 00 |9e4.............| +00000240 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| +... diff --git a/busybox-1_37_0/docs/tcp.txt b/busybox-1_37_0/docs/tcp.txt new file mode 100644 index 000000000..2000f3110 --- /dev/null +++ b/busybox-1_37_0/docs/tcp.txt @@ -0,0 +1,93 @@ + Some less-widely known details of TCP connections. + + Properly closing the connection. + +After this code sequence: + + sock = socket(AF_INET, SOCK_STREAM, 0); + connect(sock, &remote, sizeof(remote)); + write(sock, buffer, 1000000); + +a large block of data is only buffered by kernel, it can't be sent all at once. +What will happen if we close the socket? + +"A host MAY implement a 'half-duplex' TCP close sequence, so that + an application that has called close() cannot continue to read + data from the connection. If such a host issues a close() call + while received data is still pending in TCP, or if new data is + received after close() is called, its TCP SHOULD send a RST + to show that data was lost." + +IOW: if we just close(sock) now, kernel can reset the TCP connection +(send RST packet). + +This is problematic for two reasons: it discards some not-yet sent +data, and it may be reported as error, not EOF, on peer's side. + +What can be done about it? + +Solution #1: block until sending is done: + + /* When enabled, a close(2) or shutdown(2) will not return until + * all queued messages for the socket have been successfully sent + * or the linger timeout has been reached. + */ + struct linger { + int l_onoff; /* linger active */ + int l_linger; /* how many seconds to linger for */ + } linger; + linger.l_onoff = 1; + linger.l_linger = SOME_NUM; + setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); + close(sock); + +Solution #2: tell kernel that you are done sending. +This makes kernel send FIN after all data is written: + + shutdown(sock, SHUT_WR); + close(sock); + +However, experiments on Linux 3.9.4 show that kernel can return from +shutdown() and from close() before all data is sent, +and if peer sends any data to us after this, kernel still responds with +RST before all our data is sent. + +In practice the protocol in use often does not allow peer to send +such data to us, in which case this solution is acceptable. + +Solution #3: if you know that peer is going to close its end after it sees +our FIN (as EOF), it might be a good idea to perform a read after shutdown(). +When read finishes with 0-sized result, we conclude that peer received all +the data, saw EOF, and closed its end. + +However, this incurs small performance penalty (we run for a longer time) +and requires safeguards (nonblocking reads, timeouts etc) against +malicious peers which don't close the connection. + +Solutions #1 and #2 can be combined: + + /* ...set up struct linger... then: */ + setsockopt(sock, SOL_SOCKET, SO_LINGER, &linger, sizeof(linger)); + shutdown(sock, SHUT_WR); + /* At this point, kernel sent FIN packet, not RST, to the peer, */ + /* even if there is buffered read data from the peer. */ + close(sock); + + Defeating Nagle. + +Method #1: manually control whether partial sends are allowed: + +This prevents partially filled packets being sent: + + int state = 1; + setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); + +and this forces last, partially filled packet (if any) to be sent: + + int state = 0; + setsockopt(fd, IPPROTO_TCP, TCP_CORK, &state, sizeof(state)); + +Method #2: make any write to immediately send data, even if it's partial: + + int state = 1; + setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, &state, sizeof(state)); diff --git a/busybox-1_37_0/docs/unicode.txt b/busybox-1_37_0/docs/unicode.txt new file mode 100644 index 000000000..9c159ce2a --- /dev/null +++ b/busybox-1_37_0/docs/unicode.txt @@ -0,0 +1,71 @@ + Unicode support in busybox + +There are several scenarios where we need to handle unicode +correctly. + + Shell input + +We want to correctly handle input of unicode characters. +There are several problems with it. Just handling input +as sequence of bytes would break any editing. This was fixed +and now lineedit operates on the array of wchar_t's. +But we also need to handle the following problematic moments: + +* It is unreasonable to expect that output device supports + _any_ unicode chars. Perhaps we need to avoid printing + those chars which are not supported by output device. + Examples: chars which are not present in the font, + chars which are not assigned in unicode, + combining chars (especially trying to combine bad pairs: + a_chinese_symbol + "combining grave accent" = ??!) + +* We need to account for the fact that unicode chars have + different widths: 0 for combining chars, 1 for usual, + 2 for ideograms (are there 3+ wide chars?). + +* Bidirectional handling. If user wants to echo a phrase + in Hebrew, he types: echo "srettel werbeH" + + Editors (vi, ed) + +This case is a bit similar to "shell input", but unlike shell, +editors may encounter many more unexpected unicode sequences +(try to load a random binary file...), and they need to preserve +them, unlike shell which can afford to drop bogus input. + + more, less + +Need to correctly display any input file. Ideally, with +ASCII/unicode/filtered_unicode option or keyboard switch. +Note: need to handle tabs and backspaces specially +(bksp is for manpage compat). + + cut, fold, watch + +May need ability to cut unicode string to specified number of wchars +and/or to specified screen width. Need to handle tabs specially. + + sed, awk, grep + +Handle unicode-aware regexp match + + ls (multi-column display) + +ls will fail to line up columnar output if it will not account +for character widths (and maybe filter out some of them, see +above). OTOH, non-columnar views (ls -1, ls -l, ls | car) +should NOT filter out bad unicode (but need to filter out +control chars (coreutils does that). Note that unlike more/less, +tabs and backspaces need not special handling. + + top, ps + +Need to perform filtering similar to ls. + + Filename display (in error messages and elsewhere) + +Need to perform filtering similar to ls. + + +TODO: write an email to Asmus Freytag (asmus@unicode.org), +author of http://unicode.org/reports/tr11/ diff --git a/busybox-1_37_0/docs/unicode_UTF-8-test.txt b/busybox-1_37_0/docs/unicode_UTF-8-test.txt new file mode 100644 index 000000000..abd16f725 Binary files /dev/null and b/busybox-1_37_0/docs/unicode_UTF-8-test.txt differ diff --git a/busybox-1_37_0/docs/unicode_full-bmp.txt b/busybox-1_37_0/docs/unicode_full-bmp.txt new file mode 100644 index 000000000..2aeaa1e2b --- /dev/null +++ b/busybox-1_37_0/docs/unicode_full-bmp.txt @@ -0,0 +1,2079 @@ + +Full BMP Test File +------------------ + +Markus Kuhn -- 2003-04-22 + +This file contains the UTF-8 sequences of all code positions in the +ISO 10646-1 Basic Multilingual Plane, except for the C0 and C1 control +character areas. This corresponds to all codes in the range U+0020 - +U+007E and U+00A0 - U+FFFF. [uniset +0000..ffff utf8-list] + + +Basic Latin (U+0000-U+007F): + + !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ +`abcdefghijklmnopqrstuvwxyz{|}~ + +Latin-1 Supplement (U+0080-U+00FF): + + ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÃÂÃÄÅÆÇÈÉÊËÌÃÃŽÃÃÑÒÓÔÕÖ×ØÙÚÛÜÃÞß +àáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ + +Latin Extended-A (U+0100-U+017F): + +Ä€ÄĂ㥹ĆćĈĉĊċČÄÄŽÄÄđĒēĔĕĖėĘęĚěĜÄĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıIJijĴĵĶķĸĹĺĻļĽľĿ +Å€ÅłŃńŅņŇňʼnŊŋŌÅÅŽÅÅőŒœŔŕŖŗŘřŚśŜÅŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſ + +Latin Extended-B (U+0180-U+024F): + +Æ€ÆƂƃƄƅƆƇƈƉƊƋƌÆÆŽÆÆƑƒƓƔƕƖƗƘƙƚƛƜÆƞƟƠơƢƣƤƥƦƧƨƩƪƫƬƭƮƯưƱƲƳƴƵƶƷƸƹƺƻƼƽƾƿ +Ç€ÇǂǃDŽDždžLJLjljNJNjnjÇÇŽÇÇǑǒǓǔǕǖǗǘǙǚǛǜÇǞǟǠǡǢǣǤǥǦǧǨǩǪǫǬǭǮǯǰDZDzdzǴǵǶǷǸǹǺǻǼǽǾǿ +È€ÈȂȃȄȅȆȇȈȉȊȋȌÈÈŽÈÈȑȒȓȔȕȖȗȘșȚțȜÈȞȟȠȡȢȣȤȥȦȧȨȩȪȫȬȭȮȯȰȱȲȳȴȵȶȷȸȹȺȻȼȽȾȿ +É€ÉɂɃɄɅɆɇɈɉɊɋɌÉÉŽÉ + +IPA Extensions (U+0250-U+02AF): + +ÉɑɒɓɔɕɖɗɘəɚɛɜÉɞɟɠɡɢɣɤɥɦɧɨɩɪɫɬɭɮɯɰɱɲɳɴɵɶɷɸɹɺɻɼɽɾɿʀÊʂʃʄʅʆʇʈʉʊʋʌÊÊŽÊ +ÊʑʒʓʔʕʖʗʘʙʚʛʜÊʞʟʠʡʢʣʤʥʦʧʨʩʪʫʬʭʮʯ + +Spacing Modifier Letters (U+02B0-U+02FF): + +ʰʱʲʳʴʵʶʷʸʹʺʻʼʽʾʿˀË˂˃˄˅ˆˇˈˉˊˋˌËËŽËËˑ˒˓˔˕˖˗˘˙˚˛˜Ë˞˟ˠˡˢˣˤ˥˦˧˨˩˪˫ˬ˭ˮ˯ +˰˱˲˳˴˵˶˷˸˹˺˻˼˽˾˿ + +Combining Diacritical Marks (U+0300-U+036F): + +◌̀◌Ì◌̂◌̃◌̄◌̅◌̆◌̇◌̈◌̉◌̊◌̋◌̌◌Ì◌̎◌Ìâ—ŒÌ◌̑◌̒◌̓◌̔◌̕◌̖◌̗◌̘◌̙◌̚◌̛◌̜◌Ì◌̞◌̟◌̠◌̡◌̢◌̣◌̤◌̥◌̦◌̧◌̨◌̩◌̪◌̫◌̬◌̭◌̮◌̯◌̰◌̱◌̲◌̳◌̴◌̵◌̶◌̷◌̸◌̹◌̺◌̻◌̼◌̽◌̾◌̿ +◌̀◌Í◌͂◌̓◌̈́◌ͅ◌͆◌͇◌͈◌͉◌͊◌͋◌͌◌Í◌͎◌ÍÍ͓͔͕͖͙͚͑͒͗͛͘͜Í͟͞◌͠◌͡◌͢◌ͣ◌ͤ◌ͥ◌ͦ◌ͧ◌ͨ◌ͩ◌ͪ◌ͫ◌ͬ◌ͭ◌ͮ◌ͯ + +Greek and Coptic (U+0370-U+03FF): + +ͰͱͲͳʹ͵Ͷͷ͸͹ͺͻͼͽ;Ϳ΀Î΂΃΄΅Ά·ΈΉΊ΋ΌÎÎŽÎÎΑΒΓΔΕΖΗΘΙΚΛΜÎΞΟΠΡ΢ΣΤΥΦΧΨΩΪΫάέήί +ΰαβγδεζηθικλμνξοπÏςστυφχψωϊϋόÏÏŽÏÏϑϒϓϔϕϖϗϘϙϚϛϜÏϞϟϠϡϢϣϤϥϦϧϨϩϪϫϬϭϮϯ +ϰϱϲϳϴϵ϶ϷϸϹϺϻϼϽϾϿ + +Cyrillic (U+0400-U+04FF): + +ЀÐЂЃЄЅІЇЈЉЊЋЌÐÐŽÐÐБВГДЕЖЗИЙКЛМÐОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмноп +Ñ€ÑтуфхцчшщъыьÑÑŽÑÑёђѓєѕіїјљњћќÑўџѠѡѢѣѤѥѦѧѨѩѪѫѬѭѮѯѰѱѲѳѴѵѶѷѸѹѺѻѼѽѾѿ +Ò€Ò҂◌҃◌҄◌҅◌҆҇ Òˆ Ò‰ÒŠÒ‹ÒŒÒÒŽÒÒÒ‘Ò’Ò“Ò”Ò•Ò–Ò—Ò˜Ò™ÒšÒ›ÒœÒÒžÒŸÒ Ò¡Ò¢Ò£Ò¤Ò¥Ò¦Ò§Ò¨Ò©ÒªÒ«Ò¬Ò­Ò®Ò¯Ò°Ò±Ò²Ò³Ò´ÒµÒ¶Ò·Ò¸Ò¹ÒºÒ»Ò¼Ò½Ò¾Ò¿ +Ó€ÓÓ‚ÓƒÓ„Ó…Ó†Ó‡ÓˆÓ‰ÓŠÓ‹ÓŒÓÓŽÓÓÓ‘Ó’Ó“Ó”Ó•Ó–Ó—Ó˜Ó™ÓšÓ›ÓœÓÓžÓŸÓ Ó¡Ó¢Ó£Ó¤Ó¥Ó¦Ó§Ó¨Ó©ÓªÓ«Ó¬Ó­Ó®Ó¯Ó°Ó±Ó²Ó³Ó´ÓµÓ¶Ó·Ó¸Ó¹ÓºÓ»Ó¼Ó½Ó¾Ó¿ + +Cyrillic Supplementary (U+0500-U+052F): + +Ô€ÔÔ‚ÔƒÔ„Ô…Ô†Ô‡ÔˆÔ‰ÔŠÔ‹ÔŒÔÔŽÔÔÔ‘Ô’Ô“Ô”Ô•Ô–Ô—Ô˜Ô™ÔšÔ›ÔœÔÔžÔŸÔ Ô¡Ô¢Ô£Ô¤Ô¥Ô¦Ô§Ô¨Ô©ÔªÔ«Ô¬Ô­Ô®Ô¯ + +Armenian (U+0530-U+058F): + +Ô°Ô±Ô²Ô³Ô´ÔµÔ¶Ô·Ô¸Ô¹ÔºÔ»Ô¼Ô½Ô¾Ô¿Õ€ÕÕ‚ÕƒÕ„Õ…Õ†Õ‡ÕˆÕ‰ÕŠÕ‹ÕŒÕÕŽÕÕÕ‘Õ’Õ“Õ”Õ•Õ–Õ—Õ˜Õ™ÕšÕ›ÕœÕÕžÕŸÕ Õ¡Õ¢Õ£Õ¤Õ¥Õ¦Õ§Õ¨Õ©ÕªÕ«Õ¬Õ­Õ®Õ¯ +Õ°Õ±Õ²Õ³Õ´ÕµÕ¶Õ·Õ¸Õ¹ÕºÕ»Õ¼Õ½Õ¾Õ¿Ö€ÖÖ‚ÖƒÖ„Ö…Ö†Ö‡ÖˆÖ‰ÖŠÖ‹ÖŒÖÖŽÖ + +Hebrew (U+0590-U+05FF): + +Ö◌֑◌֒◌֓◌֔◌֕◌֖◌֗◌֘◌֙◌֚◌֛◌֜◌Ö◌֞◌֟◌֠◌֢֡◌֣◌֤◌֥◌֦◌֧◌֨◌֩◌֪◌֫◌֬◌֭◌֮◌֯◌ְ◌ֱ◌ֲ◌ֳ◌ִ◌ֵ◌ֶ◌ַ◌ָ◌ֹֺ◌ֻ◌ּ◌ֽ־◌ֿ׀◌×◌ׂ׃◌ׅׄ׆ׇ׈׉׊׋׌××Ž× +×בגדהוזחטיךכל×מןנסעףפץצקרשת׫׬׭׮ׯװױײ׳״׵׶׷׸׹׺׻׼׽׾׿ + +Arabic (U+0600-U+06FF): + +Ø€Ø؂؃؄؅؆؇؈؉؊؋،ØØŽØØؘؙؚؑؒؓؔؕؖؗ؛؜Ø؞؟ؠءآأؤإئابةتثجحخدذرزسشصضطظعغػؼؽؾؿ +Ù€Ùقكلمنهوىي◌ً◌ٌ◌Ù◌َ◌Ùâ—ŒÙ◌ّ◌ْ◌ٓ◌ٔ◌ٕٖٜٗ٘ٙٚٛÙٟٞ٠١٢٣٤٥٦٧٨٩٪٫٬٭ٮٯ◌ٰٱٲٳٴٵٶٷٸٹٺٻټٽپٿ +Ú€ÚÚ‚ÚƒÚ„Ú…Ú†Ú‡ÚˆÚ‰ÚŠÚ‹ÚŒÚÚŽÚÚÚ‘Ú’Ú“Ú”Ú•Ú–Ú—Ú˜Ú™ÚšÚ›ÚœÚÚžÚŸÚ Ú¡Ú¢Ú£Ú¤Ú¥Ú¦Ú§Ú¨Ú©ÚªÚ«Ú¬Ú­Ú®Ú¯Ú°Ú±Ú²Ú³Ú´ÚµÚ¶Ú·Ú¸Ú¹ÚºÚ»Ú¼Ú½Ú¾Ú¿ +Û€ÛÛ‚ÛƒÛ„Û…Û†Û‡ÛˆÛ‰ÛŠÛ‹ÛŒÛÛŽÛÛÛ‘Û’Û“Û”Û•â—ŒÛ–â—ŒÛ—â—ŒÛ˜â—ŒÛ™â—ŒÛšâ—ŒÛ›â—ŒÛœÛ Ûžâ—ŒÛŸâ—ŒÛ â—ŒÛ¡â—ŒÛ¢â—ŒÛ£â—ŒÛ¤Û¥Û¦â—ŒÛ§â—ŒÛ¨Û©â—ŒÛªâ—ŒÛ«â—ŒÛ¬â—ŒÛ­Û®Û¯Û°Û±Û²Û³Û´ÛµÛ¶Û·Û¸Û¹ÛºÛ»Û¼Û½Û¾Û¿ + +Syriac (U+0700-U+074F): + +Ü€Ü܂܃܄܅܆܇܈܉܊܋܌ÜÜŽÜÜ◌ܑܒܓܔܕܖܗܘܙܚܛܜÜܞܟܠܡܢܣܤܥܦܧܨܩܪܫܬܭܮܯ◌ܰ◌ܱ◌ܲ◌ܳ◌ܴ◌ܵ◌ܶ◌ܷ◌ܸ◌ܹ◌ܺ◌ܻ◌ܼ◌ܽ◌ܾ◌ܿ +◌݀◌Ý◌݂◌݃◌݄◌݅◌݆◌݇◌݈◌݉◌݊݋݌ÝÝŽÝ + +Free block (U+0750-U+077F): + +ÝݑݒݓݔݕݖݗݘݙݚݛݜÝݞݟݠݡݢݣݤݥݦݧݨݩݪݫݬݭݮݯݰݱݲݳݴݵݶݷݸݹݺݻݼݽݾݿ + +Thaana (U+0780-U+07BF): + +Þ€ÞÞ‚ÞƒÞ„Þ…Þ†Þ‡ÞˆÞ‰ÞŠÞ‹ÞŒÞÞŽÞÞÞ‘Þ’Þ“Þ”Þ•Þ–Þ—Þ˜Þ™ÞšÞ›ÞœÞޞޟޠޡޢޣޤޥ◌ަ◌ާ◌ި◌ީ◌ު◌ޫ◌ެ◌ޭ◌ޮ◌ޯ◌ްޱ޲޳޴޵޶޷޸޹޺޻޼޽޾޿ + +Free block (U+07C0-U+08FF): + +߀ß߂߃߄߅߆߇߈߉ߊߋߌßߎßßߑߒߓߔߕߖߗߘߙߚߛߜßߞߟߠߡߢߣߤߥߦߧߨߩߪ߲߫߬߭߮߯߰߱߳ߴߵ߶߷߸߹ߺ߻߼߽߾߿ +à €à à ‚ࠃࠄࠅࠆࠇࠈࠉࠊࠋࠌà à Žà à à ‘ࠒࠓࠔࠕࠖࠗ࠘࠙ࠚࠛࠜà à žà Ÿà  à ¡à ¢à £à ¤à ¥à ¦à §à ¨à ©à ªà «à ¬à ­à ®à ¯à °à ±à ²à ³à ´à µà ¶à ·à ¸à ¹à ºà »à ¼à ½à ¾à ¿ +à¡€à¡à¡‚ࡃࡄࡅࡆࡇࡈࡉࡊࡋࡌà¡à¡Žà¡à¡à¡‘ࡒࡓࡔࡕࡖࡗࡘ࡙࡚࡛࡜à¡à¡žà¡Ÿà¡ à¡¡à¡¢à¡£à¡¤à¡¥à¡¦à¡§à¡¨à¡©à¡ªà¡«à¡¬à¡­à¡®à¡¯à¡°à¡±à¡²à¡³à¡´à¡µà¡¶à¡·à¡¸à¡¹à¡ºà¡»à¡¼à¡½à¡¾à¡¿ +ࢀà¢à¢‚ࢃࢄࢅࢆࢇ࢈ࢉࢊࢋࢌà¢à¢Žà¢à¢à¢‘࢒࢓࢔࢕࢖࢙࢚࢛ࢗ࢘࢜à¢à¢žà¢Ÿà¢ à¢¡à¢¢à¢£à¢¤à¢¥à¢¦à¢§à¢¨à¢©à¢ªà¢«à¢¬à¢­à¢®à¢¯à¢°à¢±à¢²à¢³à¢´à¢µà¢¶à¢·à¢¸à¢¹à¢ºà¢»à¢¼à¢½à¢¾à¢¿ +ࣀà£à£‚ࣃࣄࣅࣆࣇࣈࣉ࣊࣋࣌à£à£Žà£à£à£‘࣒࣓ࣔࣕࣖࣗࣘࣙࣚࣛࣜà£à£žà£Ÿà£ à£¡à£¢à££à£¤à£¥à£¦à£§à£¨à£©à£ªà£«à£¬à£­à£®à£¯à£°à£±à£²à£³à£´à£µà£¶à£·à£¸à£¹à£ºà£»à£¼à£½à£¾à£¿ + +Devanagari (U+0900-U+097F): + +ऀ◌à¤â—Œà¤‚ःऄअआइईउऊऋऌà¤à¤Žà¤à¤à¤‘ऒओऔकखगघङचछजà¤à¤žà¤Ÿà¤ à¤¡à¤¢à¤£à¤¤à¤¥à¤¦à¤§à¤¨à¤©à¤ªà¤«à¤¬à¤­à¤®à¤¯à¤°à¤±à¤²à¤³à¤´à¤µà¤¶à¤·à¤¸à¤¹à¤ºà¤»â—Œà¤¼à¤½à¤¾à¤¿ +ी◌à¥â—Œà¥‚◌ृ◌ॄ◌ॅ◌ॆ◌े◌ैॉॊोौ◌à¥à¥Žà¥à¥â—Œà¥‘◌॒◌॓◌॔ॕॖॗक़ख़ग़ज़ड़à¥à¥žà¥Ÿà¥ à¥¡â—Œà¥¢â—Œà¥£à¥¤à¥¥à¥¦à¥§à¥¨à¥©à¥ªà¥«à¥¬à¥­à¥®à¥¯à¥°à¥±à¥²à¥³à¥´à¥µà¥¶à¥·à¥¸à¥¹à¥ºà¥»à¥¼à¥½à¥¾à¥¿ + +Bengali (U+0980-U+09FF): + +ঀ◌à¦à¦‚ঃ঄অআইঈউঊঋঌà¦à¦Žà¦à¦à¦‘঒ওঔকখগঘঙচছজà¦à¦žà¦Ÿà¦ à¦¡à¦¢à¦£à¦¤à¦¥à¦¦à¦§à¦¨à¦©à¦ªà¦«à¦¬à¦­à¦®à¦¯à¦°à¦±à¦²à¦³à¦´à¦µà¦¶à¦·à¦¸à¦¹à¦ºà¦»â—Œà¦¼à¦½à¦¾à¦¿ +ী◌à§â—Œà§‚◌ৃ◌ৄ৅৆েৈ৉৊োৌ◌à§à§Žà§à§à§‘৒৓৔৕৖ৗ৘৙৚৛ড়à§à§žà§Ÿà§ à§¡â—Œà§¢â—Œà§£à§¤à§¥à§¦à§§à§¨à§©à§ªà§«à§¬à§­à§®à§¯à§°à§±à§²à§³à§´à§µà§¶à§·à§¸à§¹à§ºà§»à§¼à§½à§¾à§¿ + +Gurmukhi (U+0A00-U+0A7F): + +਀à¨â—Œà¨‚ਃ਄ਅਆਇਈਉਊ਋਌à¨à¨Žà¨à¨à¨‘਒ਓਔਕਖਗਘਙਚਛਜà¨à¨žà¨Ÿà¨ à¨¡à¨¢à¨£à¨¤à¨¥à¨¦à¨§à¨¨à¨©à¨ªà¨«à¨¬à¨­à¨®à¨¯à¨°à¨±à¨²à¨³à¨´à¨µà¨¶à¨·à¨¸à¨¹à¨ºà¨»â—Œà¨¼à¨½à¨¾à¨¿ +ੀ◌à©â—Œà©‚੃੄੅੆◌ੇ◌ੈ੉੊◌ੋ◌ੌ◌à©à©Žà©à©à©‘੒੓੔੕੖੗੘ਖ਼ਗ਼ਜ਼ੜà©à©žà©Ÿà© à©¡à©¢à©£à©¤à©¥à©¦à©§à©¨à©©à©ªà©«à©¬à©­à©®à©¯â—Œà©°â—Œà©±à©²à©³à©´à©µà©¶à©·à©¸à©¹à©ºà©»à©¼à©½à©¾à©¿ + +Gujarati (U+0A80-U+0AFF): + +઀◌àªâ—Œàª‚ઃ઄અઆઇઈઉઊઋઌàªàªŽàªàªàª‘઒ઓઔકખગઘઙચછજàªàªžàªŸàª àª¡àª¢àª£àª¤àª¥àª¦àª§àª¨àª©àªªàª«àª¬àª­àª®àª¯àª°àª±àª²àª³àª´àªµàª¶àª·àª¸àª¹àªºàª»â—Œàª¼àª½àª¾àª¿ +ી◌à«â—Œà«‚◌ૃ◌ૄ◌ૅ૆◌ે◌ૈૉ૊ોૌ◌à«à«Žà«à«à«‘૒૓૔૕૖૗૘૙૚૛૜à«à«žà«Ÿà« à«¡à«¢à«£à«¤à«¥à«¦à«§à«¨à«©à«ªà««à«¬à«­à«®à«¯à«°à«±à«²à«³à«´à«µà«¶à«·à«¸à«¹à«ºà«»à«¼à«½à«¾à«¿ + +Oriya (U+0B00-U+0B7F): + +଀◌à¬à¬‚ଃ଄ଅଆଇଈଉଊଋଌà¬à¬Žà¬à¬à¬‘଒ଓଔକଖଗଘଙଚଛଜà¬à¬žà¬Ÿà¬ à¬¡à¬¢à¬£à¬¤à¬¥à¬¦à¬§à¬¨à¬©à¬ªà¬«à¬¬à¬­à¬®à¬¯à¬°à¬±à¬²à¬³à¬´à¬µà¬¶à¬·à¬¸à¬¹à¬ºà¬»â—Œà¬¼à¬½à¬¾â—Œà¬¿ +ୀ◌à­â—Œà­‚◌ୃୄ୅୆େୈ୉୊ୋୌ◌à­à­Žà­à­à­‘୒୓୔୕◌ୖୗ୘୙୚୛ଡ଼à­à­žà­Ÿà­ à­¡à­¢à­£à­¤à­¥à­¦à­§à­¨à­©à­ªà­«à­¬à­­à­®à­¯à­°à­±à­²à­³à­´à­µà­¶à­·à­¸à­¹à­ºà­»à­¼à­½à­¾à­¿ + +Tamil (U+0B80-U+0BFF): + +஀à®â—Œà®‚ஃ஄அஆஇஈஉஊ஋஌à®à®Žà®à®à®‘ஒஓஔக஖஗஘ஙச஛ஜà®à®žà®Ÿà® à®¡à®¢à®£à®¤à®¥à®¦à®§à®¨à®©à®ªà®«à®¬à®­à®®à®¯à®°à®±à®²à®³à®´à®µà®¶à®·à®¸à®¹à®ºà®»à®¼à®½à®¾à®¿ +◌ீà¯à¯‚௃௄௅ெேை௉ொோௌ◌à¯à¯Žà¯à¯à¯‘௒௓௔௕௖ௗ௘௙௚௛௜à¯à¯žà¯Ÿà¯ à¯¡à¯¢à¯£à¯¤à¯¥à¯¦à¯§à¯¨à¯©à¯ªà¯«à¯¬à¯­à¯®à¯¯à¯°à¯±à¯²à¯³à¯´à¯µà¯¶à¯·à¯¸à¯¹à¯ºà¯»à¯¼à¯½à¯¾à¯¿ + +Telugu (U+0C00-U+0C7F): + +à°€à°à°‚ఃఄఅఆఇఈఉఊఋఌà°à°Žà°à°à°‘ఒఓఔకఖగఘఙచఛజà°à°žà°Ÿà° à°¡à°¢à°£à°¤à°¥à°¦à°§à°¨à°©à°ªà°«à°¬à°­à°®à°¯à°°à°±à°²à°³à°´à°µà°¶à°·à°¸à°¹à°ºà°»à°¼à°½â—Œà°¾â—Œà°¿ +◌ీà±à±‚ృౄ౅◌ె◌ే◌ై౉◌ొ◌ో◌ౌ◌à±à±Žà±à±à±‘౒౓౔◌ౕ◌ౖ౗ౘౙౚ౛౜à±à±žà±Ÿà± à±¡à±¢à±£à±¤à±¥à±¦à±§à±¨à±©à±ªà±«à±¬à±­à±®à±¯à±°à±±à±²à±³à±´à±µà±¶à±·à±¸à±¹à±ºà±»à±¼à±½à±¾à±¿ + +Kannada (U+0C80-U+0CFF): + +ಀà²à²‚ಃ಄ಅಆಇಈಉಊಋಌà²à²Žà²à²à²‘ಒಓಔಕಖಗಘಙಚಛಜà²à²žà²Ÿà² à²¡à²¢à²£à²¤à²¥à²¦à²§à²¨à²©à²ªà²«à²¬à²­à²®à²¯à²°à²±à²²à²³à²´à²µà²¶à²·à²¸à²¹à²ºà²»à²¼à²½à²¾â—Œà²¿ +à³€à³à³‚ೃೄ೅◌ೆೇೈ೉ೊೋ◌ೌ◌à³à³Žà³à³à³‘೒೓೔ೕೖ೗೘೙೚೛೜à³à³žà³Ÿà³ à³¡à³¢à³£à³¤à³¥à³¦à³§à³¨à³©à³ªà³«à³¬à³­à³®à³¯à³°à³±à³²à³³à³´à³µà³¶à³·à³¸à³¹à³ºà³»à³¼à³½à³¾à³¿ + +Malayalam (U+0D00-U+0D7F): + +à´€à´à´‚ഃഄഅആഇഈഉഊഋഌà´à´Žà´à´à´‘ഒഓഔകഖഗഘങചഛജà´à´žà´Ÿà´ à´¡à´¢à´£à´¤à´¥à´¦à´§à´¨à´©à´ªà´«à´¬à´­à´®à´¯à´°à´±à´²à´³à´´à´µà´¶à´·à´¸à´¹à´ºà´»à´¼à´½à´¾à´¿ +ീ◌àµâ—Œàµ‚◌ൃൄ൅െേൈ൉ൊോൌ◌àµàµŽàµàµàµ‘൒൓ൔൕൖൗ൘൙൚൛൜àµàµžàµŸàµ àµ¡àµ¢àµ£àµ¤àµ¥àµ¦àµ§àµ¨àµ©àµªàµ«àµ¬àµ­àµ®àµ¯àµ°àµ±àµ²àµ³àµ´àµµàµ¶àµ·àµ¸àµ¹àµºàµ»àµ¼àµ½àµ¾àµ¿ + +Sinhala (U+0D80-U+0DFF): + +඀à¶à¶‚ඃ඄අආඇඈඉඊඋඌà¶à¶Žà¶à¶à¶‘ඒඓඔඕඖ඗඘඙කඛගà¶à¶žà¶Ÿà¶ à¶¡à¶¢à¶£à¶¤à¶¥à¶¦à¶§à¶¨à¶©à¶ªà¶«à¶¬à¶­à¶®à¶¯à¶°à¶±à¶²à¶³à¶´à¶µà¶¶à¶·à¶¸à¶¹à¶ºà¶»à¶¼à¶½à¶¾à¶¿ +à·€à·à·‚සහළෆ෇෈෉◌්෋෌à·à·Žà·à·à·‘◌ි◌ී◌ු෕◌ූ෗ෘෙේෛොà·à·žà·Ÿà· à·¡à·¢à·£à·¤à·¥à·¦à·§à·¨à·©à·ªà·«à·¬à·­à·®à·¯à·°à·±à·²à·³à·´à·µà·¶à··à·¸à·¹à·ºà·»à·¼à·½à·¾à·¿ + +Thai (U+0E00-U+0E7F): + +฀à¸à¸‚ฃคฅฆงจฉชซฌà¸à¸Žà¸à¸à¸‘ฒณดตถทธนบปผà¸à¸žà¸Ÿà¸ à¸¡à¸¢à¸£à¸¤à¸¥à¸¦à¸§à¸¨à¸©à¸ªà¸«à¸¬à¸­à¸®à¸¯à¸°â—Œà¸±à¸²à¸³â—Œà¸´â—Œà¸µâ—Œà¸¶â—Œà¸·â—Œà¸¸â—Œà¸¹â—Œà¸ºà¸»à¸¼à¸½à¸¾à¸¿ +เà¹à¹‚ใไๅๆ◌็◌่◌้◌๊◌๋◌์◌à¹â—Œà¹Žà¹à¹à¹‘๒๓๔๕๖๗๘๙๚๛๜à¹à¹žà¹Ÿà¹ à¹¡à¹¢à¹£à¹¤à¹¥à¹¦à¹§à¹¨à¹©à¹ªà¹«à¹¬à¹­à¹®à¹¯à¹°à¹±à¹²à¹³à¹´à¹µà¹¶à¹·à¹¸à¹¹à¹ºà¹»à¹¼à¹½à¹¾à¹¿ + +Lao (U+0E80-U+0EFF): + +຀àºàº‚຃ຄ຅ຆງຈຉຊ຋ຌàºàºŽàºàºàº‘ຒຓດຕຖທຘນບປຜàºàºžàºŸàº àº¡àº¢àº£àº¤àº¥àº¦àº§àº¨àº©àºªàº«àº¬àº­àº®àº¯àº°â—Œàº±àº²àº³â—Œàº´â—Œàºµâ—Œàº¶â—Œàº·â—Œàº¸â—Œàº¹àººâ—Œàº»â—Œàº¼àº½àº¾àº¿ +ເà»à»‚ໃໄ໅ໆ໇◌່◌້◌໊◌໋◌໌◌à»à»Žà»à»à»‘໒໓໔໕໖໗໘໙໚໛ໜà»à»žà»Ÿà» à»¡à»¢à»£à»¤à»¥à»¦à»§à»¨à»©à»ªà»«à»¬à»­à»®à»¯à»°à»±à»²à»³à»´à»µà»¶à»·à»¸à»¹à»ºà»»à»¼à»½à»¾à»¿ + +Tibetan (U+0F00-U+0FFF): + +ༀà¼à¼‚༃༄༅༆༇༈༉༊་༌à¼à¼Žà¼à¼à¼‘༒༓༔༕༖༗◌༘◌༙༚༛༜à¼à¼žà¼Ÿà¼ à¼¡à¼¢à¼£à¼¤à¼¥à¼¦à¼§à¼¨à¼©à¼ªà¼«à¼¬à¼­à¼®à¼¯à¼°à¼±à¼²à¼³à¼´â—Œà¼µà¼¶â—Œà¼·à¼¸â—Œà¼¹à¼ºà¼»à¼¼à¼½à¼¾à¼¿ +ཀà½à½‚གྷངཅཆཇ཈ཉཊཋཌà½à½Žà½à½à½‘དྷནཔཕབབྷམཙཚཛཛྷà½à½žà½Ÿà½ à½¡à½¢à½£à½¤à½¥à½¦à½§à½¨à½©à½ªà½«à½¬à½­à½®à½¯à½°â—Œà½±â—Œà½²â—Œà½³â—Œà½´â—Œà½µâ—Œà½¶â—Œà½·â—Œà½¸â—Œà½¹â—Œà½ºâ—Œà½»â—Œà½¼â—Œà½½â—Œà½¾à½¿ +◌ྀ◌à¾â—Œà¾‚◌ྃ◌྄྅◌྆◌྇ྈྉྊྋྌà¾à¾Žà¾â—Œà¾â—Œà¾‘◌ྒ◌ྒྷ◌ྔ◌ྕ◌ྖ◌ྗ྘◌ྙ◌ྚ◌ྛ◌ྜ◌à¾â—Œà¾žâ—Œà¾Ÿâ—Œà¾ â—Œà¾¡â—Œà¾¢â—Œà¾£â—Œà¾¤â—Œà¾¥â—Œà¾¦â—Œà¾§â—Œà¾¨â—Œà¾©â—Œà¾ªâ—Œà¾«â—Œà¾¬â—Œà¾­â—Œà¾®â—Œà¾¯â—Œà¾°â—Œà¾±â—Œà¾²â—Œà¾³â—Œà¾´â—Œà¾µâ—Œà¾¶â—Œà¾·â—Œà¾¸â—Œà¾¹â—Œà¾ºâ—Œà¾»â—Œà¾¼à¾½à¾¾à¾¿ +à¿€à¿à¿‚࿃࿄࿅◌࿆࿇࿈࿉࿊࿋࿌à¿à¿Žà¿à¿à¿‘࿒࿓࿔࿕࿖࿗࿘࿙࿚࿛࿜à¿à¿žà¿Ÿà¿ à¿¡à¿¢à¿£à¿¤à¿¥à¿¦à¿§à¿¨à¿©à¿ªà¿«à¿¬à¿­à¿®à¿¯à¿°à¿±à¿²à¿³à¿´à¿µà¿¶à¿·à¿¸à¿¹à¿ºà¿»à¿¼à¿½à¿¾à¿¿ + +Myanmar (U+1000-U+109F): + +ကá€á€‚ဃငစဆဇဈဉညဋဌá€á€Žá€á€á€‘ဒဓနပဖဗဘမယရလá€á€žá€Ÿá€ á€¡á€¢á€£á€¤á€¥á€¦á€§á€¨á€©á€ªá€«á€¬â—Œá€­â—Œá€®â—Œá€¯â—Œá€°á€±â—Œá€²á€³á€´á€µâ—Œá€¶â—Œá€·á€¸â—Œá€¹á€ºá€»á€¼á€½á€¾á€¿ +á€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘á’á“á”á•á–á—â—Œá˜â—Œá™ášá›áœáážáŸá á¡á¢á£á¤á¥á¦á§á¨á©áªá«á¬á­á®á¯á°á±á²á³á´áµá¶á·á¸á¹áºá»á¼á½á¾á¿ +á‚€á‚ႂႃႄႅႆႇႈႉႊႋႌá‚á‚Žá‚á‚႑႒႓႔႕႖႗႘႙ႚႛႜá‚á‚žá‚Ÿ + +Georgian (U+10A0-U+10FF): + +ႠႡႢႣႤႥႦႧႨႩႪႫႬႭႮႯႰႱႲႳႴႵႶႷႸႹႺႻႼႽႾႿჀáƒáƒ‚ჃჄჅ჆Ⴧ჈჉჊჋჌áƒáƒŽáƒáƒáƒ‘გდევზთიკლმნáƒáƒžáƒŸ +რსტუფქღყშჩცძწჭხჯჰჱჲჳჴჵჶჷჸჹჺ჻ჼჽჾჿ + +Hangul Jamo (U+1100-U+11FF): + +á„€á„ᄂᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌá„á„Žá„á„ᄑᄒᄓᄔᄕᄖᄗᄘᄙᄚᄛᄜá„á„žá„Ÿ +ᄠᄡᄢᄣᄤᄥᄦᄧᄨᄩᄪᄫᄬᄭᄮᄯᄰᄱᄲᄳᄴᄵᄶᄷᄸᄹᄺᄻᄼᄽᄾᄿ +á…€á…ᅂᅃᅄᅅᅆᅇᅈᅉᅊᅋᅌá…á…Žá…á…ᅑᅒᅓᅔᅕᅖᅗᅘᅙᅚᅛᅜá…á…žá…Ÿ +ᅠᅡᅢᅣᅤᅥᅦᅧᅨᅩᅪᅫᅬᅭᅮᅯᅰᅱᅲᅳᅴᅵᅶᅷᅸᅹᅺᅻᅼᅽᅾᅿᆀá†á†‚ᆃᆄᆅᆆᆇᆈᆉᆊᆋᆌá†á†Žá†á†á†‘ᆒᆓᆔᆕᆖᆗᆘᆙᆚᆛᆜá†á†žá†Ÿ +ᆠᆡᆢᆣᆤᆥᆦᆧᆨᆩᆪᆫᆬᆭᆮᆯᆰᆱᆲᆳᆴᆵᆶᆷᆸᆹᆺᆻᆼᆽᆾᆿᇀá‡á‡‚ᇃᇄᇅᇆᇇᇈᇉᇊᇋᇌá‡á‡Žá‡á‡á‡‘ᇒᇓᇔᇕᇖᇗᇘᇙᇚᇛᇜá‡á‡žá‡Ÿ +ᇠᇡᇢᇣᇤᇥᇦᇧᇨᇩᇪᇫᇬᇭᇮᇯᇰᇱᇲᇳᇴᇵᇶᇷᇸᇹᇺᇻᇼᇽᇾᇿ + +Ethiopic (U+1200-U+137F): + +ሀáˆáˆ‚ሃሄህሆሇለሉሊላሌáˆáˆŽáˆáˆáˆ‘ሒሓሔሕሖሗመሙሚማሜáˆáˆžáˆŸáˆ áˆ¡áˆ¢áˆ£áˆ¤áˆ¥áˆ¦áˆ§áˆ¨áˆ©áˆªáˆ«áˆ¬áˆ­áˆ®áˆ¯áˆ°áˆ±áˆ²áˆ³áˆ´áˆµáˆ¶áˆ·áˆ¸áˆ¹áˆºáˆ»áˆ¼áˆ½áˆ¾áˆ¿ +ቀá‰á‰‚ቃቄቅቆቇቈ቉ቊቋቌá‰á‰Žá‰á‰á‰‘ቒቓቔቕቖ቗ቘ቙ቚቛቜá‰á‰žá‰Ÿá‰ á‰¡á‰¢á‰£á‰¤á‰¥á‰¦á‰§á‰¨á‰©á‰ªá‰«á‰¬á‰­á‰®á‰¯á‰°á‰±á‰²á‰³á‰´á‰µá‰¶á‰·á‰¸á‰¹á‰ºá‰»á‰¼á‰½á‰¾á‰¿ +ኀáŠáŠ‚ኃኄኅኆኇኈ኉ኊኋኌáŠáŠŽáŠáŠáŠ‘ኒናኔንኖኗኘኙኚኛኜáŠáŠžáŠŸáŠ áŠ¡áŠ¢áŠ£áŠ¤áŠ¥áŠ¦áŠ§áŠ¨áŠ©áŠªáŠ«áŠ¬áŠ­áŠ®áŠ¯áŠ°áŠ±áŠ²áŠ³áŠ´áŠµáŠ¶áŠ·áŠ¸áŠ¹áŠºáŠ»áŠ¼áŠ½áŠ¾áŠ¿ +á‹€á‹á‹‚ዃዄዅ዆዇ወዉዊዋዌá‹á‹Žá‹á‹á‹‘ዒዓዔዕዖ዗ዘዙዚዛዜá‹á‹žá‹Ÿá‹ á‹¡á‹¢á‹£á‹¤á‹¥á‹¦á‹§á‹¨á‹©á‹ªá‹«á‹¬á‹­á‹®á‹¯á‹°á‹±á‹²á‹³á‹´á‹µá‹¶á‹·á‹¸á‹¹á‹ºá‹»á‹¼á‹½á‹¾á‹¿ +ጀáŒáŒ‚ጃጄጅጆጇገጉጊጋጌáŒáŒŽáŒáŒáŒ‘ጒጓጔጕ጖጗ጘጙጚጛጜáŒáŒžáŒŸáŒ áŒ¡áŒ¢áŒ£áŒ¤áŒ¥áŒ¦áŒ§áŒ¨áŒ©áŒªáŒ«áŒ¬áŒ­áŒ®áŒ¯áŒ°áŒ±áŒ²áŒ³áŒ´áŒµáŒ¶áŒ·áŒ¸áŒ¹áŒºáŒ»áŒ¼áŒ½áŒ¾áŒ¿ +á€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘á’á“á”á•á–á—á˜á™ášá›áœáážáŸá á¡á¢á£á¤á¥á¦á§á¨á©áªá«á¬á­á®á¯á°á±á²á³á´áµá¶á·á¸á¹áºá»á¼á½á¾á¿ + +Free block (U+1380-U+139F): + +ᎀáŽáŽ‚ᎃᎄᎅᎆᎇᎈᎉᎊᎋᎌáŽáŽŽáŽáŽáŽ‘᎒᎓᎔᎕᎖᎗᎘᎙᎚᎛᎜áŽáŽžáŽŸ + +Cherokee (U+13A0-U+13FF): + +ᎠᎡᎢᎣᎤᎥᎦᎧᎨᎩᎪᎫᎬᎭᎮᎯᎰᎱᎲᎳᎴᎵᎶᎷᎸᎹᎺᎻᎼᎽᎾᎿá€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘á’á“á”á•á–á—á˜á™ášá›áœáážáŸ +á á¡á¢á£á¤á¥á¦á§á¨á©áªá«á¬á­á®á¯á°á±á²á³á´áµá¶á·á¸á¹áºá»á¼á½á¾á¿ + +Unified Canadian Aboriginal Syllabics (U+1400-U+167F): + +á€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘á’á“á”á•á–á—á˜á™ášá›áœáážáŸá á¡á¢á£á¤á¥á¦á§á¨á©áªá«á¬á­á®á¯á°á±á²á³á´áµá¶á·á¸á¹áºá»á¼á½á¾á¿ +á‘€á‘ᑂᑃᑄᑅᑆᑇᑈᑉᑊᑋᑌá‘á‘Žá‘á‘ᑑᑒᑓᑔᑕᑖᑗᑘᑙᑚᑛᑜá‘ᑞᑟᑠᑡᑢᑣᑤᑥᑦᑧᑨᑩᑪᑫᑬᑭᑮᑯᑰᑱᑲᑳᑴᑵᑶᑷᑸᑹᑺᑻᑼᑽᑾᑿ +á’€á’ᒂᒃᒄᒅᒆᒇᒈᒉᒊᒋᒌá’á’Žá’á’ᒑᒒᒓᒔᒕᒖᒗᒘᒙᒚᒛᒜá’ᒞᒟᒠᒡᒢᒣᒤᒥᒦᒧᒨᒩᒪᒫᒬᒭᒮᒯᒰᒱᒲᒳᒴᒵᒶᒷᒸᒹᒺᒻᒼᒽᒾᒿ +á“€á“ᓂᓃᓄᓅᓆᓇᓈᓉᓊᓋᓌá“á“Žá“á“ᓑᓒᓓᓔᓕᓖᓗᓘᓙᓚᓛᓜá“ᓞᓟᓠᓡᓢᓣᓤᓥᓦᓧᓨᓩᓪᓫᓬᓭᓮᓯᓰᓱᓲᓳᓴᓵᓶᓷᓸᓹᓺᓻᓼᓽᓾᓿ +ᔀá”ᔂᔃᔄᔅᔆᔇᔈᔉᔊᔋᔌá”ᔎá”á”ᔑᔒᔓᔔᔕᔖᔗᔘᔙᔚᔛᔜá”ᔞᔟᔠᔡᔢᔣᔤᔥᔦᔧᔨᔩᔪᔫᔬᔭᔮᔯᔰᔱᔲᔳᔴᔵᔶᔷᔸᔹᔺᔻᔼᔽᔾᔿ +á•€á•á•‚ᕃᕄᕅᕆᕇᕈᕉᕊᕋᕌá•á•Žá•á•á•‘ᕒᕓᕔᕕᕖᕗᕘᕙᕚᕛᕜá•á•žá•Ÿá• á•¡á•¢á•£á•¤á•¥á•¦á•§á•¨á•©á•ªá•«á•¬á•­á•®á•¯á•°á•±á•²á•³á•´á•µá•¶á•·á•¸á•¹á•ºá•»á•¼á•½á•¾á•¿ +á–€á–ᖂᖃᖄᖅᖆᖇᖈᖉᖊᖋᖌá–á–Žá–á–ᖑᖒᖓᖔᖕᖖᖗᖘᖙᖚᖛᖜá–ᖞᖟᖠᖡᖢᖣᖤᖥᖦᖧᖨᖩᖪᖫᖬᖭᖮᖯᖰᖱᖲᖳᖴᖵᖶᖷᖸᖹᖺᖻᖼᖽᖾᖿ +á—€á—ᗂᗃᗄᗅᗆᗇᗈᗉᗊᗋᗌá—á—Žá—á—ᗑᗒᗓᗔᗕᗖᗗᗘᗙᗚᗛᗜá—ᗞᗟᗠᗡᗢᗣᗤᗥᗦᗧᗨᗩᗪᗫᗬᗭᗮᗯᗰᗱᗲᗳᗴᗵᗶᗷᗸᗹᗺᗻᗼᗽᗾᗿ +ᘀá˜á˜‚ᘃᘄᘅᘆᘇᘈᘉᘊᘋᘌá˜á˜Žá˜á˜á˜‘ᘒᘓᘔᘕᘖᘗᘘᘙᘚᘛᘜá˜á˜žá˜Ÿá˜ á˜¡á˜¢á˜£á˜¤á˜¥á˜¦á˜§á˜¨á˜©á˜ªá˜«á˜¬á˜­á˜®á˜¯á˜°á˜±á˜²á˜³á˜´á˜µá˜¶á˜·á˜¸á˜¹á˜ºá˜»á˜¼á˜½á˜¾á˜¿ +ᙀá™á™‚ᙃᙄᙅᙆᙇᙈᙉᙊᙋᙌá™á™Žá™á™á™‘ᙒᙓᙔᙕᙖᙗᙘᙙᙚᙛᙜá™á™žá™Ÿá™ á™¡á™¢á™£á™¤á™¥á™¦á™§á™¨á™©á™ªá™«á™¬á™­á™®á™¯á™°á™±á™²á™³á™´á™µá™¶á™·á™¸á™¹á™ºá™»á™¼á™½á™¾á™¿ + +Ogham (U+1680-U+169F): + + ášáš‚ᚃᚄᚅᚆᚇᚈᚉᚊᚋᚌášášŽášášáš‘ᚒᚓᚔᚕᚖᚗᚘᚙᚚ᚛᚜ášášžášŸ + +Runic (U+16A0-U+16FF): + +ᚠᚡᚢᚣᚤᚥᚦᚧᚨᚩᚪᚫᚬᚭᚮᚯᚰᚱᚲᚳᚴᚵᚶᚷᚸᚹᚺᚻᚼᚽᚾᚿᛀá›á›‚ᛃᛄᛅᛆᛇᛈᛉᛊᛋᛌá›á›Žá›á›á›‘ᛒᛓᛔᛕᛖᛗᛘᛙᛚᛛᛜá›á›žá›Ÿ +ᛠᛡᛢᛣᛤᛥᛦᛧᛨᛩᛪ᛫᛬᛭ᛮᛯᛰᛱᛲᛳᛴᛵᛶᛷᛸ᛹᛺᛻᛼᛽᛾᛿ + +Tagalog (U+1700-U+171F): + +ᜀáœáœ‚ᜃᜄᜅᜆᜇᜈᜉᜊᜋᜌáœáœŽáœáœáœ‘◌ᜒ◌ᜓ◌᜔᜕᜖᜗᜘᜙᜚᜛᜜áœáœžáœŸ + +Hanunoo (U+1720-U+173F): + +ᜠᜡᜢᜣᜤᜥᜦᜧᜨᜩᜪᜫᜬᜭᜮᜯᜰᜱ◌ᜲ◌ᜳ◌᜴᜵᜶᜷᜸᜹᜺᜻᜼᜽᜾᜿ + +Buhid (U+1740-U+175F): + +á€áá‚áƒá„á…á†á‡áˆá‰áŠá‹áŒááŽááá‘â—Œá’â—Œá“á”á•á–á—á˜á™ášá›áœáážáŸ + +Tagbanwa (U+1760-U+177F): + +á á¡á¢á£á¤á¥á¦á§á¨á©áªá«á¬á­á®á¯á°á±â—Œá²â—Œá³á´áµá¶á·á¸á¹áºá»á¼á½á¾á¿ + +Khmer (U+1780-U+17FF): + +កážáž‚ឃងចឆជឈញដឋឌážážŽážážáž‘ធនបផពភមយរលវážážžážŸáž áž¡áž¢áž£áž¤áž¥áž¦áž§áž¨áž©ážªáž«áž¬áž­áž®áž¯áž°áž±áž²áž³áž´ážµáž¶â—Œáž·â—Œáž¸â—Œáž¹â—Œážºâ—Œáž»â—Œáž¼â—Œáž½áž¾áž¿ +ៀáŸáŸ‚ៃោៅ◌ំះៈ◌៉◌៊◌់◌៌◌áŸâ—ŒáŸŽâ—ŒáŸâ—ŒáŸâ—ŒáŸ‘◌្◌៓។៕៖ៗ៘៙៚៛ៜáŸáŸžáŸŸáŸ áŸ¡áŸ¢áŸ£áŸ¤áŸ¥áŸ¦áŸ§áŸ¨áŸ©áŸªáŸ«áŸ¬áŸ­áŸ®áŸ¯áŸ°áŸ±áŸ²áŸ³áŸ´áŸµáŸ¶áŸ·áŸ¸áŸ¹áŸºáŸ»áŸ¼áŸ½áŸ¾áŸ¿ + +Mongolian (U+1800-U+18AF): + +á €á á ‚᠃᠄᠅᠆᠇᠈᠉᠊◌᠋◌᠌◌á á Žá á á ‘᠒᠓᠔᠕᠖᠗᠘᠙᠚᠛᠜á á žá Ÿá  á ¡á ¢á £á ¤á ¥á ¦á §á ¨á ©á ªá «á ¬á ­á ®á ¯á °á ±á ²á ³á ´á µá ¶á ·á ¸á ¹á ºá »á ¼á ½á ¾á ¿ +á¡€á¡á¡‚ᡃᡄᡅᡆᡇᡈᡉᡊᡋᡌá¡á¡Žá¡á¡á¡‘ᡒᡓᡔᡕᡖᡗᡘᡙᡚᡛᡜá¡á¡žá¡Ÿá¡ á¡¡á¡¢á¡£á¡¤á¡¥á¡¦á¡§á¡¨á¡©á¡ªá¡«á¡¬á¡­á¡®á¡¯á¡°á¡±á¡²á¡³á¡´á¡µá¡¶á¡·á¡¸á¡¹á¡ºá¡»á¡¼á¡½á¡¾á¡¿ +ᢀá¢á¢‚ᢃᢄᢅᢆᢇᢈᢉᢊᢋᢌá¢á¢Žá¢á¢á¢‘ᢒᢓᢔᢕᢖᢗᢘᢙᢚᢛᢜá¢á¢žá¢Ÿá¢ á¢¡á¢¢á¢£á¢¤á¢¥á¢¦á¢§á¢¨â—Œá¢©á¢ªá¢«á¢¬á¢­á¢®á¢¯ + +Free block (U+18B0-U+18FF): + +ᢰᢱᢲᢳᢴᢵᢶᢷᢸᢹᢺᢻᢼᢽᢾᢿᣀá£á£‚ᣃᣄᣅᣆᣇᣈᣉᣊᣋᣌá£á£Žá£á£á£‘ᣒᣓᣔᣕᣖᣗᣘᣙᣚᣛᣜá£á£žá£Ÿá£ á£¡á£¢á££á£¤á£¥á£¦á£§á£¨á£©á£ªá£«á£¬á£­á£®á£¯ +ᣰᣱᣲᣳᣴᣵ᣶᣷᣸᣹᣺᣻᣼᣽᣾᣿ + +Limbu (U+1900-U+194F): + +ᤀá¤á¤‚ᤃᤄᤅᤆᤇᤈᤉᤊᤋᤌá¤á¤Žá¤á¤á¤‘ᤒᤓᤔᤕᤖᤗᤘᤙᤚᤛᤜá¤á¤žá¤Ÿá¤ á¤¡á¤¢á¤£á¤¤á¤¥á¤¦á¤§á¤¨á¤©á¤ªá¤«á¤¬á¤­á¤®á¤¯á¤°á¤±á¤²á¤³á¤´á¤µá¤¶á¤·á¤¸á¤¹á¤ºá¤»á¤¼á¤½á¤¾á¤¿ +᥀á¥á¥‚᥃᥄᥅᥆᥇᥈᥉᥊᥋᥌á¥á¥Žá¥ + +Tai Le (U+1950-U+197F): + +á¥á¥‘ᥒᥓᥔᥕᥖᥗᥘᥙᥚᥛᥜá¥á¥žá¥Ÿá¥ á¥¡á¥¢á¥£á¥¤á¥¥á¥¦á¥§á¥¨á¥©á¥ªá¥«á¥¬á¥­á¥®á¥¯á¥°á¥±á¥²á¥³á¥´á¥µá¥¶á¥·á¥¸á¥¹á¥ºá¥»á¥¼á¥½á¥¾á¥¿ + +Free block (U+1980-U+19DF): + +ᦀá¦á¦‚ᦃᦄᦅᦆᦇᦈᦉᦊᦋᦌá¦á¦Žá¦á¦á¦‘ᦒᦓᦔᦕᦖᦗᦘᦙᦚᦛᦜá¦á¦žá¦Ÿá¦ á¦¡á¦¢á¦£á¦¤á¦¥á¦¦á¦§á¦¨á¦©á¦ªá¦«á¦¬á¦­á¦®á¦¯á¦°á¦±á¦²á¦³á¦´á¦µá¦¶á¦·á¦¸á¦¹á¦ºá¦»á¦¼á¦½á¦¾á¦¿ +ᧀá§á§‚ᧃᧄᧅᧆᧇᧈᧉ᧊᧋᧌á§á§Žá§á§á§‘᧒᧓᧔᧕᧖᧗᧘᧙᧚᧛᧜á§á§žá§Ÿ + +Khmer Symbols (U+19E0-U+19FF): + +᧠᧡᧢᧣᧤᧥᧦᧧᧨᧩᧪᧫᧬᧭᧮᧯᧰᧱᧲᧳᧴᧵᧶᧷᧸᧹᧺᧻᧼᧽᧾᧿ + +Free block (U+1A00-U+1CFF): + +ᨀá¨á¨‚ᨃᨄᨅᨆᨇᨈᨉᨊᨋᨌá¨á¨Žá¨á¨á¨‘ᨒᨓᨔᨕᨖᨘᨗᨙᨚᨛ᨜á¨á¨žá¨Ÿá¨ á¨¡á¨¢á¨£á¨¤á¨¥á¨¦á¨§á¨¨á¨©á¨ªá¨«á¨¬á¨­á¨®á¨¯á¨°á¨±á¨²á¨³á¨´á¨µá¨¶á¨·á¨¸á¨¹á¨ºá¨»á¨¼á¨½á¨¾á¨¿ +á©€á©á©‚ᩃᩄᩅᩆᩇᩈᩉᩊᩋᩌá©á©Žá©á©á©‘ᩒᩓᩔᩕᩖᩗᩘᩙᩚᩛᩜá©á©žá©Ÿá© á©¡á©¢á©£á©¤á©¥á©¦á©§á©¨á©©á©ªá©«á©¬á©­á©®á©¯á©°á©±á©²á©³á©´á©µá©¶á©·á©¸á©¹á©ºá©»á©¼á©½á©¾á©¿ +᪀áªáª‚᪃᪄᪅᪆᪇᪈᪉᪊᪋᪌áªáªŽáªáªáª‘᪒᪓᪔᪕᪖᪗᪘᪙᪚᪛᪜áªáªžáªŸáª áª¡áª¢áª£áª¤áª¥áª¦áª§áª¨áª©áªªáª«áª¬áª­áª®áª¯áª°áª±áª²áª³áª´áªµáª¶áª·áª¸áª¹áªºáª»áª¼áª½áª¾áª¿ +á«€á«á«‚᫃᫄᫊᫅᫆᫇᫈᫉᫋ᫌá«á«Žá«á«á«‘᫒᫓᫔᫕᫖᫗᫘᫙᫚᫛᫜á«á«žá«Ÿá« á«¡á«¢á«£á«¤á«¥á«¦á«§á«¨á«©á«ªá««á«¬á«­á«®á«¯á«°á«±á«²á«³á«´á«µá«¶á«·á«¸á«¹á«ºá«»á«¼á«½á«¾á«¿ +ᬀá¬á¬‚ᬃᬄᬅᬆᬇᬈᬉᬊᬋᬌá¬á¬Žá¬á¬á¬‘ᬒᬓᬔᬕᬖᬗᬘᬙᬚᬛᬜá¬á¬žá¬Ÿá¬ á¬¡á¬¢á¬£á¬¤á¬¥á¬¦á¬§á¬¨á¬©á¬ªá¬«á¬¬á¬­á¬®á¬¯á¬°á¬±á¬²á¬³á¬´á¬µá¬¶á¬·á¬¸á¬¹á¬ºá¬»á¬¼á¬½á¬¾á¬¿ +á­€á­á­‚ᭃ᭄ᭅᭆᭇᭈᭉᭊᭋᭌá­á­Žá­á­á­‘᭒᭓᭔᭕᭖᭗᭘᭙᭚᭛᭜á­á­žá­Ÿá­ á­¡á­¢á­£á­¤á­¥á­¦á­§á­¨á­©á­ªá­«á­¬á­­á­®á­¯á­°á­±á­²á­³á­´á­µá­¶á­·á­¸á­¹á­ºá­»á­¼á­½á­¾á­¿ +ᮀá®á®‚ᮃᮄᮅᮆᮇᮈᮉᮊᮋᮌá®á®Žá®á®á®‘ᮒᮓᮔᮕᮖᮗᮘᮙᮚᮛᮜá®á®žá®Ÿá® á®¡á®¢á®£á®¤á®¥á®¦á®§á®¨á®©á®ªá®«á®¬á®­á®®á®¯á®°á®±á®²á®³á®´á®µá®¶á®·á®¸á®¹á®ºá®»á®¼á®½á®¾á®¿ +ᯀá¯á¯‚ᯃᯄᯅᯆᯇᯈᯉᯊᯋᯌá¯á¯Žá¯á¯á¯‘ᯒᯓᯔᯕᯖᯗᯘᯙᯚᯛᯜá¯á¯žá¯Ÿá¯ á¯¡á¯¢á¯£á¯¤á¯¥á¯¦á¯§á¯¨á¯©á¯ªá¯«á¯¬á¯­á¯®á¯¯á¯°á¯±á¯²á¯³á¯´á¯µá¯¶á¯·á¯¸á¯¹á¯ºá¯»á¯¼á¯½á¯¾á¯¿ +á°€á°á°‚ᰃᰄᰅᰆᰇᰈᰉᰊᰋᰌá°á°Žá°á°á°‘ᰒᰓᰔᰕᰖᰗᰘᰙᰚᰛᰜá°á°žá°Ÿá° á°¡á°¢á°£á°¤á°¥á°¦á°§á°¨á°©á°ªá°«á°¬á°­á°®á°¯á°°á°±á°²á°³á°´á°µá°¶á°·á°¸á°¹á°ºá°»á°¼á°½á°¾á°¿ +á±€á±á±‚᱃᱄᱅᱆᱇᱈᱉᱊᱋᱌á±á±Žá±á±á±‘᱒᱓᱔᱕᱖᱗᱘᱙ᱚᱛᱜá±á±žá±Ÿá± á±¡á±¢á±£á±¤á±¥á±¦á±§á±¨á±©á±ªá±«á±¬á±­á±®á±¯á±°á±±á±²á±³á±´á±µá±¶á±·á±¸á±¹á±ºá±»á±¼á±½á±¾á±¿ +á²€á²á²‚ᲃᲄᲅᲆᲇᲈᲉᲊ᲋᲌á²á²Žá²á²á²‘ᲒᲓᲔᲕᲖᲗᲘᲙᲚᲛᲜá²á²žá²Ÿá² á²¡á²¢á²£á²¤á²¥á²¦á²§á²¨á²©á²ªá²«á²¬á²­á²®á²¯á²°á²±á²²á²³á²´á²µá²¶á²·á²¸á²¹á²ºá²»á²¼á²½á²¾á²¿ +á³€á³á³‚᳃᳄᳅᳆᳇᳈᳉᳊᳋᳌á³á³Žá³á³á³‘᳒᳓᳔᳕᳖᳗᳘᳙᳜᳚᳛á³á³žá³Ÿá³ á³¡á³¢á³£á³¤á³¥á³¦á³§á³¨á³©á³ªá³«á³¬á³­á³®á³¯á³°á³±á³²á³³á³´á³µá³¶á³·á³¸á³¹á³ºá³»á³¼á³½á³¾á³¿ + +Phonetic Extensions (U+1D00-U+1D7F): + +á´€á´á´‚ᴃᴄᴅᴆᴇᴈᴉᴊᴋᴌá´á´Žá´á´á´‘ᴒᴓᴔᴕᴖᴗᴘᴙᴚᴛᴜá´á´žá´Ÿá´ á´¡á´¢á´£á´¤á´¥á´¦á´§á´¨á´©á´ªá´«á´¬á´­á´®á´¯á´°á´±á´²á´³á´´á´µá´¶á´·á´¸á´¹á´ºá´»á´¼á´½á´¾á´¿ +áµ€áµáµ‚ᵃᵄᵅᵆᵇᵈᵉᵊᵋᵌáµáµŽáµáµáµ‘ᵒᵓᵔᵕᵖᵗᵘᵙᵚᵛᵜáµáµžáµŸáµ áµ¡áµ¢áµ£áµ¤áµ¥áµ¦áµ§áµ¨áµ©áµªáµ«áµ¬áµ­áµ®áµ¯áµ°áµ±áµ²áµ³áµ´áµµáµ¶áµ·áµ¸áµ¹áµºáµ»áµ¼áµ½áµ¾áµ¿ + +Free block (U+1D80-U+1DFF): + +ᶀá¶á¶‚ᶃᶄᶅᶆᶇᶈᶉᶊᶋᶌá¶á¶Žá¶á¶á¶‘ᶒᶓᶔᶕᶖᶗᶘᶙᶚᶛᶜá¶á¶žá¶Ÿá¶ á¶¡á¶¢á¶£á¶¤á¶¥á¶¦á¶§á¶¨á¶©á¶ªá¶«á¶¬á¶­á¶®á¶¯á¶°á¶±á¶²á¶³á¶´á¶µá¶¶á¶·á¶¸á¶¹á¶ºá¶»á¶¼á¶½á¶¾á¶¿ +á·€á·á·‚᷊᷃᷄᷅᷆᷇᷈᷉᷋᷌á·á·Žá·á·á·‘᷒ᷓᷔᷕᷖᷗᷘᷙᷚᷛᷜá·á·žá·Ÿá· á·¡á·¢á·£á·¤á·¥á·¦á·§á·¨á·©á·ªá·«á·¬á·­á·®á·¯á·°á·±á·²á·³á·´á·µá·¶á··á·¸á·¹á·ºá·»á·¼á·½á·¾á·¿ + +Latin Extended Additional (U+1E00-U+1EFF): + +Ḁá¸á¸‚ḃḄḅḆḇḈḉḊḋḌá¸á¸Žá¸á¸á¸‘ḒḓḔḕḖḗḘḙḚḛḜá¸á¸žá¸Ÿá¸ á¸¡á¸¢á¸£á¸¤á¸¥á¸¦á¸§á¸¨á¸©á¸ªá¸«á¸¬á¸­á¸®á¸¯á¸°á¸±á¸²á¸³á¸´á¸µá¸¶á¸·á¸¸á¸¹á¸ºá¸»á¸¼á¸½á¸¾á¸¿ +á¹€á¹á¹‚ṃṄṅṆṇṈṉṊṋṌá¹á¹Žá¹á¹á¹‘ṒṓṔṕṖṗṘṙṚṛṜá¹á¹žá¹Ÿá¹ á¹¡á¹¢á¹£á¹¤á¹¥á¹¦á¹§á¹¨á¹©á¹ªá¹«á¹¬á¹­á¹®á¹¯á¹°á¹±á¹²á¹³á¹´á¹µá¹¶á¹·á¹¸á¹¹á¹ºá¹»á¹¼á¹½á¹¾á¹¿ +Ẁáºáº‚ẃẄẅẆẇẈẉẊẋẌáºáºŽáºáºáº‘ẒẓẔẕẖẗẘẙẚẛẜáºáºžáºŸáº áº¡áº¢áº£áº¤áº¥áº¦áº§áº¨áº©áºªáº«áº¬áº­áº®áº¯áº°áº±áº²áº³áº´áºµáº¶áº·áº¸áº¹áººáº»áº¼áº½áº¾áº¿ +Ềá»á»‚ểỄễỆệỈỉỊịỌá»á»Žá»á»á»‘ỒồỔổỖỗỘộỚớỜá»á»žá»Ÿá» á»¡á»¢á»£á»¤á»¥á»¦á»§á»¨á»©á»ªá»«á»¬á»­á»®á»¯á»°á»±á»²á»³á»´á»µá»¶á»·á»¸á»¹á»ºá»»á»¼á»½á»¾á»¿ + +Greek Extended (U+1F00-U+1FFF): + +á¼€á¼á¼‚ἃἄἅἆἇἈἉἊἋἌá¼á¼Žá¼á¼á¼‘ἒἓἔἕ἖἗ἘἙἚἛἜá¼á¼žá¼Ÿá¼ á¼¡á¼¢á¼£á¼¤á¼¥á¼¦á¼§á¼¨á¼©á¼ªá¼«á¼¬á¼­á¼®á¼¯á¼°á¼±á¼²á¼³á¼´á¼µá¼¶á¼·á¼¸á¼¹á¼ºá¼»á¼¼á¼½á¼¾á¼¿ +á½€á½á½‚ὃὄὅ὆὇ὈὉὊὋὌá½á½Žá½á½á½‘ὒὓὔὕὖὗ὘Ὑ὚Ὓ὜á½á½žá½Ÿá½ á½¡á½¢á½£á½¤á½¥á½¦á½§á½¨á½©á½ªá½«á½¬á½­á½®á½¯á½°á½±á½²á½³á½´á½µá½¶á½·á½¸á½¹á½ºá½»á½¼á½½á½¾á½¿ +á¾€á¾á¾‚ᾃᾄᾅᾆᾇᾈᾉᾊᾋᾌá¾á¾Žá¾á¾á¾‘ᾒᾓᾔᾕᾖᾗᾘᾙᾚᾛᾜá¾á¾žá¾Ÿá¾ á¾¡á¾¢á¾£á¾¤á¾¥á¾¦á¾§á¾¨á¾©á¾ªá¾«á¾¬á¾­á¾®á¾¯á¾°á¾±á¾²á¾³á¾´á¾µá¾¶á¾·á¾¸á¾¹á¾ºá¾»á¾¼á¾½á¾¾á¾¿ +á¿€á¿á¿‚ῃῄ῅ῆῇῈΈῊΉῌá¿á¿Žá¿á¿á¿‘ῒΐ῔῕ῖῗῘῙῚΊ῜á¿á¿žá¿Ÿá¿ á¿¡á¿¢á¿£á¿¤á¿¥á¿¦á¿§á¿¨á¿©á¿ªá¿«á¿¬á¿­á¿®á¿¯á¿°á¿±á¿²á¿³á¿´á¿µá¿¶á¿·á¿¸á¿¹á¿ºá¿»á¿¼á¿½á¿¾á¿¿ + +General Punctuation (U+2000-U+206F): + + â€â€‚        ​‌â€â€Žâ€â€â€‘‒–—―‖‗‘’‚‛“â€â€žâ€Ÿâ€ â€¡â€¢â€£â€¤â€¥â€¦â€§â€¨â€©â€ªâ€«â€¬â€­â€®â€¯â€°â€±â€²â€³â€´â€µâ€¶â€·â€¸â€¹â€ºâ€»â€¼â€½â€¾â€¿ +â€ââ‚âƒâ„â…â†â‡âˆâ‰âŠâ‹âŒââŽâââ‘â’â“â”â•â–â—â˜â™âšâ›âœââžâŸâ â¡â¢â£â¤â¥â¦â§â¨â©âªâ«â¬â­â®â¯ + +Superscripts and Subscripts (U+2070-U+209F): + +â°â±â²â³â´âµâ¶â·â¸â¹âºâ»â¼â½â¾â¿â‚€â‚₂₃₄₅₆₇₈₉₊₋₌â‚â‚Žâ‚â‚ₑₒₓₔₕₖₗₘₙₚₛₜâ‚â‚žâ‚Ÿ + +Currency Symbols (U+20A0-U+20CF): + +₠₡₢₣₤₥₦₧₨₩₪₫€₭₮₯₰₱₲₳₴₵₶₷₸₹₺₻₼₽₾₿⃀âƒâƒ‚⃃⃄⃅⃆⃇⃈⃉⃊⃋⃌âƒâƒŽâƒ + +Combining Diacritical Marks for Symbols (U+20D0-U+20FF): + +â—Œâƒâ—Œâƒ‘◌⃒◌⃓◌⃔◌⃕◌⃖◌⃗◌⃘◌⃙◌⃚◌⃛◌⃜ ⃠⃞ ⃟ ⃠◌⃡ ⃢ ⃣ ⃤◌⃥◌⃦◌⃧◌⃨◌⃩◌⃪⃫⃬⃭⃮⃯⃰⃱⃲⃳⃴⃵⃶⃷⃸⃹⃺⃻⃼⃽⃾⃿ + +Letterlike Symbols (U+2100-U+214F): + +â„€â„ℂ℃℄℅℆ℇ℈℉ℊℋℌâ„â„Žâ„â„ℑℒℓ℔ℕ№℗℘ℙℚℛℜâ„℞℟℠℡™℣ℤ℥Ω℧ℨ℩KÅℬℭ℮ℯℰℱℲℳℴℵℶℷℸℹ℺℻ℼℽℾℿ +â…€â…⅂⅃⅄ⅅⅆⅇⅈⅉ⅊⅋⅌â…â…Žâ… + +Number Forms (U+2150-U+218F): + +â…⅑⅒⅓⅔⅕⅖⅗⅘⅙⅚⅛⅜â…⅞⅟ⅠⅡⅢⅣⅤⅥⅦⅧⅨⅩⅪⅫⅬⅭⅮⅯⅰⅱⅲⅳⅴⅵⅶⅷⅸⅹⅺⅻⅼⅽⅾⅿↀâ†â†‚Ↄↄↅↆↇↈ↉↊↋↌â†â†Žâ† + +Arrows (U+2190-U+21FF): + +â†â†‘→↓↔↕↖↗↘↙↚↛↜â†â†žâ†Ÿâ† â†¡â†¢â†£â†¤â†¥â†¦â†§â†¨â†©â†ªâ†«â†¬â†­â†®â†¯â†°â†±â†²â†³â†´â†µâ†¶â†·â†¸â†¹â†ºâ†»â†¼â†½â†¾â†¿â‡€â‡â‡‚⇃⇄⇅⇆⇇⇈⇉⇊⇋⇌â‡â‡Žâ‡ +â‡â‡‘⇒⇓⇔⇕⇖⇗⇘⇙⇚⇛⇜â‡â‡žâ‡Ÿâ‡ â‡¡â‡¢â‡£â‡¤â‡¥â‡¦â‡§â‡¨â‡©â‡ªâ‡«â‡¬â‡­â‡®â‡¯â‡°â‡±â‡²â‡³â‡´â‡µâ‡¶â‡·â‡¸â‡¹â‡ºâ‡»â‡¼â‡½â‡¾â‡¿ + +Mathematical Operators (U+2200-U+22FF): + +∀âˆâˆ‚∃∄∅∆∇∈∉∊∋∌âˆâˆŽâˆâˆâˆ‘−∓∔∕∖∗∘∙√∛∜âˆâˆžâˆŸâˆ âˆ¡âˆ¢âˆ£âˆ¤âˆ¥âˆ¦âˆ§âˆ¨âˆ©âˆªâˆ«âˆ¬âˆ­âˆ®âˆ¯âˆ°âˆ±âˆ²âˆ³âˆ´âˆµâˆ¶âˆ·âˆ¸âˆ¹âˆºâˆ»âˆ¼âˆ½âˆ¾âˆ¿ +≀â‰â‰‚≃≄≅≆≇≈≉≊≋≌â‰â‰Žâ‰â‰â‰‘≒≓≔≕≖≗≘≙≚≛≜â‰â‰žâ‰Ÿâ‰ â‰¡â‰¢â‰£â‰¤â‰¥â‰¦â‰§â‰¨â‰©â‰ªâ‰«â‰¬â‰­â‰®â‰¯â‰°â‰±â‰²â‰³â‰´â‰µâ‰¶â‰·â‰¸â‰¹â‰ºâ‰»â‰¼â‰½â‰¾â‰¿ +⊀âŠâŠ‚⊃⊄⊅⊆⊇⊈⊉⊊⊋⊌âŠâŠŽâŠâŠâŠ‘⊒⊓⊔⊕⊖⊗⊘⊙⊚⊛⊜âŠâŠžâŠŸâŠ âŠ¡âŠ¢âŠ£âŠ¤âŠ¥âŠ¦âŠ§âŠ¨âŠ©âŠªâŠ«âŠ¬âŠ­âŠ®âŠ¯âŠ°âŠ±âŠ²âŠ³âŠ´âŠµâŠ¶âŠ·âŠ¸âŠ¹âŠºâŠ»âŠ¼âŠ½âŠ¾âŠ¿ +â‹€â‹â‹‚⋃⋄⋅⋆⋇⋈⋉⋊⋋⋌â‹â‹Žâ‹â‹â‹‘⋒⋓⋔⋕⋖⋗⋘⋙⋚⋛⋜â‹â‹žâ‹Ÿâ‹ â‹¡â‹¢â‹£â‹¤â‹¥â‹¦â‹§â‹¨â‹©â‹ªâ‹«â‹¬â‹­â‹®â‹¯â‹°â‹±â‹²â‹³â‹´â‹µâ‹¶â‹·â‹¸â‹¹â‹ºâ‹»â‹¼â‹½â‹¾â‹¿ + +Miscellaneous Technical (U+2300-U+23FF): + +⌀âŒâŒ‚⌃⌄⌅⌆⌇⌈⌉⌊⌋⌌âŒâŒŽâŒâŒâŒ‘⌒⌓⌔⌕⌖⌗⌘⌙⌚⌛⌜âŒâŒžâŒŸâŒ âŒ¡âŒ¢âŒ£âŒ¤âŒ¥âŒ¦âŒ§âŒ¨âŒ©âŒªâŒ«âŒ¬âŒ­âŒ®âŒ¯âŒ°âŒ±âŒ²âŒ³âŒ´âŒµâŒ¶âŒ·âŒ¸âŒ¹âŒºâŒ»âŒ¼âŒ½ +⌾⌿â€ââ‚âƒâ„â…â†â‡âˆâ‰âŠâ‹âŒââŽâââ‘â’â“â”â•â–â—â˜â™âšâ›âœââžâŸâ â¡â¢â£â¤â¥â¦â§â¨â©âªâ«â¬â­â®â¯â°â±â²â³â´âµâ¶â·â¸â¹âºâ»â¼â½ +â¾â¿âŽ€âŽâŽ‚⎃⎄⎅⎆⎇⎈⎉⎊⎋⎌âŽâŽŽâŽâŽâŽ‘⎒⎓⎔⎕⎖⎗⎘⎙⎚⎛⎜âŽâŽžâŽŸâŽ âŽ¡âŽ¢âŽ£âŽ¤âŽ¥âŽ¦âŽ§âŽ¨âŽ©âŽªâŽ«âŽ¬âŽ­âŽ®âŽ¯âŽ°âŽ±âŽ²âŽ³âŽ´âŽµâŽ¶âŽ·âŽ¸âŽ¹âŽºâŽ»âŽ¼âŽ½ +⎾⎿â€ââ‚âƒâ„â…â†â‡âˆâ‰âŠâ‹âŒââŽâââ‘â’â“â”â•â–â—â˜â™âšâ›âœââžâŸâ â¡â¢â£â¤â¥â¦â§â¨â©âªâ«â¬â­â®â¯â°â±â²â³â´âµâ¶â·â¸â¹âºâ»â¼â½ +â¾â¿ + +Control Pictures (U+2400-U+243F): + +â€ââ‚âƒâ„â…â†â‡âˆâ‰âŠâ‹âŒââŽâââ‘â’â“â”â•â–â—â˜â™âšâ›âœââžâŸâ â¡â¢â£â¤â¥â¦â§â¨â©âªâ«â¬â­â®â¯â°â±â²â³â´âµâ¶â·â¸â¹âºâ»â¼â½â¾â¿ + +Optical Character Recognition (U+2440-U+245F): + +â‘€â‘⑂⑃⑄⑅⑆⑇⑈⑉⑊⑋⑌â‘â‘Žâ‘â‘⑑⑒⑓⑔⑕⑖⑗⑘⑙⑚⑛⑜â‘â‘žâ‘Ÿ + +Enclosed Alphanumerics (U+2460-U+24FF): + +①②③④⑤⑥⑦⑧⑨⑩⑪⑫⑬⑭⑮⑯⑰⑱⑲⑳⑴⑵⑶⑷⑸⑹⑺⑻⑼⑽⑾⑿⒀â’⒂⒃⒄⒅⒆⒇⒈⒉⒊⒋⒌â’â’Žâ’â’⒑⒒⒓⒔⒕⒖⒗⒘⒙⒚⒛⒜â’â’žâ’Ÿ +⒠⒡⒢⒣⒤⒥⒦⒧⒨⒩⒪⒫⒬⒭⒮⒯⒰⒱⒲⒳⒴⒵ⒶⒷⒸⒹⒺⒻⒼⒽⒾⒿⓀâ“ⓂⓃⓄⓅⓆⓇⓈⓉⓊⓋⓌâ“â“Žâ“â“ⓑⓒⓓⓔⓕⓖⓗⓘⓙⓚⓛⓜâ“â“žâ“Ÿ +ⓠⓡⓢⓣⓤⓥⓦⓧⓨⓩ⓪⓫⓬⓭⓮⓯⓰⓱⓲⓳⓴⓵⓶⓷⓸⓹⓺⓻⓼⓽⓾⓿ + +Box Drawing (U+2500-U+257F): + +─â”│┃┄┅┆┇┈┉┊┋┌â”┎â”â”┑┒┓└┕┖┗┘┙┚┛├â”┞┟┠┡┢┣┤┥┦┧┨┩┪┫┬┭┮┯┰┱┲┳┴┵┶┷┸┹┺┻┼┽┾┿ +â•€â•â•‚╃╄╅╆╇╈╉╊╋╌â•â•Žâ•â•â•‘╒╓╔╕╖╗╘╙╚╛╜â•â•žâ•Ÿâ• â•¡â•¢â•£â•¤â•¥â•¦â•§â•¨â•©â•ªâ•«â•¬â•­â•®â•¯â•°â•±â•²â•³â•´â•µâ•¶â•·â•¸â•¹â•ºâ•»â•¼â•½â•¾â•¿ + +Block Elements (U+2580-U+259F): + +â–€â–▂▃▄▅▆▇█▉▊▋▌â–â–Žâ–â–░▒▓▔▕▖▗▘▙▚▛▜â–â–žâ–Ÿ + +Geometric Shapes (U+25A0-U+25FF): + +■□▢▣▤▥▦▧▨▩▪▫▬▭▮▯▰▱▲△▴▵▶▷▸▹►▻▼▽▾▿◀â—◂◃◄◅◆◇◈◉◊○◌â—â—Žâ—â—◑◒◓◔◕◖◗◘◙◚◛◜â—â—žâ—Ÿ +◠◡◢◣◤◥◦◧◨◩◪◫◬◭◮◯◰◱◲◳◴◵◶◷◸◹◺◻◼◽◾◿ + +Miscellaneous Symbols (U+2600-U+26FF): + +☀â˜â˜‚☃☄★☆☇☈☉☊☋☌â˜â˜Žâ˜â˜â˜‘☒☓☔☕☖☗☘☙☚☛☜â˜â˜žâ˜Ÿâ˜ â˜¡â˜¢â˜£â˜¤â˜¥â˜¦â˜§â˜¨â˜©â˜ªâ˜«â˜¬â˜­â˜®â˜¯â˜°â˜±â˜²â˜³â˜´â˜µâ˜¶â˜·â˜¸â˜¹â˜ºâ˜»â˜¼â˜½â˜¾â˜¿ +♀â™â™‚♃♄♅♆♇♈♉♊♋♌â™â™Žâ™â™â™‘♒♓♔♕♖♗♘♙♚♛♜â™â™žâ™Ÿâ™ â™¡â™¢â™£â™¤â™¥â™¦â™§â™¨â™©â™ªâ™«â™¬â™­â™®â™¯â™°â™±â™²â™³â™´â™µâ™¶â™·â™¸â™¹â™ºâ™»â™¼â™½â™¾â™¿ +⚀âšâš‚⚃⚄⚅⚆⚇⚈⚉⚊⚋⚌âšâšŽâšâšâš‘⚒⚓⚔⚕⚖⚗⚘⚙⚚⚛⚜âšâšžâšŸâš âš¡âš¢âš£âš¤âš¥âš¦âš§âš¨âš©âšªâš«âš¬âš­âš®âš¯âš°âš±âš²âš³âš´âšµâš¶âš·âš¸âš¹âšºâš»âš¼âš½âš¾âš¿ +⛀â›â›‚⛃⛄⛅⛆⛇⛈⛉⛊⛋⛌â›â›Žâ›â›â›‘⛒⛓⛔⛕⛖⛗⛘⛙⛚⛛⛜â›â›žâ›Ÿâ› â›¡â›¢â›£â›¤â›¥â›¦â›§â›¨â›©â›ªâ›«â›¬â›­â›®â›¯â›°â›±â›²â›³â›´â›µâ›¶â›·â›¸â›¹â›ºâ›»â›¼â›½â›¾â›¿ + +Dingbats (U+2700-U+27BF): + +✀âœâœ‚✃✄✅✆✇✈✉✊✋✌âœâœŽâœâœâœ‘✒✓✔✕✖✗✘✙✚✛✜âœâœžâœŸâœ âœ¡âœ¢âœ£âœ¤âœ¥âœ¦âœ§âœ¨âœ©âœªâœ«âœ¬âœ­âœ®âœ¯âœ°âœ±âœ²âœ³âœ´âœµâœ¶âœ·âœ¸âœ¹âœºâœ»âœ¼âœ½âœ¾âœ¿ +â€ââ‚âƒâ„â…â†â‡âˆâ‰âŠâ‹âŒââŽâââ‘â’â“â”â•â–â—â˜â™âšâ›âœââžâŸâ â¡â¢â£â¤â¥â¦â§â¨â©âªâ«â¬â­â®â¯â°â±â²â³â´âµâ¶â·â¸â¹âºâ»â¼â½â¾â¿ +➀âžâž‚➃➄➅➆➇➈➉➊➋➌âžâžŽâžâžâž‘➒➓➔➕➖➗➘➙➚➛➜âžâžžâžŸâž âž¡âž¢âž£âž¤âž¥âž¦âž§âž¨âž©âžªâž«âž¬âž­âž®âž¯âž°âž±âž²âž³âž´âžµâž¶âž·âž¸âž¹âžºâž»âž¼âž½âž¾âž¿ + +Miscellaneous Mathematical Symbols-A (U+27C0-U+27EF): + +⟀âŸâŸ‚⟃⟄⟅⟆⟇⟈⟉⟊⟋⟌âŸâŸŽâŸâŸâŸ‘⟒⟓⟔⟕⟖⟗⟘⟙⟚⟛⟜âŸâŸžâŸŸâŸ âŸ¡âŸ¢âŸ£âŸ¤âŸ¥âŸ¦âŸ§âŸ¨âŸ©âŸªâŸ«âŸ¬âŸ­âŸ®âŸ¯ + +Supplemental Arrows-A (U+27F0-U+27FF): + +⟰⟱⟲⟳⟴⟵⟶⟷⟸⟹⟺⟻⟼⟽⟾⟿ + +Braille Patterns (U+2800-U+28FF): + +â €â â ‚⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌â â Žâ â â ‘⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜â â žâ Ÿâ  â ¡â ¢â £â ¤â ¥â ¦â §â ¨â ©â ªâ «â ¬â ­â ®â ¯â °â ±â ²â ³â ´â µâ ¶â ·â ¸â ¹â ºâ »â ¼â ½â ¾â ¿ +â¡€â¡â¡‚⡃⡄⡅⡆⡇⡈⡉⡊⡋⡌â¡â¡Žâ¡â¡â¡‘⡒⡓⡔⡕⡖⡗⡘⡙⡚⡛⡜â¡â¡žâ¡Ÿâ¡ â¡¡â¡¢â¡£â¡¤â¡¥â¡¦â¡§â¡¨â¡©â¡ªâ¡«â¡¬â¡­â¡®â¡¯â¡°â¡±â¡²â¡³â¡´â¡µâ¡¶â¡·â¡¸â¡¹â¡ºâ¡»â¡¼â¡½â¡¾â¡¿ +⢀â¢â¢‚⢃⢄⢅⢆⢇⢈⢉⢊⢋⢌â¢â¢Žâ¢â¢â¢‘⢒⢓⢔⢕⢖⢗⢘⢙⢚⢛⢜â¢â¢žâ¢Ÿâ¢ â¢¡â¢¢â¢£â¢¤â¢¥â¢¦â¢§â¢¨â¢©â¢ªâ¢«â¢¬â¢­â¢®â¢¯â¢°â¢±â¢²â¢³â¢´â¢µâ¢¶â¢·â¢¸â¢¹â¢ºâ¢»â¢¼â¢½â¢¾â¢¿ +⣀â£â£‚⣃⣄⣅⣆⣇⣈⣉⣊⣋⣌â£â£Žâ£â£â£‘⣒⣓⣔⣕⣖⣗⣘⣙⣚⣛⣜â£â£žâ£Ÿâ£ â£¡â£¢â££â£¤â£¥â£¦â£§â£¨â£©â£ªâ£«â£¬â£­â£®â£¯â£°â£±â£²â£³â£´â£µâ£¶â£·â£¸â£¹â£ºâ£»â£¼â£½â£¾â£¿ + +Supplemental Arrows-B (U+2900-U+297F): + +⤀â¤â¤‚⤃⤄⤅⤆⤇⤈⤉⤊⤋⤌â¤â¤Žâ¤â¤â¤‘⤒⤓⤔⤕⤖⤗⤘⤙⤚⤛⤜â¤â¤žâ¤Ÿâ¤ â¤¡â¤¢â¤£â¤¤â¤¥â¤¦â¤§â¤¨â¤©â¤ªâ¤«â¤¬â¤­â¤®â¤¯â¤°â¤±â¤²â¤³â¤´â¤µâ¤¶â¤·â¤¸â¤¹â¤ºâ¤»â¤¼â¤½â¤¾â¤¿ +⥀â¥â¥‚⥃⥄⥅⥆⥇⥈⥉⥊⥋⥌â¥â¥Žâ¥â¥â¥‘⥒⥓⥔⥕⥖⥗⥘⥙⥚⥛⥜â¥â¥žâ¥Ÿâ¥ â¥¡â¥¢â¥£â¥¤â¥¥â¥¦â¥§â¥¨â¥©â¥ªâ¥«â¥¬â¥­â¥®â¥¯â¥°â¥±â¥²â¥³â¥´â¥µâ¥¶â¥·â¥¸â¥¹â¥ºâ¥»â¥¼â¥½â¥¾â¥¿ + +Miscellaneous Mathematical Symbols-B (U+2980-U+29FF): + +⦀â¦â¦‚⦃⦄⦅⦆⦇⦈⦉⦊⦋⦌â¦â¦Žâ¦â¦â¦‘⦒⦓⦔⦕⦖⦗⦘⦙⦚⦛⦜â¦â¦žâ¦Ÿâ¦ â¦¡â¦¢â¦£â¦¤â¦¥â¦¦â¦§â¦¨â¦©â¦ªâ¦«â¦¬â¦­â¦®â¦¯â¦°â¦±â¦²â¦³â¦´â¦µâ¦¶â¦·â¦¸â¦¹â¦ºâ¦»â¦¼â¦½â¦¾â¦¿ +⧀â§â§‚⧃⧄⧅⧆⧇⧈⧉⧊⧋⧌â§â§Žâ§â§â§‘⧒⧓⧔⧕⧖⧗⧘⧙⧚⧛⧜â§â§žâ§Ÿâ§ â§¡â§¢â§£â§¤â§¥â§¦â§§â§¨â§©â§ªâ§«â§¬â§­â§®â§¯â§°â§±â§²â§³â§´â§µâ§¶â§·â§¸â§¹â§ºâ§»â§¼â§½â§¾â§¿ + +Supplemental Mathematical Operators (U+2A00-U+2AFF): + +⨀â¨â¨‚⨃⨄⨅⨆⨇⨈⨉⨊⨋⨌â¨â¨Žâ¨â¨â¨‘⨒⨓⨔⨕⨖⨗⨘⨙⨚⨛⨜â¨â¨žâ¨Ÿâ¨ â¨¡â¨¢â¨£â¨¤â¨¥â¨¦â¨§â¨¨â¨©â¨ªâ¨«â¨¬â¨­â¨®â¨¯â¨°â¨±â¨²â¨³â¨´â¨µâ¨¶â¨·â¨¸â¨¹â¨ºâ¨»â¨¼â¨½â¨¾â¨¿ +â©€â©â©‚⩃⩄⩅⩆⩇⩈⩉⩊⩋⩌â©â©Žâ©â©â©‘⩒⩓⩔⩕⩖⩗⩘⩙⩚⩛⩜â©â©žâ©Ÿâ© â©¡â©¢â©£â©¤â©¥â©¦â©§â©¨â©©â©ªâ©«â©¬â©­â©®â©¯â©°â©±â©²â©³â©´â©µâ©¶â©·â©¸â©¹â©ºâ©»â©¼â©½â©¾â©¿ +⪀âªâª‚⪃⪄⪅⪆⪇⪈⪉⪊⪋⪌âªâªŽâªâªâª‘⪒⪓⪔⪕⪖⪗⪘⪙⪚⪛⪜âªâªžâªŸâª âª¡âª¢âª£âª¤âª¥âª¦âª§âª¨âª©âªªâª«âª¬âª­âª®âª¯âª°âª±âª²âª³âª´âªµâª¶âª·âª¸âª¹âªºâª»âª¼âª½âª¾âª¿ +â«€â«â«‚⫃⫄⫅⫆⫇⫈⫉⫊⫋⫌â«â«Žâ«â«â«‘⫒⫓⫔⫕⫖⫗⫘⫙⫚⫛⫝̸â«â«žâ«Ÿâ« â«¡â«¢â«£â«¤â«¥â«¦â«§â«¨â«©â«ªâ««â«¬â«­â«®â«¯â«°â«±â«²â«³â«´â«µâ«¶â«·â«¸â«¹â«ºâ«»â«¼â«½â«¾â«¿ + +Miscellaneous Symbols and Arrows (U+2B00-U+2BFF): + +⬀â¬â¬‚⬃⬄⬅⬆⬇⬈⬉⬊⬋⬌â¬â¬Žâ¬â¬â¬‘⬒⬓⬔⬕⬖⬗⬘⬙⬚⬛⬜â¬â¬žâ¬Ÿâ¬ â¬¡â¬¢â¬£â¬¤â¬¥â¬¦â¬§â¬¨â¬©â¬ªâ¬«â¬¬â¬­â¬®â¬¯â¬°â¬±â¬²â¬³â¬´â¬µâ¬¶â¬·â¬¸â¬¹â¬ºâ¬»â¬¼â¬½â¬¾â¬¿ +â­€â­â­‚⭃⭄⭅⭆⭇⭈⭉⭊⭋⭌â­â­Žâ­â­â­‘⭒⭓⭔⭕⭖⭗⭘⭙⭚⭛⭜â­â­žâ­Ÿâ­ â­¡â­¢â­£â­¤â­¥â­¦â­§â­¨â­©â­ªâ­«â­¬â­­â­®â­¯â­°â­±â­²â­³â­´â­µâ­¶â­·â­¸â­¹â­ºâ­»â­¼â­½â­¾â­¿ +⮀â®â®‚⮃⮄⮅⮆⮇⮈⮉⮊⮋⮌â®â®Žâ®â®â®‘⮒⮓⮔⮕⮖⮗⮘⮙⮚⮛⮜â®â®žâ®Ÿâ® â®¡â®¢â®£â®¤â®¥â®¦â®§â®¨â®©â®ªâ®«â®¬â®­â®®â®¯â®°â®±â®²â®³â®´â®µâ®¶â®·â®¸â®¹â®ºâ®»â®¼â®½â®¾â®¿ +⯀â¯â¯‚⯃⯄⯅⯆⯇⯈⯉⯊⯋⯌â¯â¯Žâ¯â¯â¯‘⯒⯓⯔⯕⯖⯗⯘⯙⯚⯛⯜â¯â¯žâ¯Ÿâ¯ â¯¡â¯¢â¯£â¯¤â¯¥â¯¦â¯§â¯¨â¯©â¯ªâ¯«â¯¬â¯­â¯®â¯¯â¯°â¯±â¯²â¯³â¯´â¯µâ¯¶â¯·â¯¸â¯¹â¯ºâ¯»â¯¼â¯½â¯¾â¯¿ + +Free block (U+2C00-U+2E7F): + +â°€â°â°‚ⰃⰄⰅⰆⰇⰈⰉⰊⰋⰌâ°â°Žâ°â°â°‘ⰒⰓⰔⰕⰖⰗⰘⰙⰚⰛⰜâ°â°žâ°Ÿâ° â°¡â°¢â°£â°¤â°¥â°¦â°§â°¨â°©â°ªâ°«â°¬â°­â°®â°¯â°°â°±â°²â°³â°´â°µâ°¶â°·â°¸â°¹â°ºâ°»â°¼â°½â°¾â°¿ +â±€â±â±‚ⱃⱄⱅⱆⱇⱈⱉⱊⱋⱌâ±â±Žâ±â±â±‘ⱒⱓⱔⱕⱖⱗⱘⱙⱚⱛⱜâ±â±žâ±Ÿâ± â±¡â±¢â±£â±¤â±¥â±¦â±§â±¨â±©â±ªâ±«â±¬â±­â±®â±¯â±°â±±â±²â±³â±´â±µâ±¶â±·â±¸â±¹â±ºâ±»â±¼â±½â±¾â±¿ +â²€â²â²‚ⲃⲄⲅⲆⲇⲈⲉⲊⲋⲌâ²â²Žâ²â²â²‘ⲒⲓⲔⲕⲖⲗⲘⲙⲚⲛⲜâ²â²žâ²Ÿâ² â²¡â²¢â²£â²¤â²¥â²¦â²§â²¨â²©â²ªâ²«â²¬â²­â²®â²¯â²°â²±â²²â²³â²´â²µâ²¶â²·â²¸â²¹â²ºâ²»â²¼â²½â²¾â²¿ +â³€â³â³‚ⳃⳄⳅⳆⳇⳈⳉⳊⳋⳌâ³â³Žâ³â³â³‘ⳒⳓⳔⳕⳖⳗⳘⳙⳚⳛⳜâ³â³žâ³Ÿâ³ â³¡â³¢â³£â³¤â³¥â³¦â³§â³¨â³©â³ªâ³«â³¬â³­â³®â³¯â³°â³±â³²â³³â³´â³µâ³¶â³·â³¸â³¹â³ºâ³»â³¼â³½â³¾â³¿ +â´€â´â´‚ⴃⴄⴅⴆⴇⴈⴉⴊⴋⴌâ´â´Žâ´â´â´‘ⴒⴓⴔⴕⴖⴗⴘⴙⴚⴛⴜâ´â´žâ´Ÿâ´ â´¡â´¢â´£â´¤â´¥â´¦â´§â´¨â´©â´ªâ´«â´¬â´­â´®â´¯â´°â´±â´²â´³â´´â´µâ´¶â´·â´¸â´¹â´ºâ´»â´¼â´½â´¾â´¿ +âµ€âµâµ‚ⵃⵄⵅⵆⵇⵈⵉⵊⵋⵌâµâµŽâµâµâµ‘ⵒⵓⵔⵕⵖⵗⵘⵙⵚⵛⵜâµâµžâµŸâµ âµ¡âµ¢âµ£âµ¤âµ¥âµ¦âµ§âµ¨âµ©âµªâµ«âµ¬âµ­âµ®âµ¯âµ°âµ±âµ²âµ³âµ´âµµâµ¶âµ·âµ¸âµ¹âµºâµ»âµ¼âµ½âµ¾âµ¿ +ⶀâ¶â¶‚ⶃⶄⶅⶆⶇⶈⶉⶊⶋⶌâ¶â¶Žâ¶â¶â¶‘ⶒⶓⶔⶕⶖ⶗⶘⶙⶚⶛⶜â¶â¶žâ¶Ÿâ¶ â¶¡â¶¢â¶£â¶¤â¶¥â¶¦â¶§â¶¨â¶©â¶ªâ¶«â¶¬â¶­â¶®â¶¯â¶°â¶±â¶²â¶³â¶´â¶µâ¶¶â¶·â¶¸â¶¹â¶ºâ¶»â¶¼â¶½â¶¾â¶¿ +â·€â·â·‚ⷃⷄⷅⷆ⷇ⷈⷉⷊⷋⷌâ·â·Žâ·â·â·‘ⷒⷓⷔⷕⷖ⷗ⷘⷙⷚⷛⷜâ·â·žâ·Ÿâ· â·¡â·¢â·£â·¤â·¥â·¦â·§â·¨â·©â·ªâ·«â·¬â·­â·®â·¯â·°â·±â·²â·³â·´â·µâ·¶â··â·¸â·¹â·ºâ·»â·¼â·½â·¾â·¿ +⸀â¸â¸‚⸃⸄⸅⸆⸇⸈⸉⸊⸋⸌â¸â¸Žâ¸â¸â¸‘⸒⸓⸔⸕⸖⸗⸘⸙⸚⸛⸜â¸â¸žâ¸Ÿâ¸ â¸¡â¸¢â¸£â¸¤â¸¥â¸¦â¸§â¸¨â¸©â¸ªâ¸«â¸¬â¸­â¸®â¸¯â¸°â¸±â¸²â¸³â¸´â¸µâ¸¶â¸·â¸¸â¸¹â¸ºâ¸»â¸¼â¸½â¸¾â¸¿ +â¹€â¹â¹‚⹃⹄⹅⹆⹇⹈⹉⹊⹋⹌â¹â¹Žâ¹â¹â¹‘⹒⹓⹔⹕⹖⹗⹘⹙⹚⹛⹜â¹â¹žâ¹Ÿâ¹ â¹¡â¹¢â¹£â¹¤â¹¥â¹¦â¹§â¹¨â¹©â¹ªâ¹«â¹¬â¹­â¹®â¹¯â¹°â¹±â¹²â¹³â¹´â¹µâ¹¶â¹·â¹¸â¹¹â¹ºâ¹»â¹¼â¹½â¹¾â¹¿ + +CJK Radicals Supplement (U+2E80-U+2EFF): + +⺀âºâº‚⺃⺄⺅⺆⺇⺈⺉⺊⺋⺌âºâºŽâºâºâº‘⺒⺓⺔⺕⺖⺗⺘⺙⺚⺛⺜âºâºžâºŸ +⺠⺡⺢⺣⺤⺥⺦⺧⺨⺩⺪⺫⺬⺭⺮⺯⺰⺱⺲⺳⺴⺵⺶⺷⺸⺹⺺⺻⺼⺽⺾⺿ +⻀â»â»‚⻃⻄⻅⻆⻇⻈⻉⻊⻋⻌â»â»Žâ»â»â»‘⻒⻓⻔⻕⻖⻗⻘⻙⻚⻛⻜â»â»žâ»Ÿ +⻠⻡⻢⻣⻤⻥⻦⻧⻨⻩⻪⻫⻬⻭⻮⻯⻰⻱⻲⻳⻴⻵⻶⻷⻸⻹⻺⻻⻼⻽⻾⻿ + +Kangxi Radicals (U+2F00-U+2FDF): + +â¼€â¼â¼‚⼃⼄⼅⼆⼇⼈⼉⼊⼋⼌â¼â¼Žâ¼â¼â¼‘⼒⼓⼔⼕⼖⼗⼘⼙⼚⼛⼜â¼â¼žâ¼Ÿ +⼠⼡⼢⼣⼤⼥⼦⼧⼨⼩⼪⼫⼬⼭⼮⼯⼰⼱⼲⼳⼴⼵⼶⼷⼸⼹⼺⼻⼼⼽⼾⼿ +â½€â½â½‚⽃⽄⽅⽆⽇⽈⽉⽊⽋⽌â½â½Žâ½â½â½‘⽒⽓⽔⽕⽖⽗⽘⽙⽚⽛⽜â½â½žâ½Ÿ +⽠⽡⽢⽣⽤⽥⽦⽧⽨⽩⽪⽫⽬⽭⽮⽯⽰⽱⽲⽳⽴⽵⽶⽷⽸⽹⽺⽻⽼⽽⽾⽿ +â¾€â¾â¾‚⾃⾄⾅⾆⾇⾈⾉⾊⾋⾌â¾â¾Žâ¾â¾â¾‘⾒⾓⾔⾕⾖⾗⾘⾙⾚⾛⾜â¾â¾žâ¾Ÿ +⾠⾡⾢⾣⾤⾥⾦⾧⾨⾩⾪⾫⾬⾭⾮⾯⾰⾱⾲⾳⾴⾵⾶⾷⾸⾹⾺⾻⾼⾽⾾⾿ +â¿€â¿â¿‚⿃⿄⿅⿆⿇⿈⿉⿊⿋⿌â¿â¿Žâ¿â¿â¿‘⿒⿓⿔⿕⿖⿗⿘⿙⿚⿛⿜â¿â¿žâ¿Ÿ + +Free block (U+2FE0-U+2FEF): + +⿠⿡⿢⿣⿤⿥⿦⿧⿨⿩⿪⿫⿬⿭⿮⿯ + +Ideographic Description Characters (U+2FF0-U+2FFF): + +⿰⿱⿲⿳⿴⿵⿶⿷⿸⿹⿺⿻⿼⿽⿾⿿ + +CJK Symbols and Punctuation (U+3000-U+303F): + + ã€ã€‚〃〄々〆〇〈〉《》「ã€ã€Žã€ã€ã€‘〒〓〔〕〖〗〘〙〚〛〜ã€ã€žã€Ÿ +〠〡〢〣〤〥〦〧〨〩◌〪◌〫◌〬◌〭◌〮◌〯〰〱〲〳〴〵〶〷〸〹〺〻〼〽〾〿 + +Hiragana (U+3040-U+309F): + +ã€ãã‚ãƒã„ã…ã†ã‡ãˆã‰ãŠã‹ãŒããŽããã‘ã’ã“ã”ã•ã–ã—ã˜ã™ãšã›ãœããžãŸ +ã ã¡ã¢ã£ã¤ã¥ã¦ã§ã¨ã©ãªã«ã¬ã­ã®ã¯ã°ã±ã²ã³ã´ãµã¶ã·ã¸ã¹ãºã»ã¼ã½ã¾ã¿ +ã‚€ã‚もゃやゅゆょよらりるれã‚ã‚Žã‚ã‚ゑをんゔゕゖ゗゘◌゙◌゚゛゜ã‚ã‚žã‚Ÿ + +Katakana (U+30A0-U+30FF): + +゠ァアィイゥウェエォオカガキギクグケゲコゴサザシジスズセゼソゾタ +ダãƒãƒ‚ッツヅテデトドナニヌãƒãƒŽãƒãƒãƒ‘ヒビピフブプヘベペホボãƒãƒžãƒŸ +ムメモャヤュユョヨラリルレロヮワヰヱヲンヴヵヶヷヸヹヺ・ーヽヾヿ + +Bopomofo (U+3100-U+312F): + +ã„€ã„㄂㄃㄄ㄅㄆㄇㄈㄉㄊㄋㄌã„ã„Žã„ã„ㄑㄒㄓㄔㄕㄖㄗㄘㄙㄚㄛㄜã„ã„žã„Ÿ +ㄠㄡㄢㄣㄤㄥㄦㄧㄨㄩㄪㄫㄬㄭㄮㄯ + +Hangul Compatibility Jamo (U+3130-U+318F): + +㄰ㄱㄲㄳㄴㄵㄶㄷㄸㄹㄺㄻㄼㄽㄾㄿㅀã…ㅂㅃㅄㅅㅆㅇㅈㅉㅊㅋㅌã…ã…Žã… +ã…ㅑㅒㅓㅔㅕㅖㅗㅘㅙㅚㅛㅜã…ㅞㅟㅠㅡㅢㅣㅤㅥㅦㅧㅨㅩㅪㅫㅬㅭㅮㅯ +ㅰㅱㅲㅳㅴㅵㅶㅷㅸㅹㅺㅻㅼㅽㅾㅿㆀã†ã†‚ㆃㆄㆅㆆㆇㆈㆉㆊㆋㆌã†ã†Žã† + +Kanbun (U+3190-U+319F): + +ã†ã†‘㆒㆓㆔㆕㆖㆗㆘㆙㆚㆛㆜ã†ã†žã†Ÿ + +Bopomofo Extended (U+31A0-U+31BF): + +ㆠㆡㆢㆣㆤㆥㆦㆧㆨㆩㆪㆫㆬㆭㆮㆯㆰㆱㆲㆳㆴㆵㆶㆷㆸㆹㆺㆻㆼㆽㆾㆿ + +Free block (U+31C0-U+31EF): + +㇀ã‡ã‡‚㇃㇄㇅㇆㇇㇈㇉㇊㇋㇌ã‡ã‡Žã‡ã‡ã‡‘㇒㇓㇔㇕㇖㇗㇘㇙㇚㇛㇜ã‡ã‡žã‡Ÿ +㇠㇡㇢㇣㇤㇥㇦㇧㇨㇩㇪㇫㇬㇭㇮㇯ + +Katakana Phonetic Extensions (U+31F0-U+31FF): + +ㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ + +Enclosed CJK Letters and Months (U+3200-U+32FF): + +㈀ãˆãˆ‚㈃㈄㈅㈆㈇㈈㈉㈊㈋㈌ãˆãˆŽãˆãˆãˆ‘㈒㈓㈔㈕㈖㈗㈘㈙㈚㈛㈜ãˆãˆžãˆŸ +㈠㈡㈢㈣㈤㈥㈦㈧㈨㈩㈪㈫㈬㈭㈮㈯㈰㈱㈲㈳㈴㈵㈶㈷㈸㈹㈺㈻㈼㈽㈾㈿ +㉀ã‰ã‰‚㉃㉄㉅㉆㉇㉈㉉㉊㉋㉌ã‰ã‰Žã‰ã‰ã‰‘㉒㉓㉔㉕㉖㉗㉘㉙㉚㉛㉜ã‰ã‰žã‰Ÿ +㉠㉡㉢㉣㉤㉥㉦㉧㉨㉩㉪㉫㉬㉭㉮㉯㉰㉱㉲㉳㉴㉵㉶㉷㉸㉹㉺㉻㉼㉽㉾㉿ +㊀ãŠãŠ‚㊃㊄㊅㊆㊇㊈㊉㊊㊋㊌ãŠãŠŽãŠãŠãŠ‘㊒㊓㊔㊕㊖㊗㊘㊙㊚㊛㊜ãŠãŠžãŠŸ +㊠㊡㊢㊣㊤㊥㊦㊧㊨㊩㊪㊫㊬㊭㊮㊯㊰㊱㊲㊳㊴㊵㊶㊷㊸㊹㊺㊻㊼㊽㊾㊿ +ã‹€ã‹ã‹‚㋃㋄㋅㋆㋇㋈㋉㋊㋋㋌ã‹ã‹Žã‹ã‹ã‹‘㋒㋓㋔㋕㋖㋗㋘㋙㋚㋛㋜ã‹ã‹žã‹Ÿ +㋠㋡㋢㋣㋤㋥㋦㋧㋨㋩㋪㋫㋬㋭㋮㋯㋰㋱㋲㋳㋴㋵㋶㋷㋸㋹㋺㋻㋼㋽㋾㋿ + +CJK Compatibility (U+3300-U+33FF): + +㌀ãŒãŒ‚㌃㌄㌅㌆㌇㌈㌉㌊㌋㌌ãŒãŒŽãŒãŒãŒ‘㌒㌓㌔㌕㌖㌗㌘㌙㌚㌛㌜ãŒãŒžãŒŸ +㌠㌡㌢㌣㌤㌥㌦㌧㌨㌩㌪㌫㌬㌭㌮㌯㌰㌱㌲㌳㌴㌵㌶㌷㌸㌹㌺㌻㌼㌽㌾㌿ +ã€ãã‚ãƒã„ã…ã†ã‡ãˆã‰ãŠã‹ãŒããŽããã‘ã’ã“ã”ã•ã–ã—ã˜ã™ãšã›ãœããžãŸ +ã ã¡ã¢ã£ã¤ã¥ã¦ã§ã¨ã©ãªã«ã¬ã­ã®ã¯ã°ã±ã²ã³ã´ãµã¶ã·ã¸ã¹ãºã»ã¼ã½ã¾ã¿ +㎀ãŽãŽ‚㎃㎄㎅㎆㎇㎈㎉㎊㎋㎌ãŽãŽŽãŽãŽãŽ‘㎒㎓㎔㎕㎖㎗㎘㎙㎚㎛㎜ãŽãŽžãŽŸ +㎠㎡㎢㎣㎤㎥㎦㎧㎨㎩㎪㎫㎬㎭㎮㎯㎰㎱㎲㎳㎴㎵㎶㎷㎸㎹㎺㎻㎼㎽㎾㎿ +ã€ãã‚ãƒã„ã…ã†ã‡ãˆã‰ãŠã‹ãŒããŽããã‘ã’ã“ã”ã•ã–ã—ã˜ã™ãšã›ãœããžãŸ +ã ã¡ã¢ã£ã¤ã¥ã¦ã§ã¨ã©ãªã«ã¬ã­ã®ã¯ã°ã±ã²ã³ã´ãµã¶ã·ã¸ã¹ãºã»ã¼ã½ã¾ã¿ + +CJK Unified Ideographs Extension A (U+3400-U+4DBF): + +ã€ãã‚ãƒã„ã…ã†ã‡ãˆã‰ãŠã‹ãŒããŽããã‘ã’ã“ã”ã•ã–ã—ã˜ã™ãšã›ãœããžãŸ +ã ã¡ã¢ã£ã¤ã¥ã¦ã§ã¨ã©ãªã«ã¬ã­ã®ã¯ã°ã±ã²ã³ã´ãµã¶ã·ã¸ã¹ãºã»ã¼ã½ã¾ã¿ +ã‘€ã‘㑂㑃㑄㑅㑆㑇㑈㑉㑊㑋㑌ã‘ã‘Žã‘ã‘㑑㑒㑓㑔㑕㑖㑗㑘㑙㑚㑛㑜ã‘ã‘žã‘Ÿ +㑠㑡㑢㑣㑤㑥㑦㑧㑨㑩㑪㑫㑬㑭㑮㑯㑰㑱㑲㑳㑴㑵㑶㑷㑸㑹㑺㑻㑼㑽㑾㑿 +ã’€ã’㒂㒃㒄㒅㒆㒇㒈㒉㒊㒋㒌ã’ã’Žã’ã’㒑㒒㒓㒔㒕㒖㒗㒘㒙㒚㒛㒜ã’ã’žã’Ÿ +㒠㒡㒢㒣㒤㒥㒦㒧㒨㒩㒪㒫㒬㒭㒮㒯㒰㒱㒲㒳㒴㒵㒶㒷㒸㒹㒺㒻㒼㒽㒾㒿 +ã“€ã“㓂㓃㓄㓅㓆㓇㓈㓉㓊㓋㓌ã“ã“Žã“ã“㓑㓒㓓㓔㓕㓖㓗㓘㓙㓚㓛㓜ã“ã“žã“Ÿ +㓠㓡㓢㓣㓤㓥㓦㓧㓨㓩㓪㓫㓬㓭㓮㓯㓰㓱㓲㓳㓴㓵㓶㓷㓸㓹㓺㓻㓼㓽㓾㓿 +㔀ã”㔂㔃㔄㔅㔆㔇㔈㔉㔊㔋㔌ã”㔎ã”ã”㔑㔒㔓㔔㔕㔖㔗㔘㔙㔚㔛㔜ã”㔞㔟 +㔠㔡㔢㔣㔤㔥㔦㔧㔨㔩㔪㔫㔬㔭㔮㔯㔰㔱㔲㔳㔴㔵㔶㔷㔸㔹㔺㔻㔼㔽㔾㔿 +ã•€ã•ã•‚㕃㕄㕅㕆㕇㕈㕉㕊㕋㕌ã•ã•Žã•ã•ã•‘㕒㕓㕔㕕㕖㕗㕘㕙㕚㕛㕜ã•ã•žã•Ÿ +㕠㕡㕢㕣㕤㕥㕦㕧㕨㕩㕪㕫㕬㕭㕮㕯㕰㕱㕲㕳㕴㕵㕶㕷㕸㕹㕺㕻㕼㕽㕾㕿 +ã–€ã–㖂㖃㖄㖅㖆㖇㖈㖉㖊㖋㖌ã–ã–Žã–ã–㖑㖒㖓㖔㖕㖖㖗㖘㖙㖚㖛㖜ã–ã–žã–Ÿ +㖠㖡㖢㖣㖤㖥㖦㖧㖨㖩㖪㖫㖬㖭㖮㖯㖰㖱㖲㖳㖴㖵㖶㖷㖸㖹㖺㖻㖼㖽㖾㖿 +ã—€ã—㗂㗃㗄㗅㗆㗇㗈㗉㗊㗋㗌ã—ã—Žã—ã—㗑㗒㗓㗔㗕㗖㗗㗘㗙㗚㗛㗜ã—ã—žã—Ÿ +㗠㗡㗢㗣㗤㗥㗦㗧㗨㗩㗪㗫㗬㗭㗮㗯㗰㗱㗲㗳㗴㗵㗶㗷㗸㗹㗺㗻㗼㗽㗾㗿 +㘀ã˜ã˜‚㘃㘄㘅㘆㘇㘈㘉㘊㘋㘌ã˜ã˜Žã˜ã˜ã˜‘㘒㘓㘔㘕㘖㘗㘘㘙㘚㘛㘜ã˜ã˜žã˜Ÿ +㘠㘡㘢㘣㘤㘥㘦㘧㘨㘩㘪㘫㘬㘭㘮㘯㘰㘱㘲㘳㘴㘵㘶㘷㘸㘹㘺㘻㘼㘽㘾㘿 +㙀ã™ã™‚㙃㙄㙅㙆㙇㙈㙉㙊㙋㙌ã™ã™Žã™ã™ã™‘㙒㙓㙔㙕㙖㙗㙘㙙㙚㙛㙜ã™ã™žã™Ÿ +㙠㙡㙢㙣㙤㙥㙦㙧㙨㙩㙪㙫㙬㙭㙮㙯㙰㙱㙲㙳㙴㙵㙶㙷㙸㙹㙺㙻㙼㙽㙾㙿 +㚀ãšãš‚㚃㚄㚅㚆㚇㚈㚉㚊㚋㚌ãšãšŽãšãšãš‘㚒㚓㚔㚕㚖㚗㚘㚙㚚㚛㚜ãšãšžãšŸ +㚠㚡㚢㚣㚤㚥㚦㚧㚨㚩㚪㚫㚬㚭㚮㚯㚰㚱㚲㚳㚴㚵㚶㚷㚸㚹㚺㚻㚼㚽㚾㚿 +㛀ã›ã›‚㛃㛄㛅㛆㛇㛈㛉㛊㛋㛌ã›ã›Žã›ã›ã›‘㛒㛓㛔㛕㛖㛗㛘㛙㛚㛛㛜ã›ã›žã›Ÿ +㛠㛡㛢㛣㛤㛥㛦㛧㛨㛩㛪㛫㛬㛭㛮㛯㛰㛱㛲㛳㛴㛵㛶㛷㛸㛹㛺㛻㛼㛽㛾㛿 +㜀ãœãœ‚㜃㜄㜅㜆㜇㜈㜉㜊㜋㜌ãœãœŽãœãœãœ‘㜒㜓㜔㜕㜖㜗㜘㜙㜚㜛㜜ãœãœžãœŸ +㜠㜡㜢㜣㜤㜥㜦㜧㜨㜩㜪㜫㜬㜭㜮㜯㜰㜱㜲㜳㜴㜵㜶㜷㜸㜹㜺㜻㜼㜽㜾㜿 +ã€ãã‚ãƒã„ã…ã†ã‡ãˆã‰ãŠã‹ãŒããŽããã‘ã’ã“ã”ã•ã–ã—ã˜ã™ãšã›ãœããžãŸ +ã ã¡ã¢ã£ã¤ã¥ã¦ã§ã¨ã©ãªã«ã¬ã­ã®ã¯ã°ã±ã²ã³ã´ãµã¶ã·ã¸ã¹ãºã»ã¼ã½ã¾ã¿ +㞀ãžãž‚㞃㞄㞅㞆㞇㞈㞉㞊㞋㞌ãžãžŽãžãžãž‘㞒㞓㞔㞕㞖㞗㞘㞙㞚㞛㞜ãžãžžãžŸ +㞠㞡㞢㞣㞤㞥㞦㞧㞨㞩㞪㞫㞬㞭㞮㞯㞰㞱㞲㞳㞴㞵㞶㞷㞸㞹㞺㞻㞼㞽㞾㞿 +㟀ãŸãŸ‚㟃㟄㟅㟆㟇㟈㟉㟊㟋㟌ãŸãŸŽãŸãŸãŸ‘㟒㟓㟔㟕㟖㟗㟘㟙㟚㟛㟜ãŸãŸžãŸŸ +㟠㟡㟢㟣㟤㟥㟦㟧㟨㟩㟪㟫㟬㟭㟮㟯㟰㟱㟲㟳㟴㟵㟶㟷㟸㟹㟺㟻㟼㟽㟾㟿 +ã €ã ã ‚㠃㠄㠅㠆㠇㠈㠉㠊㠋㠌ã ã Žã ã ã ‘㠒㠓㠔㠕㠖㠗㠘㠙㠚㠛㠜ã ã žã Ÿ +㠠㠡㠢㠣㠤㠥㠦㠧㠨㠩㠪㠫㠬㠭㠮㠯㠰㠱㠲㠳㠴㠵㠶㠷㠸㠹㠺㠻㠼㠽㠾㠿 +ã¡€ã¡ã¡‚㡃㡄㡅㡆㡇㡈㡉㡊㡋㡌ã¡ã¡Žã¡ã¡ã¡‘㡒㡓㡔㡕㡖㡗㡘㡙㡚㡛㡜ã¡ã¡žã¡Ÿ +㡠㡡㡢㡣㡤㡥㡦㡧㡨㡩㡪㡫㡬㡭㡮㡯㡰㡱㡲㡳㡴㡵㡶㡷㡸㡹㡺㡻㡼㡽㡾㡿 +㢀ã¢ã¢‚㢃㢄㢅㢆㢇㢈㢉㢊㢋㢌ã¢ã¢Žã¢ã¢ã¢‘㢒㢓㢔㢕㢖㢗㢘㢙㢚㢛㢜ã¢ã¢žã¢Ÿ +㢠㢡㢢㢣㢤㢥㢦㢧㢨㢩㢪㢫㢬㢭㢮㢯㢰㢱㢲㢳㢴㢵㢶㢷㢸㢹㢺㢻㢼㢽㢾㢿 +㣀ã£ã£‚㣃㣄㣅㣆㣇㣈㣉㣊㣋㣌ã£ã£Žã£ã£ã£‘㣒㣓㣔㣕㣖㣗㣘㣙㣚㣛㣜ã£ã£žã£Ÿ +㣠㣡㣢㣣㣤㣥㣦㣧㣨㣩㣪㣫㣬㣭㣮㣯㣰㣱㣲㣳㣴㣵㣶㣷㣸㣹㣺㣻㣼㣽㣾㣿 +㤀ã¤ã¤‚㤃㤄㤅㤆㤇㤈㤉㤊㤋㤌ã¤ã¤Žã¤ã¤ã¤‘㤒㤓㤔㤕㤖㤗㤘㤙㤚㤛㤜ã¤ã¤žã¤Ÿ +㤠㤡㤢㤣㤤㤥㤦㤧㤨㤩㤪㤫㤬㤭㤮㤯㤰㤱㤲㤳㤴㤵㤶㤷㤸㤹㤺㤻㤼㤽㤾㤿 +㥀ã¥ã¥‚㥃㥄㥅㥆㥇㥈㥉㥊㥋㥌ã¥ã¥Žã¥ã¥ã¥‘㥒㥓㥔㥕㥖㥗㥘㥙㥚㥛㥜ã¥ã¥žã¥Ÿ +㥠㥡㥢㥣㥤㥥㥦㥧㥨㥩㥪㥫㥬㥭㥮㥯㥰㥱㥲㥳㥴㥵㥶㥷㥸㥹㥺㥻㥼㥽㥾㥿 +㦀ã¦ã¦‚㦃㦄㦅㦆㦇㦈㦉㦊㦋㦌ã¦ã¦Žã¦ã¦ã¦‘㦒㦓㦔㦕㦖㦗㦘㦙㦚㦛㦜ã¦ã¦žã¦Ÿ +㦠㦡㦢㦣㦤㦥㦦㦧㦨㦩㦪㦫㦬㦭㦮㦯㦰㦱㦲㦳㦴㦵㦶㦷㦸㦹㦺㦻㦼㦽㦾㦿 +㧀ã§ã§‚㧃㧄㧅㧆㧇㧈㧉㧊㧋㧌ã§ã§Žã§ã§ã§‘㧒㧓㧔㧕㧖㧗㧘㧙㧚㧛㧜ã§ã§žã§Ÿ +㧠㧡㧢㧣㧤㧥㧦㧧㧨㧩㧪㧫㧬㧭㧮㧯㧰㧱㧲㧳㧴㧵㧶㧷㧸㧹㧺㧻㧼㧽㧾㧿 +㨀ã¨ã¨‚㨃㨄㨅㨆㨇㨈㨉㨊㨋㨌ã¨ã¨Žã¨ã¨ã¨‘㨒㨓㨔㨕㨖㨗㨘㨙㨚㨛㨜ã¨ã¨žã¨Ÿ +㨠㨡㨢㨣㨤㨥㨦㨧㨨㨩㨪㨫㨬㨭㨮㨯㨰㨱㨲㨳㨴㨵㨶㨷㨸㨹㨺㨻㨼㨽㨾㨿 +ã©€ã©ã©‚㩃㩄㩅㩆㩇㩈㩉㩊㩋㩌ã©ã©Žã©ã©ã©‘㩒㩓㩔㩕㩖㩗㩘㩙㩚㩛㩜ã©ã©žã©Ÿ +㩠㩡㩢㩣㩤㩥㩦㩧㩨㩩㩪㩫㩬㩭㩮㩯㩰㩱㩲㩳㩴㩵㩶㩷㩸㩹㩺㩻㩼㩽㩾㩿 +㪀ãªãª‚㪃㪄㪅㪆㪇㪈㪉㪊㪋㪌ãªãªŽãªãªãª‘㪒㪓㪔㪕㪖㪗㪘㪙㪚㪛㪜ãªãªžãªŸ +㪠㪡㪢㪣㪤㪥㪦㪧㪨㪩㪪㪫㪬㪭㪮㪯㪰㪱㪲㪳㪴㪵㪶㪷㪸㪹㪺㪻㪼㪽㪾㪿 +ã«€ã«ã«‚㫃㫄㫅㫆㫇㫈㫉㫊㫋㫌ã«ã«Žã«ã«ã«‘㫒㫓㫔㫕㫖㫗㫘㫙㫚㫛㫜ã«ã«žã«Ÿ +㫠㫡㫢㫣㫤㫥㫦㫧㫨㫩㫪㫫㫬㫭㫮㫯㫰㫱㫲㫳㫴㫵㫶㫷㫸㫹㫺㫻㫼㫽㫾㫿 +㬀ã¬ã¬‚㬃㬄㬅㬆㬇㬈㬉㬊㬋㬌ã¬ã¬Žã¬ã¬ã¬‘㬒㬓㬔㬕㬖㬗㬘㬙㬚㬛㬜ã¬ã¬žã¬Ÿ +㬠㬡㬢㬣㬤㬥㬦㬧㬨㬩㬪㬫㬬㬭㬮㬯㬰㬱㬲㬳㬴㬵㬶㬷㬸㬹㬺㬻㬼㬽㬾㬿 +ã­€ã­ã­‚㭃㭄㭅㭆㭇㭈㭉㭊㭋㭌ã­ã­Žã­ã­ã­‘㭒㭓㭔㭕㭖㭗㭘㭙㭚㭛㭜ã­ã­žã­Ÿ +㭠㭡㭢㭣㭤㭥㭦㭧㭨㭩㭪㭫㭬㭭㭮㭯㭰㭱㭲㭳㭴㭵㭶㭷㭸㭹㭺㭻㭼㭽㭾㭿 +㮀ã®ã®‚㮃㮄㮅㮆㮇㮈㮉㮊㮋㮌ã®ã®Žã®ã®ã®‘㮒㮓㮔㮕㮖㮗㮘㮙㮚㮛㮜ã®ã®žã®Ÿ +㮠㮡㮢㮣㮤㮥㮦㮧㮨㮩㮪㮫㮬㮭㮮㮯㮰㮱㮲㮳㮴㮵㮶㮷㮸㮹㮺㮻㮼㮽㮾㮿 +㯀ã¯ã¯‚㯃㯄㯅㯆㯇㯈㯉㯊㯋㯌ã¯ã¯Žã¯ã¯ã¯‘㯒㯓㯔㯕㯖㯗㯘㯙㯚㯛㯜ã¯ã¯žã¯Ÿ +㯠㯡㯢㯣㯤㯥㯦㯧㯨㯩㯪㯫㯬㯭㯮㯯㯰㯱㯲㯳㯴㯵㯶㯷㯸㯹㯺㯻㯼㯽㯾㯿 +ã°€ã°ã°‚㰃㰄㰅㰆㰇㰈㰉㰊㰋㰌ã°ã°Žã°ã°ã°‘㰒㰓㰔㰕㰖㰗㰘㰙㰚㰛㰜ã°ã°žã°Ÿ +㰠㰡㰢㰣㰤㰥㰦㰧㰨㰩㰪㰫㰬㰭㰮㰯㰰㰱㰲㰳㰴㰵㰶㰷㰸㰹㰺㰻㰼㰽㰾㰿 +ã±€ã±ã±‚㱃㱄㱅㱆㱇㱈㱉㱊㱋㱌ã±ã±Žã±ã±ã±‘㱒㱓㱔㱕㱖㱗㱘㱙㱚㱛㱜ã±ã±žã±Ÿ +㱠㱡㱢㱣㱤㱥㱦㱧㱨㱩㱪㱫㱬㱭㱮㱯㱰㱱㱲㱳㱴㱵㱶㱷㱸㱹㱺㱻㱼㱽㱾㱿 +ã²€ã²ã²‚㲃㲄㲅㲆㲇㲈㲉㲊㲋㲌ã²ã²Žã²ã²ã²‘㲒㲓㲔㲕㲖㲗㲘㲙㲚㲛㲜ã²ã²žã²Ÿ +㲠㲡㲢㲣㲤㲥㲦㲧㲨㲩㲪㲫㲬㲭㲮㲯㲰㲱㲲㲳㲴㲵㲶㲷㲸㲹㲺㲻㲼㲽㲾㲿 +ã³€ã³ã³‚㳃㳄㳅㳆㳇㳈㳉㳊㳋㳌ã³ã³Žã³ã³ã³‘㳒㳓㳔㳕㳖㳗㳘㳙㳚㳛㳜ã³ã³žã³Ÿ +㳠㳡㳢㳣㳤㳥㳦㳧㳨㳩㳪㳫㳬㳭㳮㳯㳰㳱㳲㳳㳴㳵㳶㳷㳸㳹㳺㳻㳼㳽㳾㳿 +ã´€ã´ã´‚㴃㴄㴅㴆㴇㴈㴉㴊㴋㴌ã´ã´Žã´ã´ã´‘㴒㴓㴔㴕㴖㴗㴘㴙㴚㴛㴜ã´ã´žã´Ÿ +㴠㴡㴢㴣㴤㴥㴦㴧㴨㴩㴪㴫㴬㴭㴮㴯㴰㴱㴲㴳㴴㴵㴶㴷㴸㴹㴺㴻㴼㴽㴾㴿 +ãµ€ãµãµ‚㵃㵄㵅㵆㵇㵈㵉㵊㵋㵌ãµãµŽãµãµãµ‘㵒㵓㵔㵕㵖㵗㵘㵙㵚㵛㵜ãµãµžãµŸ +㵠㵡㵢㵣㵤㵥㵦㵧㵨㵩㵪㵫㵬㵭㵮㵯㵰㵱㵲㵳㵴㵵㵶㵷㵸㵹㵺㵻㵼㵽㵾㵿 +㶀ã¶ã¶‚㶃㶄㶅㶆㶇㶈㶉㶊㶋㶌ã¶ã¶Žã¶ã¶ã¶‘㶒㶓㶔㶕㶖㶗㶘㶙㶚㶛㶜ã¶ã¶žã¶Ÿ +㶠㶡㶢㶣㶤㶥㶦㶧㶨㶩㶪㶫㶬㶭㶮㶯㶰㶱㶲㶳㶴㶵㶶㶷㶸㶹㶺㶻㶼㶽㶾㶿 +ã·€ã·ã·‚㷃㷄㷅㷆㷇㷈㷉㷊㷋㷌ã·ã·Žã·ã·ã·‘㷒㷓㷔㷕㷖㷗㷘㷙㷚㷛㷜ã·ã·žã·Ÿ +㷠㷡㷢㷣㷤㷥㷦㷧㷨㷩㷪㷫㷬㷭㷮㷯㷰㷱㷲㷳㷴㷵㷶㷷㷸㷹㷺㷻㷼㷽㷾㷿 +㸀ã¸ã¸‚㸃㸄㸅㸆㸇㸈㸉㸊㸋㸌ã¸ã¸Žã¸ã¸ã¸‘㸒㸓㸔㸕㸖㸗㸘㸙㸚㸛㸜ã¸ã¸žã¸Ÿ +㸠㸡㸢㸣㸤㸥㸦㸧㸨㸩㸪㸫㸬㸭㸮㸯㸰㸱㸲㸳㸴㸵㸶㸷㸸㸹㸺㸻㸼㸽㸾㸿 +ã¹€ã¹ã¹‚㹃㹄㹅㹆㹇㹈㹉㹊㹋㹌ã¹ã¹Žã¹ã¹ã¹‘㹒㹓㹔㹕㹖㹗㹘㹙㹚㹛㹜ã¹ã¹žã¹Ÿ +㹠㹡㹢㹣㹤㹥㹦㹧㹨㹩㹪㹫㹬㹭㹮㹯㹰㹱㹲㹳㹴㹵㹶㹷㹸㹹㹺㹻㹼㹽㹾㹿 +㺀ãºãº‚㺃㺄㺅㺆㺇㺈㺉㺊㺋㺌ãºãºŽãºãºãº‘㺒㺓㺔㺕㺖㺗㺘㺙㺚㺛㺜ãºãºžãºŸ +㺠㺡㺢㺣㺤㺥㺦㺧㺨㺩㺪㺫㺬㺭㺮㺯㺰㺱㺲㺳㺴㺵㺶㺷㺸㺹㺺㺻㺼㺽㺾㺿 +㻀ã»ã»‚㻃㻄㻅㻆㻇㻈㻉㻊㻋㻌ã»ã»Žã»ã»ã»‘㻒㻓㻔㻕㻖㻗㻘㻙㻚㻛㻜ã»ã»žã»Ÿ +㻠㻡㻢㻣㻤㻥㻦㻧㻨㻩㻪㻫㻬㻭㻮㻯㻰㻱㻲㻳㻴㻵㻶㻷㻸㻹㻺㻻㻼㻽㻾㻿 +ã¼€ã¼ã¼‚㼃㼄㼅㼆㼇㼈㼉㼊㼋㼌ã¼ã¼Žã¼ã¼ã¼‘㼒㼓㼔㼕㼖㼗㼘㼙㼚㼛㼜ã¼ã¼žã¼Ÿ +㼠㼡㼢㼣㼤㼥㼦㼧㼨㼩㼪㼫㼬㼭㼮㼯㼰㼱㼲㼳㼴㼵㼶㼷㼸㼹㼺㼻㼼㼽㼾㼿 +ã½€ã½ã½‚㽃㽄㽅㽆㽇㽈㽉㽊㽋㽌ã½ã½Žã½ã½ã½‘㽒㽓㽔㽕㽖㽗㽘㽙㽚㽛㽜ã½ã½žã½Ÿ +㽠㽡㽢㽣㽤㽥㽦㽧㽨㽩㽪㽫㽬㽭㽮㽯㽰㽱㽲㽳㽴㽵㽶㽷㽸㽹㽺㽻㽼㽽㽾㽿 +ã¾€ã¾ã¾‚㾃㾄㾅㾆㾇㾈㾉㾊㾋㾌ã¾ã¾Žã¾ã¾ã¾‘㾒㾓㾔㾕㾖㾗㾘㾙㾚㾛㾜ã¾ã¾žã¾Ÿ +㾠㾡㾢㾣㾤㾥㾦㾧㾨㾩㾪㾫㾬㾭㾮㾯㾰㾱㾲㾳㾴㾵㾶㾷㾸㾹㾺㾻㾼㾽㾾㾿 +ã¿€ã¿ã¿‚㿃㿄㿅㿆㿇㿈㿉㿊㿋㿌ã¿ã¿Žã¿ã¿ã¿‘㿒㿓㿔㿕㿖㿗㿘㿙㿚㿛㿜ã¿ã¿žã¿Ÿ +㿠㿡㿢㿣㿤㿥㿦㿧㿨㿩㿪㿫㿬㿭㿮㿯㿰㿱㿲㿳㿴㿵㿶㿷㿸㿹㿺㿻㿼㿽㿾㿿 +䀀ä€ä€‚䀃䀄䀅䀆䀇䀈䀉䀊䀋䀌ä€ä€Žä€ä€ä€‘䀒䀓䀔䀕䀖䀗䀘䀙䀚䀛䀜ä€ä€žä€Ÿ +䀠䀡䀢䀣䀤䀥䀦䀧䀨䀩䀪䀫䀬䀭䀮䀯䀰䀱䀲䀳䀴䀵䀶䀷䀸䀹䀺䀻䀼䀽䀾䀿 +ä€ää‚äƒä„ä…ä†ä‡äˆä‰äŠä‹äŒääŽäää‘ä’ä“ä”ä•ä–ä—ä˜ä™äšä›äœääžäŸ +ä ä¡ä¢ä£ä¤ä¥ä¦ä§ä¨ä©äªä«ä¬ä­ä®ä¯ä°ä±ä²ä³ä´äµä¶ä·ä¸ä¹äºä»ä¼ä½ä¾ä¿ +ä‚€ä‚䂂䂃䂄䂅䂆䂇䂈䂉䂊䂋䂌ä‚ä‚Žä‚ä‚䂑䂒䂓䂔䂕䂖䂗䂘䂙䂚䂛䂜ä‚ä‚žä‚Ÿ +䂠䂡䂢䂣䂤䂥䂦䂧䂨䂩䂪䂫䂬䂭䂮䂯䂰䂱䂲䂳䂴䂵䂶䂷䂸䂹䂺䂻䂼䂽䂾䂿 +䃀äƒäƒ‚䃃䃄䃅䃆䃇䃈䃉䃊䃋䃌äƒäƒŽäƒäƒäƒ‘䃒䃓䃔䃕䃖䃗䃘䃙䃚䃛䃜äƒäƒžäƒŸ +䃠䃡䃢䃣䃤䃥䃦䃧䃨䃩䃪䃫䃬䃭䃮䃯䃰䃱䃲䃳䃴䃵䃶䃷䃸䃹䃺䃻䃼䃽䃾䃿 +ä„€ä„䄂䄃䄄䄅䄆䄇䄈䄉䄊䄋䄌ä„ä„Žä„ä„䄑䄒䄓䄔䄕䄖䄗䄘䄙䄚䄛䄜ä„ä„žä„Ÿ +䄠䄡䄢䄣䄤䄥䄦䄧䄨䄩䄪䄫䄬䄭䄮䄯䄰䄱䄲䄳䄴䄵䄶䄷䄸䄹䄺䄻䄼䄽䄾䄿 +ä…€ä…䅂䅃䅄䅅䅆䅇䅈䅉䅊䅋䅌ä…ä…Žä…ä…䅑䅒䅓䅔䅕䅖䅗䅘䅙䅚䅛䅜ä…ä…žä…Ÿ +䅠䅡䅢䅣䅤䅥䅦䅧䅨䅩䅪䅫䅬䅭䅮䅯䅰䅱䅲䅳䅴䅵䅶䅷䅸䅹䅺䅻䅼䅽䅾䅿 +䆀ä†ä†‚䆃䆄䆅䆆䆇䆈䆉䆊䆋䆌ä†ä†Žä†ä†ä†‘䆒䆓䆔䆕䆖䆗䆘䆙䆚䆛䆜ä†ä†žä†Ÿ +䆠䆡䆢䆣䆤䆥䆦䆧䆨䆩䆪䆫䆬䆭䆮䆯䆰䆱䆲䆳䆴䆵䆶䆷䆸䆹䆺䆻䆼䆽䆾䆿 +䇀ä‡ä‡‚䇃䇄䇅䇆䇇䇈䇉䇊䇋䇌ä‡ä‡Žä‡ä‡ä‡‘䇒䇓䇔䇕䇖䇗䇘䇙䇚䇛䇜ä‡ä‡žä‡Ÿ +䇠䇡䇢䇣䇤䇥䇦䇧䇨䇩䇪䇫䇬䇭䇮䇯䇰䇱䇲䇳䇴䇵䇶䇷䇸䇹䇺䇻䇼䇽䇾䇿 +䈀äˆäˆ‚䈃䈄䈅䈆䈇䈈䈉䈊䈋䈌äˆäˆŽäˆäˆäˆ‘䈒䈓䈔䈕䈖䈗䈘䈙䈚䈛䈜äˆäˆžäˆŸ +䈠䈡䈢䈣䈤䈥䈦䈧䈨䈩䈪䈫䈬䈭䈮䈯䈰䈱䈲䈳䈴䈵䈶䈷䈸䈹䈺䈻䈼䈽䈾䈿 +䉀ä‰ä‰‚䉃䉄䉅䉆䉇䉈䉉䉊䉋䉌ä‰ä‰Žä‰ä‰ä‰‘䉒䉓䉔䉕䉖䉗䉘䉙䉚䉛䉜ä‰ä‰žä‰Ÿ +䉠䉡䉢䉣䉤䉥䉦䉧䉨䉩䉪䉫䉬䉭䉮䉯䉰䉱䉲䉳䉴䉵䉶䉷䉸䉹䉺䉻䉼䉽䉾䉿 +䊀äŠäŠ‚䊃䊄䊅䊆䊇䊈䊉䊊䊋䊌äŠäŠŽäŠäŠäŠ‘䊒䊓䊔䊕䊖䊗䊘䊙䊚䊛䊜äŠäŠžäŠŸ +䊠䊡䊢䊣䊤䊥䊦䊧䊨䊩䊪䊫䊬䊭䊮䊯䊰䊱䊲䊳䊴䊵䊶䊷䊸䊹䊺䊻䊼䊽䊾䊿 +ä‹€ä‹ä‹‚䋃䋄䋅䋆䋇䋈䋉䋊䋋䋌ä‹ä‹Žä‹ä‹ä‹‘䋒䋓䋔䋕䋖䋗䋘䋙䋚䋛䋜ä‹ä‹žä‹Ÿ +䋠䋡䋢䋣䋤䋥䋦䋧䋨䋩䋪䋫䋬䋭䋮䋯䋰䋱䋲䋳䋴䋵䋶䋷䋸䋹䋺䋻䋼䋽䋾䋿 +䌀äŒäŒ‚䌃䌄䌅䌆䌇䌈䌉䌊䌋䌌äŒäŒŽäŒäŒäŒ‘䌒䌓䌔䌕䌖䌗䌘䌙䌚䌛䌜äŒäŒžäŒŸ +䌠䌡䌢䌣䌤䌥䌦䌧䌨䌩䌪䌫䌬䌭䌮䌯䌰䌱䌲䌳䌴䌵䌶䌷䌸䌹䌺䌻䌼䌽䌾䌿 +ä€ää‚äƒä„ä…ä†ä‡äˆä‰äŠä‹äŒääŽäää‘ä’ä“ä”ä•ä–ä—ä˜ä™äšä›äœääžäŸ +ä ä¡ä¢ä£ä¤ä¥ä¦ä§ä¨ä©äªä«ä¬ä­ä®ä¯ä°ä±ä²ä³ä´äµä¶ä·ä¸ä¹äºä»ä¼ä½ä¾ä¿ +䎀äŽäŽ‚䎃䎄䎅䎆䎇䎈䎉䎊䎋䎌äŽäŽŽäŽäŽäŽ‘䎒䎓䎔䎕䎖䎗䎘䎙䎚䎛䎜äŽäŽžäŽŸ +䎠䎡䎢䎣䎤䎥䎦䎧䎨䎩䎪䎫䎬䎭䎮䎯䎰䎱䎲䎳䎴䎵䎶䎷䎸䎹䎺䎻䎼䎽䎾䎿 +ä€ää‚äƒä„ä…ä†ä‡äˆä‰äŠä‹äŒääŽäää‘ä’ä“ä”ä•ä–ä—ä˜ä™äšä›äœääžäŸ +ä ä¡ä¢ä£ä¤ä¥ä¦ä§ä¨ä©äªä«ä¬ä­ä®ä¯ä°ä±ä²ä³ä´äµä¶ä·ä¸ä¹äºä»ä¼ä½ä¾ä¿ +ä€ää‚äƒä„ä…ä†ä‡äˆä‰äŠä‹äŒääŽäää‘ä’ä“ä”ä•ä–ä—ä˜ä™äšä›äœääžäŸ +ä ä¡ä¢ä£ä¤ä¥ä¦ä§ä¨ä©äªä«ä¬ä­ä®ä¯ä°ä±ä²ä³ä´äµä¶ä·ä¸ä¹äºä»ä¼ä½ä¾ä¿ +ä‘€ä‘䑂䑃䑄䑅䑆䑇䑈䑉䑊䑋䑌ä‘ä‘Žä‘ä‘䑑䑒䑓䑔䑕䑖䑗䑘䑙䑚䑛䑜ä‘ä‘žä‘Ÿ +䑠䑡䑢䑣䑤䑥䑦䑧䑨䑩䑪䑫䑬䑭䑮䑯䑰䑱䑲䑳䑴䑵䑶䑷䑸䑹䑺䑻䑼䑽䑾䑿 +ä’€ä’䒂䒃䒄䒅䒆䒇䒈䒉䒊䒋䒌ä’ä’Žä’ä’䒑䒒䒓䒔䒕䒖䒗䒘䒙䒚䒛䒜ä’ä’žä’Ÿ +䒠䒡䒢䒣䒤䒥䒦䒧䒨䒩䒪䒫䒬䒭䒮䒯䒰䒱䒲䒳䒴䒵䒶䒷䒸䒹䒺䒻䒼䒽䒾䒿 +ä“€ä“䓂䓃䓄䓅䓆䓇䓈䓉䓊䓋䓌ä“ä“Žä“ä“䓑䓒䓓䓔䓕䓖䓗䓘䓙䓚䓛䓜ä“ä“žä“Ÿ +䓠䓡䓢䓣䓤䓥䓦䓧䓨䓩䓪䓫䓬䓭䓮䓯䓰䓱䓲䓳䓴䓵䓶䓷䓸䓹䓺䓻䓼䓽䓾䓿 +䔀ä”䔂䔃䔄䔅䔆䔇䔈䔉䔊䔋䔌ä”䔎ä”ä”䔑䔒䔓䔔䔕䔖䔗䔘䔙䔚䔛䔜ä”䔞䔟 +䔠䔡䔢䔣䔤䔥䔦䔧䔨䔩䔪䔫䔬䔭䔮䔯䔰䔱䔲䔳䔴䔵䔶䔷䔸䔹䔺䔻䔼䔽䔾䔿 +ä•€ä•ä•‚䕃䕄䕅䕆䕇䕈䕉䕊䕋䕌ä•ä•Žä•ä•ä•‘䕒䕓䕔䕕䕖䕗䕘䕙䕚䕛䕜ä•ä•žä•Ÿ +䕠䕡䕢䕣䕤䕥䕦䕧䕨䕩䕪䕫䕬䕭䕮䕯䕰䕱䕲䕳䕴䕵䕶䕷䕸䕹䕺䕻䕼䕽䕾䕿 +ä–€ä–䖂䖃䖄䖅䖆䖇䖈䖉䖊䖋䖌ä–ä–Žä–ä–䖑䖒䖓䖔䖕䖖䖗䖘䖙䖚䖛䖜ä–ä–žä–Ÿ +䖠䖡䖢䖣䖤䖥䖦䖧䖨䖩䖪䖫䖬䖭䖮䖯䖰䖱䖲䖳䖴䖵䖶䖷䖸䖹䖺䖻䖼䖽䖾䖿 +ä—€ä—䗂䗃䗄䗅䗆䗇䗈䗉䗊䗋䗌ä—ä—Žä—ä—䗑䗒䗓䗔䗕䗖䗗䗘䗙䗚䗛䗜ä—ä—žä—Ÿ +䗠䗡䗢䗣䗤䗥䗦䗧䗨䗩䗪䗫䗬䗭䗮䗯䗰䗱䗲䗳䗴䗵䗶䗷䗸䗹䗺䗻䗼䗽䗾䗿 +䘀ä˜ä˜‚䘃䘄䘅䘆䘇䘈䘉䘊䘋䘌ä˜ä˜Žä˜ä˜ä˜‘䘒䘓䘔䘕䘖䘗䘘䘙䘚䘛䘜ä˜ä˜žä˜Ÿ +䘠䘡䘢䘣䘤䘥䘦䘧䘨䘩䘪䘫䘬䘭䘮䘯䘰䘱䘲䘳䘴䘵䘶䘷䘸䘹䘺䘻䘼䘽䘾䘿 +䙀ä™ä™‚䙃䙄䙅䙆䙇䙈䙉䙊䙋䙌ä™ä™Žä™ä™ä™‘䙒䙓䙔䙕䙖䙗䙘䙙䙚䙛䙜ä™ä™žä™Ÿ +䙠䙡䙢䙣䙤䙥䙦䙧䙨䙩䙪䙫䙬䙭䙮䙯䙰䙱䙲䙳䙴䙵䙶䙷䙸䙹䙺䙻䙼䙽䙾䙿 +䚀äšäš‚䚃䚄䚅䚆䚇䚈䚉䚊䚋䚌äšäšŽäšäšäš‘䚒䚓䚔䚕䚖䚗䚘䚙䚚䚛䚜äšäšžäšŸ +䚠䚡䚢䚣䚤䚥䚦䚧䚨䚩䚪䚫䚬䚭䚮䚯䚰䚱䚲䚳䚴䚵䚶䚷䚸䚹䚺䚻䚼䚽䚾䚿 +䛀ä›ä›‚䛃䛄䛅䛆䛇䛈䛉䛊䛋䛌ä›ä›Žä›ä›ä›‘䛒䛓䛔䛕䛖䛗䛘䛙䛚䛛䛜ä›ä›žä›Ÿ +䛠䛡䛢䛣䛤䛥䛦䛧䛨䛩䛪䛫䛬䛭䛮䛯䛰䛱䛲䛳䛴䛵䛶䛷䛸䛹䛺䛻䛼䛽䛾䛿 +䜀äœäœ‚䜃䜄䜅䜆䜇䜈䜉䜊䜋䜌äœäœŽäœäœäœ‘䜒䜓䜔䜕䜖䜗䜘䜙䜚䜛䜜äœäœžäœŸ +䜠䜡䜢䜣䜤䜥䜦䜧䜨䜩䜪䜫䜬䜭䜮䜯䜰䜱䜲䜳䜴䜵䜶䜷䜸䜹䜺䜻䜼䜽䜾䜿 +ä€ää‚äƒä„ä…ä†ä‡äˆä‰äŠä‹äŒääŽäää‘ä’ä“ä”ä•ä–ä—ä˜ä™äšä›äœääžäŸ +ä ä¡ä¢ä£ä¤ä¥ä¦ä§ä¨ä©äªä«ä¬ä­ä®ä¯ä°ä±ä²ä³ä´äµä¶ä·ä¸ä¹äºä»ä¼ä½ä¾ä¿ +䞀äžäž‚䞃䞄䞅䞆䞇䞈䞉䞊䞋䞌äžäžŽäžäžäž‘䞒䞓䞔䞕䞖䞗䞘䞙䞚䞛䞜äžäžžäžŸ +䞠䞡䞢䞣䞤䞥䞦䞧䞨䞩䞪䞫䞬䞭䞮䞯䞰䞱䞲䞳䞴䞵䞶䞷䞸䞹䞺䞻䞼䞽䞾䞿 +䟀äŸäŸ‚䟃䟄䟅䟆䟇䟈䟉䟊䟋䟌äŸäŸŽäŸäŸäŸ‘䟒䟓䟔䟕䟖䟗䟘䟙䟚䟛䟜äŸäŸžäŸŸ +䟠䟡䟢䟣䟤䟥䟦䟧䟨䟩䟪䟫䟬䟭䟮䟯䟰䟱䟲䟳䟴䟵䟶䟷䟸䟹䟺䟻䟼䟽䟾䟿 +ä €ä ä ‚䠃䠄䠅䠆䠇䠈䠉䠊䠋䠌ä ä Žä ä ä ‘䠒䠓䠔䠕䠖䠗䠘䠙䠚䠛䠜ä ä žä Ÿ +䠠䠡䠢䠣䠤䠥䠦䠧䠨䠩䠪䠫䠬䠭䠮䠯䠰䠱䠲䠳䠴䠵䠶䠷䠸䠹䠺䠻䠼䠽䠾䠿 +ä¡€ä¡ä¡‚䡃䡄䡅䡆䡇䡈䡉䡊䡋䡌ä¡ä¡Žä¡ä¡ä¡‘䡒䡓䡔䡕䡖䡗䡘䡙䡚䡛䡜ä¡ä¡žä¡Ÿ +䡠䡡䡢䡣䡤䡥䡦䡧䡨䡩䡪䡫䡬䡭䡮䡯䡰䡱䡲䡳䡴䡵䡶䡷䡸䡹䡺䡻䡼䡽䡾䡿 +䢀ä¢ä¢‚䢃䢄䢅䢆䢇䢈䢉䢊䢋䢌ä¢ä¢Žä¢ä¢ä¢‘䢒䢓䢔䢕䢖䢗䢘䢙䢚䢛䢜ä¢ä¢žä¢Ÿ +䢠䢡䢢䢣䢤䢥䢦䢧䢨䢩䢪䢫䢬䢭䢮䢯䢰䢱䢲䢳䢴䢵䢶䢷䢸䢹䢺䢻䢼䢽䢾䢿 +䣀ä£ä£‚䣃䣄䣅䣆䣇䣈䣉䣊䣋䣌ä£ä£Žä£ä£ä£‘䣒䣓䣔䣕䣖䣗䣘䣙䣚䣛䣜ä£ä£žä£Ÿ +䣠䣡䣢䣣䣤䣥䣦䣧䣨䣩䣪䣫䣬䣭䣮䣯䣰䣱䣲䣳䣴䣵䣶䣷䣸䣹䣺䣻䣼䣽䣾䣿 +䤀ä¤ä¤‚䤃䤄䤅䤆䤇䤈䤉䤊䤋䤌ä¤ä¤Žä¤ä¤ä¤‘䤒䤓䤔䤕䤖䤗䤘䤙䤚䤛䤜ä¤ä¤žä¤Ÿ +䤠䤡䤢䤣䤤䤥䤦䤧䤨䤩䤪䤫䤬䤭䤮䤯䤰䤱䤲䤳䤴䤵䤶䤷䤸䤹䤺䤻䤼䤽䤾䤿 +䥀ä¥ä¥‚䥃䥄䥅䥆䥇䥈䥉䥊䥋䥌ä¥ä¥Žä¥ä¥ä¥‘䥒䥓䥔䥕䥖䥗䥘䥙䥚䥛䥜ä¥ä¥žä¥Ÿ +䥠䥡䥢䥣䥤䥥䥦䥧䥨䥩䥪䥫䥬䥭䥮䥯䥰䥱䥲䥳䥴䥵䥶䥷䥸䥹䥺䥻䥼䥽䥾䥿 +䦀ä¦ä¦‚䦃䦄䦅䦆䦇䦈䦉䦊䦋䦌ä¦ä¦Žä¦ä¦ä¦‘䦒䦓䦔䦕䦖䦗䦘䦙䦚䦛䦜ä¦ä¦žä¦Ÿ +䦠䦡䦢䦣䦤䦥䦦䦧䦨䦩䦪䦫䦬䦭䦮䦯䦰䦱䦲䦳䦴䦵䦶䦷䦸䦹䦺䦻䦼䦽䦾䦿 +䧀ä§ä§‚䧃䧄䧅䧆䧇䧈䧉䧊䧋䧌ä§ä§Žä§ä§ä§‘䧒䧓䧔䧕䧖䧗䧘䧙䧚䧛䧜ä§ä§žä§Ÿ +䧠䧡䧢䧣䧤䧥䧦䧧䧨䧩䧪䧫䧬䧭䧮䧯䧰䧱䧲䧳䧴䧵䧶䧷䧸䧹䧺䧻䧼䧽䧾䧿 +䨀ä¨ä¨‚䨃䨄䨅䨆䨇䨈䨉䨊䨋䨌ä¨ä¨Žä¨ä¨ä¨‘䨒䨓䨔䨕䨖䨗䨘䨙䨚䨛䨜ä¨ä¨žä¨Ÿ +䨠䨡䨢䨣䨤䨥䨦䨧䨨䨩䨪䨫䨬䨭䨮䨯䨰䨱䨲䨳䨴䨵䨶䨷䨸䨹䨺䨻䨼䨽䨾䨿 +ä©€ä©ä©‚䩃䩄䩅䩆䩇䩈䩉䩊䩋䩌ä©ä©Žä©ä©ä©‘䩒䩓䩔䩕䩖䩗䩘䩙䩚䩛䩜ä©ä©žä©Ÿ +䩠䩡䩢䩣䩤䩥䩦䩧䩨䩩䩪䩫䩬䩭䩮䩯䩰䩱䩲䩳䩴䩵䩶䩷䩸䩹䩺䩻䩼䩽䩾䩿 +䪀äªäª‚䪃䪄䪅䪆䪇䪈䪉䪊䪋䪌äªäªŽäªäªäª‘䪒䪓䪔䪕䪖䪗䪘䪙䪚䪛䪜äªäªžäªŸ +䪠䪡䪢䪣䪤䪥䪦䪧䪨䪩䪪䪫䪬䪭䪮䪯䪰䪱䪲䪳䪴䪵䪶䪷䪸䪹䪺䪻䪼䪽䪾䪿 +ä«€ä«ä«‚䫃䫄䫅䫆䫇䫈䫉䫊䫋䫌ä«ä«Žä«ä«ä«‘䫒䫓䫔䫕䫖䫗䫘䫙䫚䫛䫜ä«ä«žä«Ÿ +䫠䫡䫢䫣䫤䫥䫦䫧䫨䫩䫪䫫䫬䫭䫮䫯䫰䫱䫲䫳䫴䫵䫶䫷䫸䫹䫺䫻䫼䫽䫾䫿 +䬀ä¬ä¬‚䬃䬄䬅䬆䬇䬈䬉䬊䬋䬌ä¬ä¬Žä¬ä¬ä¬‘䬒䬓䬔䬕䬖䬗䬘䬙䬚䬛䬜ä¬ä¬žä¬Ÿ +䬠䬡䬢䬣䬤䬥䬦䬧䬨䬩䬪䬫䬬䬭䬮䬯䬰䬱䬲䬳䬴䬵䬶䬷䬸䬹䬺䬻䬼䬽䬾䬿 +ä­€ä­ä­‚䭃䭄䭅䭆䭇䭈䭉䭊䭋䭌ä­ä­Žä­ä­ä­‘䭒䭓䭔䭕䭖䭗䭘䭙䭚䭛䭜ä­ä­žä­Ÿ +䭠䭡䭢䭣䭤䭥䭦䭧䭨䭩䭪䭫䭬䭭䭮䭯䭰䭱䭲䭳䭴䭵䭶䭷䭸䭹䭺䭻䭼䭽䭾䭿 +䮀ä®ä®‚䮃䮄䮅䮆䮇䮈䮉䮊䮋䮌ä®ä®Žä®ä®ä®‘䮒䮓䮔䮕䮖䮗䮘䮙䮚䮛䮜ä®ä®žä®Ÿ +䮠䮡䮢䮣䮤䮥䮦䮧䮨䮩䮪䮫䮬䮭䮮䮯䮰䮱䮲䮳䮴䮵䮶䮷䮸䮹䮺䮻䮼䮽䮾䮿 +䯀ä¯ä¯‚䯃䯄䯅䯆䯇䯈䯉䯊䯋䯌ä¯ä¯Žä¯ä¯ä¯‘䯒䯓䯔䯕䯖䯗䯘䯙䯚䯛䯜ä¯ä¯žä¯Ÿ +䯠䯡䯢䯣䯤䯥䯦䯧䯨䯩䯪䯫䯬䯭䯮䯯䯰䯱䯲䯳䯴䯵䯶䯷䯸䯹䯺䯻䯼䯽䯾䯿 +ä°€ä°ä°‚䰃䰄䰅䰆䰇䰈䰉䰊䰋䰌ä°ä°Žä°ä°ä°‘䰒䰓䰔䰕䰖䰗䰘䰙䰚䰛䰜ä°ä°žä°Ÿ +䰠䰡䰢䰣䰤䰥䰦䰧䰨䰩䰪䰫䰬䰭䰮䰯䰰䰱䰲䰳䰴䰵䰶䰷䰸䰹䰺䰻䰼䰽䰾䰿 +ä±€ä±ä±‚䱃䱄䱅䱆䱇䱈䱉䱊䱋䱌ä±ä±Žä±ä±ä±‘䱒䱓䱔䱕䱖䱗䱘䱙䱚䱛䱜ä±ä±žä±Ÿ +䱠䱡䱢䱣䱤䱥䱦䱧䱨䱩䱪䱫䱬䱭䱮䱯䱰䱱䱲䱳䱴䱵䱶䱷䱸䱹䱺䱻䱼䱽䱾䱿 +ä²€ä²ä²‚䲃䲄䲅䲆䲇䲈䲉䲊䲋䲌ä²ä²Žä²ä²ä²‘䲒䲓䲔䲕䲖䲗䲘䲙䲚䲛䲜ä²ä²žä²Ÿ +䲠䲡䲢䲣䲤䲥䲦䲧䲨䲩䲪䲫䲬䲭䲮䲯䲰䲱䲲䲳䲴䲵䲶䲷䲸䲹䲺䲻䲼䲽䲾䲿 +ä³€ä³ä³‚䳃䳄䳅䳆䳇䳈䳉䳊䳋䳌ä³ä³Žä³ä³ä³‘䳒䳓䳔䳕䳖䳗䳘䳙䳚䳛䳜ä³ä³žä³Ÿ +䳠䳡䳢䳣䳤䳥䳦䳧䳨䳩䳪䳫䳬䳭䳮䳯䳰䳱䳲䳳䳴䳵䳶䳷䳸䳹䳺䳻䳼䳽䳾䳿 +ä´€ä´ä´‚䴃䴄䴅䴆䴇䴈䴉䴊䴋䴌ä´ä´Žä´ä´ä´‘䴒䴓䴔䴕䴖䴗䴘䴙䴚䴛䴜ä´ä´žä´Ÿ +䴠䴡䴢䴣䴤䴥䴦䴧䴨䴩䴪䴫䴬䴭䴮䴯䴰䴱䴲䴳䴴䴵䴶䴷䴸䴹䴺䴻䴼䴽䴾䴿 +äµ€äµäµ‚䵃䵄䵅䵆䵇䵈䵉䵊䵋䵌äµäµŽäµäµäµ‘䵒䵓䵔䵕䵖䵗䵘䵙䵚䵛䵜äµäµžäµŸ +䵠䵡䵢䵣䵤䵥䵦䵧䵨䵩䵪䵫䵬䵭䵮䵯䵰䵱䵲䵳䵴䵵䵶䵷䵸䵹䵺䵻䵼䵽䵾䵿 +䶀ä¶ä¶‚䶃䶄䶅䶆䶇䶈䶉䶊䶋䶌ä¶ä¶Žä¶ä¶ä¶‘䶒䶓䶔䶕䶖䶗䶘䶙䶚䶛䶜ä¶ä¶žä¶Ÿ +䶠䶡䶢䶣䶤䶥䶦䶧䶨䶩䶪䶫䶬䶭䶮䶯䶰䶱䶲䶳䶴䶵䶶䶷䶸䶹䶺䶻䶼䶽䶾䶿 + +Yijing Hexagram Symbols (U+4DC0-U+4DFF): + +ä·€ä·ä·‚䷃䷄䷅䷆䷇䷈䷉䷊䷋䷌ä·ä·Žä·ä·ä·‘䷒䷓䷔䷕䷖䷗䷘䷙䷚䷛䷜ä·ä·žä·Ÿ +䷠䷡䷢䷣䷤䷥䷦䷧䷨䷩䷪䷫䷬䷭䷮䷯䷰䷱䷲䷳䷴䷵䷶䷷䷸䷹䷺䷻䷼䷽䷾䷿ + +CJK Unified Ideographs (U+4E00-U+9FFF): + +一ä¸ä¸‚七丄丅丆万丈三上下丌ä¸ä¸Žä¸ä¸ä¸‘丒专且丕世丗丘丙业丛东ä¸ä¸žä¸Ÿ +丠両丢丣两严並丧丨丩个丫丬中丮丯丰丱串丳临丵丶丷丸丹为主丼丽举丿 +ä¹€ä¹ä¹‚乃乄久乆乇么义乊之乌ä¹ä¹Žä¹ä¹ä¹‘乒乓乔乕乖乗乘乙乚乛乜ä¹ä¹žä¹Ÿ +习乡乢乣乤乥书乧乨乩乪乫乬乭乮乯买乱乲乳乴乵乶乷乸乹乺乻乼乽乾乿 +亀äºäº‚亃亄亅了亇予争亊事二äºäºŽäºäºäº‘互亓五井亖亗亘亙亚些亜äºäºžäºŸ +亠亡亢亣交亥亦产亨亩亪享京亭亮亯亰亱亲亳亴亵亶亷亸亹人亻亼亽亾亿 +什ä»ä»‚仃仄仅仆仇仈仉今介仌ä»ä»Žä»ä»ä»‘仒仓仔仕他仗付仙仚仛仜ä»ä»žä»Ÿ +仠仡仢代令以仦仧仨仩仪仫们仭仮仯仰仱仲仳仴仵件价仸仹仺任仼份仾仿 +ä¼€ä¼ä¼‚伃伄伅伆伇伈伉伊伋伌ä¼ä¼Žä¼ä¼ä¼‘伒伓伔伕伖众优伙会伛伜ä¼ä¼žä¼Ÿ +传伡伢伣伤伥伦伧伨伩伪伫伬伭伮伯估伱伲伳伴伵伶伷伸伹伺伻似伽伾伿 +ä½€ä½ä½‚佃佄佅但佇佈佉佊佋佌ä½ä½Žä½ä½ä½‘佒体佔何佖佗佘余佚佛作ä½ä½žä½Ÿ +你佡佢佣佤佥佦佧佨佩佪佫佬佭佮佯佰佱佲佳佴併佶佷佸佹佺佻佼佽佾使 +ä¾€ä¾ä¾‚侃侄侅來侇侈侉侊例侌ä¾ä¾Žä¾ä¾ä¾‘侒侓侔侕侖侗侘侙侚供侜ä¾ä¾žä¾Ÿ +侠価侢侣侤侥侦侧侨侩侪侫侬侭侮侯侰侱侲侳侴侵侶侷侸侹侺侻侼侽侾便 +ä¿€ä¿ä¿‚促俄俅俆俇俈俉俊俋俌ä¿ä¿Žä¿ä¿ä¿‘俒俓俔俕俖俗俘俙俚俛俜ä¿ä¿žä¿Ÿ +俠信俢俣俤俥俦俧俨俩俪俫俬俭修俯俰俱俲俳俴俵俶俷俸俹俺俻俼俽俾俿 +倀å€å€‚倃倄倅倆倇倈倉倊個倌å€å€Žå€å€å€‘倒倓倔倕倖倗倘候倚倛倜å€å€žå€Ÿ +倠倡倢倣値倥倦倧倨倩倪倫倬倭倮倯倰倱倲倳倴倵倶倷倸倹债倻值倽倾倿 +å€åå‚åƒå„å…å†å‡åˆå‰åŠå‹åŒååŽååå‘å’å“å”å•å–å—å˜å™åšå›åœååžåŸ +å å¡å¢å£å¤å¥å¦å§å¨å©åªå«å¬å­å®å¯å°å±å²å³å´åµå¶å·å¸å¹åºå»å¼å½å¾å¿ +å‚€å‚傂傃傄傅傆傇傈傉傊傋傌å‚å‚Žå‚å‚傑傒傓傔傕傖傗傘備傚傛傜å‚å‚žå‚Ÿ +傠傡傢傣傤傥傦傧储傩傪傫催傭傮傯傰傱傲傳傴債傶傷傸傹傺傻傼傽傾傿 +僀åƒåƒ‚僃僄僅僆僇僈僉僊僋僌åƒåƒŽåƒåƒåƒ‘僒僓僔僕僖僗僘僙僚僛僜åƒåƒžåƒŸ +僠僡僢僣僤僥僦僧僨僩僪僫僬僭僮僯僰僱僲僳僴僵僶僷僸價僺僻僼僽僾僿 +å„€å„儂儃億儅儆儇儈儉儊儋儌å„å„Žå„å„儑儒儓儔儕儖儗儘儙儚儛儜å„å„žå„Ÿ +儠儡儢儣儤儥儦儧儨儩優儫儬儭儮儯儰儱儲儳儴儵儶儷儸儹儺儻儼儽儾儿 +å…€å…兂元兄充兆兇先光兊克兌å…å…Žå…å…兑兒兓兔兕兖兗兘兙党兛兜å…å…žå…Ÿ +兠兡兢兣兤入兦內全兩兪八公六兮兯兰共兲关兴兵其具典兹兺养兼兽兾兿 +冀å†å†‚冃冄内円冇冈冉冊冋册å†å†Žå†å†å†‘冒冓冔冕冖冗冘写冚军农å†å†žå†Ÿ +冠冡冢冣冤冥冦冧冨冩冪冫冬冭冮冯冰冱冲决冴况冶冷冸冹冺冻冼冽冾冿 +净å‡å‡‚凃凄凅准凇凈凉凊凋凌å‡å‡Žå‡å‡å‡‘凒凓凔凕凖凗凘凙凚凛凜å‡å‡žå‡Ÿ +几凡凢凣凤凥処凧凨凩凪凫凬凭凮凯凰凱凲凳凴凵凶凷凸凹出击凼函凾凿 +刀åˆåˆ‚刃刄刅分切刈刉刊刋刌åˆåˆŽåˆåˆåˆ‘划刓刔刕刖列刘则刚创刜åˆåˆžåˆŸ +删刡刢刣判別刦刧刨利刪别刬刭刮刯到刱刲刳刴刵制刷券刹刺刻刼刽刾刿 +剀å‰å‰‚剃剄剅剆則剈剉削剋剌å‰å‰Žå‰å‰å‰‘剒剓剔剕剖剗剘剙剚剛剜å‰å‰žå‰Ÿ +剠剡剢剣剤剥剦剧剨剩剪剫剬剭剮副剰剱割剳剴創剶剷剸剹剺剻剼剽剾剿 +劀åŠåŠ‚劃劄劅劆劇劈劉劊劋劌åŠåŠŽåŠåŠåŠ‘劒劓劔劕劖劗劘劙劚力劜åŠåŠžåŠŸ +加务劢劣劤劥劦劧动助努劫劬劭劮劯劰励劲劳労劵劶劷劸効劺劻劼劽劾势 +å‹€å‹å‹‚勃勄勅勆勇勈勉勊勋勌å‹å‹Žå‹å‹å‹‘勒勓勔動勖勗勘務勚勛勜å‹å‹žå‹Ÿ +勠勡勢勣勤勥勦勧勨勩勪勫勬勭勮勯勰勱勲勳勴勵勶勷勸勹勺勻勼勽勾勿 +匀åŒåŒ‚匃匄包匆匇匈匉匊匋匌åŒåŒŽåŒåŒåŒ‘匒匓匔匕化北匘匙匚匛匜åŒåŒžåŒŸ +匠匡匢匣匤匥匦匧匨匩匪匫匬匭匮匯匰匱匲匳匴匵匶匷匸匹区医匼匽匾匿 +å€åå‚åƒå„å…å†å‡åˆå‰åŠå‹åŒååŽååå‘å’å“å”å•å–å—å˜å™åšå›åœååžåŸ +å å¡å¢å£å¤å¥å¦å§å¨å©åªå«å¬å­å®å¯å°å±å²å³å´åµå¶å·å¸å¹åºå»å¼å½å¾å¿ +厀åŽåŽ‚厃厄厅历厇厈厉厊压厌åŽåŽŽåŽåŽåŽ‘厒厓厔厕厖厗厘厙厚厛厜åŽåŽžåŽŸ +厠厡厢厣厤厥厦厧厨厩厪厫厬厭厮厯厰厱厲厳厴厵厶厷厸厹厺去厼厽厾县 +å€åå‚åƒå„å…å†å‡åˆå‰åŠå‹åŒååŽååå‘å’å“å”å•å–å—å˜å™åšå›åœååžåŸ +å å¡å¢å£å¤å¥å¦å§å¨å©åªå«å¬å­å®å¯å°å±å²å³å´åµå¶å·å¸å¹åºå»å¼å½å¾å¿ +å€åå‚åƒå„å…å†å‡åˆå‰åŠå‹åŒååŽååå‘å’å“å”å•å–å—å˜å™åšå›åœååžåŸ +å å¡å¢å£å¤å¥å¦å§å¨å©åªå«å¬å­å®å¯å°å±å²å³å´åµå¶å·å¸å¹åºå»å¼å½å¾å¿ +å‘€å‘呂呃呄呅呆呇呈呉告呋呌å‘å‘Žå‘å‘呑呒呓呔呕呖呗员呙呚呛呜å‘å‘žå‘Ÿ +呠呡呢呣呤呥呦呧周呩呪呫呬呭呮呯呰呱呲味呴呵呶呷呸呹呺呻呼命呾呿 +å’€å’咂咃咄咅咆咇咈咉咊咋和å’å’Žå’å’咑咒咓咔咕咖咗咘咙咚咛咜å’å’žå’Ÿ +咠咡咢咣咤咥咦咧咨咩咪咫咬咭咮咯咰咱咲咳咴咵咶咷咸咹咺咻咼咽咾咿 +å“€å“哂哃哄哅哆哇哈哉哊哋哌å“å“Žå“å“哑哒哓哔哕哖哗哘哙哚哛哜å“å“žå“Ÿ +哠員哢哣哤哥哦哧哨哩哪哫哬哭哮哯哰哱哲哳哴哵哶哷哸哹哺哻哼哽哾哿 +唀å”唂唃唄唅唆唇唈唉唊唋唌å”唎å”å”唑唒唓唔唕唖唗唘唙唚唛唜å”唞唟 +唠唡唢唣唤唥唦唧唨唩唪唫唬唭售唯唰唱唲唳唴唵唶唷唸唹唺唻唼唽唾唿 +å•€å•å•‚啃啄啅商啇啈啉啊啋啌å•å•Žå•å•å•‘啒啓啔啕啖啗啘啙啚啛啜å•å•žå•Ÿ +啠啡啢啣啤啥啦啧啨啩啪啫啬啭啮啯啰啱啲啳啴啵啶啷啸啹啺啻啼啽啾啿 +å–€å–喂喃善喅喆喇喈喉喊喋喌å–å–Žå–å–喑喒喓喔喕喖喗喘喙喚喛喜å–å–žå–Ÿ +喠喡喢喣喤喥喦喧喨喩喪喫喬喭單喯喰喱喲喳喴喵営喷喸喹喺喻喼喽喾喿 +å—€å—嗂嗃嗄嗅嗆嗇嗈嗉嗊嗋嗌å—å—Žå—å—嗑嗒嗓嗔嗕嗖嗗嗘嗙嗚嗛嗜å—å—žå—Ÿ +嗠嗡嗢嗣嗤嗥嗦嗧嗨嗩嗪嗫嗬嗭嗮嗯嗰嗱嗲嗳嗴嗵嗶嗷嗸嗹嗺嗻嗼嗽嗾嗿 +嘀å˜å˜‚嘃嘄嘅嘆嘇嘈嘉嘊嘋嘌å˜å˜Žå˜å˜å˜‘嘒嘓嘔嘕嘖嘗嘘嘙嘚嘛嘜å˜å˜žå˜Ÿ +嘠嘡嘢嘣嘤嘥嘦嘧嘨嘩嘪嘫嘬嘭嘮嘯嘰嘱嘲嘳嘴嘵嘶嘷嘸嘹嘺嘻嘼嘽嘾嘿 +噀å™å™‚噃噄噅噆噇噈噉噊噋噌å™å™Žå™å™å™‘噒噓噔噕噖噗噘噙噚噛噜å™å™žå™Ÿ +噠噡噢噣噤噥噦噧器噩噪噫噬噭噮噯噰噱噲噳噴噵噶噷噸噹噺噻噼噽噾噿 +嚀åšåš‚嚃嚄嚅嚆嚇嚈嚉嚊嚋嚌åšåšŽåšåšåš‘嚒嚓嚔嚕嚖嚗嚘嚙嚚嚛嚜åšåšžåšŸ +嚠嚡嚢嚣嚤嚥嚦嚧嚨嚩嚪嚫嚬嚭嚮嚯嚰嚱嚲嚳嚴嚵嚶嚷嚸嚹嚺嚻嚼嚽嚾嚿 +囀å›å›‚囃囄囅囆囇囈囉囊囋囌å›å›Žå›å›å›‘囒囓囔囕囖囗囘囙囚四囜å›å›žå›Ÿ +因囡团団囤囥囦囧囨囩囪囫囬园囮囯困囱囲図围囵囶囷囸囹固囻囼国图囿 +圀åœåœ‚圃圄圅圆圇圈圉圊國圌åœåœŽåœåœåœ‘園圓圔圕圖圗團圙圚圛圜åœåœžåœŸ +圠圡圢圣圤圥圦圧在圩圪圫圬圭圮圯地圱圲圳圴圵圶圷圸圹场圻圼圽圾圿 +å€åå‚åƒå„å…å†å‡åˆå‰åŠå‹åŒååŽååå‘å’å“å”å•å–å—å˜å™åšå›åœååžåŸ +å å¡å¢å£å¤å¥å¦å§å¨å©åªå«å¬å­å®å¯å°å±å²å³å´åµå¶å·å¸å¹åºå»å¼å½å¾å¿ +垀åžåž‚垃垄垅垆垇垈垉垊型垌åžåžŽåžåžåž‘垒垓垔垕垖垗垘垙垚垛垜åžåžžåžŸ +垠垡垢垣垤垥垦垧垨垩垪垫垬垭垮垯垰垱垲垳垴垵垶垷垸垹垺垻垼垽垾垿 +埀åŸåŸ‚埃埄埅埆埇埈埉埊埋埌åŸåŸŽåŸåŸåŸ‘埒埓埔埕埖埗埘埙埚埛埜åŸåŸžåŸŸ +埠埡埢埣埤埥埦埧埨埩埪埫埬埭埮埯埰埱埲埳埴埵埶執埸培基埻埼埽埾埿 +å €å å ‚堃堄堅堆堇堈堉堊堋堌å å Žå å å ‘堒堓堔堕堖堗堘堙堚堛堜å å žå Ÿ +堠堡堢堣堤堥堦堧堨堩堪堫堬堭堮堯堰報堲堳場堵堶堷堸堹堺堻堼堽堾堿 +å¡€å¡å¡‚塃塄塅塆塇塈塉塊塋塌å¡å¡Žå¡å¡å¡‘塒塓塔塕塖塗塘塙塚塛塜å¡å¡žå¡Ÿ +塠塡塢塣塤塥塦塧塨塩塪填塬塭塮塯塰塱塲塳塴塵塶塷塸塹塺塻塼塽塾塿 +墀å¢å¢‚境墄墅墆墇墈墉墊墋墌å¢å¢Žå¢å¢å¢‘墒墓墔墕墖増墘墙墚墛墜å¢å¢žå¢Ÿ +墠墡墢墣墤墥墦墧墨墩墪墫墬墭墮墯墰墱墲墳墴墵墶墷墸墹墺墻墼墽墾墿 +壀å£å£‚壃壄壅壆壇壈壉壊壋壌å£å£Žå£å£å£‘壒壓壔壕壖壗壘壙壚壛壜å£å£žå£Ÿ +壠壡壢壣壤壥壦壧壨壩壪士壬壭壮壯声壱売壳壴壵壶壷壸壹壺壻壼壽壾壿 +夀å¤å¤‚夃处夅夆备夈変夊夋夌å¤å¤Žå¤å¤å¤‘夒夓夔夕外夗夘夙多夛夜å¤å¤žå¤Ÿ +夠夡夢夣夤夥夦大夨天太夫夬夭央夯夰失夲夳头夵夶夷夸夹夺夻夼夽夾夿 +奀å¥å¥‚奃奄奅奆奇奈奉奊奋奌å¥å¥Žå¥å¥å¥‘奒奓奔奕奖套奘奙奚奛奜å¥å¥žå¥Ÿ +奠奡奢奣奤奥奦奧奨奩奪奫奬奭奮奯奰奱奲女奴奵奶奷奸她奺奻奼好奾奿 +妀å¦å¦‚妃妄妅妆妇妈妉妊妋妌å¦å¦Žå¦å¦å¦‘妒妓妔妕妖妗妘妙妚妛妜å¦å¦žå¦Ÿ +妠妡妢妣妤妥妦妧妨妩妪妫妬妭妮妯妰妱妲妳妴妵妶妷妸妹妺妻妼妽妾妿 +姀å§å§‚姃姄姅姆姇姈姉姊始姌å§å§Žå§å§å§‘姒姓委姕姖姗姘姙姚姛姜å§å§žå§Ÿ +姠姡姢姣姤姥姦姧姨姩姪姫姬姭姮姯姰姱姲姳姴姵姶姷姸姹姺姻姼姽姾姿 +娀å¨å¨‚娃娄娅娆娇娈娉娊娋娌å¨å¨Žå¨å¨å¨‘娒娓娔娕娖娗娘娙娚娛娜å¨å¨žå¨Ÿ +娠娡娢娣娤娥娦娧娨娩娪娫娬娭娮娯娰娱娲娳娴娵娶娷娸娹娺娻娼娽娾娿 +å©€å©å©‚婃婄婅婆婇婈婉婊婋婌å©å©Žå©å©å©‘婒婓婔婕婖婗婘婙婚婛婜å©å©žå©Ÿ +婠婡婢婣婤婥婦婧婨婩婪婫婬婭婮婯婰婱婲婳婴婵婶婷婸婹婺婻婼婽婾婿 +媀åªåª‚媃媄媅媆媇媈媉媊媋媌åªåªŽåªåªåª‘媒媓媔媕媖媗媘媙媚媛媜åªåªžåªŸ +媠媡媢媣媤媥媦媧媨媩媪媫媬媭媮媯媰媱媲媳媴媵媶媷媸媹媺媻媼媽媾媿 +å«€å«å«‚嫃嫄嫅嫆嫇嫈嫉嫊嫋嫌å«å«Žå«å«å«‘嫒嫓嫔嫕嫖嫗嫘嫙嫚嫛嫜å«å«žå«Ÿ +嫠嫡嫢嫣嫤嫥嫦嫧嫨嫩嫪嫫嫬嫭嫮嫯嫰嫱嫲嫳嫴嫵嫶嫷嫸嫹嫺嫻嫼嫽嫾嫿 +嬀å¬å¬‚嬃嬄嬅嬆嬇嬈嬉嬊嬋嬌å¬å¬Žå¬å¬å¬‘嬒嬓嬔嬕嬖嬗嬘嬙嬚嬛嬜å¬å¬žå¬Ÿ +嬠嬡嬢嬣嬤嬥嬦嬧嬨嬩嬪嬫嬬嬭嬮嬯嬰嬱嬲嬳嬴嬵嬶嬷嬸嬹嬺嬻嬼嬽嬾嬿 +å­€å­å­‚孃孄孅孆孇孈孉孊孋孌å­å­Žå­å­å­‘孒孓孔孕孖字存孙孚孛孜å­å­žå­Ÿ +孠孡孢季孤孥学孧孨孩孪孫孬孭孮孯孰孱孲孳孴孵孶孷學孹孺孻孼孽孾孿 +宀å®å®‚它宄宅宆宇守安宊宋完å®å®Žå®å®å®‘宒宓宔宕宖宗官宙定宛宜å®å®žå®Ÿ +宠审客宣室宥宦宧宨宩宪宫宬宭宮宯宰宱宲害宴宵家宷宸容宺宻宼宽宾宿 +寀å¯å¯‚寃寄寅密寇寈寉寊寋富å¯å¯Žå¯å¯å¯‘寒寓寔寕寖寗寘寙寚寛寜å¯å¯žå¯Ÿ +寠寡寢寣寤寥實寧寨審寪寫寬寭寮寯寰寱寲寳寴寵寶寷寸对寺寻导寽対寿 +å°€å°å°‚尃射尅将將專尉尊尋尌å°å°Žå°å°å°‘尒尓尔尕尖尗尘尙尚尛尜å°å°žå°Ÿ +尠尡尢尣尤尥尦尧尨尩尪尫尬尭尮尯尰就尲尳尴尵尶尷尸尹尺尻尼尽尾尿 +å±€å±å±‚屃屄居屆屇屈屉届屋屌å±å±Žå±å±å±‘屒屓屔展屖屗屘屙屚屛屜å±å±žå±Ÿ +屠屡屢屣層履屦屧屨屩屪屫屬屭屮屯屰山屲屳屴屵屶屷屸屹屺屻屼屽屾屿 +å²€å²å²‚岃岄岅岆岇岈岉岊岋岌å²å²Žå²å²å²‘岒岓岔岕岖岗岘岙岚岛岜å²å²žå²Ÿ +岠岡岢岣岤岥岦岧岨岩岪岫岬岭岮岯岰岱岲岳岴岵岶岷岸岹岺岻岼岽岾岿 +å³€å³å³‚峃峄峅峆峇峈峉峊峋峌å³å³Žå³å³å³‘峒峓峔峕峖峗峘峙峚峛峜å³å³žå³Ÿ +峠峡峢峣峤峥峦峧峨峩峪峫峬峭峮峯峰峱峲峳峴峵島峷峸峹峺峻峼峽峾峿 +å´€å´å´‚崃崄崅崆崇崈崉崊崋崌å´å´Žå´å´å´‘崒崓崔崕崖崗崘崙崚崛崜å´å´žå´Ÿ +崠崡崢崣崤崥崦崧崨崩崪崫崬崭崮崯崰崱崲崳崴崵崶崷崸崹崺崻崼崽崾崿 +åµ€åµåµ‚嵃嵄嵅嵆嵇嵈嵉嵊嵋嵌åµåµŽåµåµåµ‘嵒嵓嵔嵕嵖嵗嵘嵙嵚嵛嵜åµåµžåµŸ +嵠嵡嵢嵣嵤嵥嵦嵧嵨嵩嵪嵫嵬嵭嵮嵯嵰嵱嵲嵳嵴嵵嵶嵷嵸嵹嵺嵻嵼嵽嵾嵿 +嶀å¶å¶‚嶃嶄嶅嶆嶇嶈嶉嶊嶋嶌å¶å¶Žå¶å¶å¶‘嶒嶓嶔嶕嶖嶗嶘嶙嶚嶛嶜å¶å¶žå¶Ÿ +嶠嶡嶢嶣嶤嶥嶦嶧嶨嶩嶪嶫嶬嶭嶮嶯嶰嶱嶲嶳嶴嶵嶶嶷嶸嶹嶺嶻嶼嶽嶾嶿 +å·€å·å·‚巃巄巅巆巇巈巉巊巋巌å·å·Žå·å·å·‘巒巓巔巕巖巗巘巙巚巛巜å·å·žå·Ÿ +巠巡巢巣巤工左巧巨巩巪巫巬巭差巯巰己已巳巴巵巶巷巸巹巺巻巼巽巾巿 +帀å¸å¸‚布帄帅帆帇师帉帊帋希å¸å¸Žå¸å¸å¸‘帒帓帔帕帖帗帘帙帚帛帜å¸å¸žå¸Ÿ +帠帡帢帣帤帥带帧帨帩帪師帬席帮帯帰帱帲帳帴帵帶帷常帹帺帻帼帽帾帿 +å¹€å¹å¹‚幃幄幅幆幇幈幉幊幋幌å¹å¹Žå¹å¹å¹‘幒幓幔幕幖幗幘幙幚幛幜å¹å¹žå¹Ÿ +幠幡幢幣幤幥幦幧幨幩幪幫幬幭幮幯幰幱干平年幵并幷幸幹幺幻幼幽幾广 +庀åºåº‚広庄庅庆庇庈庉床庋庌åºåºŽåºåºåº‘庒库应底庖店庘庙庚庛府åºåºžåºŸ +庠庡庢庣庤庥度座庨庩庪庫庬庭庮庯庰庱庲庳庴庵庶康庸庹庺庻庼庽庾庿 +廀å»å»‚廃廄廅廆廇廈廉廊廋廌å»å»Žå»å»å»‘廒廓廔廕廖廗廘廙廚廛廜å»å»žå»Ÿ +廠廡廢廣廤廥廦廧廨廩廪廫廬廭廮廯廰廱廲廳廴廵延廷廸廹建廻廼廽廾廿 +å¼€å¼å¼‚弃弄弅弆弇弈弉弊弋弌å¼å¼Žå¼å¼å¼‘弒弓弔引弖弗弘弙弚弛弜å¼å¼žå¼Ÿ +张弡弢弣弤弥弦弧弨弩弪弫弬弭弮弯弰弱弲弳弴張弶強弸弹强弻弼弽弾弿 +å½€å½å½‚彃彄彅彆彇彈彉彊彋彌å½å½Žå½å½å½‘归当彔录彖彗彘彙彚彛彜å½å½žå½Ÿ +彠彡形彣彤彥彦彧彨彩彪彫彬彭彮彯彰影彲彳彴彵彶彷彸役彺彻彼彽彾彿 +å¾€å¾å¾‚徃径待徆徇很徉徊律後å¾å¾Žå¾å¾å¾‘徒従徔徕徖得徘徙徚徛徜å¾å¾žå¾Ÿ +徠御徢徣徤徥徦徧徨復循徫徬徭微徯徰徱徲徳徴徵徶德徸徹徺徻徼徽徾徿 +å¿€å¿å¿‚心忄必忆忇忈忉忊忋忌å¿å¿Žå¿å¿å¿‘忒忓忔忕忖志忘忙忚忛応å¿å¿žå¿Ÿ +忠忡忢忣忤忥忦忧忨忩忪快忬忭忮忯忰忱忲忳忴念忶忷忸忹忺忻忼忽忾忿 +怀æ€æ€‚怃怄怅怆怇怈怉怊怋怌æ€æ€Žæ€æ€æ€‘怒怓怔怕怖怗怘怙怚怛怜æ€æ€žæ€Ÿ +怠怡怢怣怤急怦性怨怩怪怫怬怭怮怯怰怱怲怳怴怵怶怷怸怹怺总怼怽怾怿 +æ€ææ‚æƒæ„æ…æ†æ‡æˆæ‰æŠæ‹æŒææŽæææ‘æ’æ“æ”æ•æ–æ—æ˜æ™æšæ›æœææžæŸ +æ æ¡æ¢æ£æ¤æ¥æ¦æ§æ¨æ©æªæ«æ¬æ­æ®æ¯æ°æ±æ²æ³æ´æµæ¶æ·æ¸æ¹æºæ»æ¼æ½æ¾æ¿ +æ‚€æ‚悂悃悄悅悆悇悈悉悊悋悌æ‚æ‚Žæ‚æ‚悑悒悓悔悕悖悗悘悙悚悛悜æ‚æ‚žæ‚Ÿ +悠悡悢患悤悥悦悧您悩悪悫悬悭悮悯悰悱悲悳悴悵悶悷悸悹悺悻悼悽悾悿 +惀æƒæƒ‚惃惄情惆惇惈惉惊惋惌æƒæƒŽæƒæƒæƒ‘惒惓惔惕惖惗惘惙惚惛惜æƒæƒžæƒŸ +惠惡惢惣惤惥惦惧惨惩惪惫惬惭惮惯惰惱惲想惴惵惶惷惸惹惺惻惼惽惾惿 +æ„€æ„愂愃愄愅愆愇愈愉愊愋愌æ„æ„Žæ„æ„愑愒愓愔愕愖愗愘愙愚愛愜æ„æ„žæ„Ÿ +愠愡愢愣愤愥愦愧愨愩愪愫愬愭愮愯愰愱愲愳愴愵愶愷愸愹愺愻愼愽愾愿 +æ…€æ…慂慃慄慅慆慇慈慉慊態慌æ…æ…Žæ…æ…慑慒慓慔慕慖慗慘慙慚慛慜æ…æ…žæ…Ÿ +慠慡慢慣慤慥慦慧慨慩慪慫慬慭慮慯慰慱慲慳慴慵慶慷慸慹慺慻慼慽慾慿 +憀æ†æ†‚憃憄憅憆憇憈憉憊憋憌æ†æ†Žæ†æ†æ†‘憒憓憔憕憖憗憘憙憚憛憜æ†æ†žæ†Ÿ +憠憡憢憣憤憥憦憧憨憩憪憫憬憭憮憯憰憱憲憳憴憵憶憷憸憹憺憻憼憽憾憿 +懀æ‡æ‡‚懃懄懅懆懇懈應懊懋懌æ‡æ‡Žæ‡æ‡æ‡‘懒懓懔懕懖懗懘懙懚懛懜æ‡æ‡žæ‡Ÿ +懠懡懢懣懤懥懦懧懨懩懪懫懬懭懮懯懰懱懲懳懴懵懶懷懸懹懺懻懼懽懾懿 +戀æˆæˆ‚戃戄戅戆戇戈戉戊戋戌æˆæˆŽæˆæˆæˆ‘戒戓戔戕或戗战戙戚戛戜æˆæˆžæˆŸ +戠戡戢戣戤戥戦戧戨戩截戫戬戭戮戯戰戱戲戳戴戵戶户戸戹戺戻戼戽戾房 +所æ‰æ‰‚扃扄扅扆扇扈扉扊手扌æ‰æ‰Žæ‰æ‰æ‰‘扒打扔払扖扗托扙扚扛扜æ‰æ‰žæ‰Ÿ +扠扡扢扣扤扥扦执扨扩扪扫扬扭扮扯扰扱扲扳扴扵扶扷扸批扺扻扼扽找承 +技æŠæŠ‚抃抄抅抆抇抈抉把抋抌æŠæŠŽæŠæŠæŠ‘抒抓抔投抖抗折抙抚抛抜æŠæŠžæŠŸ +抠抡抢抣护报抦抧抨抩抪披抬抭抮抯抰抱抲抳抴抵抶抷抸抹抺抻押抽抾抿 +æ‹€æ‹æ‹‚拃拄担拆拇拈拉拊拋拌æ‹æ‹Žæ‹æ‹æ‹‘拒拓拔拕拖拗拘拙拚招拜æ‹æ‹žæ‹Ÿ +拠拡拢拣拤拥拦拧拨择拪拫括拭拮拯拰拱拲拳拴拵拶拷拸拹拺拻拼拽拾拿 +挀æŒæŒ‚挃挄挅挆指挈按挊挋挌æŒæŒŽæŒæŒæŒ‘挒挓挔挕挖挗挘挙挚挛挜æŒæŒžæŒŸ +挠挡挢挣挤挥挦挧挨挩挪挫挬挭挮振挰挱挲挳挴挵挶挷挸挹挺挻挼挽挾挿 +æ€ææ‚æƒæ„æ…æ†æ‡æˆæ‰æŠæ‹æŒææŽæææ‘æ’æ“æ”æ•æ–æ—æ˜æ™æšæ›æœææžæŸ +æ æ¡æ¢æ£æ¤æ¥æ¦æ§æ¨æ©æªæ«æ¬æ­æ®æ¯æ°æ±æ²æ³æ´æµæ¶æ·æ¸æ¹æºæ»æ¼æ½æ¾æ¿ +掀æŽæŽ‚掃掄掅掆掇授掉掊掋掌æŽæŽŽæŽæŽæŽ‘排掓掔掕掖掗掘掙掚掛掜æŽæŽžæŽŸ +掠採探掣掤接掦控推掩措掫掬掭掮掯掰掱掲掳掴掵掶掷掸掹掺掻掼掽掾掿 +æ€ææ‚æƒæ„æ…æ†æ‡æˆæ‰æŠæ‹æŒææŽæææ‘æ’æ“æ”æ•æ–æ—æ˜æ™æšæ›æœææžæŸ +æ æ¡æ¢æ£æ¤æ¥æ¦æ§æ¨æ©æªæ«æ¬æ­æ®æ¯æ°æ±æ²æ³æ´æµæ¶æ·æ¸æ¹æºæ»æ¼æ½æ¾æ¿ +æ€ææ‚æƒæ„æ…æ†æ‡æˆæ‰æŠæ‹æŒææŽæææ‘æ’æ“æ”æ•æ–æ—æ˜æ™æšæ›æœææžæŸ +æ æ¡æ¢æ£æ¤æ¥æ¦æ§æ¨æ©æªæ«æ¬æ­æ®æ¯æ°æ±æ²æ³æ´æµæ¶æ·æ¸æ¹æºæ»æ¼æ½æ¾æ¿ +æ‘€æ‘摂摃摄摅摆摇摈摉摊摋摌æ‘æ‘Žæ‘æ‘摑摒摓摔摕摖摗摘摙摚摛摜æ‘æ‘žæ‘Ÿ +摠摡摢摣摤摥摦摧摨摩摪摫摬摭摮摯摰摱摲摳摴摵摶摷摸摹摺摻摼摽摾摿 +æ’€æ’撂撃撄撅撆撇撈撉撊撋撌æ’æ’Žæ’æ’撑撒撓撔撕撖撗撘撙撚撛撜æ’æ’žæ’Ÿ +撠撡撢撣撤撥撦撧撨撩撪撫撬播撮撯撰撱撲撳撴撵撶撷撸撹撺撻撼撽撾撿 +æ“€æ“擂擃擄擅擆擇擈擉擊擋擌æ“æ“Žæ“æ“擑擒擓擔擕擖擗擘擙據擛擜æ“æ“žæ“Ÿ +擠擡擢擣擤擥擦擧擨擩擪擫擬擭擮擯擰擱擲擳擴擵擶擷擸擹擺擻擼擽擾擿 +攀æ”攂攃攄攅攆攇攈攉攊攋攌æ”攎æ”æ”攑攒攓攔攕攖攗攘攙攚攛攜æ”攞攟 +攠攡攢攣攤攥攦攧攨攩攪攫攬攭攮支攰攱攲攳攴攵收攷攸改攺攻攼攽放政 +æ•€æ•æ•‚敃敄故敆敇效敉敊敋敌æ•æ•Žæ•æ•æ•‘敒敓敔敕敖敗敘教敚敛敜æ•æ•žæ•Ÿ +敠敡敢散敤敥敦敧敨敩敪敫敬敭敮敯数敱敲敳整敵敶敷數敹敺敻敼敽敾敿 +æ–€æ–斂斃斄斅斆文斈斉斊斋斌æ–æ–Žæ–æ–斑斒斓斔斕斖斗斘料斚斛斜æ–æ–žæ–Ÿ +斠斡斢斣斤斥斦斧斨斩斪斫斬断斮斯新斱斲斳斴斵斶斷斸方斺斻於施斾斿 +æ—€æ—旂旃旄旅旆旇旈旉旊旋旌æ—æ—Žæ—æ—旑旒旓旔旕旖旗旘旙旚旛旜æ—æ—žæ—Ÿ +无旡既旣旤日旦旧旨早旪旫旬旭旮旯旰旱旲旳旴旵时旷旸旹旺旻旼旽旾旿 +昀æ˜æ˜‚昃昄昅昆昇昈昉昊昋昌æ˜æ˜Žæ˜æ˜æ˜‘昒易昔昕昖昗昘昙昚昛昜æ˜æ˜žæ˜Ÿ +映昡昢昣昤春昦昧昨昩昪昫昬昭昮是昰昱昲昳昴昵昶昷昸昹昺昻昼昽显昿 +晀æ™æ™‚晃晄晅晆晇晈晉晊晋晌æ™æ™Žæ™æ™æ™‘晒晓晔晕晖晗晘晙晚晛晜æ™æ™žæ™Ÿ +晠晡晢晣晤晥晦晧晨晩晪晫晬晭普景晰晱晲晳晴晵晶晷晸晹智晻晼晽晾晿 +暀æšæš‚暃暄暅暆暇暈暉暊暋暌æšæšŽæšæšæš‘暒暓暔暕暖暗暘暙暚暛暜æšæšžæšŸ +暠暡暢暣暤暥暦暧暨暩暪暫暬暭暮暯暰暱暲暳暴暵暶暷暸暹暺暻暼暽暾暿 +曀æ›æ›‚曃曄曅曆曇曈曉曊曋曌æ›æ›Žæ›æ›æ›‘曒曓曔曕曖曗曘曙曚曛曜æ›æ›žæ›Ÿ +曠曡曢曣曤曥曦曧曨曩曪曫曬曭曮曯曰曱曲曳更曵曶曷書曹曺曻曼曽曾替 +最æœæœ‚會朄朅朆朇月有朊朋朌æœæœŽæœæœæœ‘朒朓朔朕朖朗朘朙朚望朜æœæœžæœŸ +朠朡朢朣朤朥朦朧木朩未末本札朮术朰朱朲朳朴朵朶朷朸朹机朻朼朽朾朿 +æ€ææ‚æƒæ„æ…æ†æ‡æˆæ‰æŠæ‹æŒææŽæææ‘æ’æ“æ”æ•æ–æ—æ˜æ™æšæ›æœææžæŸ +æ æ¡æ¢æ£æ¤æ¥æ¦æ§æ¨æ©æªæ«æ¬æ­æ®æ¯æ°æ±æ²æ³æ´æµæ¶æ·æ¸æ¹æºæ»æ¼æ½æ¾æ¿ +枀æžæž‚枃构枅枆枇枈枉枊枋枌æžæžŽæžæžæž‘枒枓枔枕枖林枘枙枚枛果æžæžžæžŸ +枠枡枢枣枤枥枦枧枨枩枪枫枬枭枮枯枰枱枲枳枴枵架枷枸枹枺枻枼枽枾枿 +柀æŸæŸ‚柃柄柅柆柇柈柉柊柋柌æŸæŸŽæŸæŸæŸ‘柒染柔柕柖柗柘柙柚柛柜æŸæŸžæŸŸ +柠柡柢柣柤查柦柧柨柩柪柫柬柭柮柯柰柱柲柳柴柵柶柷柸柹柺査柼柽柾柿 +æ €æ æ ‚栃栄栅栆标栈栉栊栋栌æ æ Žæ æ æ ‘栒栓栔栕栖栗栘栙栚栛栜æ æ žæ Ÿ +栠校栢栣栤栥栦栧栨栩株栫栬栭栮栯栰栱栲栳栴栵栶样核根栺栻格栽栾栿 +æ¡€æ¡æ¡‚桃桄桅框桇案桉桊桋桌æ¡æ¡Žæ¡æ¡æ¡‘桒桓桔桕桖桗桘桙桚桛桜æ¡æ¡žæ¡Ÿ +桠桡桢档桤桥桦桧桨桩桪桫桬桭桮桯桰桱桲桳桴桵桶桷桸桹桺桻桼桽桾桿 +梀æ¢æ¢‚梃梄梅梆梇梈梉梊梋梌æ¢æ¢Žæ¢æ¢æ¢‘梒梓梔梕梖梗梘梙梚梛梜æ¢æ¢žæ¢Ÿ +梠梡梢梣梤梥梦梧梨梩梪梫梬梭梮梯械梱梲梳梴梵梶梷梸梹梺梻梼梽梾梿 +检æ£æ£‚棃棄棅棆棇棈棉棊棋棌æ£æ£Žæ£æ£æ£‘棒棓棔棕棖棗棘棙棚棛棜æ£æ£žæ£Ÿ +棠棡棢棣棤棥棦棧棨棩棪棫棬棭森棯棰棱棲棳棴棵棶棷棸棹棺棻棼棽棾棿 +椀æ¤æ¤‚椃椄椅椆椇椈椉椊椋椌æ¤æ¤Žæ¤æ¤æ¤‘椒椓椔椕椖椗椘椙椚椛検æ¤æ¤žæ¤Ÿ +椠椡椢椣椤椥椦椧椨椩椪椫椬椭椮椯椰椱椲椳椴椵椶椷椸椹椺椻椼椽椾椿 +楀æ¥æ¥‚楃楄楅楆楇楈楉楊楋楌æ¥æ¥Žæ¥æ¥æ¥‘楒楓楔楕楖楗楘楙楚楛楜æ¥æ¥žæ¥Ÿ +楠楡楢楣楤楥楦楧楨楩楪楫楬業楮楯楰楱楲楳楴極楶楷楸楹楺楻楼楽楾楿 +榀æ¦æ¦‚榃榄榅榆榇榈榉榊榋榌æ¦æ¦Žæ¦æ¦æ¦‘榒榓榔榕榖榗榘榙榚榛榜æ¦æ¦žæ¦Ÿ +榠榡榢榣榤榥榦榧榨榩榪榫榬榭榮榯榰榱榲榳榴榵榶榷榸榹榺榻榼榽榾榿 +槀æ§æ§‚槃槄槅槆槇槈槉槊構槌æ§æ§Žæ§æ§æ§‘槒槓槔槕槖槗様槙槚槛槜æ§æ§žæ§Ÿ +槠槡槢槣槤槥槦槧槨槩槪槫槬槭槮槯槰槱槲槳槴槵槶槷槸槹槺槻槼槽槾槿 +樀æ¨æ¨‚樃樄樅樆樇樈樉樊樋樌æ¨æ¨Žæ¨æ¨æ¨‘樒樓樔樕樖樗樘標樚樛樜æ¨æ¨žæ¨Ÿ +樠模樢樣樤樥樦樧樨権横樫樬樭樮樯樰樱樲樳樴樵樶樷樸樹樺樻樼樽樾樿 +æ©€æ©æ©‚橃橄橅橆橇橈橉橊橋橌æ©æ©Žæ©æ©æ©‘橒橓橔橕橖橗橘橙橚橛橜æ©æ©žæ©Ÿ +橠橡橢橣橤橥橦橧橨橩橪橫橬橭橮橯橰橱橲橳橴橵橶橷橸橹橺橻橼橽橾橿 +檀æªæª‚檃檄檅檆檇檈檉檊檋檌æªæªŽæªæªæª‘檒檓檔檕檖檗檘檙檚檛檜æªæªžæªŸ +檠檡檢檣檤檥檦檧檨檩檪檫檬檭檮檯檰檱檲檳檴檵檶檷檸檹檺檻檼檽檾檿 +æ«€æ«æ«‚櫃櫄櫅櫆櫇櫈櫉櫊櫋櫌æ«æ«Žæ«æ«æ«‘櫒櫓櫔櫕櫖櫗櫘櫙櫚櫛櫜æ«æ«žæ«Ÿ +櫠櫡櫢櫣櫤櫥櫦櫧櫨櫩櫪櫫櫬櫭櫮櫯櫰櫱櫲櫳櫴櫵櫶櫷櫸櫹櫺櫻櫼櫽櫾櫿 +欀æ¬æ¬‚欃欄欅欆欇欈欉權欋欌æ¬æ¬Žæ¬æ¬æ¬‘欒欓欔欕欖欗欘欙欚欛欜æ¬æ¬žæ¬Ÿ +欠次欢欣欤欥欦欧欨欩欪欫欬欭欮欯欰欱欲欳欴欵欶欷欸欹欺欻欼欽款欿 +æ­€æ­æ­‚歃歄歅歆歇歈歉歊歋歌æ­æ­Žæ­æ­æ­‘歒歓歔歕歖歗歘歙歚歛歜æ­æ­žæ­Ÿ +歠歡止正此步武歧歨歩歪歫歬歭歮歯歰歱歲歳歴歵歶歷歸歹歺死歼歽歾歿 +殀æ®æ®‚殃殄殅殆殇殈殉殊残殌æ®æ®Žæ®æ®æ®‘殒殓殔殕殖殗殘殙殚殛殜æ®æ®žæ®Ÿ +殠殡殢殣殤殥殦殧殨殩殪殫殬殭殮殯殰殱殲殳殴段殶殷殸殹殺殻殼殽殾殿 +毀æ¯æ¯‚毃毄毅毆毇毈毉毊毋毌æ¯æ¯Žæ¯æ¯æ¯‘毒毓比毕毖毗毘毙毚毛毜æ¯æ¯žæ¯Ÿ +毠毡毢毣毤毥毦毧毨毩毪毫毬毭毮毯毰毱毲毳毴毵毶毷毸毹毺毻毼毽毾毿 +æ°€æ°æ°‚氃氄氅氆氇氈氉氊氋氌æ°æ°Žæ°æ°æ°‘氒氓气氕氖気氘氙氚氛氜æ°æ°žæ°Ÿ +氠氡氢氣氤氥氦氧氨氩氪氫氬氭氮氯氰氱氲氳水氵氶氷永氹氺氻氼氽氾氿 +æ±€æ±æ±‚汃汄汅汆汇汈汉汊汋汌æ±æ±Žæ±æ±æ±‘汒汓汔汕汖汗汘汙汚汛汜æ±æ±žæ±Ÿ +池污汢汣汤汥汦汧汨汩汪汫汬汭汮汯汰汱汲汳汴汵汶汷汸汹決汻汼汽汾汿 +æ²€æ²æ²‚沃沄沅沆沇沈沉沊沋沌æ²æ²Žæ²æ²æ²‘沒沓沔沕沖沗沘沙沚沛沜æ²æ²žæ²Ÿ +沠没沢沣沤沥沦沧沨沩沪沫沬沭沮沯沰沱沲河沴沵沶沷沸油沺治沼沽沾沿 +æ³€æ³æ³‚泃泄泅泆泇泈泉泊泋泌æ³æ³Žæ³æ³æ³‘泒泓泔法泖泗泘泙泚泛泜æ³æ³žæ³Ÿ +泠泡波泣泤泥泦泧注泩泪泫泬泭泮泯泰泱泲泳泴泵泶泷泸泹泺泻泼泽泾泿 +æ´€æ´æ´‚洃洄洅洆洇洈洉洊洋洌æ´æ´Žæ´æ´æ´‘洒洓洔洕洖洗洘洙洚洛洜æ´æ´žæ´Ÿ +洠洡洢洣洤津洦洧洨洩洪洫洬洭洮洯洰洱洲洳洴洵洶洷洸洹洺活洼洽派洿 +æµ€æµæµ‚浃浄浅浆浇浈浉浊测浌æµæµŽæµæµæµ‘浒浓浔浕浖浗浘浙浚浛浜æµæµžæµŸ +浠浡浢浣浤浥浦浧浨浩浪浫浬浭浮浯浰浱浲浳浴浵浶海浸浹浺浻浼浽浾浿 +涀æ¶æ¶‚涃涄涅涆涇消涉涊涋涌æ¶æ¶Žæ¶æ¶æ¶‘涒涓涔涕涖涗涘涙涚涛涜æ¶æ¶žæ¶Ÿ +涠涡涢涣涤涥润涧涨涩涪涫涬涭涮涯涰涱液涳涴涵涶涷涸涹涺涻涼涽涾涿 +æ·€æ·æ·‚淃淄淅淆淇淈淉淊淋淌æ·æ·Žæ·æ·æ·‘淒淓淔淕淖淗淘淙淚淛淜æ·æ·žæ·Ÿ +淠淡淢淣淤淥淦淧淨淩淪淫淬淭淮淯淰深淲淳淴淵淶混淸淹淺添淼淽淾淿 +渀æ¸æ¸‚渃渄清渆渇済渉渊渋渌æ¸æ¸Žæ¸æ¸æ¸‘渒渓渔渕渖渗渘渙渚減渜æ¸æ¸žæ¸Ÿ +渠渡渢渣渤渥渦渧渨温渪渫測渭渮港渰渱渲渳渴渵渶渷游渹渺渻渼渽渾渿 +æ¹€æ¹æ¹‚湃湄湅湆湇湈湉湊湋湌æ¹æ¹Žæ¹æ¹æ¹‘湒湓湔湕湖湗湘湙湚湛湜æ¹æ¹žæ¹Ÿ +湠湡湢湣湤湥湦湧湨湩湪湫湬湭湮湯湰湱湲湳湴湵湶湷湸湹湺湻湼湽湾湿 +満æºæº‚溃溄溅溆溇溈溉溊溋溌æºæºŽæºæºæº‘溒溓溔溕準溗溘溙溚溛溜æºæºžæºŸ +溠溡溢溣溤溥溦溧溨溩溪溫溬溭溮溯溰溱溲溳溴溵溶溷溸溹溺溻溼溽溾溿 +滀æ»æ»‚滃滄滅滆滇滈滉滊滋滌æ»æ»Žæ»æ»æ»‘滒滓滔滕滖滗滘滙滚滛滜æ»æ»žæ»Ÿ +滠满滢滣滤滥滦滧滨滩滪滫滬滭滮滯滰滱滲滳滴滵滶滷滸滹滺滻滼滽滾滿 +æ¼€æ¼æ¼‚漃漄漅漆漇漈漉漊漋漌æ¼æ¼Žæ¼æ¼æ¼‘漒漓演漕漖漗漘漙漚漛漜æ¼æ¼žæ¼Ÿ +漠漡漢漣漤漥漦漧漨漩漪漫漬漭漮漯漰漱漲漳漴漵漶漷漸漹漺漻漼漽漾漿 +æ½€æ½æ½‚潃潄潅潆潇潈潉潊潋潌æ½æ½Žæ½æ½æ½‘潒潓潔潕潖潗潘潙潚潛潜æ½æ½žæ½Ÿ +潠潡潢潣潤潥潦潧潨潩潪潫潬潭潮潯潰潱潲潳潴潵潶潷潸潹潺潻潼潽潾潿 +æ¾€æ¾æ¾‚澃澄澅澆澇澈澉澊澋澌æ¾æ¾Žæ¾æ¾æ¾‘澒澓澔澕澖澗澘澙澚澛澜æ¾æ¾žæ¾Ÿ +澠澡澢澣澤澥澦澧澨澩澪澫澬澭澮澯澰澱澲澳澴澵澶澷澸澹澺澻澼澽澾澿 +æ¿€æ¿æ¿‚濃濄濅濆濇濈濉濊濋濌æ¿æ¿Žæ¿æ¿æ¿‘濒濓濔濕濖濗濘濙濚濛濜æ¿æ¿žæ¿Ÿ +濠濡濢濣濤濥濦濧濨濩濪濫濬濭濮濯濰濱濲濳濴濵濶濷濸濹濺濻濼濽濾濿 +瀀ç€ç€‚瀃瀄瀅瀆瀇瀈瀉瀊瀋瀌ç€ç€Žç€ç€ç€‘瀒瀓瀔瀕瀖瀗瀘瀙瀚瀛瀜ç€ç€žç€Ÿ +瀠瀡瀢瀣瀤瀥瀦瀧瀨瀩瀪瀫瀬瀭瀮瀯瀰瀱瀲瀳瀴瀵瀶瀷瀸瀹瀺瀻瀼瀽瀾瀿 +ç€çç‚çƒç„ç…ç†ç‡çˆç‰çŠç‹çŒççŽççç‘ç’ç“ç”ç•ç–ç—ç˜ç™çšç›çœççžçŸ +ç ç¡ç¢ç£ç¤ç¥ç¦ç§ç¨ç©çªç«ç¬ç­ç®ç¯ç°ç±ç²ç³ç´çµç¶ç·ç¸ç¹çºç»ç¼ç½ç¾ç¿ +ç‚€ç‚炂炃炄炅炆炇炈炉炊炋炌ç‚ç‚Žç‚ç‚炑炒炓炔炕炖炗炘炙炚炛炜ç‚ç‚žç‚Ÿ +炠炡炢炣炤炥炦炧炨炩炪炫炬炭炮炯炰炱炲炳炴炵炶炷炸点為炻炼炽炾炿 +烀çƒçƒ‚烃烄烅烆烇烈烉烊烋烌çƒçƒŽçƒçƒçƒ‘烒烓烔烕烖烗烘烙烚烛烜çƒçƒžçƒŸ +烠烡烢烣烤烥烦烧烨烩烪烫烬热烮烯烰烱烲烳烴烵烶烷烸烹烺烻烼烽烾烿 +ç„€ç„焂焃焄焅焆焇焈焉焊焋焌ç„ç„Žç„ç„焑焒焓焔焕焖焗焘焙焚焛焜ç„ç„žç„Ÿ +焠無焢焣焤焥焦焧焨焩焪焫焬焭焮焯焰焱焲焳焴焵然焷焸焹焺焻焼焽焾焿 +ç…€ç…煂煃煄煅煆煇煈煉煊煋煌ç…ç…Žç…ç…煑煒煓煔煕煖煗煘煙煚煛煜ç…ç…žç…Ÿ +煠煡煢煣煤煥煦照煨煩煪煫煬煭煮煯煰煱煲煳煴煵煶煷煸煹煺煻煼煽煾煿 +熀ç†ç†‚熃熄熅熆熇熈熉熊熋熌ç†ç†Žç†ç†ç†‘熒熓熔熕熖熗熘熙熚熛熜ç†ç†žç†Ÿ +熠熡熢熣熤熥熦熧熨熩熪熫熬熭熮熯熰熱熲熳熴熵熶熷熸熹熺熻熼熽熾熿 +燀ç‡ç‡‚燃燄燅燆燇燈燉燊燋燌ç‡ç‡Žç‡ç‡ç‡‘燒燓燔燕燖燗燘燙燚燛燜ç‡ç‡žç‡Ÿ +燠燡燢燣燤燥燦燧燨燩燪燫燬燭燮燯燰燱燲燳燴燵燶燷燸燹燺燻燼燽燾燿 +爀çˆçˆ‚爃爄爅爆爇爈爉爊爋爌çˆçˆŽçˆçˆçˆ‘爒爓爔爕爖爗爘爙爚爛爜çˆçˆžçˆŸ +爠爡爢爣爤爥爦爧爨爩爪爫爬爭爮爯爰爱爲爳爴爵父爷爸爹爺爻爼爽爾爿 +牀ç‰ç‰‚牃牄牅牆片版牉牊牋牌ç‰ç‰Žç‰ç‰ç‰‘牒牓牔牕牖牗牘牙牚牛牜ç‰ç‰žç‰Ÿ +牠牡牢牣牤牥牦牧牨物牪牫牬牭牮牯牰牱牲牳牴牵牶牷牸特牺牻牼牽牾牿 +犀çŠçŠ‚犃犄犅犆犇犈犉犊犋犌çŠçŠŽçŠçŠçŠ‘犒犓犔犕犖犗犘犙犚犛犜çŠçŠžçŠŸ +犠犡犢犣犤犥犦犧犨犩犪犫犬犭犮犯犰犱犲犳犴犵状犷犸犹犺犻犼犽犾犿 +ç‹€ç‹ç‹‚狃狄狅狆狇狈狉狊狋狌ç‹ç‹Žç‹ç‹ç‹‘狒狓狔狕狖狗狘狙狚狛狜ç‹ç‹žç‹Ÿ +狠狡狢狣狤狥狦狧狨狩狪狫独狭狮狯狰狱狲狳狴狵狶狷狸狹狺狻狼狽狾狿 +猀çŒçŒ‚猃猄猅猆猇猈猉猊猋猌çŒçŒŽçŒçŒçŒ‘猒猓猔猕猖猗猘猙猚猛猜çŒçŒžçŒŸ +猠猡猢猣猤猥猦猧猨猩猪猫猬猭献猯猰猱猲猳猴猵猶猷猸猹猺猻猼猽猾猿 +ç€çç‚çƒç„ç…ç†ç‡çˆç‰çŠç‹çŒççŽççç‘ç’ç“ç”ç•ç–ç—ç˜ç™çšç›çœççžçŸ +ç ç¡ç¢ç£ç¤ç¥ç¦ç§ç¨ç©çªç«ç¬ç­ç®ç¯ç°ç±ç²ç³ç´çµç¶ç·ç¸ç¹çºç»ç¼ç½ç¾ç¿ +玀çŽçŽ‚玃玄玅玆率玈玉玊王玌çŽçŽŽçŽçŽçŽ‘玒玓玔玕玖玗玘玙玚玛玜çŽçŽžçŽŸ +玠玡玢玣玤玥玦玧玨玩玪玫玬玭玮环现玱玲玳玴玵玶玷玸玹玺玻玼玽玾玿 +ç€çç‚çƒç„ç…ç†ç‡çˆç‰çŠç‹çŒççŽççç‘ç’ç“ç”ç•ç–ç—ç˜ç™çšç›çœççžçŸ +ç ç¡ç¢ç£ç¤ç¥ç¦ç§ç¨ç©çªç«ç¬ç­ç®ç¯ç°ç±ç²ç³ç´çµç¶ç·ç¸ç¹çºç»ç¼ç½ç¾ç¿ +ç€çç‚çƒç„ç…ç†ç‡çˆç‰çŠç‹çŒççŽççç‘ç’ç“ç”ç•ç–ç—ç˜ç™çšç›çœççžçŸ +ç ç¡ç¢ç£ç¤ç¥ç¦ç§ç¨ç©çªç«ç¬ç­ç®ç¯ç°ç±ç²ç³ç´çµç¶ç·ç¸ç¹çºç»ç¼ç½ç¾ç¿ +ç‘€ç‘瑂瑃瑄瑅瑆瑇瑈瑉瑊瑋瑌ç‘ç‘Žç‘ç‘瑑瑒瑓瑔瑕瑖瑗瑘瑙瑚瑛瑜ç‘ç‘žç‘Ÿ +瑠瑡瑢瑣瑤瑥瑦瑧瑨瑩瑪瑫瑬瑭瑮瑯瑰瑱瑲瑳瑴瑵瑶瑷瑸瑹瑺瑻瑼瑽瑾瑿 +ç’€ç’璂璃璄璅璆璇璈璉璊璋璌ç’ç’Žç’ç’璑璒璓璔璕璖璗璘璙璚璛璜ç’ç’žç’Ÿ +璠璡璢璣璤璥璦璧璨璩璪璫璬璭璮璯環璱璲璳璴璵璶璷璸璹璺璻璼璽璾璿 +ç“€ç“瓂瓃瓄瓅瓆瓇瓈瓉瓊瓋瓌ç“ç“Žç“ç“瓑瓒瓓瓔瓕瓖瓗瓘瓙瓚瓛瓜ç“ç“žç“Ÿ +瓠瓡瓢瓣瓤瓥瓦瓧瓨瓩瓪瓫瓬瓭瓮瓯瓰瓱瓲瓳瓴瓵瓶瓷瓸瓹瓺瓻瓼瓽瓾瓿 +甀ç”甂甃甄甅甆甇甈甉甊甋甌ç”甎ç”ç”甑甒甓甔甕甖甗甘甙甚甛甜ç”甞生 +甠甡產産甤甥甦甧用甩甪甫甬甭甮甯田由甲申甴电甶男甸甹町画甼甽甾甿 +ç•€ç•ç•‚畃畄畅畆畇畈畉畊畋界ç•ç•Žç•ç•ç•‘畒畓畔畕畖畗畘留畚畛畜ç•ç•žç•Ÿ +畠畡畢畣畤略畦畧畨畩番畫畬畭畮畯異畱畲畳畴畵當畷畸畹畺畻畼畽畾畿 +ç–€ç–疂疃疄疅疆疇疈疉疊疋疌ç–ç–Žç–ç–疑疒疓疔疕疖疗疘疙疚疛疜ç–ç–žç–Ÿ +疠疡疢疣疤疥疦疧疨疩疪疫疬疭疮疯疰疱疲疳疴疵疶疷疸疹疺疻疼疽疾疿 +ç—€ç—痂痃痄病痆症痈痉痊痋痌ç—ç—Žç—ç—痑痒痓痔痕痖痗痘痙痚痛痜ç—ç—žç—Ÿ +痠痡痢痣痤痥痦痧痨痩痪痫痬痭痮痯痰痱痲痳痴痵痶痷痸痹痺痻痼痽痾痿 +瘀ç˜ç˜‚瘃瘄瘅瘆瘇瘈瘉瘊瘋瘌ç˜ç˜Žç˜ç˜ç˜‘瘒瘓瘔瘕瘖瘗瘘瘙瘚瘛瘜ç˜ç˜žç˜Ÿ +瘠瘡瘢瘣瘤瘥瘦瘧瘨瘩瘪瘫瘬瘭瘮瘯瘰瘱瘲瘳瘴瘵瘶瘷瘸瘹瘺瘻瘼瘽瘾瘿 +癀ç™ç™‚癃癄癅癆癇癈癉癊癋癌ç™ç™Žç™ç™ç™‘癒癓癔癕癖癗癘癙癚癛癜ç™ç™žç™Ÿ +癠癡癢癣癤癥癦癧癨癩癪癫癬癭癮癯癰癱癲癳癴癵癶癷癸癹発登發白百癿 +皀çšçš‚皃的皅皆皇皈皉皊皋皌çšçšŽçšçšçš‘皒皓皔皕皖皗皘皙皚皛皜çšçšžçšŸ +皠皡皢皣皤皥皦皧皨皩皪皫皬皭皮皯皰皱皲皳皴皵皶皷皸皹皺皻皼皽皾皿 +盀ç›ç›‚盃盄盅盆盇盈盉益盋盌ç›ç›Žç›ç›ç›‘盒盓盔盕盖盗盘盙盚盛盜ç›ç›žç›Ÿ +盠盡盢監盤盥盦盧盨盩盪盫盬盭目盯盰盱盲盳直盵盶盷相盹盺盻盼盽盾盿 +眀çœçœ‚眃眄眅眆眇眈眉眊看県çœçœŽçœçœçœ‘眒眓眔眕眖眗眘眙眚眛眜çœçœžçœŸ +眠眡眢眣眤眥眦眧眨眩眪眫眬眭眮眯眰眱眲眳眴眵眶眷眸眹眺眻眼眽眾眿 +ç€çç‚çƒç„ç…ç†ç‡çˆç‰çŠç‹çŒççŽççç‘ç’ç“ç”ç•ç–ç—ç˜ç™çšç›çœççžçŸ +ç ç¡ç¢ç£ç¤ç¥ç¦ç§ç¨ç©çªç«ç¬ç­ç®ç¯ç°ç±ç²ç³ç´çµç¶ç·ç¸ç¹çºç»ç¼ç½ç¾ç¿ +瞀çžçž‚瞃瞄瞅瞆瞇瞈瞉瞊瞋瞌çžçžŽçžçžçž‘瞒瞓瞔瞕瞖瞗瞘瞙瞚瞛瞜çžçžžçžŸ +瞠瞡瞢瞣瞤瞥瞦瞧瞨瞩瞪瞫瞬瞭瞮瞯瞰瞱瞲瞳瞴瞵瞶瞷瞸瞹瞺瞻瞼瞽瞾瞿 +矀çŸçŸ‚矃矄矅矆矇矈矉矊矋矌çŸçŸŽçŸçŸçŸ‘矒矓矔矕矖矗矘矙矚矛矜çŸçŸžçŸŸ +矠矡矢矣矤知矦矧矨矩矪矫矬短矮矯矰矱矲石矴矵矶矷矸矹矺矻矼矽矾矿 +ç €ç ç ‚砃砄砅砆砇砈砉砊砋砌ç ç Žç ç ç ‘砒砓研砕砖砗砘砙砚砛砜ç ç žç Ÿ +砠砡砢砣砤砥砦砧砨砩砪砫砬砭砮砯砰砱砲砳破砵砶砷砸砹砺砻砼砽砾砿 +ç¡€ç¡ç¡‚硃硄硅硆硇硈硉硊硋硌ç¡ç¡Žç¡ç¡ç¡‘硒硓硔硕硖硗硘硙硚硛硜ç¡ç¡žç¡Ÿ +硠硡硢硣硤硥硦硧硨硩硪硫硬硭确硯硰硱硲硳硴硵硶硷硸硹硺硻硼硽硾硿 +碀ç¢ç¢‚碃碄碅碆碇碈碉碊碋碌ç¢ç¢Žç¢ç¢ç¢‘碒碓碔碕碖碗碘碙碚碛碜ç¢ç¢žç¢Ÿ +碠碡碢碣碤碥碦碧碨碩碪碫碬碭碮碯碰碱碲碳碴碵碶碷碸碹確碻碼碽碾碿 +磀ç£ç£‚磃磄磅磆磇磈磉磊磋磌ç£ç£Žç£ç£ç£‘磒磓磔磕磖磗磘磙磚磛磜ç£ç£žç£Ÿ +磠磡磢磣磤磥磦磧磨磩磪磫磬磭磮磯磰磱磲磳磴磵磶磷磸磹磺磻磼磽磾磿 +礀ç¤ç¤‚礃礄礅礆礇礈礉礊礋礌ç¤ç¤Žç¤ç¤ç¤‘礒礓礔礕礖礗礘礙礚礛礜ç¤ç¤žç¤Ÿ +礠礡礢礣礤礥礦礧礨礩礪礫礬礭礮礯礰礱礲礳礴礵礶礷礸礹示礻礼礽社礿 +祀ç¥ç¥‚祃祄祅祆祇祈祉祊祋祌ç¥ç¥Žç¥ç¥ç¥‘祒祓祔祕祖祗祘祙祚祛祜ç¥ç¥žç¥Ÿ +祠祡祢祣祤祥祦祧票祩祪祫祬祭祮祯祰祱祲祳祴祵祶祷祸祹祺祻祼祽祾祿 +禀ç¦ç¦‚禃禄禅禆禇禈禉禊禋禌ç¦ç¦Žç¦ç¦ç¦‘禒禓禔禕禖禗禘禙禚禛禜ç¦ç¦žç¦Ÿ +禠禡禢禣禤禥禦禧禨禩禪禫禬禭禮禯禰禱禲禳禴禵禶禷禸禹禺离禼禽禾禿 +秀ç§ç§‚秃秄秅秆秇秈秉秊秋秌ç§ç§Žç§ç§ç§‘秒秓秔秕秖秗秘秙秚秛秜ç§ç§žç§Ÿ +秠秡秢秣秤秥秦秧秨秩秪秫秬秭秮积称秱秲秳秴秵秶秷秸秹秺移秼秽秾秿 +稀ç¨ç¨‚稃稄稅稆稇稈稉稊程稌ç¨ç¨Žç¨ç¨ç¨‘稒稓稔稕稖稗稘稙稚稛稜ç¨ç¨žç¨Ÿ +稠稡稢稣稤稥稦稧稨稩稪稫稬稭種稯稰稱稲稳稴稵稶稷稸稹稺稻稼稽稾稿 +ç©€ç©ç©‚穃穄穅穆穇穈穉穊穋穌ç©ç©Žç©ç©ç©‘穒穓穔穕穖穗穘穙穚穛穜ç©ç©žç©Ÿ +穠穡穢穣穤穥穦穧穨穩穪穫穬穭穮穯穰穱穲穳穴穵究穷穸穹空穻穼穽穾穿 +窀çªçª‚窃窄窅窆窇窈窉窊窋窌çªçªŽçªçªçª‘窒窓窔窕窖窗窘窙窚窛窜çªçªžçªŸ +窠窡窢窣窤窥窦窧窨窩窪窫窬窭窮窯窰窱窲窳窴窵窶窷窸窹窺窻窼窽窾窿 +ç«€ç«ç«‚竃竄竅竆竇竈竉竊立竌ç«ç«Žç«ç«ç«‘竒竓竔竕竖竗竘站竚竛竜ç«ç«žç«Ÿ +章竡竢竣竤童竦竧竨竩竪竫竬竭竮端竰竱竲竳竴竵競竷竸竹竺竻竼竽竾竿 +笀ç¬ç¬‚笃笄笅笆笇笈笉笊笋笌ç¬ç¬Žç¬ç¬ç¬‘笒笓笔笕笖笗笘笙笚笛笜ç¬ç¬žç¬Ÿ +笠笡笢笣笤笥符笧笨笩笪笫第笭笮笯笰笱笲笳笴笵笶笷笸笹笺笻笼笽笾笿 +ç­€ç­ç­‚筃筄筅筆筇筈等筊筋筌ç­ç­Žç­ç­ç­‘筒筓答筕策筗筘筙筚筛筜ç­ç­žç­Ÿ +筠筡筢筣筤筥筦筧筨筩筪筫筬筭筮筯筰筱筲筳筴筵筶筷筸筹筺筻筼筽签筿 +简ç®ç®‚箃箄箅箆箇箈箉箊箋箌ç®ç®Žç®ç®ç®‘箒箓箔箕箖算箘箙箚箛箜ç®ç®žç®Ÿ +箠管箢箣箤箥箦箧箨箩箪箫箬箭箮箯箰箱箲箳箴箵箶箷箸箹箺箻箼箽箾箿 +節ç¯ç¯‚篃範篅篆篇篈築篊篋篌ç¯ç¯Žç¯ç¯ç¯‘篒篓篔篕篖篗篘篙篚篛篜ç¯ç¯žç¯Ÿ +篠篡篢篣篤篥篦篧篨篩篪篫篬篭篮篯篰篱篲篳篴篵篶篷篸篹篺篻篼篽篾篿 +ç°€ç°ç°‚簃簄簅簆簇簈簉簊簋簌ç°ç°Žç°ç°ç°‘簒簓簔簕簖簗簘簙簚簛簜ç°ç°žç°Ÿ +簠簡簢簣簤簥簦簧簨簩簪簫簬簭簮簯簰簱簲簳簴簵簶簷簸簹簺簻簼簽簾簿 +ç±€ç±ç±‚籃籄籅籆籇籈籉籊籋籌ç±ç±Žç±ç±ç±‘籒籓籔籕籖籗籘籙籚籛籜ç±ç±žç±Ÿ +籠籡籢籣籤籥籦籧籨籩籪籫籬籭籮籯籰籱籲米籴籵籶籷籸籹籺类籼籽籾籿 +ç²€ç²ç²‚粃粄粅粆粇粈粉粊粋粌ç²ç²Žç²ç²ç²‘粒粓粔粕粖粗粘粙粚粛粜ç²ç²žç²Ÿ +粠粡粢粣粤粥粦粧粨粩粪粫粬粭粮粯粰粱粲粳粴粵粶粷粸粹粺粻粼粽精粿 +ç³€ç³ç³‚糃糄糅糆糇糈糉糊糋糌ç³ç³Žç³ç³ç³‘糒糓糔糕糖糗糘糙糚糛糜ç³ç³žç³Ÿ +糠糡糢糣糤糥糦糧糨糩糪糫糬糭糮糯糰糱糲糳糴糵糶糷糸糹糺系糼糽糾糿 +ç´€ç´ç´‚紃約紅紆紇紈紉紊紋紌ç´ç´Žç´ç´ç´‘紒紓純紕紖紗紘紙級紛紜ç´ç´žç´Ÿ +素紡索紣紤紥紦紧紨紩紪紫紬紭紮累細紱紲紳紴紵紶紷紸紹紺紻紼紽紾紿 +çµ€çµçµ‚絃組絅絆絇絈絉絊絋経çµçµŽçµçµçµ‘絒絓絔絕絖絗絘絙絚絛絜çµçµžçµŸ +絠絡絢絣絤絥給絧絨絩絪絫絬絭絮絯絰統絲絳絴絵絶絷絸絹絺絻絼絽絾絿 +綀ç¶ç¶‚綃綄綅綆綇綈綉綊綋綌ç¶ç¶Žç¶ç¶ç¶‘綒經綔綕綖綗綘継続綛綜ç¶ç¶žç¶Ÿ +綠綡綢綣綤綥綦綧綨綩綪綫綬維綮綯綰綱網綳綴綵綶綷綸綹綺綻綼綽綾綿 +ç·€ç·ç·‚緃緄緅緆緇緈緉緊緋緌ç·ç·Žç·ç·ç·‘緒緓緔緕緖緗緘緙線緛緜ç·ç·žç·Ÿ +締緡緢緣緤緥緦緧編緩緪緫緬緭緮緯緰緱緲緳練緵緶緷緸緹緺緻緼緽緾緿 +縀ç¸ç¸‚縃縄縅縆縇縈縉縊縋縌ç¸ç¸Žç¸ç¸ç¸‘縒縓縔縕縖縗縘縙縚縛縜ç¸ç¸žç¸Ÿ +縠縡縢縣縤縥縦縧縨縩縪縫縬縭縮縯縰縱縲縳縴縵縶縷縸縹縺縻縼總績縿 +ç¹€ç¹ç¹‚繃繄繅繆繇繈繉繊繋繌ç¹ç¹Žç¹ç¹ç¹‘繒繓織繕繖繗繘繙繚繛繜ç¹ç¹žç¹Ÿ +繠繡繢繣繤繥繦繧繨繩繪繫繬繭繮繯繰繱繲繳繴繵繶繷繸繹繺繻繼繽繾繿 +纀çºçº‚纃纄纅纆纇纈纉纊纋續çºçºŽçºçºçº‘纒纓纔纕纖纗纘纙纚纛纜çºçºžçºŸ +纠纡红纣纤纥约级纨纩纪纫纬纭纮纯纰纱纲纳纴纵纶纷纸纹纺纻纼纽纾线 +绀ç»ç»‚练组绅细织终绉绊绋绌ç»ç»Žç»ç»ç»‘绒结绔绕绖绗绘给绚绛络ç»ç»žç»Ÿ +绠绡绢绣绤绥绦继绨绩绪绫绬续绮绯绰绱绲绳维绵绶绷绸绹绺绻综绽绾绿 +ç¼€ç¼ç¼‚缃缄缅缆缇缈缉缊缋缌ç¼ç¼Žç¼ç¼ç¼‘缒缓缔缕编缗缘缙缚缛缜ç¼ç¼žç¼Ÿ +缠缡缢缣缤缥缦缧缨缩缪缫缬缭缮缯缰缱缲缳缴缵缶缷缸缹缺缻缼缽缾缿 +ç½€ç½ç½‚罃罄罅罆罇罈罉罊罋罌ç½ç½Žç½ç½ç½‘罒罓罔罕罖罗罘罙罚罛罜ç½ç½žç½Ÿ +罠罡罢罣罤罥罦罧罨罩罪罫罬罭置罯罰罱署罳罴罵罶罷罸罹罺罻罼罽罾罿 +ç¾€ç¾ç¾‚羃羄羅羆羇羈羉羊羋羌ç¾ç¾Žç¾ç¾ç¾‘羒羓羔羕羖羗羘羙羚羛羜ç¾ç¾žç¾Ÿ +羠羡羢羣群羥羦羧羨義羪羫羬羭羮羯羰羱羲羳羴羵羶羷羸羹羺羻羼羽羾羿 +ç¿€ç¿ç¿‚翃翄翅翆翇翈翉翊翋翌ç¿ç¿Žç¿ç¿ç¿‘習翓翔翕翖翗翘翙翚翛翜ç¿ç¿žç¿Ÿ +翠翡翢翣翤翥翦翧翨翩翪翫翬翭翮翯翰翱翲翳翴翵翶翷翸翹翺翻翼翽翾翿 +耀è€è€‚考耄者耆耇耈耉耊耋而è€è€Žè€è€è€‘耒耓耔耕耖耗耘耙耚耛耜è€è€žè€Ÿ +耠耡耢耣耤耥耦耧耨耩耪耫耬耭耮耯耰耱耲耳耴耵耶耷耸耹耺耻耼耽耾耿 +è€èè‚èƒè„è…è†è‡èˆè‰èŠè‹èŒèèŽèèè‘è’è“è”è•è–è—è˜è™èšè›èœèèžèŸ +è è¡è¢è£è¤è¥è¦è§è¨è©èªè«è¬è­è®è¯è°è±è²è³è´èµè¶è·è¸è¹èºè»è¼è½è¾è¿ +è‚€è‚肂肃肄肅肆肇肈肉肊肋肌è‚è‚Žè‚è‚肑肒肓肔肕肖肗肘肙肚肛肜è‚è‚žè‚Ÿ +肠股肢肣肤肥肦肧肨肩肪肫肬肭肮肯肰肱育肳肴肵肶肷肸肹肺肻肼肽肾肿 +胀èƒèƒ‚胃胄胅胆胇胈胉胊胋背èƒèƒŽèƒèƒèƒ‘胒胓胔胕胖胗胘胙胚胛胜èƒèƒžèƒŸ +胠胡胢胣胤胥胦胧胨胩胪胫胬胭胮胯胰胱胲胳胴胵胶胷胸胹胺胻胼能胾胿 +è„€è„脂脃脄脅脆脇脈脉脊脋脌è„è„Žè„è„脑脒脓脔脕脖脗脘脙脚脛脜è„è„žè„Ÿ +脠脡脢脣脤脥脦脧脨脩脪脫脬脭脮脯脰脱脲脳脴脵脶脷脸脹脺脻脼脽脾脿 +è…€è…腂腃腄腅腆腇腈腉腊腋腌è…è…Žè…è…腑腒腓腔腕腖腗腘腙腚腛腜è…è…žè…Ÿ +腠腡腢腣腤腥腦腧腨腩腪腫腬腭腮腯腰腱腲腳腴腵腶腷腸腹腺腻腼腽腾腿 +膀è†è†‚膃膄膅膆膇膈膉膊膋膌è†è†Žè†è†è†‘膒膓膔膕膖膗膘膙膚膛膜è†è†žè†Ÿ +膠膡膢膣膤膥膦膧膨膩膪膫膬膭膮膯膰膱膲膳膴膵膶膷膸膹膺膻膼膽膾膿 +臀è‡è‡‚臃臄臅臆臇臈臉臊臋臌è‡è‡Žè‡è‡è‡‘臒臓臔臕臖臗臘臙臚臛臜è‡è‡žè‡Ÿ +臠臡臢臣臤臥臦臧臨臩自臫臬臭臮臯臰臱臲至致臵臶臷臸臹臺臻臼臽臾臿 +舀èˆèˆ‚舃舄舅舆與興舉舊舋舌èˆèˆŽèˆèˆèˆ‘舒舓舔舕舖舗舘舙舚舛舜èˆèˆžèˆŸ +舠舡舢舣舤舥舦舧舨舩航舫般舭舮舯舰舱舲舳舴舵舶舷舸船舺舻舼舽舾舿 +艀è‰è‰‚艃艄艅艆艇艈艉艊艋艌è‰è‰Žè‰è‰è‰‘艒艓艔艕艖艗艘艙艚艛艜è‰è‰žè‰Ÿ +艠艡艢艣艤艥艦艧艨艩艪艫艬艭艮良艰艱色艳艴艵艶艷艸艹艺艻艼艽艾艿 +芀èŠèŠ‚芃芄芅芆芇芈芉芊芋芌èŠèŠŽèŠèŠèŠ‘芒芓芔芕芖芗芘芙芚芛芜èŠèŠžèŠŸ +芠芡芢芣芤芥芦芧芨芩芪芫芬芭芮芯芰花芲芳芴芵芶芷芸芹芺芻芼芽芾芿 +è‹€è‹è‹‚苃苄苅苆苇苈苉苊苋苌è‹è‹Žè‹è‹è‹‘苒苓苔苕苖苗苘苙苚苛苜è‹è‹žè‹Ÿ +苠苡苢苣苤若苦苧苨苩苪苫苬苭苮苯苰英苲苳苴苵苶苷苸苹苺苻苼苽苾苿 +茀èŒèŒ‚范茄茅茆茇茈茉茊茋茌èŒèŒŽèŒèŒèŒ‘茒茓茔茕茖茗茘茙茚茛茜èŒèŒžèŒŸ +茠茡茢茣茤茥茦茧茨茩茪茫茬茭茮茯茰茱茲茳茴茵茶茷茸茹茺茻茼茽茾茿 +è€èè‚èƒè„è…è†è‡èˆè‰èŠè‹èŒèèŽèèè‘è’è“è”è•è–è—è˜è™èšè›èœèèžèŸ +è è¡è¢è£è¤è¥è¦è§è¨è©èªè«è¬è­è®è¯è°è±è²è³è´èµè¶è·è¸è¹èºè»è¼è½è¾è¿ +莀èŽèŽ‚莃莄莅莆莇莈莉莊莋莌èŽèŽŽèŽèŽèŽ‘莒莓莔莕莖莗莘莙莚莛莜èŽèŽžèŽŸ +莠莡莢莣莤莥莦莧莨莩莪莫莬莭莮莯莰莱莲莳莴莵莶获莸莹莺莻莼莽莾莿 +è€èè‚èƒè„è…è†è‡èˆè‰èŠè‹èŒèèŽèèè‘è’è“è”è•è–è—è˜è™èšè›èœèèžèŸ +è è¡è¢è£è¤è¥è¦è§è¨è©èªè«è¬è­è®è¯è°è±è²è³è´èµè¶è·è¸è¹èºè»è¼è½è¾è¿ +è€èè‚èƒè„è…è†è‡èˆè‰èŠè‹èŒèèŽèèè‘è’è“è”è•è–è—è˜è™èšè›èœèèžèŸ +è è¡è¢è£è¤è¥è¦è§è¨è©èªè«è¬è­è®è¯è°è±è²è³è´èµè¶è·è¸è¹èºè»è¼è½è¾è¿ +è‘€è‘葂葃葄葅葆葇葈葉葊葋葌è‘è‘Žè‘è‘葑葒葓葔葕葖著葘葙葚葛葜è‘è‘žè‘Ÿ +葠葡葢董葤葥葦葧葨葩葪葫葬葭葮葯葰葱葲葳葴葵葶葷葸葹葺葻葼葽葾葿 +è’€è’蒂蒃蒄蒅蒆蒇蒈蒉蒊蒋蒌è’è’Žè’è’蒑蒒蒓蒔蒕蒖蒗蒘蒙蒚蒛蒜è’è’žè’Ÿ +蒠蒡蒢蒣蒤蒥蒦蒧蒨蒩蒪蒫蒬蒭蒮蒯蒰蒱蒲蒳蒴蒵蒶蒷蒸蒹蒺蒻蒼蒽蒾蒿 +è“€è“蓂蓃蓄蓅蓆蓇蓈蓉蓊蓋蓌è“è“Žè“è“蓑蓒蓓蓔蓕蓖蓗蓘蓙蓚蓛蓜è“è“žè“Ÿ +蓠蓡蓢蓣蓤蓥蓦蓧蓨蓩蓪蓫蓬蓭蓮蓯蓰蓱蓲蓳蓴蓵蓶蓷蓸蓹蓺蓻蓼蓽蓾蓿 +蔀è”蔂蔃蔄蔅蔆蔇蔈蔉蔊蔋蔌è”蔎è”è”蔑蔒蔓蔔蔕蔖蔗蔘蔙蔚蔛蔜è”蔞蔟 +蔠蔡蔢蔣蔤蔥蔦蔧蔨蔩蔪蔫蔬蔭蔮蔯蔰蔱蔲蔳蔴蔵蔶蔷蔸蔹蔺蔻蔼蔽蔾蔿 +è•€è•è•‚蕃蕄蕅蕆蕇蕈蕉蕊蕋蕌è•è•Žè•è•è•‘蕒蕓蕔蕕蕖蕗蕘蕙蕚蕛蕜è•è•žè•Ÿ +蕠蕡蕢蕣蕤蕥蕦蕧蕨蕩蕪蕫蕬蕭蕮蕯蕰蕱蕲蕳蕴蕵蕶蕷蕸蕹蕺蕻蕼蕽蕾蕿 +è–€è–薂薃薄薅薆薇薈薉薊薋薌è–è–Žè–è–薑薒薓薔薕薖薗薘薙薚薛薜è–è–žè–Ÿ +薠薡薢薣薤薥薦薧薨薩薪薫薬薭薮薯薰薱薲薳薴薵薶薷薸薹薺薻薼薽薾薿 +è—€è—藂藃藄藅藆藇藈藉藊藋藌è—è—Žè—è—藑藒藓藔藕藖藗藘藙藚藛藜è—è—žè—Ÿ +藠藡藢藣藤藥藦藧藨藩藪藫藬藭藮藯藰藱藲藳藴藵藶藷藸藹藺藻藼藽藾藿 +蘀è˜è˜‚蘃蘄蘅蘆蘇蘈蘉蘊蘋蘌è˜è˜Žè˜è˜è˜‘蘒蘓蘔蘕蘖蘗蘘蘙蘚蘛蘜è˜è˜žè˜Ÿ +蘠蘡蘢蘣蘤蘥蘦蘧蘨蘩蘪蘫蘬蘭蘮蘯蘰蘱蘲蘳蘴蘵蘶蘷蘸蘹蘺蘻蘼蘽蘾蘿 +虀è™è™‚虃虄虅虆虇虈虉虊虋虌è™è™Žè™è™è™‘虒虓虔處虖虗虘虙虚虛虜è™è™žè™Ÿ +虠虡虢虣虤虥虦虧虨虩虪虫虬虭虮虯虰虱虲虳虴虵虶虷虸虹虺虻虼虽虾虿 +蚀èšèš‚蚃蚄蚅蚆蚇蚈蚉蚊蚋蚌èšèšŽèšèšèš‘蚒蚓蚔蚕蚖蚗蚘蚙蚚蚛蚜èšèšžèšŸ +蚠蚡蚢蚣蚤蚥蚦蚧蚨蚩蚪蚫蚬蚭蚮蚯蚰蚱蚲蚳蚴蚵蚶蚷蚸蚹蚺蚻蚼蚽蚾蚿 +蛀è›è›‚蛃蛄蛅蛆蛇蛈蛉蛊蛋蛌è›è›Žè›è›è›‘蛒蛓蛔蛕蛖蛗蛘蛙蛚蛛蛜è›è›žè›Ÿ +蛠蛡蛢蛣蛤蛥蛦蛧蛨蛩蛪蛫蛬蛭蛮蛯蛰蛱蛲蛳蛴蛵蛶蛷蛸蛹蛺蛻蛼蛽蛾蛿 +蜀èœèœ‚蜃蜄蜅蜆蜇蜈蜉蜊蜋蜌èœèœŽèœèœèœ‘蜒蜓蜔蜕蜖蜗蜘蜙蜚蜛蜜èœèœžèœŸ +蜠蜡蜢蜣蜤蜥蜦蜧蜨蜩蜪蜫蜬蜭蜮蜯蜰蜱蜲蜳蜴蜵蜶蜷蜸蜹蜺蜻蜼蜽蜾蜿 +è€èè‚èƒè„è…è†è‡èˆè‰èŠè‹èŒèèŽèèè‘è’è“è”è•è–è—è˜è™èšè›èœèèžèŸ +è è¡è¢è£è¤è¥è¦è§è¨è©èªè«è¬è­è®è¯è°è±è²è³è´èµè¶è·è¸è¹èºè»è¼è½è¾è¿ +螀èžèž‚螃螄螅螆螇螈螉螊螋螌èžèžŽèžèžèž‘螒螓螔螕螖螗螘螙螚螛螜èžèžžèžŸ +螠螡螢螣螤螥螦螧螨螩螪螫螬螭螮螯螰螱螲螳螴螵螶螷螸螹螺螻螼螽螾螿 +蟀èŸèŸ‚蟃蟄蟅蟆蟇蟈蟉蟊蟋蟌èŸèŸŽèŸèŸèŸ‘蟒蟓蟔蟕蟖蟗蟘蟙蟚蟛蟜èŸèŸžèŸŸ +蟠蟡蟢蟣蟤蟥蟦蟧蟨蟩蟪蟫蟬蟭蟮蟯蟰蟱蟲蟳蟴蟵蟶蟷蟸蟹蟺蟻蟼蟽蟾蟿 +è €è è ‚蠃蠄蠅蠆蠇蠈蠉蠊蠋蠌è è Žè è è ‘蠒蠓蠔蠕蠖蠗蠘蠙蠚蠛蠜è è žè Ÿ +蠠蠡蠢蠣蠤蠥蠦蠧蠨蠩蠪蠫蠬蠭蠮蠯蠰蠱蠲蠳蠴蠵蠶蠷蠸蠹蠺蠻蠼蠽蠾蠿 +è¡€è¡è¡‚衃衄衅衆衇衈衉衊衋行è¡è¡Žè¡è¡è¡‘衒術衔衕衖街衘衙衚衛衜è¡è¡žè¡Ÿ +衠衡衢衣衤补衦衧表衩衪衫衬衭衮衯衰衱衲衳衴衵衶衷衸衹衺衻衼衽衾衿 +袀è¢è¢‚袃袄袅袆袇袈袉袊袋袌è¢è¢Žè¢è¢è¢‘袒袓袔袕袖袗袘袙袚袛袜è¢è¢žè¢Ÿ +袠袡袢袣袤袥袦袧袨袩袪被袬袭袮袯袰袱袲袳袴袵袶袷袸袹袺袻袼袽袾袿 +裀è£è£‚裃裄装裆裇裈裉裊裋裌è£è£Žè£è£è£‘裒裓裔裕裖裗裘裙裚裛補è£è£žè£Ÿ +裠裡裢裣裤裥裦裧裨裩裪裫裬裭裮裯裰裱裲裳裴裵裶裷裸裹裺裻裼製裾裿 +褀è¤è¤‚褃褄褅褆複褈褉褊褋褌è¤è¤Žè¤è¤è¤‘褒褓褔褕褖褗褘褙褚褛褜è¤è¤žè¤Ÿ +褠褡褢褣褤褥褦褧褨褩褪褫褬褭褮褯褰褱褲褳褴褵褶褷褸褹褺褻褼褽褾褿 +襀è¥è¥‚襃襄襅襆襇襈襉襊襋襌è¥è¥Žè¥è¥è¥‘襒襓襔襕襖襗襘襙襚襛襜è¥è¥žè¥Ÿ +襠襡襢襣襤襥襦襧襨襩襪襫襬襭襮襯襰襱襲襳襴襵襶襷襸襹襺襻襼襽襾西 +覀è¦è¦‚覃覄覅覆覇覈覉覊見覌è¦è¦Žè¦è¦è¦‘覒覓覔覕視覗覘覙覚覛覜è¦è¦žè¦Ÿ +覠覡覢覣覤覥覦覧覨覩親覫覬覭覮覯覰覱覲観覴覵覶覷覸覹覺覻覼覽覾覿 +觀è§è§‚觃规觅视觇览觉觊觋觌è§è§Žè§è§è§‘角觓觔觕觖觗觘觙觚觛觜è§è§žè§Ÿ +觠觡觢解觤觥触觧觨觩觪觫觬觭觮觯觰觱觲觳觴觵觶觷觸觹觺觻觼觽觾觿 +言è¨è¨‚訃訄訅訆訇計訉訊訋訌è¨è¨Žè¨è¨è¨‘訒訓訔訕訖託記訙訚訛訜è¨è¨žè¨Ÿ +訠訡訢訣訤訥訦訧訨訩訪訫訬設訮訯訰許訲訳訴訵訶訷訸訹診註証訽訾訿 +è©€è©è©‚詃詄詅詆詇詈詉詊詋詌è©è©Žè©è©è©‘詒詓詔評詖詗詘詙詚詛詜è©è©žè©Ÿ +詠詡詢詣詤詥試詧詨詩詪詫詬詭詮詯詰話該詳詴詵詶詷詸詹詺詻詼詽詾詿 +誀èªèª‚誃誄誅誆誇誈誉誊誋誌èªèªŽèªèªèª‘誒誓誔誕誖誗誘誙誚誛誜èªèªžèªŸ +誠誡誢誣誤誥誦誧誨誩說誫説読誮誯誰誱課誳誴誵誶誷誸誹誺誻誼誽誾調 +è«€è«è«‚諃諄諅諆談諈諉諊請諌è«è«Žè«è«è«‘諒諓諔諕論諗諘諙諚諛諜è«è«žè«Ÿ +諠諡諢諣諤諥諦諧諨諩諪諫諬諭諮諯諰諱諲諳諴諵諶諷諸諹諺諻諼諽諾諿 +謀è¬è¬‚謃謄謅謆謇謈謉謊謋謌è¬è¬Žè¬è¬è¬‘謒謓謔謕謖謗謘謙謚講謜è¬è¬žè¬Ÿ +謠謡謢謣謤謥謦謧謨謩謪謫謬謭謮謯謰謱謲謳謴謵謶謷謸謹謺謻謼謽謾謿 +è­€è­è­‚譃譄譅譆譇譈證譊譋譌è­è­Žè­è­è­‘譒譓譔譕譖譗識譙譚譛譜è­è­žè­Ÿ +譠譡譢譣譤譥警譧譨譩譪譫譬譭譮譯議譱譲譳譴譵譶護譸譹譺譻譼譽譾譿 +讀è®è®‚讃讄讅讆讇讈讉變讋讌è®è®Žè®è®è®‘讒讓讔讕讖讗讘讙讚讛讜è®è®žè®Ÿ +讠计订讣认讥讦讧讨让讪讫讬训议讯记讱讲讳讴讵讶讷许讹论讻讼讽设访 +诀è¯è¯‚诃评诅识诇诈诉诊诋诌è¯è¯Žè¯è¯è¯‘诒诓诔试诖诗诘诙诚诛诜è¯è¯žè¯Ÿ +诠诡询诣诤该详诧诨诩诪诫诬语诮误诰诱诲诳说诵诶请诸诹诺读诼诽课诿 +è°€è°è°‚调谄谅谆谇谈谉谊谋谌è°è°Žè°è°è°‘谒谓谔谕谖谗谘谙谚谛谜è°è°žè°Ÿ +谠谡谢谣谤谥谦谧谨谩谪谫谬谭谮谯谰谱谲谳谴谵谶谷谸谹谺谻谼谽谾谿 +è±€è±è±‚豃豄豅豆豇豈豉豊豋豌è±è±Žè±è±è±‘豒豓豔豕豖豗豘豙豚豛豜è±è±žè±Ÿ +豠象豢豣豤豥豦豧豨豩豪豫豬豭豮豯豰豱豲豳豴豵豶豷豸豹豺豻豼豽豾豿 +è²€è²è²‚貃貄貅貆貇貈貉貊貋貌è²è²Žè²è²è²‘貒貓貔貕貖貗貘貙貚貛貜è²è²žè²Ÿ +負財貢貣貤貥貦貧貨販貪貫責貭貮貯貰貱貲貳貴貵貶買貸貹貺費貼貽貾貿 +è³€è³è³‚賃賄賅賆資賈賉賊賋賌è³è³Žè³è³è³‘賒賓賔賕賖賗賘賙賚賛賜è³è³žè³Ÿ +賠賡賢賣賤賥賦賧賨賩質賫賬賭賮賯賰賱賲賳賴賵賶賷賸賹賺賻購賽賾賿 +è´€è´è´‚贃贄贅贆贇贈贉贊贋贌è´è´Žè´è´è´‘贒贓贔贕贖贗贘贙贚贛贜è´è´žè´Ÿ +贠贡财责贤败账货质贩贪贫贬购贮贯贰贱贲贳贴贵贶贷贸费贺贻贼贽贾贿 +èµ€èµèµ‚赃资赅赆赇赈赉赊赋赌èµèµŽèµèµèµ‘赒赓赔赕赖赗赘赙赚赛赜èµèµžèµŸ +赠赡赢赣赤赥赦赧赨赩赪赫赬赭赮赯走赱赲赳赴赵赶起赸赹赺赻赼赽赾赿 +趀è¶è¶‚趃趄超趆趇趈趉越趋趌è¶è¶Žè¶è¶è¶‘趒趓趔趕趖趗趘趙趚趛趜è¶è¶žè¶Ÿ +趠趡趢趣趤趥趦趧趨趩趪趫趬趭趮趯趰趱趲足趴趵趶趷趸趹趺趻趼趽趾趿 +è·€è·è·‚跃跄跅跆跇跈跉跊跋跌è·è·Žè·è·è·‘跒跓跔跕跖跗跘跙跚跛跜è·è·žè·Ÿ +跠跡跢跣跤跥跦跧跨跩跪跫跬跭跮路跰跱跲跳跴践跶跷跸跹跺跻跼跽跾跿 +踀è¸è¸‚踃踄踅踆踇踈踉踊踋踌è¸è¸Žè¸è¸è¸‘踒踓踔踕踖踗踘踙踚踛踜è¸è¸žè¸Ÿ +踠踡踢踣踤踥踦踧踨踩踪踫踬踭踮踯踰踱踲踳踴踵踶踷踸踹踺踻踼踽踾踿 +è¹€è¹è¹‚蹃蹄蹅蹆蹇蹈蹉蹊蹋蹌è¹è¹Žè¹è¹è¹‘蹒蹓蹔蹕蹖蹗蹘蹙蹚蹛蹜è¹è¹žè¹Ÿ +蹠蹡蹢蹣蹤蹥蹦蹧蹨蹩蹪蹫蹬蹭蹮蹯蹰蹱蹲蹳蹴蹵蹶蹷蹸蹹蹺蹻蹼蹽蹾蹿 +躀èºèº‚躃躄躅躆躇躈躉躊躋躌èºèºŽèºèºèº‘躒躓躔躕躖躗躘躙躚躛躜èºèºžèºŸ +躠躡躢躣躤躥躦躧躨躩躪身躬躭躮躯躰躱躲躳躴躵躶躷躸躹躺躻躼躽躾躿 +軀è»è»‚軃軄軅軆軇軈軉車軋軌è»è»Žè»è»è»‘軒軓軔軕軖軗軘軙軚軛軜è»è»žè»Ÿ +軠軡転軣軤軥軦軧軨軩軪軫軬軭軮軯軰軱軲軳軴軵軶軷軸軹軺軻軼軽軾軿 +è¼€è¼è¼‚較輄輅輆輇輈載輊輋輌è¼è¼Žè¼è¼è¼‘輒輓輔輕輖輗輘輙輚輛輜è¼è¼žè¼Ÿ +輠輡輢輣輤輥輦輧輨輩輪輫輬輭輮輯輰輱輲輳輴輵輶輷輸輹輺輻輼輽輾輿 +è½€è½è½‚轃轄轅轆轇轈轉轊轋轌è½è½Žè½è½è½‘轒轓轔轕轖轗轘轙轚轛轜è½è½žè½Ÿ +轠轡轢轣轤轥车轧轨轩轪轫转轭轮软轰轱轲轳轴轵轶轷轸轹轺轻轼载轾轿 +è¾€è¾è¾‚较辄辅辆辇辈辉辊辋辌è¾è¾Žè¾è¾è¾‘辒输辔辕辖辗辘辙辚辛辜è¾è¾žè¾Ÿ +辠辡辢辣辤辥辦辧辨辩辪辫辬辭辮辯辰辱農辳辴辵辶辷辸边辺辻込辽达辿 +è¿€è¿è¿‚迃迄迅迆过迈迉迊迋迌è¿è¿Žè¿è¿è¿‘迒迓返迕迖迗还这迚进远è¿è¿žè¿Ÿ +迠迡迢迣迤迥迦迧迨迩迪迫迬迭迮迯述迱迲迳迴迵迶迷迸迹迺迻迼追迾迿 +退é€é€‚逃逄逅逆逇逈选逊逋逌é€é€Žé€é€é€‘递逓途逕逖逗逘這通逛逜é€é€žé€Ÿ +造逡逢連逤逥逦逧逨逩逪逫逬逭逮逯逰週進逳逴逵逶逷逸逹逺逻逼逽逾逿 +é€éé‚éƒé„é…é†é‡éˆé‰éŠé‹éŒééŽééé‘é’é“é”é•é–é—é˜é™éšé›éœééžéŸ +é é¡é¢é£é¤é¥é¦é§é¨é©éªé«é¬é­é®é¯é°é±é²é³é´éµé¶é·é¸é¹éºé»é¼é½é¾é¿ +é‚€é‚邂邃還邅邆邇邈邉邊邋邌é‚é‚Žé‚é‚邑邒邓邔邕邖邗邘邙邚邛邜é‚é‚žé‚Ÿ +邠邡邢那邤邥邦邧邨邩邪邫邬邭邮邯邰邱邲邳邴邵邶邷邸邹邺邻邼邽邾邿 +郀éƒéƒ‚郃郄郅郆郇郈郉郊郋郌éƒéƒŽéƒéƒéƒ‘郒郓郔郕郖郗郘郙郚郛郜éƒéƒžéƒŸ +郠郡郢郣郤郥郦郧部郩郪郫郬郭郮郯郰郱郲郳郴郵郶郷郸郹郺郻郼都郾郿 +é„€é„鄂鄃鄄鄅鄆鄇鄈鄉鄊鄋鄌é„é„Žé„é„鄑鄒鄓鄔鄕鄖鄗鄘鄙鄚鄛鄜é„é„žé„Ÿ +鄠鄡鄢鄣鄤鄥鄦鄧鄨鄩鄪鄫鄬鄭鄮鄯鄰鄱鄲鄳鄴鄵鄶鄷鄸鄹鄺鄻鄼鄽鄾鄿 +é…€é…酂酃酄酅酆酇酈酉酊酋酌é…é…Žé…é…酑酒酓酔酕酖酗酘酙酚酛酜é…é…žé…Ÿ +酠酡酢酣酤酥酦酧酨酩酪酫酬酭酮酯酰酱酲酳酴酵酶酷酸酹酺酻酼酽酾酿 +醀é†é†‚醃醄醅醆醇醈醉醊醋醌é†é†Žé†é†é†‘醒醓醔醕醖醗醘醙醚醛醜é†é†žé†Ÿ +醠醡醢醣醤醥醦醧醨醩醪醫醬醭醮醯醰醱醲醳醴醵醶醷醸醹醺醻醼醽醾醿 +釀é‡é‡‚釃釄釅釆采釈釉释釋里é‡é‡Žé‡é‡é‡‘釒釓釔釕釖釗釘釙釚釛釜é‡é‡žé‡Ÿ +釠釡釢釣釤釥釦釧釨釩釪釫釬釭釮釯釰釱釲釳釴釵釶釷釸釹釺釻釼釽釾釿 +鈀éˆéˆ‚鈃鈄鈅鈆鈇鈈鈉鈊鈋鈌éˆéˆŽéˆéˆéˆ‘鈒鈓鈔鈕鈖鈗鈘鈙鈚鈛鈜éˆéˆžéˆŸ +鈠鈡鈢鈣鈤鈥鈦鈧鈨鈩鈪鈫鈬鈭鈮鈯鈰鈱鈲鈳鈴鈵鈶鈷鈸鈹鈺鈻鈼鈽鈾鈿 +鉀é‰é‰‚鉃鉄鉅鉆鉇鉈鉉鉊鉋鉌é‰é‰Žé‰é‰é‰‘鉒鉓鉔鉕鉖鉗鉘鉙鉚鉛鉜é‰é‰žé‰Ÿ +鉠鉡鉢鉣鉤鉥鉦鉧鉨鉩鉪鉫鉬鉭鉮鉯鉰鉱鉲鉳鉴鉵鉶鉷鉸鉹鉺鉻鉼鉽鉾鉿 +銀éŠéŠ‚銃銄銅銆銇銈銉銊銋銌éŠéŠŽéŠéŠéŠ‘銒銓銔銕銖銗銘銙銚銛銜éŠéŠžéŠŸ +銠銡銢銣銤銥銦銧銨銩銪銫銬銭銮銯銰銱銲銳銴銵銶銷銸銹銺銻銼銽銾銿 +é‹€é‹é‹‚鋃鋄鋅鋆鋇鋈鋉鋊鋋鋌é‹é‹Žé‹é‹é‹‘鋒鋓鋔鋕鋖鋗鋘鋙鋚鋛鋜é‹é‹žé‹Ÿ +鋠鋡鋢鋣鋤鋥鋦鋧鋨鋩鋪鋫鋬鋭鋮鋯鋰鋱鋲鋳鋴鋵鋶鋷鋸鋹鋺鋻鋼鋽鋾鋿 +錀éŒéŒ‚錃錄錅錆錇錈錉錊錋錌éŒéŒŽéŒéŒéŒ‘錒錓錔錕錖錗錘錙錚錛錜éŒéŒžéŒŸ +錠錡錢錣錤錥錦錧錨錩錪錫錬錭錮錯錰錱録錳錴錵錶錷錸錹錺錻錼錽錾錿 +é€éé‚éƒé„é…é†é‡éˆé‰éŠé‹éŒééŽééé‘é’é“é”é•é–é—é˜é™éšé›éœééžéŸ +é é¡é¢é£é¤é¥é¦é§é¨é©éªé«é¬é­é®é¯é°é±é²é³é´éµé¶é·é¸é¹éºé»é¼é½é¾é¿ +鎀éŽéŽ‚鎃鎄鎅鎆鎇鎈鎉鎊鎋鎌éŽéŽŽéŽéŽéŽ‘鎒鎓鎔鎕鎖鎗鎘鎙鎚鎛鎜éŽéŽžéŽŸ +鎠鎡鎢鎣鎤鎥鎦鎧鎨鎩鎪鎫鎬鎭鎮鎯鎰鎱鎲鎳鎴鎵鎶鎷鎸鎹鎺鎻鎼鎽鎾鎿 +é€éé‚éƒé„é…é†é‡éˆé‰éŠé‹éŒééŽééé‘é’é“é”é•é–é—é˜é™éšé›éœééžéŸ +é é¡é¢é£é¤é¥é¦é§é¨é©éªé«é¬é­é®é¯é°é±é²é³é´éµé¶é·é¸é¹éºé»é¼é½é¾é¿ +é€éé‚éƒé„é…é†é‡éˆé‰éŠé‹éŒééŽééé‘é’é“é”é•é–é—é˜é™éšé›éœééžéŸ +é é¡é¢é£é¤é¥é¦é§é¨é©éªé«é¬é­é®é¯é°é±é²é³é´éµé¶é·é¸é¹éºé»é¼é½é¾é¿ +é‘€é‘鑂鑃鑄鑅鑆鑇鑈鑉鑊鑋鑌é‘é‘Žé‘é‘鑑鑒鑓鑔鑕鑖鑗鑘鑙鑚鑛鑜é‘é‘žé‘Ÿ +鑠鑡鑢鑣鑤鑥鑦鑧鑨鑩鑪鑫鑬鑭鑮鑯鑰鑱鑲鑳鑴鑵鑶鑷鑸鑹鑺鑻鑼鑽鑾鑿 +é’€é’钂钃钄钅钆钇针钉钊钋钌é’é’Žé’é’钑钒钓钔钕钖钗钘钙钚钛钜é’é’žé’Ÿ +钠钡钢钣钤钥钦钧钨钩钪钫钬钭钮钯钰钱钲钳钴钵钶钷钸钹钺钻钼钽钾钿 +é“€é“铂铃铄铅铆铇铈铉铊铋铌é“é“Žé“é“铑铒铓铔铕铖铗铘铙铚铛铜é“é“žé“Ÿ +铠铡铢铣铤铥铦铧铨铩铪铫铬铭铮铯铰铱铲铳铴铵银铷铸铹铺铻铼铽链铿 +销é”锂锃锄锅锆锇锈锉锊锋锌é”锎é”é”锑锒锓锔锕锖锗锘错锚锛锜é”锞锟 +锠锡锢锣锤锥锦锧锨锩锪锫锬锭键锯锰锱锲锳锴锵锶锷锸锹锺锻锼锽锾锿 +é•€é•é•‚镃镄镅镆镇镈镉镊镋镌é•é•Žé•é•é•‘镒镓镔镕镖镗镘镙镚镛镜é•é•žé•Ÿ +镠镡镢镣镤镥镦镧镨镩镪镫镬镭镮镯镰镱镲镳镴镵镶長镸镹镺镻镼镽镾长 +é–€é–閂閃閄閅閆閇閈閉閊開閌é–é–Žé–é–閑閒間閔閕閖閗閘閙閚閛閜é–é–žé–Ÿ +閠閡関閣閤閥閦閧閨閩閪閫閬閭閮閯閰閱閲閳閴閵閶閷閸閹閺閻閼閽閾閿 +é—€é—闂闃闄闅闆闇闈闉闊闋闌é—é—Žé—é—闑闒闓闔闕闖闗闘闙闚闛關é—é—žé—Ÿ +闠闡闢闣闤闥闦闧门闩闪闫闬闭问闯闰闱闲闳间闵闶闷闸闹闺闻闼闽闾闿 +阀é˜é˜‚阃阄阅阆阇阈阉阊阋阌é˜é˜Žé˜é˜é˜‘阒阓阔阕阖阗阘阙阚阛阜é˜é˜žé˜Ÿ +阠阡阢阣阤阥阦阧阨阩阪阫阬阭阮阯阰阱防阳阴阵阶阷阸阹阺阻阼阽阾阿 +陀é™é™‚陃附际陆陇陈陉陊陋陌é™é™Žé™é™é™‘陒陓陔陕陖陗陘陙陚陛陜é™é™žé™Ÿ +陠陡院陣除陥陦陧陨险陪陫陬陭陮陯陰陱陲陳陴陵陶陷陸陹険陻陼陽陾陿 +隀éšéš‚隃隄隅隆隇隈隉隊隋隌éšéšŽéšéšéš‘隒隓隔隕隖隗隘隙隚際障éšéšžéšŸ +隠隡隢隣隤隥隦隧隨隩險隫隬隭隮隯隰隱隲隳隴隵隶隷隸隹隺隻隼隽难隿 +雀é›é›‚雃雄雅集雇雈雉雊雋雌é›é›Žé›é›é›‘雒雓雔雕雖雗雘雙雚雛雜é›é›žé›Ÿ +雠雡離難雤雥雦雧雨雩雪雫雬雭雮雯雰雱雲雳雴雵零雷雸雹雺電雼雽雾雿 +需éœéœ‚霃霄霅霆震霈霉霊霋霌éœéœŽéœéœéœ‘霒霓霔霕霖霗霘霙霚霛霜éœéœžéœŸ +霠霡霢霣霤霥霦霧霨霩霪霫霬霭霮霯霰霱露霳霴霵霶霷霸霹霺霻霼霽霾霿 +é€éé‚éƒé„é…é†é‡éˆé‰éŠé‹éŒééŽééé‘é’é“é”é•é–é—é˜é™éšé›éœééžéŸ +é é¡é¢é£é¤é¥é¦é§é¨é©éªé«é¬é­é®é¯é°é±é²é³é´éµé¶é·é¸é¹éºé»é¼é½é¾é¿ +鞀éžéž‚鞃鞄鞅鞆鞇鞈鞉鞊鞋鞌éžéžŽéžéžéž‘鞒鞓鞔鞕鞖鞗鞘鞙鞚鞛鞜éžéžžéžŸ +鞠鞡鞢鞣鞤鞥鞦鞧鞨鞩鞪鞫鞬鞭鞮鞯鞰鞱鞲鞳鞴鞵鞶鞷鞸鞹鞺鞻鞼鞽鞾鞿 +韀éŸéŸ‚韃韄韅韆韇韈韉韊韋韌éŸéŸŽéŸéŸéŸ‘韒韓韔韕韖韗韘韙韚韛韜éŸéŸžéŸŸ +韠韡韢韣韤韥韦韧韨韩韪韫韬韭韮韯韰韱韲音韴韵韶韷韸韹韺韻韼韽韾響 +é €é é ‚頃頄項順頇須頉頊頋頌é é Žé é é ‘頒頓頔頕頖頗領頙頚頛頜é é žé Ÿ +頠頡頢頣頤頥頦頧頨頩頪頫頬頭頮頯頰頱頲頳頴頵頶頷頸頹頺頻頼頽頾頿 +é¡€é¡é¡‚顃顄顅顆顇顈顉顊顋題é¡é¡Žé¡é¡é¡‘顒顓顔顕顖顗願顙顚顛顜é¡é¡žé¡Ÿ +顠顡顢顣顤顥顦顧顨顩顪顫顬顭顮顯顰顱顲顳顴页顶顷顸项顺须顼顽顾顿 +颀é¢é¢‚颃预颅领颇颈颉颊颋颌é¢é¢Žé¢é¢é¢‘颒颓颔颕颖颗题颙颚颛颜é¢é¢žé¢Ÿ +颠颡颢颣颤颥颦颧風颩颪颫颬颭颮颯颰颱颲颳颴颵颶颷颸颹颺颻颼颽颾颿 +飀é£é£‚飃飄飅飆飇飈飉飊飋飌é£é£Žé£é£é£‘飒飓飔飕飖飗飘飙飚飛飜é£é£žé£Ÿ +飠飡飢飣飤飥飦飧飨飩飪飫飬飭飮飯飰飱飲飳飴飵飶飷飸飹飺飻飼飽飾飿 +餀é¤é¤‚餃餄餅餆餇餈餉養餋餌é¤é¤Žé¤é¤é¤‘餒餓餔餕餖餗餘餙餚餛餜é¤é¤žé¤Ÿ +餠餡餢餣餤餥餦餧館餩餪餫餬餭餮餯餰餱餲餳餴餵餶餷餸餹餺餻餼餽餾餿 +饀é¥é¥‚饃饄饅饆饇饈饉饊饋饌é¥é¥Žé¥é¥é¥‘饒饓饔饕饖饗饘饙饚饛饜é¥é¥žé¥Ÿ +饠饡饢饣饤饥饦饧饨饩饪饫饬饭饮饯饰饱饲饳饴饵饶饷饸饹饺饻饼饽饾饿 +馀é¦é¦‚馃馄馅馆馇馈馉馊馋馌é¦é¦Žé¦é¦é¦‘馒馓馔馕首馗馘香馚馛馜é¦é¦žé¦Ÿ +馠馡馢馣馤馥馦馧馨馩馪馫馬馭馮馯馰馱馲馳馴馵馶馷馸馹馺馻馼馽馾馿 +駀é§é§‚駃駄駅駆駇駈駉駊駋駌é§é§Žé§é§é§‘駒駓駔駕駖駗駘駙駚駛駜é§é§žé§Ÿ +駠駡駢駣駤駥駦駧駨駩駪駫駬駭駮駯駰駱駲駳駴駵駶駷駸駹駺駻駼駽駾駿 +騀é¨é¨‚騃騄騅騆騇騈騉騊騋騌é¨é¨Žé¨é¨é¨‘騒験騔騕騖騗騘騙騚騛騜é¨é¨žé¨Ÿ +騠騡騢騣騤騥騦騧騨騩騪騫騬騭騮騯騰騱騲騳騴騵騶騷騸騹騺騻騼騽騾騿 +é©€é©é©‚驃驄驅驆驇驈驉驊驋驌é©é©Žé©é©é©‘驒驓驔驕驖驗驘驙驚驛驜é©é©žé©Ÿ +驠驡驢驣驤驥驦驧驨驩驪驫马驭驮驯驰驱驲驳驴驵驶驷驸驹驺驻驼驽驾驿 +骀éªéª‚骃骄骅骆骇骈骉骊骋验éªéªŽéªéªéª‘骒骓骔骕骖骗骘骙骚骛骜éªéªžéªŸ +骠骡骢骣骤骥骦骧骨骩骪骫骬骭骮骯骰骱骲骳骴骵骶骷骸骹骺骻骼骽骾骿 +é«€é«é«‚髃髄髅髆髇髈髉髊髋髌é«é«Žé«é«é«‘髒髓體髕髖髗高髙髚髛髜é«é«žé«Ÿ +髠髡髢髣髤髥髦髧髨髩髪髫髬髭髮髯髰髱髲髳髴髵髶髷髸髹髺髻髼髽髾髿 +鬀é¬é¬‚鬃鬄鬅鬆鬇鬈鬉鬊鬋鬌é¬é¬Žé¬é¬é¬‘鬒鬓鬔鬕鬖鬗鬘鬙鬚鬛鬜é¬é¬žé¬Ÿ +鬠鬡鬢鬣鬤鬥鬦鬧鬨鬩鬪鬫鬬鬭鬮鬯鬰鬱鬲鬳鬴鬵鬶鬷鬸鬹鬺鬻鬼鬽鬾鬿 +é­€é­é­‚魃魄魅魆魇魈魉魊魋魌é­é­Žé­é­é­‘魒魓魔魕魖魗魘魙魚魛魜é­é­žé­Ÿ +魠魡魢魣魤魥魦魧魨魩魪魫魬魭魮魯魰魱魲魳魴魵魶魷魸魹魺魻魼魽魾魿 +鮀é®é®‚鮃鮄鮅鮆鮇鮈鮉鮊鮋鮌é®é®Žé®é®é®‘鮒鮓鮔鮕鮖鮗鮘鮙鮚鮛鮜é®é®žé®Ÿ +鮠鮡鮢鮣鮤鮥鮦鮧鮨鮩鮪鮫鮬鮭鮮鮯鮰鮱鮲鮳鮴鮵鮶鮷鮸鮹鮺鮻鮼鮽鮾鮿 +鯀é¯é¯‚鯃鯄鯅鯆鯇鯈鯉鯊鯋鯌é¯é¯Žé¯é¯é¯‘鯒鯓鯔鯕鯖鯗鯘鯙鯚鯛鯜é¯é¯žé¯Ÿ +鯠鯡鯢鯣鯤鯥鯦鯧鯨鯩鯪鯫鯬鯭鯮鯯鯰鯱鯲鯳鯴鯵鯶鯷鯸鯹鯺鯻鯼鯽鯾鯿 +é°€é°é°‚鰃鰄鰅鰆鰇鰈鰉鰊鰋鰌é°é°Žé°é°é°‘鰒鰓鰔鰕鰖鰗鰘鰙鰚鰛鰜é°é°žé°Ÿ +鰠鰡鰢鰣鰤鰥鰦鰧鰨鰩鰪鰫鰬鰭鰮鰯鰰鰱鰲鰳鰴鰵鰶鰷鰸鰹鰺鰻鰼鰽鰾鰿 +é±€é±é±‚鱃鱄鱅鱆鱇鱈鱉鱊鱋鱌é±é±Žé±é±é±‘鱒鱓鱔鱕鱖鱗鱘鱙鱚鱛鱜é±é±žé±Ÿ +鱠鱡鱢鱣鱤鱥鱦鱧鱨鱩鱪鱫鱬鱭鱮鱯鱰鱱鱲鱳鱴鱵鱶鱷鱸鱹鱺鱻鱼鱽鱾鱿 +é²€é²é²‚鲃鲄鲅鲆鲇鲈鲉鲊鲋鲌é²é²Žé²é²é²‘鲒鲓鲔鲕鲖鲗鲘鲙鲚鲛鲜é²é²žé²Ÿ +鲠鲡鲢鲣鲤鲥鲦鲧鲨鲩鲪鲫鲬鲭鲮鲯鲰鲱鲲鲳鲴鲵鲶鲷鲸鲹鲺鲻鲼鲽鲾鲿 +é³€é³é³‚鳃鳄鳅鳆鳇鳈鳉鳊鳋鳌é³é³Žé³é³é³‘鳒鳓鳔鳕鳖鳗鳘鳙鳚鳛鳜é³é³žé³Ÿ +鳠鳡鳢鳣鳤鳥鳦鳧鳨鳩鳪鳫鳬鳭鳮鳯鳰鳱鳲鳳鳴鳵鳶鳷鳸鳹鳺鳻鳼鳽鳾鳿 +é´€é´é´‚鴃鴄鴅鴆鴇鴈鴉鴊鴋鴌é´é´Žé´é´é´‘鴒鴓鴔鴕鴖鴗鴘鴙鴚鴛鴜é´é´žé´Ÿ +鴠鴡鴢鴣鴤鴥鴦鴧鴨鴩鴪鴫鴬鴭鴮鴯鴰鴱鴲鴳鴴鴵鴶鴷鴸鴹鴺鴻鴼鴽鴾鴿 +éµ€éµéµ‚鵃鵄鵅鵆鵇鵈鵉鵊鵋鵌éµéµŽéµéµéµ‘鵒鵓鵔鵕鵖鵗鵘鵙鵚鵛鵜éµéµžéµŸ +鵠鵡鵢鵣鵤鵥鵦鵧鵨鵩鵪鵫鵬鵭鵮鵯鵰鵱鵲鵳鵴鵵鵶鵷鵸鵹鵺鵻鵼鵽鵾鵿 +鶀é¶é¶‚鶃鶄鶅鶆鶇鶈鶉鶊鶋鶌é¶é¶Žé¶é¶é¶‘鶒鶓鶔鶕鶖鶗鶘鶙鶚鶛鶜é¶é¶žé¶Ÿ +鶠鶡鶢鶣鶤鶥鶦鶧鶨鶩鶪鶫鶬鶭鶮鶯鶰鶱鶲鶳鶴鶵鶶鶷鶸鶹鶺鶻鶼鶽鶾鶿 +é·€é·é·‚鷃鷄鷅鷆鷇鷈鷉鷊鷋鷌é·é·Žé·é·é·‘鷒鷓鷔鷕鷖鷗鷘鷙鷚鷛鷜é·é·žé·Ÿ +鷠鷡鷢鷣鷤鷥鷦鷧鷨鷩鷪鷫鷬鷭鷮鷯鷰鷱鷲鷳鷴鷵鷶鷷鷸鷹鷺鷻鷼鷽鷾鷿 +鸀é¸é¸‚鸃鸄鸅鸆鸇鸈鸉鸊鸋鸌é¸é¸Žé¸é¸é¸‘鸒鸓鸔鸕鸖鸗鸘鸙鸚鸛鸜é¸é¸žé¸Ÿ +鸠鸡鸢鸣鸤鸥鸦鸧鸨鸩鸪鸫鸬鸭鸮鸯鸰鸱鸲鸳鸴鸵鸶鸷鸸鸹鸺鸻鸼鸽鸾鸿 +é¹€é¹é¹‚鹃鹄鹅鹆鹇鹈鹉鹊鹋鹌é¹é¹Žé¹é¹é¹‘鹒鹓鹔鹕鹖鹗鹘鹙鹚鹛鹜é¹é¹žé¹Ÿ +鹠鹡鹢鹣鹤鹥鹦鹧鹨鹩鹪鹫鹬鹭鹮鹯鹰鹱鹲鹳鹴鹵鹶鹷鹸鹹鹺鹻鹼鹽鹾鹿 +麀éºéº‚麃麄麅麆麇麈麉麊麋麌éºéºŽéºéºéº‘麒麓麔麕麖麗麘麙麚麛麜éºéºžéºŸ +麠麡麢麣麤麥麦麧麨麩麪麫麬麭麮麯麰麱麲麳麴麵麶麷麸麹麺麻麼麽麾麿 +黀é»é»‚黃黄黅黆黇黈黉黊黋黌é»é»Žé»é»é»‘黒黓黔黕黖黗默黙黚黛黜é»é»žé»Ÿ +黠黡黢黣黤黥黦黧黨黩黪黫黬黭黮黯黰黱黲黳黴黵黶黷黸黹黺黻黼黽黾黿 +é¼€é¼é¼‚鼃鼄鼅鼆鼇鼈鼉鼊鼋鼌é¼é¼Žé¼é¼é¼‘鼒鼓鼔鼕鼖鼗鼘鼙鼚鼛鼜é¼é¼žé¼Ÿ +鼠鼡鼢鼣鼤鼥鼦鼧鼨鼩鼪鼫鼬鼭鼮鼯鼰鼱鼲鼳鼴鼵鼶鼷鼸鼹鼺鼻鼼鼽鼾鼿 +é½€é½é½‚齃齄齅齆齇齈齉齊齋齌é½é½Žé½é½é½‘齒齓齔齕齖齗齘齙齚齛齜é½é½žé½Ÿ +齠齡齢齣齤齥齦齧齨齩齪齫齬齭齮齯齰齱齲齳齴齵齶齷齸齹齺齻齼齽齾齿 +é¾€é¾é¾‚龃龄龅龆龇龈龉龊龋龌é¾é¾Žé¾é¾é¾‘龒龓龔龕龖龗龘龙龚龛龜é¾é¾žé¾Ÿ +龠龡龢龣龤龥龦龧龨龩龪龫龬龭龮龯龰龱龲龳龴龵龶龷龸龹龺龻龼龽龾龿 +é¿€é¿é¿‚鿃鿄鿅鿆鿇鿈鿉鿊鿋鿌é¿é¿Žé¿é¿é¿‘鿒鿓鿔鿕鿖鿗鿘鿙鿚鿛鿜é¿é¿žé¿Ÿ +鿠鿡鿢鿣鿤鿥鿦鿧鿨鿩鿪鿫鿬鿭鿮鿯鿰鿱鿲鿳鿴鿵鿶鿷鿸鿹鿺鿻鿼鿽鿾鿿 + +Yi Syllables (U+A000-U+A48F): + +ꀀê€ê€‚ꀃꀄꀅꀆꀇꀈꀉꀊꀋꀌê€ê€Žê€ê€ê€‘ꀒꀓꀔꀕꀖꀗꀘꀙꀚꀛꀜê€ê€žê€Ÿ +ꀠꀡꀢꀣꀤꀥꀦꀧꀨꀩꀪꀫꀬꀭꀮꀯꀰꀱꀲꀳꀴꀵꀶꀷꀸꀹꀺꀻꀼꀽꀾꀿ +ê€êê‚êƒê„ê…ê†ê‡êˆê‰êŠê‹êŒêêŽêêê‘ê’ê“ê”ê•ê–ê—ê˜ê™êšê›êœêêžêŸ +ê ê¡ê¢ê£ê¤ê¥ê¦ê§ê¨ê©êªê«ê¬ê­ê®ê¯ê°ê±ê²ê³ê´êµê¶ê·ê¸ê¹êºê»ê¼ê½ê¾ê¿ +ê‚€ê‚ꂂꂃꂄꂅꂆꂇꂈꂉꂊꂋꂌê‚ê‚Žê‚ê‚ꂑꂒꂓꂔꂕꂖꂗꂘꂙꂚꂛꂜê‚ê‚žê‚Ÿ +ꂠꂡꂢꂣꂤꂥꂦꂧꂨꂩꂪꂫꂬꂭꂮꂯꂰꂱꂲꂳꂴꂵꂶꂷꂸꂹꂺꂻꂼꂽꂾꂿ +ꃀêƒêƒ‚ꃃꃄꃅꃆꃇꃈꃉꃊꃋꃌêƒêƒŽêƒêƒêƒ‘ꃒꃓꃔꃕꃖꃗꃘꃙꃚꃛꃜêƒêƒžêƒŸ +ꃠꃡꃢꃣꃤꃥꃦꃧꃨꃩꃪꃫꃬꃭꃮꃯꃰꃱꃲꃳꃴꃵꃶꃷꃸꃹꃺꃻꃼꃽꃾꃿ +ê„€ê„ꄂꄃꄄꄅꄆꄇꄈꄉꄊꄋꄌê„ê„Žê„ê„ꄑꄒꄓꄔꄕꄖꄗꄘꄙꄚꄛꄜê„ê„žê„Ÿ +ꄠꄡꄢꄣꄤꄥꄦꄧꄨꄩꄪꄫꄬꄭꄮꄯꄰꄱꄲꄳꄴꄵꄶꄷꄸꄹꄺꄻꄼꄽꄾꄿ +ê…€ê…ꅂꅃꅄꅅꅆꅇꅈꅉꅊꅋꅌê…ê…Žê…ê…ꅑꅒꅓꅔꅕꅖꅗꅘꅙꅚꅛꅜê…ê…žê…Ÿ +ꅠꅡꅢꅣꅤꅥꅦꅧꅨꅩꅪꅫꅬꅭꅮꅯꅰꅱꅲꅳꅴꅵꅶꅷꅸꅹꅺꅻꅼꅽꅾꅿ +ꆀê†ê†‚ꆃꆄꆅꆆꆇꆈꆉꆊꆋꆌê†ê†Žê†ê†ê†‘ꆒꆓꆔꆕꆖꆗꆘꆙꆚꆛꆜê†ê†žê†Ÿ +ꆠꆡꆢꆣꆤꆥꆦꆧꆨꆩꆪꆫꆬꆭꆮꆯꆰꆱꆲꆳꆴꆵꆶꆷꆸꆹꆺꆻꆼꆽꆾꆿ +ꇀê‡ê‡‚ꇃꇄꇅꇆꇇꇈꇉꇊꇋꇌê‡ê‡Žê‡ê‡ê‡‘ꇒꇓꇔꇕꇖꇗꇘꇙꇚꇛꇜê‡ê‡žê‡Ÿ +ꇠꇡꇢꇣꇤꇥꇦꇧꇨꇩꇪꇫꇬꇭꇮꇯꇰꇱꇲꇳꇴꇵꇶꇷꇸꇹꇺꇻꇼꇽꇾꇿ +ꈀêˆêˆ‚ꈃꈄꈅꈆꈇꈈꈉꈊꈋꈌêˆêˆŽêˆêˆêˆ‘ꈒꈓꈔꈕꈖꈗꈘꈙꈚꈛꈜêˆêˆžêˆŸ +ꈠꈡꈢꈣꈤꈥꈦꈧꈨꈩꈪꈫꈬꈭꈮꈯꈰꈱꈲꈳꈴꈵꈶꈷꈸꈹꈺꈻꈼꈽꈾꈿ +ꉀê‰ê‰‚ꉃꉄꉅꉆꉇꉈꉉꉊꉋꉌê‰ê‰Žê‰ê‰ê‰‘ꉒꉓꉔꉕꉖꉗꉘꉙꉚꉛꉜê‰ê‰žê‰Ÿ +ꉠꉡꉢꉣꉤꉥꉦꉧꉨꉩꉪꉫꉬꉭꉮꉯꉰꉱꉲꉳꉴꉵꉶꉷꉸꉹꉺꉻꉼꉽꉾꉿ +ꊀêŠêŠ‚ꊃꊄꊅꊆꊇꊈꊉꊊꊋꊌêŠêŠŽêŠêŠêŠ‘ꊒꊓꊔꊕꊖꊗꊘꊙꊚꊛꊜêŠêŠžêŠŸ +ꊠꊡꊢꊣꊤꊥꊦꊧꊨꊩꊪꊫꊬꊭꊮꊯꊰꊱꊲꊳꊴꊵꊶꊷꊸꊹꊺꊻꊼꊽꊾꊿ +ê‹€ê‹ê‹‚ꋃꋄꋅꋆꋇꋈꋉꋊꋋꋌê‹ê‹Žê‹ê‹ê‹‘ꋒꋓꋔꋕꋖꋗꋘꋙꋚꋛꋜê‹ê‹žê‹Ÿ +ꋠꋡꋢꋣꋤꋥꋦꋧꋨꋩꋪꋫꋬꋭꋮꋯꋰꋱꋲꋳꋴꋵꋶꋷꋸꋹꋺꋻꋼꋽꋾꋿ +ꌀêŒêŒ‚ꌃꌄꌅꌆꌇꌈꌉꌊꌋꌌêŒêŒŽêŒêŒêŒ‘ꌒꌓꌔꌕꌖꌗꌘꌙꌚꌛꌜêŒêŒžêŒŸ +ꌠꌡꌢꌣꌤꌥꌦꌧꌨꌩꌪꌫꌬꌭꌮꌯꌰꌱꌲꌳꌴꌵꌶꌷꌸꌹꌺꌻꌼꌽꌾꌿ +ê€êê‚êƒê„ê…ê†ê‡êˆê‰êŠê‹êŒêêŽêêê‘ê’ê“ê”ê•ê–ê—ê˜ê™êšê›êœêêžêŸ +ê ê¡ê¢ê£ê¤ê¥ê¦ê§ê¨ê©êªê«ê¬ê­ê®ê¯ê°ê±ê²ê³ê´êµê¶ê·ê¸ê¹êºê»ê¼ê½ê¾ê¿ +ꎀêŽêŽ‚ꎃꎄꎅꎆꎇꎈꎉꎊꎋꎌêŽêŽŽêŽêŽêŽ‘ꎒꎓꎔꎕꎖꎗꎘꎙꎚꎛꎜêŽêŽžêŽŸ +ꎠꎡꎢꎣꎤꎥꎦꎧꎨꎩꎪꎫꎬꎭꎮꎯꎰꎱꎲꎳꎴꎵꎶꎷꎸꎹꎺꎻꎼꎽꎾꎿ +ê€êê‚êƒê„ê…ê†ê‡êˆê‰êŠê‹êŒêêŽêêê‘ê’ê“ê”ê•ê–ê—ê˜ê™êšê›êœêêžêŸ +ê ê¡ê¢ê£ê¤ê¥ê¦ê§ê¨ê©êªê«ê¬ê­ê®ê¯ê°ê±ê²ê³ê´êµê¶ê·ê¸ê¹êºê»ê¼ê½ê¾ê¿ +ê€êê‚êƒê„ê…ê†ê‡êˆê‰êŠê‹êŒêêŽêêê‘ê’ê“ê”ê•ê–ê—ê˜ê™êšê›êœêêžêŸ +ê ê¡ê¢ê£ê¤ê¥ê¦ê§ê¨ê©êªê«ê¬ê­ê®ê¯ê°ê±ê²ê³ê´êµê¶ê·ê¸ê¹êºê»ê¼ê½ê¾ê¿ +ê‘€ê‘ꑂꑃꑄꑅꑆꑇꑈꑉꑊꑋꑌê‘ê‘Žê‘ê‘ꑑꑒꑓꑔꑕꑖꑗꑘꑙꑚꑛꑜê‘ê‘žê‘Ÿ +ꑠꑡꑢꑣꑤꑥꑦꑧꑨꑩꑪꑫꑬꑭꑮꑯꑰꑱꑲꑳꑴꑵꑶꑷꑸꑹꑺꑻꑼꑽꑾꑿ +ê’€ê’ꒂꒃꒄꒅꒆꒇꒈꒉꒊꒋꒌê’ê’Žê’ + +Yi Radicals (U+A490-U+A4CF): + +ê’꒑꒒꒓꒔꒕꒖꒗꒘꒙꒚꒛꒜ê’꒞꒟꒠꒡꒢꒣꒤꒥꒦꒧꒨꒩꒪꒫꒬꒭꒮꒯ +꒰꒱꒲꒳꒴꒵꒶꒷꒸꒹꒺꒻꒼꒽꒾꒿꓀ê“꓂꓃꓄꓅꓆꓇꓈꓉꓊꓋꓌ê“ê“Žê“ + +Free block (U+A4D0-U+ABFF): + +ê“ꓑꓒꓓꓔꓕꓖꓗꓘꓙꓚꓛꓜê“ꓞꓟꓠꓡꓢꓣꓤꓥꓦꓧꓨꓩꓪꓫꓬꓭꓮꓯꓰꓱꓲꓳꓴꓵꓶꓷꓸꓹꓺꓻꓼꓽ꓾꓿ꔀê”ꔂꔃꔄꔅꔆꔇꔈꔉꔊꔋꔌê”ê”Žê” +ê”ꔑꔒꔓꔔꔕꔖꔗꔘꔙꔚꔛꔜê”ꔞꔟꔠꔡꔢꔣꔤꔥꔦꔧꔨꔩꔪꔫꔬꔭꔮꔯꔰꔱꔲꔳꔴꔵꔶꔷꔸꔹꔺꔻꔼꔽꔾꔿꕀê•ê•‚ꕃꕄꕅꕆꕇꕈꕉꕊꕋꕌê•ê•Žê• +ê•ê•‘ꕒꕓꕔꕕꕖꕗꕘꕙꕚꕛꕜê•ê•žê•Ÿê• ê•¡ê•¢ê•£ê•¤ê•¥ê•¦ê•§ê•¨ê•©ê•ªê•«ê•¬ê•­ê•®ê•¯ê•°ê•±ê•²ê•³ê•´ê•µê•¶ê•·ê•¸ê•¹ê•ºê•»ê•¼ê•½ê•¾ê•¿ê–€ê–ꖂꖃꖄꖅꖆꖇꖈꖉꖊꖋꖌê–ê–Žê– +ê–ꖑꖒꖓꖔꖕꖖꖗꖘꖙꖚꖛꖜê–ꖞꖟꖠꖡꖢꖣꖤꖥꖦꖧꖨꖩꖪꖫꖬꖭꖮꖯꖰꖱꖲꖳꖴꖵꖶꖷꖸꖹꖺꖻꖼꖽꖾꖿꗀê—ꗂꗃꗄꗅꗆꗇꗈꗉꗊꗋꗌê—ê—Žê— +ê—ꗑꗒꗓꗔꗕꗖꗗꗘꗙꗚꗛꗜê—ꗞꗟꗠꗡꗢꗣꗤꗥꗦꗧꗨꗩꗪꗫꗬꗭꗮꗯꗰꗱꗲꗳꗴꗵꗶꗷꗸꗹꗺꗻꗼꗽꗾꗿꘀê˜ê˜‚ꘃꘄꘅꘆꘇꘈꘉꘊꘋꘌê˜ê˜Žê˜ +ê˜ê˜‘ꘒꘓꘔꘕꘖꘗꘘꘙꘚꘛꘜê˜ê˜žê˜Ÿê˜ ê˜¡ê˜¢ê˜£ê˜¤ê˜¥ê˜¦ê˜§ê˜¨ê˜©ê˜ªê˜«ê˜¬ê˜­ê˜®ê˜¯ê˜°ê˜±ê˜²ê˜³ê˜´ê˜µê˜¶ê˜·ê˜¸ê˜¹ê˜ºê˜»ê˜¼ê˜½ê˜¾ê˜¿ê™€ê™ê™‚ꙃꙄꙅꙆꙇꙈꙉꙊꙋꙌê™ê™Žê™ +ê™ê™‘ꙒꙓꙔꙕꙖꙗꙘꙙꙚꙛꙜê™ê™žê™Ÿê™ ê™¡ê™¢ê™£ê™¤ê™¥ê™¦ê™§ê™¨ê™©ê™ªê™«ê™¬ê™­ê™®ê™¯ê™°ê™±ê™²ê™³ê™´ê™µê™¶ê™·ê™¸ê™¹ê™ºê™»ê™¼ê™½ê™¾ê™¿êš€êšêš‚ꚃꚄꚅꚆꚇꚈꚉꚊꚋꚌêšêšŽêš +êšêš‘ꚒꚓꚔꚕꚖꚗꚘꚙꚚꚛꚜêšêšžêšŸêš êš¡êš¢êš£êš¤êš¥êš¦êš§êš¨êš©êšªêš«êš¬êš­êš®êš¯êš°êš±êš²êš³êš´êšµêš¶êš·êš¸êš¹êšºêš»êš¼êš½êš¾êš¿ê›€ê›ê›‚ꛃꛄꛅꛆꛇꛈꛉꛊꛋꛌê›ê›Žê› +ê›ê›‘ꛒꛓꛔꛕꛖꛗꛘꛙꛚꛛꛜê›ê›žê›Ÿê› ê›¡ê›¢ê›£ê›¤ê›¥ê›¦ê›§ê›¨ê›©ê›ªê›«ê›¬ê›­ê›®ê›¯ê›°ê›±ê›²ê›³ê›´ê›µê›¶ê›·ê›¸ê›¹ê›ºê›»ê›¼ê›½ê›¾ê›¿êœ€êœêœ‚꜃꜄꜅꜆꜇꜈꜉꜊꜋꜌êœêœŽêœ +êœêœ‘꜒꜓꜔꜕꜖ꜗꜘꜙꜚꜛꜜêœêœžêœŸêœ êœ¡êœ¢êœ£êœ¤êœ¥êœ¦êœ§êœ¨êœ©êœªêœ«êœ¬êœ­êœ®êœ¯êœ°êœ±êœ²êœ³êœ´êœµêœ¶êœ·êœ¸êœ¹êœºêœ»êœ¼êœ½êœ¾êœ¿ê€êê‚êƒê„ê…ê†ê‡êˆê‰êŠê‹êŒêêŽê +êê‘ê’ê“ê”ê•ê–ê—ê˜ê™êšê›êœêêžêŸê ê¡ê¢ê£ê¤ê¥ê¦ê§ê¨ê©êªê«ê¬ê­ê®ê¯ê°ê±ê²ê³ê´êµê¶ê·ê¸ê¹êºê»ê¼ê½ê¾ê¿êž€êžêž‚ꞃꞄꞅꞆꞇꞈ꞉꞊ꞋꞌêžêžŽêž +êžêž‘ꞒꞓꞔꞕꞖꞗꞘꞙꞚꞛꞜêžêžžêžŸêž êž¡êž¢êž£êž¤êž¥êž¦êž§êž¨êž©êžªêž«êž¬êž­êž®êž¯êž°êž±êž²êž³êž´êžµêž¶êž·êž¸êž¹êžºêž»êž¼êž½êž¾êž¿êŸ€êŸêŸ‚ꟃꟄꟅꟆꟇꟈꟉꟊꟋꟌêŸêŸŽêŸ +êŸêŸ‘꟒ꟓ꟔ꟕꟖꟗꟘꟙꟚꟛꟜêŸêŸžêŸŸêŸ êŸ¡êŸ¢êŸ£êŸ¤êŸ¥êŸ¦êŸ§êŸ¨êŸ©êŸªêŸ«êŸ¬êŸ­êŸ®êŸ¯êŸ°êŸ±êŸ²êŸ³êŸ´êŸµêŸ¶êŸ·êŸ¸êŸ¹êŸºêŸ»êŸ¼êŸ½êŸ¾êŸ¿ê €ê ê ‚ꠃꠄꠅ꠆ꠇꠈꠉꠊꠋꠌê ê Žê  +ê ê ‘ꠒꠓꠔꠕꠖꠗꠘꠙꠚꠛꠜê ê žê Ÿê  ê ¡ê ¢ê £ê ¤ê ¥ê ¦ê §ê ¨ê ©ê ªê «ê ¬ê ­ê ®ê ¯ê °ê ±ê ²ê ³ê ´ê µê ¶ê ·ê ¸ê ¹ê ºê »ê ¼ê ½ê ¾ê ¿ê¡€ê¡ê¡‚ꡃꡄꡅꡆꡇꡈꡉꡊꡋꡌê¡ê¡Žê¡ +ê¡ê¡‘ꡒꡓꡔꡕꡖꡗꡘꡙꡚꡛꡜê¡ê¡žê¡Ÿê¡ ê¡¡ê¡¢ê¡£ê¡¤ê¡¥ê¡¦ê¡§ê¡¨ê¡©ê¡ªê¡«ê¡¬ê¡­ê¡®ê¡¯ê¡°ê¡±ê¡²ê¡³ê¡´ê¡µê¡¶ê¡·ê¡¸ê¡¹ê¡ºê¡»ê¡¼ê¡½ê¡¾ê¡¿ê¢€ê¢ê¢‚ꢃꢄꢅꢆꢇꢈꢉꢊꢋꢌê¢ê¢Žê¢ +ê¢ê¢‘ꢒꢓꢔꢕꢖꢗꢘꢙꢚꢛꢜê¢ê¢žê¢Ÿê¢ ê¢¡ê¢¢ê¢£ê¢¤ê¢¥ê¢¦ê¢§ê¢¨ê¢©ê¢ªê¢«ê¢¬ê¢­ê¢®ê¢¯ê¢°ê¢±ê¢²ê¢³ê¢´ê¢µê¢¶ê¢·ê¢¸ê¢¹ê¢ºê¢»ê¢¼ê¢½ê¢¾ê¢¿ê£€ê£ê£‚ꣃ꣄ꣅ꣆꣇꣈꣉꣊꣋꣌ê£ê£Žê£ +ê£ê£‘꣒꣓꣔꣕꣖꣗꣘꣙꣚꣛꣜ê£ê£žê£Ÿê£ ê£¡ê£¢ê££ê£¤ê£¥ê£¦ê£§ê£¨ê£©ê£ªê£«ê£¬ê£­ê£®ê£¯ê£°ê£±ê£²ê£³ê£´ê£µê£¶ê£·ê£¸ê£¹ê£ºê£»ê£¼ê£½ê£¾ê£¿ê¤€ê¤ê¤‚꤃꤄꤅꤆꤇꤈꤉ꤊꤋꤌê¤ê¤Žê¤ +ê¤ê¤‘ꤒꤓꤔꤕꤖꤗꤘꤙꤚꤛꤜê¤ê¤žê¤Ÿê¤ ê¤¡ê¤¢ê¤£ê¤¤ê¤¥ê¤¦ê¤§ê¤¨ê¤©ê¤ªê¤«ê¤¬ê¤­ê¤®ê¤¯ê¤°ê¤±ê¤²ê¤³ê¤´ê¤µê¤¶ê¤·ê¤¸ê¤¹ê¤ºê¤»ê¤¼ê¤½ê¤¾ê¤¿ê¥€ê¥ê¥‚ꥃꥄꥅꥆꥇꥈꥉꥊꥋꥌê¥ê¥Žê¥ +ê¥ê¥‘ꥒ꥓꥔꥕꥖꥗꥘꥙꥚꥛꥜ê¥ê¥žê¥Ÿê¥ ê¥¡ê¥¢ê¥£ê¥¤ê¥¥ê¥¦ê¥§ê¥¨ê¥©ê¥ªê¥«ê¥¬ê¥­ê¥®ê¥¯ê¥°ê¥±ê¥²ê¥³ê¥´ê¥µê¥¶ê¥·ê¥¸ê¥¹ê¥ºê¥»ê¥¼ê¥½ê¥¾ê¥¿ê¦€ê¦ê¦‚ꦃꦄꦅꦆꦇꦈꦉꦊꦋꦌê¦ê¦Žê¦ +ê¦ê¦‘ꦒꦓꦔꦕꦖꦗꦘꦙꦚꦛꦜê¦ê¦žê¦Ÿê¦ ê¦¡ê¦¢ê¦£ê¦¤ê¦¥ê¦¦ê¦§ê¦¨ê¦©ê¦ªê¦«ê¦¬ê¦­ê¦®ê¦¯ê¦°ê¦±ê¦²ê¦³ê¦´ê¦µê¦¶ê¦·ê¦¸ê¦¹ê¦ºê¦»ê¦¼ê¦½ê¦¾ê¦¿ê§€ê§ê§‚꧃꧄꧅꧆꧇꧈꧉꧊꧋꧌ê§ê§Žê§ +ê§ê§‘꧒꧓꧔꧕꧖꧗꧘꧙꧚꧛꧜ê§ê§žê§Ÿê§ ê§¡ê§¢ê§£ê§¤ê§¥ê§¦ê§§ê§¨ê§©ê§ªê§«ê§¬ê§­ê§®ê§¯ê§°ê§±ê§²ê§³ê§´ê§µê§¶ê§·ê§¸ê§¹ê§ºê§»ê§¼ê§½ê§¾ê§¿ê¨€ê¨ê¨‚ꨃꨄꨅꨆꨇꨈꨉꨊꨋꨌê¨ê¨Žê¨ +ê¨ê¨‘ꨒꨓꨔꨕꨖꨗꨘꨙꨚꨛꨜê¨ê¨žê¨Ÿê¨ ê¨¡ê¨¢ê¨£ê¨¤ê¨¥ê¨¦ê¨§ê¨¨ê¨©ê¨ªê¨«ê¨¬ê¨­ê¨®ê¨¯ê¨°ê¨±ê¨²ê¨³ê¨´ê¨µê¨¶ê¨·ê¨¸ê¨¹ê¨ºê¨»ê¨¼ê¨½ê¨¾ê¨¿ê©€ê©ê©‚ꩃꩄꩅꩆꩇꩈꩉꩊꩋꩌê©ê©Žê© +ê©ê©‘꩒꩓꩔꩕꩖꩗꩘꩙꩚꩛꩜ê©ê©žê©Ÿê© ê©¡ê©¢ê©£ê©¤ê©¥ê©¦ê©§ê©¨ê©©ê©ªê©«ê©¬ê©­ê©®ê©¯ê©°ê©±ê©²ê©³ê©´ê©µê©¶ê©·ê©¸ê©¹ê©ºê©»ê©¼ê©½ê©¾ê©¿êª€êªêª‚ꪃꪄꪅꪆꪇꪈꪉꪊꪋꪌêªêªŽêª +êªêª‘ꪒꪓꪔꪕꪖꪗꪘꪙꪚꪛꪜêªêªžêªŸêª êª¡êª¢êª£êª¤êª¥êª¦êª§êª¨êª©êªªêª«êª¬êª­êª®êª¯êª°êª±êª²êª³êª´êªµêª¶êª·êª¸êª¹êªºêª»êª¼êª½êª¾êª¿ê«€ê«ê«‚꫃꫄꫅꫆꫇꫈꫉꫊꫋꫌ê«ê«Žê« +ê«ê«‘꫒꫓꫔꫕꫖꫗꫘꫙꫚ꫛꫜê«ê«žê«Ÿê« ê«¡ê«¢ê«£ê«¤ê«¥ê«¦ê«§ê«¨ê«©ê«ªê««ê«¬ê«­ê«®ê«¯ê«°ê«±ê«²ê«³ê«´ê«µê«¶ê«·ê«¸ê«¹ê«ºê«»ê«¼ê«½ê«¾ê«¿ê¬€ê¬ê¬‚ꬃꬄꬅꬆ꬇꬈ꬉꬊꬋꬌê¬ê¬Žê¬ +ê¬ê¬‘ꬒꬓꬔꬕꬖ꬗꬘꬙꬚꬛꬜ê¬ê¬žê¬Ÿê¬ ê¬¡ê¬¢ê¬£ê¬¤ê¬¥ê¬¦ê¬§ê¬¨ê¬©ê¬ªê¬«ê¬¬ê¬­ê¬®ê¬¯ê¬°ê¬±ê¬²ê¬³ê¬´ê¬µê¬¶ê¬·ê¬¸ê¬¹ê¬ºê¬»ê¬¼ê¬½ê¬¾ê¬¿ê­€ê­ê­‚ꭃꭄꭅꭆꭇꭈꭉꭊꭋꭌê­ê­Žê­ +ê­ê­‘ꭒꭓꭔꭕꭖꭗꭘꭙꭚ꭛ꭜê­ê­žê­Ÿê­ ê­¡ê­¢ê­£ê­¤ê­¥ê­¦ê­§ê­¨ê­©ê­ªê­«ê­¬ê­­ê­®ê­¯ê­°ê­±ê­²ê­³ê­´ê­µê­¶ê­·ê­¸ê­¹ê­ºê­»ê­¼ê­½ê­¾ê­¿ê®€ê®ê®‚ꮃꮄꮅꮆꮇꮈꮉꮊꮋꮌê®ê®Žê® +ê®ê®‘ꮒꮓꮔꮕꮖꮗꮘꮙꮚꮛꮜê®ê®žê®Ÿê® ê®¡ê®¢ê®£ê®¤ê®¥ê®¦ê®§ê®¨ê®©ê®ªê®«ê®¬ê®­ê®®ê®¯ê®°ê®±ê®²ê®³ê®´ê®µê®¶ê®·ê®¸ê®¹ê®ºê®»ê®¼ê®½ê®¾ê®¿ê¯€ê¯ê¯‚ꯃꯄꯅꯆꯇꯈꯉꯊꯋꯌê¯ê¯Žê¯ +ê¯ê¯‘ꯒꯓꯔꯕꯖꯗꯘꯙꯚꯛꯜê¯ê¯žê¯Ÿê¯ ê¯¡ê¯¢ê¯£ê¯¤ê¯¥ê¯¦ê¯§ê¯¨ê¯©ê¯ªê¯«ê¯¬ê¯­ê¯®ê¯¯ê¯°ê¯±ê¯²ê¯³ê¯´ê¯µê¯¶ê¯·ê¯¸ê¯¹ê¯ºê¯»ê¯¼ê¯½ê¯¾ê¯¿ + +Hangul Syllables (U+AC00-U+D7AF): + +ê°€ê°ê°‚갃간갅갆갇갈갉갊갋갌ê°ê°Žê°ê°ê°‘값갓갔강갖갗갘같갚갛개ê°ê°žê°Ÿ +갠갡갢갣갤갥갦갧갨갩갪갫갬갭갮갯갰갱갲갳갴갵갶갷갸갹갺갻갼갽갾갿 +ê±€ê±ê±‚걃걄걅걆걇걈걉걊걋걌ê±ê±Žê±ê±ê±‘걒걓걔걕걖걗걘걙걚걛걜ê±ê±žê±Ÿ +걠걡걢걣걤걥걦걧걨걩걪걫걬걭걮걯거걱걲걳건걵걶걷걸걹걺걻걼걽걾걿 +ê²€ê²ê²‚것겄겅겆겇겈겉겊겋게ê²ê²Žê²ê²ê²‘겒겓겔겕겖겗겘겙겚겛겜ê²ê²žê²Ÿ +겠겡겢겣겤겥겦겧겨격겪겫견겭겮겯결겱겲겳겴겵겶겷겸겹겺겻겼경겾겿 +ê³€ê³ê³‚곃계곅곆곇곈곉곊곋곌ê³ê³Žê³ê³ê³‘곒곓곔곕곖곗곘곙곚곛곜ê³ê³žê³Ÿ +고곡곢곣곤곥곦곧골곩곪곫곬곭곮곯곰곱곲곳곴공곶곷곸곹곺곻과곽곾곿 +ê´€ê´ê´‚괃괄괅괆괇괈괉괊괋괌ê´ê´Žê´ê´ê´‘괒괓괔괕괖괗괘괙괚괛괜ê´ê´žê´Ÿ +괠괡괢괣괤괥괦괧괨괩괪괫괬괭괮괯괰괱괲괳괴괵괶괷괸괹괺괻괼괽괾괿 +êµ€êµêµ‚굃굄굅굆굇굈굉굊굋굌êµêµŽêµêµêµ‘굒굓굔굕굖굗굘굙굚굛굜êµêµžêµŸ +굠굡굢굣굤굥굦굧굨굩굪굫구국굮굯군굱굲굳굴굵굶굷굸굹굺굻굼굽굾굿 +궀ê¶ê¶‚궃궄궅궆궇궈궉궊궋권ê¶ê¶Žê¶ê¶ê¶‘궒궓궔궕궖궗궘궙궚궛궜ê¶ê¶žê¶Ÿ +궠궡궢궣궤궥궦궧궨궩궪궫궬궭궮궯궰궱궲궳궴궵궶궷궸궹궺궻궼궽궾궿 +ê·€ê·ê·‚귃귄귅귆귇귈귉귊귋귌ê·ê·Žê·ê·ê·‘귒귓귔귕귖귗귘귙귚귛규ê·ê·žê·Ÿ +균귡귢귣귤귥귦귧귨귩귪귫귬귭귮귯귰귱귲귳귴귵귶귷그극귺귻근귽귾귿 +글ê¸ê¸‚긃긄긅긆긇금급긊긋긌ê¸ê¸Žê¸ê¸ê¸‘긒긓긔긕긖긗긘긙긚긛긜ê¸ê¸žê¸Ÿ +긠긡긢긣긤긥긦긧긨긩긪긫긬긭긮긯기긱긲긳긴긵긶긷길긹긺긻긼긽긾긿 +ê¹€ê¹ê¹‚깃깄깅깆깇깈깉깊깋까ê¹ê¹Žê¹ê¹ê¹‘깒깓깔깕깖깗깘깙깚깛깜ê¹ê¹žê¹Ÿ +깠깡깢깣깤깥깦깧깨깩깪깫깬깭깮깯깰깱깲깳깴깵깶깷깸깹깺깻깼깽깾깿 +꺀êºêº‚꺃꺄꺅꺆꺇꺈꺉꺊꺋꺌êºêºŽêºêºêº‘꺒꺓꺔꺕꺖꺗꺘꺙꺚꺛꺜êºêºžêºŸ +꺠꺡꺢꺣꺤꺥꺦꺧꺨꺩꺪꺫꺬꺭꺮꺯꺰꺱꺲꺳꺴꺵꺶꺷꺸꺹꺺꺻꺼꺽꺾꺿 +껀ê»ê»‚껃껄껅껆껇껈껉껊껋껌ê»ê»Žê»ê»ê»‘껒껓껔껕껖껗께껙껚껛껜ê»ê»žê»Ÿ +껠껡껢껣껤껥껦껧껨껩껪껫껬껭껮껯껰껱껲껳껴껵껶껷껸껹껺껻껼껽껾껿 +ê¼€ê¼ê¼‚꼃꼄꼅꼆꼇꼈꼉꼊꼋꼌ê¼ê¼Žê¼ê¼ê¼‘꼒꼓꼔꼕꼖꼗꼘꼙꼚꼛꼜ê¼ê¼žê¼Ÿ +꼠꼡꼢꼣꼤꼥꼦꼧꼨꼩꼪꼫꼬꼭꼮꼯꼰꼱꼲꼳꼴꼵꼶꼷꼸꼹꼺꼻꼼꼽꼾꼿 +ê½€ê½ê½‚꽃꽄꽅꽆꽇꽈꽉꽊꽋꽌ê½ê½Žê½ê½ê½‘꽒꽓꽔꽕꽖꽗꽘꽙꽚꽛꽜ê½ê½žê½Ÿ +꽠꽡꽢꽣꽤꽥꽦꽧꽨꽩꽪꽫꽬꽭꽮꽯꽰꽱꽲꽳꽴꽵꽶꽷꽸꽹꽺꽻꽼꽽꽾꽿 +ê¾€ê¾ê¾‚꾃꾄꾅꾆꾇꾈꾉꾊꾋꾌ê¾ê¾Žê¾ê¾ê¾‘꾒꾓꾔꾕꾖꾗꾘꾙꾚꾛꾜ê¾ê¾žê¾Ÿ +꾠꾡꾢꾣꾤꾥꾦꾧꾨꾩꾪꾫꾬꾭꾮꾯꾰꾱꾲꾳꾴꾵꾶꾷꾸꾹꾺꾻꾼꾽꾾꾿 +ê¿€ê¿ê¿‚꿃꿄꿅꿆꿇꿈꿉꿊꿋꿌ê¿ê¿Žê¿ê¿ê¿‘꿒꿓꿔꿕꿖꿗꿘꿙꿚꿛꿜ê¿ê¿žê¿Ÿ +꿠꿡꿢꿣꿤꿥꿦꿧꿨꿩꿪꿫꿬꿭꿮꿯꿰꿱꿲꿳꿴꿵꿶꿷꿸꿹꿺꿻꿼꿽꿾꿿 +뀀ë€ë€‚뀃뀄뀅뀆뀇뀈뀉뀊뀋뀌ë€ë€Žë€ë€ë€‘뀒뀓뀔뀕뀖뀗뀘뀙뀚뀛뀜ë€ë€žë€Ÿ +뀠뀡뀢뀣뀤뀥뀦뀧뀨뀩뀪뀫뀬뀭뀮뀯뀰뀱뀲뀳뀴뀵뀶뀷뀸뀹뀺뀻뀼뀽뀾뀿 +ë€ëë‚ëƒë„ë…ë†ë‡ëˆë‰ëŠë‹ëŒëëŽëëë‘ë’ë“ë”ë•ë–ë—ë˜ë™ëšë›ëœëëžëŸ +ë ë¡ë¢ë£ë¤ë¥ë¦ë§ë¨ë©ëªë«ë¬ë­ë®ë¯ë°ë±ë²ë³ë´ëµë¶ë·ë¸ë¹ëºë»ë¼ë½ë¾ë¿ +ë‚€ë‚낂낃낄낅낆낇낈낉낊낋낌ë‚ë‚Žë‚ë‚낑낒낓낔낕낖낗나낙낚낛난ë‚ë‚žë‚Ÿ +날낡낢낣낤낥낦낧남납낪낫났낭낮낯낰낱낲낳내낵낶낷낸낹낺낻낼낽낾낿 +냀ëƒëƒ‚냃냄냅냆냇냈냉냊냋냌ëƒëƒŽëƒëƒëƒ‘냒냓냔냕냖냗냘냙냚냛냜ëƒëƒžëƒŸ +냠냡냢냣냤냥냦냧냨냩냪냫냬냭냮냯냰냱냲냳냴냵냶냷냸냹냺냻냼냽냾냿 +ë„€ë„넂넃넄넅넆넇너넉넊넋넌ë„ë„Žë„ë„넑넒넓넔넕넖넗넘넙넚넛넜ë„ë„žë„Ÿ +넠넡넢넣네넥넦넧넨넩넪넫넬넭넮넯넰넱넲넳넴넵넶넷넸넹넺넻넼넽넾넿 +ë…€ë…녂녃년녅녆녇녈녉녊녋녌ë…ë…Žë…ë…녑녒녓녔녕녖녗녘녙녚녛녜ë…ë…žë…Ÿ +녠녡녢녣녤녥녦녧녨녩녪녫녬녭녮녯녰녱녲녳녴녵녶녷노녹녺녻논녽녾녿 +놀ë†ë†‚놃놄놅놆놇놈놉놊놋놌ë†ë†Žë†ë†ë†‘높놓놔놕놖놗놘놙놚놛놜ë†ë†žë†Ÿ +놠놡놢놣놤놥놦놧놨놩놪놫놬놭놮놯놰놱놲놳놴놵놶놷놸놹놺놻놼놽놾놿 +뇀ë‡ë‡‚뇃뇄뇅뇆뇇뇈뇉뇊뇋뇌ë‡ë‡Žë‡ë‡ë‡‘뇒뇓뇔뇕뇖뇗뇘뇙뇚뇛뇜ë‡ë‡žë‡Ÿ +뇠뇡뇢뇣뇤뇥뇦뇧뇨뇩뇪뇫뇬뇭뇮뇯뇰뇱뇲뇳뇴뇵뇶뇷뇸뇹뇺뇻뇼뇽뇾뇿 +눀ëˆëˆ‚눃누눅눆눇눈눉눊눋눌ëˆëˆŽëˆëˆëˆ‘눒눓눔눕눖눗눘눙눚눛눜ëˆëˆžëˆŸ +눠눡눢눣눤눥눦눧눨눩눪눫눬눭눮눯눰눱눲눳눴눵눶눷눸눹눺눻눼눽눾눿 +뉀ë‰ë‰‚뉃뉄뉅뉆뉇뉈뉉뉊뉋뉌ë‰ë‰Žë‰ë‰ë‰‘뉒뉓뉔뉕뉖뉗뉘뉙뉚뉛뉜ë‰ë‰žë‰Ÿ +뉠뉡뉢뉣뉤뉥뉦뉧뉨뉩뉪뉫뉬뉭뉮뉯뉰뉱뉲뉳뉴뉵뉶뉷뉸뉹뉺뉻뉼뉽뉾뉿 +늀ëŠëŠ‚늃늄늅늆늇늈늉늊늋늌ëŠëŠŽëŠëŠëŠ‘늒늓는늕늖늗늘늙늚늛늜ëŠëŠžëŠŸ +늠늡늢늣늤능늦늧늨늩늪늫늬늭늮늯늰늱늲늳늴늵늶늷늸늹늺늻늼늽늾늿 +ë‹€ë‹ë‹‚닃닄닅닆닇니닉닊닋닌ë‹ë‹Žë‹ë‹ë‹‘닒닓닔닕닖닗님닙닚닛닜ë‹ë‹žë‹Ÿ +닠닡닢닣다닥닦닧단닩닪닫달닭닮닯닰닱닲닳담답닶닷닸당닺닻닼닽닾닿 +대ëŒëŒ‚댃댄댅댆댇댈댉댊댋댌ëŒëŒŽëŒëŒëŒ‘댒댓댔댕댖댗댘댙댚댛댜ëŒëŒžëŒŸ +댠댡댢댣댤댥댦댧댨댩댪댫댬댭댮댯댰댱댲댳댴댵댶댷댸댹댺댻댼댽댾댿 +ë€ëë‚ëƒë„ë…ë†ë‡ëˆë‰ëŠë‹ëŒëëŽëëë‘ë’ë“ë”ë•ë–ë—ë˜ë™ëšë›ëœëëžëŸ +ë ë¡ë¢ë£ë¤ë¥ë¦ë§ë¨ë©ëªë«ë¬ë­ë®ë¯ë°ë±ë²ë³ë´ëµë¶ë·ë¸ë¹ëºë»ë¼ë½ë¾ë¿ +뎀ëŽëŽ‚뎃뎄뎅뎆뎇뎈뎉뎊뎋뎌ëŽëŽŽëŽëŽëŽ‘뎒뎓뎔뎕뎖뎗뎘뎙뎚뎛뎜ëŽëŽžëŽŸ +뎠뎡뎢뎣뎤뎥뎦뎧뎨뎩뎪뎫뎬뎭뎮뎯뎰뎱뎲뎳뎴뎵뎶뎷뎸뎹뎺뎻뎼뎽뎾뎿 +ë€ëë‚ëƒë„ë…ë†ë‡ëˆë‰ëŠë‹ëŒëëŽëëë‘ë’ë“ë”ë•ë–ë—ë˜ë™ëšë›ëœëëžëŸ +ë ë¡ë¢ë£ë¤ë¥ë¦ë§ë¨ë©ëªë«ë¬ë­ë®ë¯ë°ë±ë²ë³ë´ëµë¶ë·ë¸ë¹ëºë»ë¼ë½ë¾ë¿ +ë€ëë‚ëƒë„ë…ë†ë‡ëˆë‰ëŠë‹ëŒëëŽëëë‘ë’ë“ë”ë•ë–ë—ë˜ë™ëšë›ëœëëžëŸ +ë ë¡ë¢ë£ë¤ë¥ë¦ë§ë¨ë©ëªë«ë¬ë­ë®ë¯ë°ë±ë²ë³ë´ëµë¶ë·ë¸ë¹ëºë»ë¼ë½ë¾ë¿ +ë‘€ë‘둂둃둄둅둆둇둈둉둊둋둌ë‘ë‘Žë‘ë‘둑둒둓둔둕둖둗둘둙둚둛둜ë‘ë‘žë‘Ÿ +둠둡둢둣둤둥둦둧둨둩둪둫둬둭둮둯둰둱둲둳둴둵둶둷둸둹둺둻둼둽둾둿 +ë’€ë’뒂뒃뒄뒅뒆뒇뒈뒉뒊뒋뒌ë’ë’Žë’ë’뒑뒒뒓뒔뒕뒖뒗뒘뒙뒚뒛뒜ë’ë’žë’Ÿ +뒠뒡뒢뒣뒤뒥뒦뒧뒨뒩뒪뒫뒬뒭뒮뒯뒰뒱뒲뒳뒴뒵뒶뒷뒸뒹뒺뒻뒼뒽뒾뒿 +ë“€ë“듂듃듄듅듆듇듈듉듊듋듌ë“ë“Žë“ë“듑듒듓듔듕듖듗듘듙듚듛드ë“ë“žë“Ÿ +든듡듢듣들듥듦듧듨듩듪듫듬듭듮듯듰등듲듳듴듵듶듷듸듹듺듻듼듽듾듿 +딀ë”딂딃딄딅딆딇딈딉딊딋딌ë”딎ë”ë”딑딒딓디딕딖딗딘딙딚딛딜ë”딞딟 +딠딡딢딣딤딥딦딧딨딩딪딫딬딭딮딯따딱딲딳딴딵딶딷딸딹딺딻딼딽딾딿 +ë•€ë•ë•‚땃땄땅땆땇땈땉땊땋때ë•ë•Žë•ë•ë•‘땒땓땔땕땖땗땘땙땚땛땜ë•ë•žë•Ÿ +땠땡땢땣땤땥땦땧땨땩땪땫땬땭땮땯땰땱땲땳땴땵땶땷땸땹땺땻땼땽땾땿 +ë–€ë–떂떃떄떅떆떇떈떉떊떋떌ë–ë–Žë–ë–떑떒떓떔떕떖떗떘떙떚떛떜ë–ë–žë–Ÿ +떠떡떢떣떤떥떦떧떨떩떪떫떬떭떮떯떰떱떲떳떴떵떶떷떸떹떺떻떼떽떾떿 +ë—€ë—뗂뗃뗄뗅뗆뗇뗈뗉뗊뗋뗌ë—ë—Žë—ë—뗑뗒뗓뗔뗕뗖뗗뗘뗙뗚뗛뗜ë—ë—žë—Ÿ +뗠뗡뗢뗣뗤뗥뗦뗧뗨뗩뗪뗫뗬뗭뗮뗯뗰뗱뗲뗳뗴뗵뗶뗷뗸뗹뗺뗻뗼뗽뗾뗿 +똀ë˜ë˜‚똃똄똅똆똇똈똉똊똋똌ë˜ë˜Žë˜ë˜ë˜‘똒똓똔똕똖똗똘똙똚똛똜ë˜ë˜žë˜Ÿ +똠똡똢똣똤똥똦똧똨똩똪똫똬똭똮똯똰똱똲똳똴똵똶똷똸똹똺똻똼똽똾똿 +뙀ë™ë™‚뙃뙄뙅뙆뙇뙈뙉뙊뙋뙌ë™ë™Žë™ë™ë™‘뙒뙓뙔뙕뙖뙗뙘뙙뙚뙛뙜ë™ë™žë™Ÿ +뙠뙡뙢뙣뙤뙥뙦뙧뙨뙩뙪뙫뙬뙭뙮뙯뙰뙱뙲뙳뙴뙵뙶뙷뙸뙹뙺뙻뙼뙽뙾뙿 +뚀ëšëš‚뚃뚄뚅뚆뚇뚈뚉뚊뚋뚌ëšëšŽëšëšëš‘뚒뚓뚔뚕뚖뚗뚘뚙뚚뚛뚜ëšëšžëšŸ +뚠뚡뚢뚣뚤뚥뚦뚧뚨뚩뚪뚫뚬뚭뚮뚯뚰뚱뚲뚳뚴뚵뚶뚷뚸뚹뚺뚻뚼뚽뚾뚿 +뛀ë›ë›‚뛃뛄뛅뛆뛇뛈뛉뛊뛋뛌ë›ë›Žë›ë›ë›‘뛒뛓뛔뛕뛖뛗뛘뛙뛚뛛뛜ë›ë›žë›Ÿ +뛠뛡뛢뛣뛤뛥뛦뛧뛨뛩뛪뛫뛬뛭뛮뛯뛰뛱뛲뛳뛴뛵뛶뛷뛸뛹뛺뛻뛼뛽뛾뛿 +뜀ëœëœ‚뜃뜄뜅뜆뜇뜈뜉뜊뜋뜌ëœëœŽëœëœëœ‘뜒뜓뜔뜕뜖뜗뜘뜙뜚뜛뜜ëœëœžëœŸ +뜠뜡뜢뜣뜤뜥뜦뜧뜨뜩뜪뜫뜬뜭뜮뜯뜰뜱뜲뜳뜴뜵뜶뜷뜸뜹뜺뜻뜼뜽뜾뜿 +ë€ëë‚ëƒë„ë…ë†ë‡ëˆë‰ëŠë‹ëŒëëŽëëë‘ë’ë“ë”ë•ë–ë—ë˜ë™ëšë›ëœëëžëŸ +ë ë¡ë¢ë£ë¤ë¥ë¦ë§ë¨ë©ëªë«ë¬ë­ë®ë¯ë°ë±ë²ë³ë´ëµë¶ë·ë¸ë¹ëºë»ë¼ë½ë¾ë¿ +란ëžëž‚랃랄랅랆랇랈랉랊랋람ëžëžŽëžëžëž‘랒랓랔랕랖랗래랙랚랛랜ëžëžžëžŸ +랠랡랢랣랤랥랦랧램랩랪랫랬랭랮랯랰랱랲랳랴략랶랷랸랹랺랻랼랽랾랿 +럀ëŸëŸ‚럃럄럅럆럇럈량럊럋럌ëŸëŸŽëŸëŸëŸ‘럒럓럔럕럖럗럘럙럚럛럜ëŸëŸžëŸŸ +럠럡럢럣럤럥럦럧럨럩럪럫러럭럮럯런럱럲럳럴럵럶럷럸럹럺럻럼럽럾럿 +ë €ë ë ‚렃렄렅렆렇레렉렊렋렌ë ë Žë ë ë ‘렒렓렔렕렖렗렘렙렚렛렜ë ë žë Ÿ +렠렡렢렣려력렦렧련렩렪렫렬렭렮렯렰렱렲렳렴렵렶렷렸령렺렻렼렽렾렿 +ë¡€ë¡ë¡‚롃롄롅롆롇롈롉롊롋롌ë¡ë¡Žë¡ë¡ë¡‘롒롓롔롕롖롗롘롙롚롛로ë¡ë¡žë¡Ÿ +론롡롢롣롤롥롦롧롨롩롪롫롬롭롮롯롰롱롲롳롴롵롶롷롸롹롺롻롼롽롾롿 +뢀ë¢ë¢‚뢃뢄뢅뢆뢇뢈뢉뢊뢋뢌ë¢ë¢Žë¢ë¢ë¢‘뢒뢓뢔뢕뢖뢗뢘뢙뢚뢛뢜ë¢ë¢žë¢Ÿ +뢠뢡뢢뢣뢤뢥뢦뢧뢨뢩뢪뢫뢬뢭뢮뢯뢰뢱뢲뢳뢴뢵뢶뢷뢸뢹뢺뢻뢼뢽뢾뢿 +룀ë£ë£‚룃룄룅룆룇룈룉룊룋료ë£ë£Žë£ë£ë£‘룒룓룔룕룖룗룘룙룚룛룜ë£ë£žë£Ÿ +룠룡룢룣룤룥룦룧루룩룪룫룬룭룮룯룰룱룲룳룴룵룶룷룸룹룺룻룼룽룾룿 +뤀ë¤ë¤‚뤃뤄뤅뤆뤇뤈뤉뤊뤋뤌ë¤ë¤Žë¤ë¤ë¤‘뤒뤓뤔뤕뤖뤗뤘뤙뤚뤛뤜ë¤ë¤žë¤Ÿ +뤠뤡뤢뤣뤤뤥뤦뤧뤨뤩뤪뤫뤬뤭뤮뤯뤰뤱뤲뤳뤴뤵뤶뤷뤸뤹뤺뤻뤼뤽뤾뤿 +륀ë¥ë¥‚륃륄륅륆륇륈륉륊륋륌ë¥ë¥Žë¥ë¥ë¥‘륒륓륔륕륖륗류륙륚륛륜ë¥ë¥žë¥Ÿ +률륡륢륣륤륥륦륧륨륩륪륫륬륭륮륯륰륱륲륳르륵륶륷른륹륺륻를륽륾륿 +릀ë¦ë¦‚릃름릅릆릇릈릉릊릋릌ë¦ë¦Žë¦ë¦ë¦‘릒릓릔릕릖릗릘릙릚릛릜ë¦ë¦žë¦Ÿ +릠릡릢릣릤릥릦릧릨릩릪릫리릭릮릯린릱릲릳릴릵릶릷릸릹릺릻림립릾릿 +맀ë§ë§‚맃맄맅맆맇마막맊맋만ë§ë§Žë§ë§ë§‘맒맓맔맕맖맗맘맙맚맛맜ë§ë§žë§Ÿ +맠맡맢맣매맥맦맧맨맩맪맫맬맭맮맯맰맱맲맳맴맵맶맷맸맹맺맻맼맽맾맿 +먀ë¨ë¨‚먃먄먅먆먇먈먉먊먋먌ë¨ë¨Žë¨ë¨ë¨‘먒먓먔먕먖먗먘먙먚먛먜ë¨ë¨žë¨Ÿ +먠먡먢먣먤먥먦먧먨먩먪먫먬먭먮먯먰먱먲먳먴먵먶먷머먹먺먻먼먽먾먿 +ë©€ë©ë©‚멃멄멅멆멇멈멉멊멋멌ë©ë©Žë©ë©ë©‘멒멓메멕멖멗멘멙멚멛멜ë©ë©žë©Ÿ +멠멡멢멣멤멥멦멧멨멩멪멫멬멭멮멯며멱멲멳면멵멶멷멸멹멺멻멼멽멾멿 +몀ëªëª‚몃몄명몆몇몈몉몊몋몌ëªëªŽëªëªëª‘몒몓몔몕몖몗몘몙몚몛몜ëªëªžëªŸ +몠몡몢몣몤몥몦몧모목몪몫몬몭몮몯몰몱몲몳몴몵몶몷몸몹몺못몼몽몾몿 +ë«€ë«ë«‚뫃뫄뫅뫆뫇뫈뫉뫊뫋뫌ë«ë«Žë«ë«ë«‘뫒뫓뫔뫕뫖뫗뫘뫙뫚뫛뫜ë«ë«žë«Ÿ +뫠뫡뫢뫣뫤뫥뫦뫧뫨뫩뫪뫫뫬뫭뫮뫯뫰뫱뫲뫳뫴뫵뫶뫷뫸뫹뫺뫻뫼뫽뫾뫿 +묀ë¬ë¬‚묃묄묅묆묇묈묉묊묋묌ë¬ë¬Žë¬ë¬ë¬‘묒묓묔묕묖묗묘묙묚묛묜ë¬ë¬žë¬Ÿ +묠묡묢묣묤묥묦묧묨묩묪묫묬묭묮묯묰묱묲묳무묵묶묷문묹묺묻물묽묾묿 +ë­€ë­ë­‚뭃뭄뭅뭆뭇뭈뭉뭊뭋뭌ë­ë­Žë­ë­ë­‘뭒뭓뭔뭕뭖뭗뭘뭙뭚뭛뭜ë­ë­žë­Ÿ +뭠뭡뭢뭣뭤뭥뭦뭧뭨뭩뭪뭫뭬뭭뭮뭯뭰뭱뭲뭳뭴뭵뭶뭷뭸뭹뭺뭻뭼뭽뭾뭿 +뮀ë®ë®‚뮃뮄뮅뮆뮇뮈뮉뮊뮋뮌ë®ë®Žë®ë®ë®‘뮒뮓뮔뮕뮖뮗뮘뮙뮚뮛뮜ë®ë®žë®Ÿ +뮠뮡뮢뮣뮤뮥뮦뮧뮨뮩뮪뮫뮬뮭뮮뮯뮰뮱뮲뮳뮴뮵뮶뮷뮸뮹뮺뮻뮼뮽뮾뮿 +므ë¯ë¯‚믃믄믅믆믇믈믉믊믋믌ë¯ë¯Žë¯ë¯ë¯‘믒믓믔믕믖믗믘믙믚믛믜ë¯ë¯žë¯Ÿ +믠믡믢믣믤믥믦믧믨믩믪믫믬믭믮믯믰믱믲믳믴믵믶믷미믹믺믻민믽믾믿 +ë°€ë°ë°‚밃밄밅밆밇밈밉밊밋밌ë°ë°Žë°ë°ë°‘밒밓바박밖밗반밙밚받발ë°ë°žë°Ÿ +밠밡밢밣밤밥밦밧밨방밪밫밬밭밮밯배백밲밳밴밵밶밷밸밹밺밻밼밽밾밿 +ë±€ë±ë±‚뱃뱄뱅뱆뱇뱈뱉뱊뱋뱌ë±ë±Žë±ë±ë±‘뱒뱓뱔뱕뱖뱗뱘뱙뱚뱛뱜ë±ë±žë±Ÿ +뱠뱡뱢뱣뱤뱥뱦뱧뱨뱩뱪뱫뱬뱭뱮뱯뱰뱱뱲뱳뱴뱵뱶뱷뱸뱹뱺뱻뱼뱽뱾뱿 +ë²€ë²ë²‚벃버벅벆벇번벉벊벋벌ë²ë²Žë²ë²ë²‘벒벓범법벖벗벘벙벚벛벜ë²ë²žë²Ÿ +베벡벢벣벤벥벦벧벨벩벪벫벬벭벮벯벰벱벲벳벴벵벶벷벸벹벺벻벼벽벾벿 +ë³€ë³ë³‚볃별볅볆볇볈볉볊볋볌ë³ë³Žë³ë³ë³‘볒볓볔볕볖볗볘볙볚볛볜ë³ë³žë³Ÿ +볠볡볢볣볤볥볦볧볨볩볪볫볬볭볮볯볰볱볲볳보복볶볷본볹볺볻볼볽볾볿 +ë´€ë´ë´‚봃봄봅봆봇봈봉봊봋봌ë´ë´Žë´ë´ë´‘봒봓봔봕봖봗봘봙봚봛봜ë´ë´žë´Ÿ +봠봡봢봣봤봥봦봧봨봩봪봫봬봭봮봯봰봱봲봳봴봵봶봷봸봹봺봻봼봽봾봿 +ëµ€ëµëµ‚뵃뵄뵅뵆뵇뵈뵉뵊뵋뵌ëµëµŽëµëµëµ‘뵒뵓뵔뵕뵖뵗뵘뵙뵚뵛뵜ëµëµžëµŸ +뵠뵡뵢뵣뵤뵥뵦뵧뵨뵩뵪뵫뵬뵭뵮뵯뵰뵱뵲뵳뵴뵵뵶뵷뵸뵹뵺뵻뵼뵽뵾뵿 +부ë¶ë¶‚붃분붅붆붇불붉붊붋붌ë¶ë¶Žë¶ë¶ë¶‘붒붓붔붕붖붗붘붙붚붛붜ë¶ë¶žë¶Ÿ +붠붡붢붣붤붥붦붧붨붩붪붫붬붭붮붯붰붱붲붳붴붵붶붷붸붹붺붻붼붽붾붿 +ë·€ë·ë·‚뷃뷄뷅뷆뷇뷈뷉뷊뷋뷌ë·ë·Žë·ë·ë·‘뷒뷓뷔뷕뷖뷗뷘뷙뷚뷛뷜ë·ë·žë·Ÿ +뷠뷡뷢뷣뷤뷥뷦뷧뷨뷩뷪뷫뷬뷭뷮뷯뷰뷱뷲뷳뷴뷵뷶뷷뷸뷹뷺뷻뷼뷽뷾뷿 +븀ë¸ë¸‚븃븄븅븆븇븈븉븊븋브ë¸ë¸Žë¸ë¸ë¸‘븒븓블븕븖븗븘븙븚븛븜ë¸ë¸žë¸Ÿ +븠븡븢븣븤븥븦븧븨븩븪븫븬븭븮븯븰븱븲븳븴븵븶븷븸븹븺븻븼븽븾븿 +ë¹€ë¹ë¹‚빃비빅빆빇빈빉빊빋빌ë¹ë¹Žë¹ë¹ë¹‘빒빓빔빕빖빗빘빙빚빛빜ë¹ë¹žë¹Ÿ +빠빡빢빣빤빥빦빧빨빩빪빫빬빭빮빯빰빱빲빳빴빵빶빷빸빹빺빻빼빽빾빿 +뺀ëºëº‚뺃뺄뺅뺆뺇뺈뺉뺊뺋뺌ëºëºŽëºëºëº‘뺒뺓뺔뺕뺖뺗뺘뺙뺚뺛뺜ëºëºžëºŸ +뺠뺡뺢뺣뺤뺥뺦뺧뺨뺩뺪뺫뺬뺭뺮뺯뺰뺱뺲뺳뺴뺵뺶뺷뺸뺹뺺뺻뺼뺽뺾뺿 +뻀ë»ë»‚뻃뻄뻅뻆뻇뻈뻉뻊뻋뻌ë»ë»Žë»ë»ë»‘뻒뻓뻔뻕뻖뻗뻘뻙뻚뻛뻜ë»ë»žë»Ÿ +뻠뻡뻢뻣뻤뻥뻦뻧뻨뻩뻪뻫뻬뻭뻮뻯뻰뻱뻲뻳뻴뻵뻶뻷뻸뻹뻺뻻뻼뻽뻾뻿 +ë¼€ë¼ë¼‚뼃뼄뼅뼆뼇뼈뼉뼊뼋뼌ë¼ë¼Žë¼ë¼ë¼‘뼒뼓뼔뼕뼖뼗뼘뼙뼚뼛뼜ë¼ë¼žë¼Ÿ +뼠뼡뼢뼣뼤뼥뼦뼧뼨뼩뼪뼫뼬뼭뼮뼯뼰뼱뼲뼳뼴뼵뼶뼷뼸뼹뼺뼻뼼뼽뼾뼿 +ë½€ë½ë½‚뽃뽄뽅뽆뽇뽈뽉뽊뽋뽌ë½ë½Žë½ë½ë½‘뽒뽓뽔뽕뽖뽗뽘뽙뽚뽛뽜ë½ë½žë½Ÿ +뽠뽡뽢뽣뽤뽥뽦뽧뽨뽩뽪뽫뽬뽭뽮뽯뽰뽱뽲뽳뽴뽵뽶뽷뽸뽹뽺뽻뽼뽽뽾뽿 +ë¾€ë¾ë¾‚뾃뾄뾅뾆뾇뾈뾉뾊뾋뾌ë¾ë¾Žë¾ë¾ë¾‘뾒뾓뾔뾕뾖뾗뾘뾙뾚뾛뾜ë¾ë¾žë¾Ÿ +뾠뾡뾢뾣뾤뾥뾦뾧뾨뾩뾪뾫뾬뾭뾮뾯뾰뾱뾲뾳뾴뾵뾶뾷뾸뾹뾺뾻뾼뾽뾾뾿 +ë¿€ë¿ë¿‚뿃뿄뿅뿆뿇뿈뿉뿊뿋뿌ë¿ë¿Žë¿ë¿ë¿‘뿒뿓뿔뿕뿖뿗뿘뿙뿚뿛뿜ë¿ë¿žë¿Ÿ +뿠뿡뿢뿣뿤뿥뿦뿧뿨뿩뿪뿫뿬뿭뿮뿯뿰뿱뿲뿳뿴뿵뿶뿷뿸뿹뿺뿻뿼뿽뿾뿿 +쀀ì€ì€‚쀃쀄쀅쀆쀇쀈쀉쀊쀋쀌ì€ì€Žì€ì€ì€‘쀒쀓쀔쀕쀖쀗쀘쀙쀚쀛쀜ì€ì€žì€Ÿ +쀠쀡쀢쀣쀤쀥쀦쀧쀨쀩쀪쀫쀬쀭쀮쀯쀰쀱쀲쀳쀴쀵쀶쀷쀸쀹쀺쀻쀼쀽쀾쀿 +ì€ìì‚ìƒì„ì…ì†ì‡ìˆì‰ìŠì‹ìŒììŽììì‘ì’ì“ì”ì•ì–ì—ì˜ì™ìšì›ìœììžìŸ +ì ì¡ì¢ì£ì¤ì¥ì¦ì§ì¨ì©ìªì«ì¬ì­ì®ì¯ì°ì±ì²ì³ì´ìµì¶ì·ì¸ì¹ìºì»ì¼ì½ì¾ì¿ +ì‚€ì‚삂삃삄삅삆삇삈삉삊삋삌ì‚ì‚Žì‚ì‚삑삒삓삔삕삖삗삘삙삚삛삜ì‚ì‚žì‚Ÿ +삠삡삢삣삤삥삦삧삨삩삪삫사삭삮삯산삱삲삳살삵삶삷삸삹삺삻삼삽삾삿 +샀ìƒìƒ‚샃샄샅샆샇새색샊샋샌ìƒìƒŽìƒìƒìƒ‘샒샓샔샕샖샗샘샙샚샛샜ìƒìƒžìƒŸ +샠샡샢샣샤샥샦샧샨샩샪샫샬샭샮샯샰샱샲샳샴샵샶샷샸샹샺샻샼샽샾샿 +ì„€ì„섂섃섄섅섆섇섈섉섊섋섌ì„ì„Žì„ì„섑섒섓섔섕섖섗섘섙섚섛서ì„ì„žì„Ÿ +선섡섢섣설섥섦섧섨섩섪섫섬섭섮섯섰성섲섳섴섵섶섷세섹섺섻센섽섾섿 +ì…€ì…셂셃셄셅셆셇셈셉셊셋셌ì…ì…Žì…ì…셑셒셓셔셕셖셗션셙셚셛셜ì…ì…žì…Ÿ +셠셡셢셣셤셥셦셧셨셩셪셫셬셭셮셯셰셱셲셳셴셵셶셷셸셹셺셻셼셽셾셿 +솀ì†ì†‚솃솄솅솆솇솈솉솊솋소ì†ì†Žì†ì†ì†‘솒솓솔솕솖솗솘솙솚솛솜ì†ì†žì†Ÿ +솠송솢솣솤솥솦솧솨솩솪솫솬솭솮솯솰솱솲솳솴솵솶솷솸솹솺솻솼솽솾솿 +쇀ì‡ì‡‚쇃쇄쇅쇆쇇쇈쇉쇊쇋쇌ì‡ì‡Žì‡ì‡ì‡‘쇒쇓쇔쇕쇖쇗쇘쇙쇚쇛쇜ì‡ì‡žì‡Ÿ +쇠쇡쇢쇣쇤쇥쇦쇧쇨쇩쇪쇫쇬쇭쇮쇯쇰쇱쇲쇳쇴쇵쇶쇷쇸쇹쇺쇻쇼쇽쇾쇿 +숀ìˆìˆ‚숃숄숅숆숇숈숉숊숋숌ìˆìˆŽìˆìˆìˆ‘숒숓숔숕숖숗수숙숚숛순ìˆìˆžìˆŸ +술숡숢숣숤숥숦숧숨숩숪숫숬숭숮숯숰숱숲숳숴숵숶숷숸숹숺숻숼숽숾숿 +쉀ì‰ì‰‚쉃쉄쉅쉆쉇쉈쉉쉊쉋쉌ì‰ì‰Žì‰ì‰ì‰‘쉒쉓쉔쉕쉖쉗쉘쉙쉚쉛쉜ì‰ì‰žì‰Ÿ +쉠쉡쉢쉣쉤쉥쉦쉧쉨쉩쉪쉫쉬쉭쉮쉯쉰쉱쉲쉳쉴쉵쉶쉷쉸쉹쉺쉻쉼쉽쉾쉿 +슀ìŠìŠ‚슃슄슅슆슇슈슉슊슋슌ìŠìŠŽìŠìŠìŠ‘슒슓슔슕슖슗슘슙슚슛슜ìŠìŠžìŠŸ +슠슡슢슣스슥슦슧슨슩슪슫슬슭슮슯슰슱슲슳슴습슶슷슸승슺슻슼슽슾슿 +ì‹€ì‹ì‹‚싃싄싅싆싇싈싉싊싋싌ì‹ì‹Žì‹ì‹ì‹‘싒싓싔싕싖싗싘싙싚싛시ì‹ì‹žì‹Ÿ +신싡싢싣실싥싦싧싨싩싪싫심십싮싯싰싱싲싳싴싵싶싷싸싹싺싻싼싽싾싿 +쌀ìŒìŒ‚쌃쌄쌅쌆쌇쌈쌉쌊쌋쌌ìŒìŒŽìŒìŒìŒ‘쌒쌓쌔쌕쌖쌗쌘쌙쌚쌛쌜ìŒìŒžìŒŸ +쌠쌡쌢쌣쌤쌥쌦쌧쌨쌩쌪쌫쌬쌭쌮쌯쌰쌱쌲쌳쌴쌵쌶쌷쌸쌹쌺쌻쌼쌽쌾쌿 +ì€ìì‚ìƒì„ì…ì†ì‡ìˆì‰ìŠì‹ìŒììŽììì‘ì’ì“ì”ì•ì–ì—ì˜ì™ìšì›ìœììžìŸ +ì ì¡ì¢ì£ì¤ì¥ì¦ì§ì¨ì©ìªì«ì¬ì­ì®ì¯ì°ì±ì²ì³ì´ìµì¶ì·ì¸ì¹ìºì»ì¼ì½ì¾ì¿ +쎀ìŽìŽ‚쎃쎄쎅쎆쎇쎈쎉쎊쎋쎌ìŽìŽŽìŽìŽìŽ‘쎒쎓쎔쎕쎖쎗쎘쎙쎚쎛쎜ìŽìŽžìŽŸ +쎠쎡쎢쎣쎤쎥쎦쎧쎨쎩쎪쎫쎬쎭쎮쎯쎰쎱쎲쎳쎴쎵쎶쎷쎸쎹쎺쎻쎼쎽쎾쎿 +ì€ìì‚ìƒì„ì…ì†ì‡ìˆì‰ìŠì‹ìŒììŽììì‘ì’ì“ì”ì•ì–ì—ì˜ì™ìšì›ìœììžìŸ +ì ì¡ì¢ì£ì¤ì¥ì¦ì§ì¨ì©ìªì«ì¬ì­ì®ì¯ì°ì±ì²ì³ì´ìµì¶ì·ì¸ì¹ìºì»ì¼ì½ì¾ì¿ +ì€ìì‚ìƒì„ì…ì†ì‡ìˆì‰ìŠì‹ìŒììŽììì‘ì’ì“ì”ì•ì–ì—ì˜ì™ìšì›ìœììžìŸ +ì ì¡ì¢ì£ì¤ì¥ì¦ì§ì¨ì©ìªì«ì¬ì­ì®ì¯ì°ì±ì²ì³ì´ìµì¶ì·ì¸ì¹ìºì»ì¼ì½ì¾ì¿ +ì‘€ì‘쑂쑃쑄쑅쑆쑇쑈쑉쑊쑋쑌ì‘ì‘Žì‘ì‘쑑쑒쑓쑔쑕쑖쑗쑘쑙쑚쑛쑜ì‘ì‘žì‘Ÿ +쑠쑡쑢쑣쑤쑥쑦쑧쑨쑩쑪쑫쑬쑭쑮쑯쑰쑱쑲쑳쑴쑵쑶쑷쑸쑹쑺쑻쑼쑽쑾쑿 +ì’€ì’쒂쒃쒄쒅쒆쒇쒈쒉쒊쒋쒌ì’ì’Žì’ì’쒑쒒쒓쒔쒕쒖쒗쒘쒙쒚쒛쒜ì’ì’žì’Ÿ +쒠쒡쒢쒣쒤쒥쒦쒧쒨쒩쒪쒫쒬쒭쒮쒯쒰쒱쒲쒳쒴쒵쒶쒷쒸쒹쒺쒻쒼쒽쒾쒿 +ì“€ì“쓂쓃쓄쓅쓆쓇쓈쓉쓊쓋쓌ì“ì“Žì“ì“쓑쓒쓓쓔쓕쓖쓗쓘쓙쓚쓛쓜ì“ì“žì“Ÿ +쓠쓡쓢쓣쓤쓥쓦쓧쓨쓩쓪쓫쓬쓭쓮쓯쓰쓱쓲쓳쓴쓵쓶쓷쓸쓹쓺쓻쓼쓽쓾쓿 +씀ì”씂씃씄씅씆씇씈씉씊씋씌ì”씎ì”ì”씑씒씓씔씕씖씗씘씙씚씛씜ì”씞씟 +씠씡씢씣씤씥씦씧씨씩씪씫씬씭씮씯씰씱씲씳씴씵씶씷씸씹씺씻씼씽씾씿 +ì•€ì•ì•‚앃아악앆앇안앉않앋알ì•ì•Žì•ì•ì•‘앒앓암압앖앗았앙앚앛앜ì•ì•žì•Ÿ +애액앢앣앤앥앦앧앨앩앪앫앬앭앮앯앰앱앲앳앴앵앶앷앸앹앺앻야약앾앿 +ì–€ì–얂얃얄얅얆얇얈얉얊얋얌ì–ì–Žì–ì–양얒얓얔얕얖얗얘얙얚얛얜ì–ì–žì–Ÿ +얠얡얢얣얤얥얦얧얨얩얪얫얬얭얮얯얰얱얲얳어억얶얷언얹얺얻얼얽얾얿 +ì—€ì—엂엃엄업없엇었엉엊엋엌ì—ì—Žì—ì—엑엒엓엔엕엖엗엘엙엚엛엜ì—ì—žì—Ÿ +엠엡엢엣엤엥엦엧엨엩엪엫여역엮엯연엱엲엳열엵엶엷엸엹엺엻염엽엾엿 +였ì˜ì˜‚옃옄옅옆옇예옉옊옋옌ì˜ì˜Žì˜ì˜ì˜‘옒옓옔옕옖옗옘옙옚옛옜ì˜ì˜žì˜Ÿ +옠옡옢옣오옥옦옧온옩옪옫올옭옮옯옰옱옲옳옴옵옶옷옸옹옺옻옼옽옾옿 +와ì™ì™‚왃완왅왆왇왈왉왊왋왌ì™ì™Žì™ì™ì™‘왒왓왔왕왖왗왘왙왚왛왜ì™ì™žì™Ÿ +왠왡왢왣왤왥왦왧왨왩왪왫왬왭왮왯왰왱왲왳왴왵왶왷외왹왺왻왼왽왾왿 +욀ìšìš‚욃욄욅욆욇욈욉욊욋욌ìšìšŽìšìšìš‘욒욓요욕욖욗욘욙욚욛욜ìšìšžìšŸ +욠욡욢욣욤욥욦욧욨용욪욫욬욭욮욯우욱욲욳운욵욶욷울욹욺욻욼욽욾욿 +움ì›ì›‚웃웄웅웆웇웈웉웊웋워ì›ì›Žì›ì›ì›‘웒웓월웕웖웗웘웙웚웛웜ì›ì›žì›Ÿ +웠웡웢웣웤웥웦웧웨웩웪웫웬웭웮웯웰웱웲웳웴웵웶웷웸웹웺웻웼웽웾웿 +윀ìœìœ‚윃위윅윆윇윈윉윊윋윌ìœìœŽìœìœìœ‘윒윓윔윕윖윗윘윙윚윛윜ìœìœžìœŸ +유육윢윣윤윥윦윧율윩윪윫윬윭윮윯윰윱윲윳윴융윶윷윸윹윺윻으윽윾윿 +ì€ìì‚ìƒì„ì…ì†ì‡ìˆì‰ìŠì‹ìŒììŽììì‘ì’ì“ì”ì•ì–ì—ì˜ì™ìšì›ìœììžìŸ +ì ì¡ì¢ì£ì¤ì¥ì¦ì§ì¨ì©ìªì«ì¬ì­ì®ì¯ì°ì±ì²ì³ì´ìµì¶ì·ì¸ì¹ìºì»ì¼ì½ì¾ì¿ +잀ìžìž‚잃임입잆잇있잉잊잋잌ìžìžŽìžìžìž‘잒잓잔잕잖잗잘잙잚잛잜ìžìžžìžŸ +잠잡잢잣잤장잦잧잨잩잪잫재잭잮잯잰잱잲잳잴잵잶잷잸잹잺잻잼잽잾잿 +쟀ìŸìŸ‚쟃쟄쟅쟆쟇쟈쟉쟊쟋쟌ìŸìŸŽìŸìŸìŸ‘쟒쟓쟔쟕쟖쟗쟘쟙쟚쟛쟜ìŸìŸžìŸŸ +쟠쟡쟢쟣쟤쟥쟦쟧쟨쟩쟪쟫쟬쟭쟮쟯쟰쟱쟲쟳쟴쟵쟶쟷쟸쟹쟺쟻쟼쟽쟾쟿 +ì €ì ì ‚젃전젅젆젇절젉젊젋젌ì ì Žì ì ì ‘젒젓젔정젖젗젘젙젚젛제ì ì žì Ÿ +젠젡젢젣젤젥젦젧젨젩젪젫젬젭젮젯젰젱젲젳젴젵젶젷져젹젺젻젼젽젾젿 +ì¡€ì¡ì¡‚졃졄졅졆졇졈졉졊졋졌ì¡ì¡Žì¡ì¡ì¡‘졒졓졔졕졖졗졘졙졚졛졜ì¡ì¡žì¡Ÿ +졠졡졢졣졤졥졦졧졨졩졪졫졬졭졮졯조족졲졳존졵졶졷졸졹졺졻졼졽졾졿 +좀ì¢ì¢‚좃좄종좆좇좈좉좊좋좌ì¢ì¢Žì¢ì¢ì¢‘좒좓좔좕좖좗좘좙좚좛좜ì¢ì¢žì¢Ÿ +좠좡좢좣좤좥좦좧좨좩좪좫좬좭좮좯좰좱좲좳좴좵좶좷좸좹좺좻좼좽좾좿 +죀ì£ì£‚죃죄죅죆죇죈죉죊죋죌ì£ì£Žì£ì£ì£‘죒죓죔죕죖죗죘죙죚죛죜ì£ì£žì£Ÿ +죠죡죢죣죤죥죦죧죨죩죪죫죬죭죮죯죰죱죲죳죴죵죶죷죸죹죺죻주죽죾죿 +준ì¤ì¤‚줃줄줅줆줇줈줉줊줋줌ì¤ì¤Žì¤ì¤ì¤‘줒줓줔줕줖줗줘줙줚줛줜ì¤ì¤žì¤Ÿ +줠줡줢줣줤줥줦줧줨줩줪줫줬줭줮줯줰줱줲줳줴줵줶줷줸줹줺줻줼줽줾줿 +쥀ì¥ì¥‚쥃쥄쥅쥆쥇쥈쥉쥊쥋쥌ì¥ì¥Žì¥ì¥ì¥‘쥒쥓쥔쥕쥖쥗쥘쥙쥚쥛쥜ì¥ì¥žì¥Ÿ +쥠쥡쥢쥣쥤쥥쥦쥧쥨쥩쥪쥫쥬쥭쥮쥯쥰쥱쥲쥳쥴쥵쥶쥷쥸쥹쥺쥻쥼쥽쥾쥿 +즀ì¦ì¦‚즃즄즅즆즇즈즉즊즋즌ì¦ì¦Žì¦ì¦ì¦‘즒즓즔즕즖즗즘즙즚즛즜ì¦ì¦žì¦Ÿ +즠즡즢즣즤즥즦즧즨즩즪즫즬즭즮즯즰즱즲즳즴즵즶즷즸즹즺즻즼즽즾즿 +지ì§ì§‚짃진짅짆짇질짉짊짋짌ì§ì§Žì§ì§ì§‘짒짓짔징짖짗짘짙짚짛짜ì§ì§žì§Ÿ +짠짡짢짣짤짥짦짧짨짩짪짫짬짭짮짯짰짱짲짳짴짵짶짷째짹짺짻짼짽짾짿 +쨀ì¨ì¨‚쨃쨄쨅쨆쨇쨈쨉쨊쨋쨌ì¨ì¨Žì¨ì¨ì¨‘쨒쨓쨔쨕쨖쨗쨘쨙쨚쨛쨜ì¨ì¨žì¨Ÿ +쨠쨡쨢쨣쨤쨥쨦쨧쨨쨩쨪쨫쨬쨭쨮쨯쨰쨱쨲쨳쨴쨵쨶쨷쨸쨹쨺쨻쨼쨽쨾쨿 +ì©€ì©ì©‚쩃쩄쩅쩆쩇쩈쩉쩊쩋쩌ì©ì©Žì©ì©ì©‘쩒쩓쩔쩕쩖쩗쩘쩙쩚쩛쩜ì©ì©žì©Ÿ +쩠쩡쩢쩣쩤쩥쩦쩧쩨쩩쩪쩫쩬쩭쩮쩯쩰쩱쩲쩳쩴쩵쩶쩷쩸쩹쩺쩻쩼쩽쩾쩿 +쪀ìªìª‚쪃쪄쪅쪆쪇쪈쪉쪊쪋쪌ìªìªŽìªìªìª‘쪒쪓쪔쪕쪖쪗쪘쪙쪚쪛쪜ìªìªžìªŸ +쪠쪡쪢쪣쪤쪥쪦쪧쪨쪩쪪쪫쪬쪭쪮쪯쪰쪱쪲쪳쪴쪵쪶쪷쪸쪹쪺쪻쪼쪽쪾쪿 +ì«€ì«ì«‚쫃쫄쫅쫆쫇쫈쫉쫊쫋쫌ì«ì«Žì«ì«ì«‘쫒쫓쫔쫕쫖쫗쫘쫙쫚쫛쫜ì«ì«žì«Ÿ +쫠쫡쫢쫣쫤쫥쫦쫧쫨쫩쫪쫫쫬쫭쫮쫯쫰쫱쫲쫳쫴쫵쫶쫷쫸쫹쫺쫻쫼쫽쫾쫿 +쬀ì¬ì¬‚쬃쬄쬅쬆쬇쬈쬉쬊쬋쬌ì¬ì¬Žì¬ì¬ì¬‘쬒쬓쬔쬕쬖쬗쬘쬙쬚쬛쬜ì¬ì¬žì¬Ÿ +쬠쬡쬢쬣쬤쬥쬦쬧쬨쬩쬪쬫쬬쬭쬮쬯쬰쬱쬲쬳쬴쬵쬶쬷쬸쬹쬺쬻쬼쬽쬾쬿 +ì­€ì­ì­‚쭃쭄쭅쭆쭇쭈쭉쭊쭋쭌ì­ì­Žì­ì­ì­‘쭒쭓쭔쭕쭖쭗쭘쭙쭚쭛쭜ì­ì­žì­Ÿ +쭠쭡쭢쭣쭤쭥쭦쭧쭨쭩쭪쭫쭬쭭쭮쭯쭰쭱쭲쭳쭴쭵쭶쭷쭸쭹쭺쭻쭼쭽쭾쭿 +쮀ì®ì®‚쮃쮄쮅쮆쮇쮈쮉쮊쮋쮌ì®ì®Žì®ì®ì®‘쮒쮓쮔쮕쮖쮗쮘쮙쮚쮛쮜ì®ì®žì®Ÿ +쮠쮡쮢쮣쮤쮥쮦쮧쮨쮩쮪쮫쮬쮭쮮쮯쮰쮱쮲쮳쮴쮵쮶쮷쮸쮹쮺쮻쮼쮽쮾쮿 +쯀ì¯ì¯‚쯃쯄쯅쯆쯇쯈쯉쯊쯋쯌ì¯ì¯Žì¯ì¯ì¯‘쯒쯓쯔쯕쯖쯗쯘쯙쯚쯛쯜ì¯ì¯žì¯Ÿ +쯠쯡쯢쯣쯤쯥쯦쯧쯨쯩쯪쯫쯬쯭쯮쯯쯰쯱쯲쯳쯴쯵쯶쯷쯸쯹쯺쯻쯼쯽쯾쯿 +ì°€ì°ì°‚찃찄찅찆찇찈찉찊찋찌ì°ì°Žì°ì°ì°‘찒찓찔찕찖찗찘찙찚찛찜ì°ì°žì°Ÿ +찠찡찢찣찤찥찦찧차착찪찫찬찭찮찯찰찱찲찳찴찵찶찷참찹찺찻찼창찾찿 +ì±€ì±ì±‚챃채책챆챇챈챉챊챋챌ì±ì±Žì±ì±ì±‘챒챓챔챕챖챗챘챙챚챛챜ì±ì±žì±Ÿ +챠챡챢챣챤챥챦챧챨챩챪챫챬챭챮챯챰챱챲챳챴챵챶챷챸챹챺챻챼챽챾챿 +ì²€ì²ì²‚첃첄첅첆첇첈첉첊첋첌ì²ì²Žì²ì²ì²‘첒첓첔첕첖첗처척첚첛천ì²ì²žì²Ÿ +철첡첢첣첤첥첦첧첨첩첪첫첬청첮첯첰첱첲첳체첵첶첷첸첹첺첻첼첽첾첿 +ì³€ì³ì³‚쳃쳄쳅쳆쳇쳈쳉쳊쳋쳌ì³ì³Žì³ì³ì³‘쳒쳓쳔쳕쳖쳗쳘쳙쳚쳛쳜ì³ì³žì³Ÿ +쳠쳡쳢쳣쳤쳥쳦쳧쳨쳩쳪쳫쳬쳭쳮쳯쳰쳱쳲쳳쳴쳵쳶쳷쳸쳹쳺쳻쳼쳽쳾쳿 +ì´€ì´ì´‚촃촄촅촆촇초촉촊촋촌ì´ì´Žì´ì´ì´‘촒촓촔촕촖촗촘촙촚촛촜ì´ì´žì´Ÿ +촠촡촢촣촤촥촦촧촨촩촪촫촬촭촮촯촰촱촲촳촴촵촶촷촸촹촺촻촼촽촾촿 +ìµ€ìµìµ‚쵃쵄쵅쵆쵇쵈쵉쵊쵋쵌ìµìµŽìµìµìµ‘쵒쵓쵔쵕쵖쵗쵘쵙쵚쵛최ìµìµžìµŸ +쵠쵡쵢쵣쵤쵥쵦쵧쵨쵩쵪쵫쵬쵭쵮쵯쵰쵱쵲쵳쵴쵵쵶쵷쵸쵹쵺쵻쵼쵽쵾쵿 +춀ì¶ì¶‚춃춄춅춆춇춈춉춊춋춌ì¶ì¶Žì¶ì¶ì¶‘춒춓추축춖춗춘춙춚춛출ì¶ì¶žì¶Ÿ +춠춡춢춣춤춥춦춧춨충춪춫춬춭춮춯춰춱춲춳춴춵춶춷춸춹춺춻춼춽춾춿 +ì·€ì·ì·‚췃췄췅췆췇췈췉췊췋췌ì·ì·Žì·ì·ì·‘췒췓췔췕췖췗췘췙췚췛췜ì·ì·žì·Ÿ +췠췡췢췣췤췥췦췧취췩췪췫췬췭췮췯췰췱췲췳췴췵췶췷췸췹췺췻췼췽췾췿 +츀ì¸ì¸‚츃츄츅츆츇츈츉츊츋츌ì¸ì¸Žì¸ì¸ì¸‘츒츓츔츕츖츗츘츙츚츛츜ì¸ì¸žì¸Ÿ +츠측츢츣츤츥츦츧츨츩츪츫츬츭츮츯츰츱츲츳츴층츶츷츸츹츺츻츼츽츾츿 +ì¹€ì¹ì¹‚칃칄칅칆칇칈칉칊칋칌ì¹ì¹Žì¹ì¹ì¹‘칒칓칔칕칖칗치칙칚칛친ì¹ì¹žì¹Ÿ +칠칡칢칣칤칥칦칧침칩칪칫칬칭칮칯칰칱칲칳카칵칶칷칸칹칺칻칼칽칾칿 +캀ìºìº‚캃캄캅캆캇캈캉캊캋캌ìºìºŽìºìºìº‘캒캓캔캕캖캗캘캙캚캛캜ìºìºžìºŸ +캠캡캢캣캤캥캦캧캨캩캪캫캬캭캮캯캰캱캲캳캴캵캶캷캸캹캺캻캼캽캾캿 +컀ì»ì»‚컃컄컅컆컇컈컉컊컋컌ì»ì»Žì»ì»ì»‘컒컓컔컕컖컗컘컙컚컛컜ì»ì»žì»Ÿ +컠컡컢컣커컥컦컧컨컩컪컫컬컭컮컯컰컱컲컳컴컵컶컷컸컹컺컻컼컽컾컿 +ì¼€ì¼ì¼‚켃켄켅켆켇켈켉켊켋켌ì¼ì¼Žì¼ì¼ì¼‘켒켓켔켕켖켗켘켙켚켛켜ì¼ì¼žì¼Ÿ +켠켡켢켣켤켥켦켧켨켩켪켫켬켭켮켯켰켱켲켳켴켵켶켷켸켹켺켻켼켽켾켿 +ì½€ì½ì½‚콃콄콅콆콇콈콉콊콋콌ì½ì½Žì½ì½ì½‘콒콓코콕콖콗콘콙콚콛콜ì½ì½žì½Ÿ +콠콡콢콣콤콥콦콧콨콩콪콫콬콭콮콯콰콱콲콳콴콵콶콷콸콹콺콻콼콽콾콿 +ì¾€ì¾ì¾‚쾃쾄쾅쾆쾇쾈쾉쾊쾋쾌ì¾ì¾Žì¾ì¾ì¾‘쾒쾓쾔쾕쾖쾗쾘쾙쾚쾛쾜ì¾ì¾žì¾Ÿ +쾠쾡쾢쾣쾤쾥쾦쾧쾨쾩쾪쾫쾬쾭쾮쾯쾰쾱쾲쾳쾴쾵쾶쾷쾸쾹쾺쾻쾼쾽쾾쾿 +ì¿€ì¿ì¿‚쿃쿄쿅쿆쿇쿈쿉쿊쿋쿌ì¿ì¿Žì¿ì¿ì¿‘쿒쿓쿔쿕쿖쿗쿘쿙쿚쿛쿜ì¿ì¿žì¿Ÿ +쿠쿡쿢쿣쿤쿥쿦쿧쿨쿩쿪쿫쿬쿭쿮쿯쿰쿱쿲쿳쿴쿵쿶쿷쿸쿹쿺쿻쿼쿽쿾쿿 +퀀í€í€‚퀃퀄퀅퀆퀇퀈퀉퀊퀋퀌í€í€Ží€í€í€‘퀒퀓퀔퀕퀖퀗퀘퀙퀚퀛퀜í€í€ží€Ÿ +퀠퀡퀢퀣퀤퀥퀦퀧퀨퀩퀪퀫퀬퀭퀮퀯퀰퀱퀲퀳퀴퀵퀶퀷퀸퀹퀺퀻퀼퀽퀾퀿 +í€íí‚íƒí„í…í†í‡íˆí‰íŠí‹íŒííŽííí‘í’í“í”í•í–í—í˜í™íší›íœíížíŸ +í í¡í¢í£í¤í¥í¦í§í¨í©íªí«í¬í­í®í¯í°í±í²í³í´íµí¶í·í¸í¹íºí»í¼í½í¾í¿ +í‚€í‚킂킃킄킅킆킇킈킉킊킋킌í‚í‚Ží‚í‚킑킒킓킔킕킖킗킘킙킚킛킜í‚í‚ží‚Ÿ +킠킡킢킣키킥킦킧킨킩킪킫킬킭킮킯킰킱킲킳킴킵킶킷킸킹킺킻킼킽킾킿 +타íƒíƒ‚탃탄탅탆탇탈탉탊탋탌íƒíƒŽíƒíƒíƒ‘탒탓탔탕탖탗탘탙탚탛태íƒíƒžíƒŸ +탠탡탢탣탤탥탦탧탨탩탪탫탬탭탮탯탰탱탲탳탴탵탶탷탸탹탺탻탼탽탾탿 +í„€í„턂턃턄턅턆턇턈턉턊턋턌í„í„Ží„í„턑턒턓턔턕턖턗턘턙턚턛턜í„í„ží„Ÿ +턠턡턢턣턤턥턦턧턨턩턪턫턬턭턮턯터턱턲턳턴턵턶턷털턹턺턻턼턽턾턿 +í…€í…텂텃텄텅텆텇텈텉텊텋테í…í…Ží…í…텑텒텓텔텕텖텗텘텙텚텛템í…í…ží…Ÿ +텠텡텢텣텤텥텦텧텨텩텪텫텬텭텮텯텰텱텲텳텴텵텶텷텸텹텺텻텼텽텾텿 +톀í†í†‚톃톄톅톆톇톈톉톊톋톌í†í†Ží†í†í†‘톒톓톔톕톖톗톘톙톚톛톜í†í†ží†Ÿ +토톡톢톣톤톥톦톧톨톩톪톫톬톭톮톯톰톱톲톳톴통톶톷톸톹톺톻톼톽톾톿 +퇀í‡í‡‚퇃퇄퇅퇆퇇퇈퇉퇊퇋퇌í‡í‡Ží‡í‡í‡‘퇒퇓퇔퇕퇖퇗퇘퇙퇚퇛퇜í‡í‡ží‡Ÿ +퇠퇡퇢퇣퇤퇥퇦퇧퇨퇩퇪퇫퇬퇭퇮퇯퇰퇱퇲퇳퇴퇵퇶퇷퇸퇹퇺퇻퇼퇽퇾퇿 +툀íˆíˆ‚툃툄툅툆툇툈툉툊툋툌íˆíˆŽíˆíˆíˆ‘툒툓툔툕툖툗툘툙툚툛툜íˆíˆžíˆŸ +툠툡툢툣툤툥툦툧툨툩툪툫투툭툮툯툰툱툲툳툴툵툶툷툸툹툺툻툼툽툾툿 +퉀í‰í‰‚퉃퉄퉅퉆퉇퉈퉉퉊퉋퉌í‰í‰Ží‰í‰í‰‘퉒퉓퉔퉕퉖퉗퉘퉙퉚퉛퉜í‰í‰ží‰Ÿ +퉠퉡퉢퉣퉤퉥퉦퉧퉨퉩퉪퉫퉬퉭퉮퉯퉰퉱퉲퉳퉴퉵퉶퉷퉸퉹퉺퉻퉼퉽퉾퉿 +튀íŠíŠ‚튃튄튅튆튇튈튉튊튋튌íŠíŠŽíŠíŠíŠ‘튒튓튔튕튖튗튘튙튚튛튜íŠíŠžíŠŸ +튠튡튢튣튤튥튦튧튨튩튪튫튬튭튮튯튰튱튲튳튴튵튶튷트특튺튻튼튽튾튿 +í‹€í‹í‹‚틃틄틅틆틇틈틉틊틋틌í‹í‹Ží‹í‹í‹‘틒틓틔틕틖틗틘틙틚틛틜í‹í‹ží‹Ÿ +틠틡틢틣틤틥틦틧틨틩틪틫틬틭틮틯티틱틲틳틴틵틶틷틸틹틺틻틼틽틾틿 +팀íŒíŒ‚팃팄팅팆팇팈팉팊팋파íŒíŒŽíŒíŒíŒ‘팒팓팔팕팖팗팘팙팚팛팜íŒíŒžíŒŸ +팠팡팢팣팤팥팦팧패팩팪팫팬팭팮팯팰팱팲팳팴팵팶팷팸팹팺팻팼팽팾팿 +í€íí‚íƒí„í…í†í‡íˆí‰íŠí‹íŒííŽííí‘í’í“í”í•í–í—í˜í™íší›íœíížíŸ +í í¡í¢í£í¤í¥í¦í§í¨í©íªí«í¬í­í®í¯í°í±í²í³í´íµí¶í·í¸í¹íºí»í¼í½í¾í¿ +펀íŽíŽ‚펃펄펅펆펇펈펉펊펋펌íŽíŽŽíŽíŽíŽ‘펒펓펔펕펖펗페펙펚펛펜íŽíŽžíŽŸ +펠펡펢펣펤펥펦펧펨펩펪펫펬펭펮펯펰펱펲펳펴펵펶펷편펹펺펻펼펽펾펿 +í€íí‚íƒí„í…í†í‡íˆí‰íŠí‹íŒííŽííí‘í’í“í”í•í–í—í˜í™íší›íœíížíŸ +í í¡í¢í£í¤í¥í¦í§í¨í©íªí«í¬í­í®í¯í°í±í²í³í´íµí¶í·í¸í¹íºí»í¼í½í¾í¿ +í€íí‚íƒí„í…í†í‡íˆí‰íŠí‹íŒííŽííí‘í’í“í”í•í–í—í˜í™íší›íœíížíŸ +í í¡í¢í£í¤í¥í¦í§í¨í©íªí«í¬í­í®í¯í°í±í²í³í´íµí¶í·í¸í¹íºí»í¼í½í¾í¿ +í‘€í‘푂푃푄푅푆푇푈푉푊푋푌í‘í‘Ží‘í‘푑푒푓푔푕푖푗푘푙푚푛표í‘í‘ží‘Ÿ +푠푡푢푣푤푥푦푧푨푩푪푫푬푭푮푯푰푱푲푳푴푵푶푷푸푹푺푻푼푽푾푿 +í’€í’풂풃풄풅풆풇품풉풊풋풌í’í’Ží’í’풑풒풓풔풕풖풗풘풙풚풛풜í’í’ží’Ÿ +풠풡풢풣풤풥풦풧풨풩풪풫풬풭풮풯풰풱풲풳풴풵풶풷풸풹풺풻풼풽풾풿 +í“€í“퓂퓃퓄퓅퓆퓇퓈퓉퓊퓋퓌í“í“Ží“í“퓑퓒퓓퓔퓕퓖퓗퓘퓙퓚퓛퓜í“í“ží“Ÿ +퓠퓡퓢퓣퓤퓥퓦퓧퓨퓩퓪퓫퓬퓭퓮퓯퓰퓱퓲퓳퓴퓵퓶퓷퓸퓹퓺퓻퓼퓽퓾퓿 +픀í”픂픃프픅픆픇픈픉픊픋플í”픎í”í”픑픒픓픔픕픖픗픘픙픚픛픜í”픞픟 +픠픡픢픣픤픥픦픧픨픩픪픫픬픭픮픯픰픱픲픳픴픵픶픷픸픹픺픻피픽픾픿 +í•€í•í•‚핃필핅핆핇핈핉핊핋핌í•í•Ží•í•í•‘핒핓핔핕핖핗하학핚핛한í•í•ží•Ÿ +할핡핢핣핤핥핦핧함합핪핫핬항핮핯핰핱핲핳해핵핶핷핸핹핺핻핼핽핾핿 +í–€í–햂햃햄햅햆햇했행햊햋햌í–í–Ží–í–햑햒햓햔햕햖햗햘햙햚햛햜í–í–ží–Ÿ +햠햡햢햣햤향햦햧햨햩햪햫햬햭햮햯햰햱햲햳햴햵햶햷햸햹햺햻햼햽햾햿 +í—€í—헂헃헄헅헆헇허헉헊헋헌í—í—Ží—í—헑헒헓헔헕헖헗험헙헚헛헜í—í—ží—Ÿ +헠헡헢헣헤헥헦헧헨헩헪헫헬헭헮헯헰헱헲헳헴헵헶헷헸헹헺헻헼헽헾헿 +혀í˜í˜‚혃현혅혆혇혈혉혊혋혌í˜í˜Ží˜í˜í˜‘혒혓혔형혖혗혘혙혚혛혜í˜í˜ží˜Ÿ +혠혡혢혣혤혥혦혧혨혩혪혫혬혭혮혯혰혱혲혳혴혵혶혷호혹혺혻혼혽혾혿 +홀í™í™‚홃홄홅홆홇홈홉홊홋홌í™í™Ží™í™í™‘홒홓화확홖홗환홙홚홛활í™í™ží™Ÿ +홠홡홢홣홤홥홦홧홨황홪홫홬홭홮홯홰홱홲홳홴홵홶홷홸홹홺홻홼홽홾홿 +횀íšíš‚횃횄횅횆횇횈횉횊횋회íšíšŽíšíšíš‘횒횓횔횕횖횗횘횙횚횛횜íšíšžíšŸ +횠횡횢횣횤횥횦횧효횩횪횫횬횭횮횯횰횱횲횳횴횵횶횷횸횹횺횻횼횽횾횿 +훀í›í›‚훃후훅훆훇훈훉훊훋훌í›í›Ží›í›í›‘훒훓훔훕훖훗훘훙훚훛훜í›í›ží›Ÿ +훠훡훢훣훤훥훦훧훨훩훪훫훬훭훮훯훰훱훲훳훴훵훶훷훸훹훺훻훼훽훾훿 +휀íœíœ‚휃휄휅휆휇휈휉휊휋휌íœíœŽíœíœíœ‘휒휓휔휕휖휗휘휙휚휛휜íœíœžíœŸ +휠휡휢휣휤휥휦휧휨휩휪휫휬휭휮휯휰휱휲휳휴휵휶휷휸휹휺휻휼휽휾휿 +í€íí‚íƒí„í…í†í‡íˆí‰íŠí‹íŒííŽííí‘í’í“í”í•í–í—í˜í™íší›íœíížíŸ +í í¡í¢í£í¤í¥í¦í§í¨í©íªí«í¬í­í®í¯í°í±í²í³í´íµí¶í·í¸í¹íºí»í¼í½í¾í¿ +힀ížíž‚힃힄힅힆힇히힉힊힋힌ížížŽížížíž‘힒힓힔힕힖힗힘힙힚힛힜ížížžížŸ +힠힡힢힣힤힥힦힧힨힩힪힫힬힭힮힯 + +Free block (U+D7B0-U+D7FF): + +ힰힱힲힳힴힵힶힷힸힹힺힻힼힽힾힿퟀíŸíŸ‚ퟃퟄퟅퟆ퟇퟈퟉퟊ퟋퟌíŸíŸŽíŸíŸíŸ‘ퟒퟓퟔퟕퟖퟗퟘퟙퟚퟛퟜíŸíŸžíŸŸíŸ íŸ¡íŸ¢íŸ£íŸ¤íŸ¥íŸ¦íŸ§íŸ¨íŸ©íŸªíŸ«íŸ¬íŸ­íŸ®íŸ¯ +ퟰퟱퟲퟳퟴퟵퟶퟷퟸퟹퟺퟻ퟼퟽퟾퟿ + +High Surrogates (U+D800-U+DB7F): + +í €í í ‚í ƒí „í …í †í ‡í ˆí ‰í Ší ‹í Œí í Ží í í ‘í ’í “í ”í •í –í —í ˜í ™í ší ›í œí í ží Ÿí  í ¡í ¢í £í ¤í ¥í ¦í §í ¨í ©í ªí «í ¬í ­í ®í ¯í °í ±í ²í ³í ´í µí ¶í ·í ¸í ¹í ºí »í ¼í ½í ¾í ¿ +í¡€í¡í¡‚í¡ƒí¡„í¡…í¡†í¡‡í¡ˆí¡‰í¡Ší¡‹í¡Œí¡í¡Ží¡í¡í¡‘í¡’í¡“í¡”í¡•í¡–í¡—í¡˜í¡™í¡ší¡›í¡œí¡í¡ží¡Ÿí¡ í¡¡í¡¢í¡£í¡¤í¡¥í¡¦í¡§í¡¨í¡©í¡ªí¡«í¡¬í¡­í¡®í¡¯í¡°í¡±í¡²í¡³í¡´í¡µí¡¶í¡·í¡¸í¡¹í¡ºí¡»í¡¼í¡½í¡¾í¡¿ +í¢€í¢í¢‚í¢ƒí¢„í¢…í¢†í¢‡í¢ˆí¢‰í¢Ší¢‹í¢Œí¢í¢Ží¢í¢í¢‘í¢’í¢“í¢”í¢•í¢–í¢—í¢˜í¢™í¢ší¢›í¢œí¢í¢ží¢Ÿí¢ í¢¡í¢¢í¢£í¢¤í¢¥í¢¦í¢§í¢¨í¢©í¢ªí¢«í¢¬í¢­í¢®í¢¯í¢°í¢±í¢²í¢³í¢´í¢µí¢¶í¢·í¢¸í¢¹í¢ºí¢»í¢¼í¢½í¢¾í¢¿ +í£€í£í£‚í£ƒí£„í£…í£†í£‡í£ˆí£‰í£Ší£‹í£Œí£í£Ží£í£í£‘í£’í£“í£”í£•í£–í£—í£˜í£™í£ší£›í£œí£í£ží£Ÿí£ í£¡í£¢í££í£¤í£¥í£¦í£§í£¨í£©í£ªí£«í£¬í£­í£®í£¯í£°í£±í£²í£³í£´í£µí£¶í£·í£¸í£¹í£ºí£»í£¼í£½í£¾í£¿ +í¤€í¤í¤‚í¤ƒí¤„í¤…í¤†í¤‡í¤ˆí¤‰í¤Ší¤‹í¤Œí¤í¤Ží¤í¤í¤‘í¤’í¤“í¤”í¤•í¤–í¤—í¤˜í¤™í¤ší¤›í¤œí¤í¤ží¤Ÿí¤ í¤¡í¤¢í¤£í¤¤í¤¥í¤¦í¤§í¤¨í¤©í¤ªí¤«í¤¬í¤­í¤®í¤¯í¤°í¤±í¤²í¤³í¤´í¤µí¤¶í¤·í¤¸í¤¹í¤ºí¤»í¤¼í¤½í¤¾í¤¿ +í¥€í¥í¥‚í¥ƒí¥„í¥…í¥†í¥‡í¥ˆí¥‰í¥Ší¥‹í¥Œí¥í¥Ží¥í¥í¥‘í¥’í¥“í¥”í¥•í¥–í¥—í¥˜í¥™í¥ší¥›í¥œí¥í¥ží¥Ÿí¥ í¥¡í¥¢í¥£í¥¤í¥¥í¥¦í¥§í¥¨í¥©í¥ªí¥«í¥¬í¥­í¥®í¥¯í¥°í¥±í¥²í¥³í¥´í¥µí¥¶í¥·í¥¸í¥¹í¥ºí¥»í¥¼í¥½í¥¾í¥¿ +í¦€í¦í¦‚í¦ƒí¦„í¦…í¦†í¦‡í¦ˆí¦‰í¦Ší¦‹í¦Œí¦í¦Ží¦í¦í¦‘í¦’í¦“í¦”í¦•í¦–í¦—í¦˜í¦™í¦ší¦›í¦œí¦í¦ží¦Ÿí¦ í¦¡í¦¢í¦£í¦¤í¦¥í¦¦í¦§í¦¨í¦©í¦ªí¦«í¦¬í¦­í¦®í¦¯í¦°í¦±í¦²í¦³í¦´í¦µí¦¶í¦·í¦¸í¦¹í¦ºí¦»í¦¼í¦½í¦¾í¦¿ +í§€í§í§‚í§ƒí§„í§…í§†í§‡í§ˆí§‰í§Ší§‹í§Œí§í§Ží§í§í§‘í§’í§“í§”í§•í§–í§—í§˜í§™í§ší§›í§œí§í§ží§Ÿí§ í§¡í§¢í§£í§¤í§¥í§¦í§§í§¨í§©í§ªí§«í§¬í§­í§®í§¯í§°í§±í§²í§³í§´í§µí§¶í§·í§¸í§¹í§ºí§»í§¼í§½í§¾í§¿ +í¨€í¨í¨‚í¨ƒí¨„í¨…í¨†í¨‡í¨ˆí¨‰í¨Ší¨‹í¨Œí¨í¨Ží¨í¨í¨‘í¨’í¨“í¨”í¨•í¨–í¨—í¨˜í¨™í¨ší¨›í¨œí¨í¨ží¨Ÿí¨ í¨¡í¨¢í¨£í¨¤í¨¥í¨¦í¨§í¨¨í¨©í¨ªí¨«í¨¬í¨­í¨®í¨¯í¨°í¨±í¨²í¨³í¨´í¨µí¨¶í¨·í¨¸í¨¹í¨ºí¨»í¨¼í¨½í¨¾í¨¿ +í©€í©í©‚í©ƒí©„í©…í©†í©‡í©ˆí©‰í©Ší©‹í©Œí©í©Ží©í©í©‘í©’í©“í©”í©•í©–í©—í©˜í©™í©ší©›í©œí©í©ží©Ÿí© í©¡í©¢í©£í©¤í©¥í©¦í©§í©¨í©©í©ªí©«í©¬í©­í©®í©¯í©°í©±í©²í©³í©´í©µí©¶í©·í©¸í©¹í©ºí©»í©¼í©½í©¾í©¿ +íª€íªíª‚íªƒíª„íª…íª†íª‡íªˆíª‰íªŠíª‹íªŒíªíªŽíªíªíª‘íª’íª“íª”íª•íª–íª—íª˜íª™íªšíª›íªœíªíªžíªŸíª íª¡íª¢íª£íª¤íª¥íª¦íª§íª¨íª©íªªíª«íª¬íª­íª®íª¯íª°íª±íª²íª³íª´íªµíª¶íª·íª¸íª¹íªºíª»íª¼íª½íª¾íª¿ +í«€í«í«‚í«ƒí«„í«…í«†í«‡í«ˆí«‰í«Ší«‹í«Œí«í«Ží«í«í«‘í«’í«“í«”í«•í«–í«—í«˜í«™í«ší«›í«œí«í«ží«Ÿí« í«¡í«¢í«£í«¤í«¥í«¦í«§í«¨í«©í«ªí««í«¬í«­í«®í«¯í«°í«±í«²í«³í«´í«µí«¶í«·í«¸í«¹í«ºí«»í«¼í«½í«¾í«¿ +í¬€í¬í¬‚í¬ƒí¬„í¬…í¬†í¬‡í¬ˆí¬‰í¬Ší¬‹í¬Œí¬í¬Ží¬í¬í¬‘í¬’í¬“í¬”í¬•í¬–í¬—í¬˜í¬™í¬ší¬›í¬œí¬í¬ží¬Ÿí¬ í¬¡í¬¢í¬£í¬¤í¬¥í¬¦í¬§í¬¨í¬©í¬ªí¬«í¬¬í¬­í¬®í¬¯í¬°í¬±í¬²í¬³í¬´í¬µí¬¶í¬·í¬¸í¬¹í¬ºí¬»í¬¼í¬½í¬¾í¬¿ +í­€í­í­‚í­ƒí­„í­…í­†í­‡í­ˆí­‰í­Ší­‹í­Œí­í­Ží­í­í­‘í­’í­“í­”í­•í­–í­—í­˜í­™í­ší­›í­œí­í­ží­Ÿí­ í­¡í­¢í­£í­¤í­¥í­¦í­§í­¨í­©í­ªí­«í­¬í­­í­®í­¯í­°í­±í­²í­³í­´í­µí­¶í­·í­¸í­¹í­ºí­»í­¼í­½í­¾í­¿ + +High Private Use Surrogates (U+DB80-U+DBFF): + +í®€í®í®‚í®ƒí®„í®…í®†í®‡í®ˆí®‰í®Ší®‹í®Œí®í®Ží®í®í®‘í®’í®“í®”í®•í®–í®—í®˜í®™í®ší®›í®œí®í®ží®Ÿí® í®¡í®¢í®£í®¤í®¥í®¦í®§í®¨í®©í®ªí®«í®¬í®­í®®í®¯í®°í®±í®²í®³í®´í®µí®¶í®·í®¸í®¹í®ºí®»í®¼í®½í®¾í®¿ +í¯€í¯í¯‚í¯ƒí¯„í¯…í¯†í¯‡í¯ˆí¯‰í¯Ší¯‹í¯Œí¯í¯Ží¯í¯í¯‘í¯’í¯“í¯”í¯•í¯–í¯—í¯˜í¯™í¯ší¯›í¯œí¯í¯ží¯Ÿí¯ í¯¡í¯¢í¯£í¯¤í¯¥í¯¦í¯§í¯¨í¯©í¯ªí¯«í¯¬í¯­í¯®í¯¯í¯°í¯±í¯²í¯³í¯´í¯µí¯¶í¯·í¯¸í¯¹í¯ºí¯»í¯¼í¯½í¯¾í¯¿ + +Low Surrogates (U+DC00-U+DFFF): + +í°€í°í°‚í°ƒí°„í°…í°†í°‡í°ˆí°‰í°Ší°‹í°Œí°í°Ží°í°í°‘í°’í°“í°”í°•í°–í°—í°˜í°™í°ší°›í°œí°í°ží°Ÿí° í°¡í°¢í°£í°¤í°¥í°¦í°§í°¨í°©í°ªí°«í°¬í°­í°®í°¯í°°í°±í°²í°³í°´í°µí°¶í°·í°¸í°¹í°ºí°»í°¼í°½í°¾í°¿ +í±€í±í±‚í±ƒí±„í±…í±†í±‡í±ˆí±‰í±Ší±‹í±Œí±í±Ží±í±í±‘í±’í±“í±”í±•í±–í±—í±˜í±™í±ší±›í±œí±í±ží±Ÿí± í±¡í±¢í±£í±¤í±¥í±¦í±§í±¨í±©í±ªí±«í±¬í±­í±®í±¯í±°í±±í±²í±³í±´í±µí±¶í±·í±¸í±¹í±ºí±»í±¼í±½í±¾í±¿ +í²€í²í²‚í²ƒí²„í²…í²†í²‡í²ˆí²‰í²Ší²‹í²Œí²í²Ží²í²í²‘í²’í²“í²”í²•í²–í²—í²˜í²™í²ší²›í²œí²í²ží²Ÿí² í²¡í²¢í²£í²¤í²¥í²¦í²§í²¨í²©í²ªí²«í²¬í²­í²®í²¯í²°í²±í²²í²³í²´í²µí²¶í²·í²¸í²¹í²ºí²»í²¼í²½í²¾í²¿ +í³€í³í³‚í³ƒí³„í³…í³†í³‡í³ˆí³‰í³Ší³‹í³Œí³í³Ží³í³í³‘í³’í³“í³”í³•í³–í³—í³˜í³™í³ší³›í³œí³í³ží³Ÿí³ í³¡í³¢í³£í³¤í³¥í³¦í³§í³¨í³©í³ªí³«í³¬í³­í³®í³¯í³°í³±í³²í³³í³´í³µí³¶í³·í³¸í³¹í³ºí³»í³¼í³½í³¾í³¿ +í´€í´í´‚í´ƒí´„í´…í´†í´‡í´ˆí´‰í´Ší´‹í´Œí´í´Ží´í´í´‘í´’í´“í´”í´•í´–í´—í´˜í´™í´ší´›í´œí´í´ží´Ÿí´ í´¡í´¢í´£í´¤í´¥í´¦í´§í´¨í´©í´ªí´«í´¬í´­í´®í´¯í´°í´±í´²í´³í´´í´µí´¶í´·í´¸í´¹í´ºí´»í´¼í´½í´¾í´¿ +íµ€íµíµ‚íµƒíµ„íµ…íµ†íµ‡íµˆíµ‰íµŠíµ‹íµŒíµíµŽíµíµíµ‘íµ’íµ“íµ”íµ•íµ–íµ—íµ˜íµ™íµšíµ›íµœíµíµžíµŸíµ íµ¡íµ¢íµ£íµ¤íµ¥íµ¦íµ§íµ¨íµ©íµªíµ«íµ¬íµ­íµ®íµ¯íµ°íµ±íµ²íµ³íµ´íµµíµ¶íµ·íµ¸íµ¹íµºíµ»íµ¼íµ½íµ¾íµ¿ +í¶€í¶í¶‚í¶ƒí¶„í¶…í¶†í¶‡í¶ˆí¶‰í¶Ší¶‹í¶Œí¶í¶Ží¶í¶í¶‘í¶’í¶“í¶”í¶•í¶–í¶—í¶˜í¶™í¶ší¶›í¶œí¶í¶ží¶Ÿí¶ í¶¡í¶¢í¶£í¶¤í¶¥í¶¦í¶§í¶¨í¶©í¶ªí¶«í¶¬í¶­í¶®í¶¯í¶°í¶±í¶²í¶³í¶´í¶µí¶¶í¶·í¶¸í¶¹í¶ºí¶»í¶¼í¶½í¶¾í¶¿ +í·€í·í·‚í·ƒí·„í·…í·†í·‡í·ˆí·‰í·Ší·‹í·Œí·í·Ží·í·í·‘í·’í·“í·”í·•í·–í·—í·˜í·™í·ší·›í·œí·í·ží·Ÿí· í·¡í·¢í·£í·¤í·¥í·¦í·§í·¨í·©í·ªí·«í·¬í·­í·®í·¯í·°í·±í·²í·³í·´í·µí·¶í··í·¸í·¹í·ºí·»í·¼í·½í·¾í·¿ +í¸€í¸í¸‚í¸ƒí¸„í¸…í¸†í¸‡í¸ˆí¸‰í¸Ší¸‹í¸Œí¸í¸Ží¸í¸í¸‘í¸’í¸“í¸”í¸•í¸–í¸—í¸˜í¸™í¸ší¸›í¸œí¸í¸ží¸Ÿí¸ í¸¡í¸¢í¸£í¸¤í¸¥í¸¦í¸§í¸¨í¸©í¸ªí¸«í¸¬í¸­í¸®í¸¯í¸°í¸±í¸²í¸³í¸´í¸µí¸¶í¸·í¸¸í¸¹í¸ºí¸»í¸¼í¸½í¸¾í¸¿ +í¹€í¹í¹‚í¹ƒí¹„í¹…í¹†í¹‡í¹ˆí¹‰í¹Ší¹‹í¹Œí¹í¹Ží¹í¹í¹‘í¹’í¹“í¹”í¹•í¹–í¹—í¹˜í¹™í¹ší¹›í¹œí¹í¹ží¹Ÿí¹ í¹¡í¹¢í¹£í¹¤í¹¥í¹¦í¹§í¹¨í¹©í¹ªí¹«í¹¬í¹­í¹®í¹¯í¹°í¹±í¹²í¹³í¹´í¹µí¹¶í¹·í¹¸í¹¹í¹ºí¹»í¹¼í¹½í¹¾í¹¿ +íº€íºíº‚íºƒíº„íº…íº†íº‡íºˆíº‰íºŠíº‹íºŒíºíºŽíºíºíº‘íº’íº“íº”íº•íº–íº—íº˜íº™íºšíº›íºœíºíºžíºŸíº íº¡íº¢íº£íº¤íº¥íº¦íº§íº¨íº©íºªíº«íº¬íº­íº®íº¯íº°íº±íº²íº³íº´íºµíº¶íº·íº¸íº¹íººíº»íº¼íº½íº¾íº¿ +í»€í»í»‚í»ƒí»„í»…í»†í»‡í»ˆí»‰í»Ší»‹í»Œí»í»Ží»í»í»‘í»’í»“í»”í»•í»–í»—í»˜í»™í»ší»›í»œí»í»ží»Ÿí» í»¡í»¢í»£í»¤í»¥í»¦í»§í»¨í»©í»ªí»«í»¬í»­í»®í»¯í»°í»±í»²í»³í»´í»µí»¶í»·í»¸í»¹í»ºí»»í»¼í»½í»¾í»¿ +í¼€í¼í¼‚í¼ƒí¼„í¼…í¼†í¼‡í¼ˆí¼‰í¼Ší¼‹í¼Œí¼í¼Ží¼í¼í¼‘í¼’í¼“í¼”í¼•í¼–í¼—í¼˜í¼™í¼ší¼›í¼œí¼í¼ží¼Ÿí¼ í¼¡í¼¢í¼£í¼¤í¼¥í¼¦í¼§í¼¨í¼©í¼ªí¼«í¼¬í¼­í¼®í¼¯í¼°í¼±í¼²í¼³í¼´í¼µí¼¶í¼·í¼¸í¼¹í¼ºí¼»í¼¼í¼½í¼¾í¼¿ +í½€í½í½‚í½ƒí½„í½…í½†í½‡í½ˆí½‰í½Ší½‹í½Œí½í½Ží½í½í½‘í½’í½“í½”í½•í½–í½—í½˜í½™í½ší½›í½œí½í½ží½Ÿí½ í½¡í½¢í½£í½¤í½¥í½¦í½§í½¨í½©í½ªí½«í½¬í½­í½®í½¯í½°í½±í½²í½³í½´í½µí½¶í½·í½¸í½¹í½ºí½»í½¼í½½í½¾í½¿ +í¾€í¾í¾‚í¾ƒí¾„í¾…í¾†í¾‡í¾ˆí¾‰í¾Ší¾‹í¾Œí¾í¾Ží¾í¾í¾‘í¾’í¾“í¾”í¾•í¾–í¾—í¾˜í¾™í¾ší¾›í¾œí¾í¾ží¾Ÿí¾ í¾¡í¾¢í¾£í¾¤í¾¥í¾¦í¾§í¾¨í¾©í¾ªí¾«í¾¬í¾­í¾®í¾¯í¾°í¾±í¾²í¾³í¾´í¾µí¾¶í¾·í¾¸í¾¹í¾ºí¾»í¾¼í¾½í¾¾í¾¿ +í¿€í¿í¿‚í¿ƒí¿„í¿…í¿†í¿‡í¿ˆí¿‰í¿Ší¿‹í¿Œí¿í¿Ží¿í¿í¿‘í¿’í¿“í¿”í¿•í¿–í¿—í¿˜í¿™í¿ší¿›í¿œí¿í¿ží¿Ÿí¿ í¿¡í¿¢í¿£í¿¤í¿¥í¿¦í¿§í¿¨í¿©í¿ªí¿«í¿¬í¿­í¿®í¿¯í¿°í¿±í¿²í¿³í¿´í¿µí¿¶í¿·í¿¸í¿¹í¿ºí¿»í¿¼í¿½í¿¾í¿¿ + +Private Use Area (U+E000-U+F8FF): + +î€î€‚î€î€Žî€î€î€‘î€î€žî€Ÿî€ î€¡î€¢î€£î€¤î€¥î€¦î€§î€¨î€©î€ªî€«î€¬î€­î€®î€¯î€°î€±î€²î€³î€´î€µî€¶î€·î€¸î€¹î€ºî€»î€¼î€½î€¾î€¿ +î€îî‚îƒî„î…î†î‡îˆî‰îŠî‹îŒîîŽîîî‘î’î“î”î•î–î—î˜î™îšî›îœîîžîŸî î¡î¢î£î¤î¥î¦î§î¨î©îªî«î¬î­î®î¯î°î±î²î³î´îµî¶î·î¸î¹îºî»î¼î½î¾î¿ +î‚€î‚î‚î‚Žî‚î‚î‚ +îƒîƒ‚îƒîƒŽîƒîƒîƒ‘îƒîƒžîƒŸîƒ îƒ¡îƒ¢îƒ£îƒ¤îƒ¥îƒ¦îƒ§îƒ¨îƒ©îƒªîƒ«îƒ¬îƒ­îƒ®îƒ¯îƒ°îƒ±îƒ²îƒ³îƒ´îƒµîƒ¶îƒ·îƒ¸îƒ¹îƒºîƒ»îƒ¼îƒ½îƒ¾îƒ¿ +î„€î„î„î„Žî„î„î„ +î…€î…î…î…Žî…î…î… +î†î†‚î†î†Žî†î†î†‘î†î†žî†Ÿî† î†¡î†¢î†£î†¤î†¥î†¦î†§î†¨î†©î†ªî†«î†¬î†­î†®î†¯î†°î†±î†²î†³î†´î†µî†¶î†·î†¸î†¹î†ºî†»î†¼î†½î†¾î†¿ +î‡î‡‚î‡î‡Žî‡î‡î‡‘î‡î‡žî‡Ÿî‡ î‡¡î‡¢î‡£î‡¤î‡¥î‡¦î‡§î‡¨î‡©î‡ªî‡«î‡¬î‡­î‡®î‡¯î‡°î‡±î‡²î‡³î‡´î‡µî‡¶î‡·î‡¸î‡¹î‡ºî‡»î‡¼î‡½î‡¾î‡¿ +îˆîˆ‚îˆîˆŽîˆîˆîˆ‘îˆîˆžîˆŸîˆ îˆ¡îˆ¢îˆ£îˆ¤îˆ¥îˆ¦îˆ§îˆ¨îˆ©îˆªîˆ«îˆ¬îˆ­îˆ®îˆ¯îˆ°îˆ±îˆ²îˆ³îˆ´îˆµîˆ¶îˆ·îˆ¸îˆ¹îˆºîˆ»îˆ¼îˆ½îˆ¾îˆ¿ +î‰î‰‚î‰î‰Žî‰î‰î‰‘î‰î‰žî‰Ÿî‰ î‰¡î‰¢î‰£î‰¤î‰¥î‰¦î‰§î‰¨î‰©î‰ªî‰«î‰¬î‰­î‰®î‰¯î‰°î‰±î‰²î‰³î‰´î‰µî‰¶î‰·î‰¸î‰¹î‰ºî‰»î‰¼î‰½î‰¾î‰¿ +îŠîŠ‚îŠîŠŽîŠîŠîŠ‘îŠîŠžîŠŸîŠ îŠ¡îŠ¢îŠ£îŠ¤îŠ¥îŠ¦îŠ§îŠ¨îŠ©îŠªîŠ«îŠ¬îŠ­îŠ®îŠ¯îŠ°îŠ±îŠ²îŠ³îŠ´îŠµîŠ¶îŠ·îŠ¸îŠ¹îŠºîŠ»îŠ¼îŠ½îŠ¾îŠ¿ +î‹€î‹î‹‚î‹î‹Žî‹î‹î‹‘î‹î‹žî‹Ÿî‹ î‹¡î‹¢î‹£î‹¤î‹¥î‹¦î‹§î‹¨î‹©î‹ªî‹«î‹¬î‹­î‹®î‹¯î‹°î‹±î‹²î‹³î‹´î‹µî‹¶î‹·î‹¸î‹¹î‹ºî‹»î‹¼î‹½î‹¾î‹¿ +îŒîŒ‚îŒîŒŽîŒîŒîŒ‘îŒîŒžîŒŸîŒ îŒ¡îŒ¢îŒ£îŒ¤îŒ¥îŒ¦îŒ§îŒ¨îŒ©îŒªîŒ«îŒ¬îŒ­îŒ®îŒ¯îŒ°îŒ±îŒ²îŒ³îŒ´îŒµîŒ¶îŒ·îŒ¸îŒ¹îŒºîŒ»îŒ¼îŒ½îŒ¾îŒ¿ +î€îî‚îƒî„î…î†î‡îˆî‰îŠî‹îŒîîŽîîî‘î’î“î”î•î–î—î˜î™îšî›îœîîžîŸî î¡î¢î£î¤î¥î¦î§î¨î©îªî«î¬î­î®î¯î°î±î²î³î´îµî¶î·î¸î¹îºî»î¼î½î¾î¿ +îŽîŽ‚îŽîŽŽîŽîŽîŽ‘îŽîŽžîŽŸîŽ îŽ¡îŽ¢îŽ£îŽ¤îŽ¥îŽ¦îŽ§îŽ¨îŽ©îŽªîŽ«îŽ¬îŽ­îŽ®îŽ¯îŽ°îŽ±îŽ²îŽ³îŽ´îŽµîŽ¶îŽ·îŽ¸îŽ¹îŽºîŽ»îŽ¼îŽ½îŽ¾îŽ¿ +î€îî‚îƒî„î…î†î‡îˆî‰îŠî‹îŒîîŽîîî‘î’î“î”î•î–î—î˜î™îšî›îœîîžîŸî î¡î¢î£î¤î¥î¦î§î¨î©îªî«î¬î­î®î¯î°î±î²î³î´îµî¶î·î¸î¹îºî»î¼î½î¾î¿ +î€îî‚îƒî„î…î†î‡îˆî‰îŠî‹îŒîîŽîîî‘î’î“î”î•î–î—î˜î™îšî›îœîîžîŸî î¡î¢î£î¤î¥î¦î§î¨î©îªî«î¬î­î®î¯î°î±î²î³î´îµî¶î·î¸î¹îºî»î¼î½î¾î¿ +î‘€î‘î‘î‘Žî‘î‘î‘ +î’€î’î’î’Žî’î’î’ +î“€î“î“î“Žî“î“î“ +î”î”î”î”î” +î•€î•î•‚î•î•Žî•î•î•‘î•î•žî•Ÿî• î•¡î•¢î•£î•¤î•¥î•¦î•§î•¨î•©î•ªî•«î•¬î•­î•®î•¯î•°î•±î•²î•³î•´î•µî•¶î•·î•¸î•¹î•ºî•»î•¼î•½î•¾î•¿ +î–€î–î–î–Žî–î–î– +î—€î—î—î—Žî—î—î— +î˜î˜‚î˜î˜Žî˜î˜î˜‘î˜î˜žî˜Ÿî˜ î˜¡î˜¢î˜£î˜¤î˜¥î˜¦î˜§î˜¨î˜©î˜ªî˜«î˜¬î˜­î˜®î˜¯î˜°î˜±î˜²î˜³î˜´î˜µî˜¶î˜·î˜¸î˜¹î˜ºî˜»î˜¼î˜½î˜¾î˜¿ +î™î™‚î™î™Žî™î™î™‘î™î™žî™Ÿî™ î™¡î™¢î™£î™¤î™¥î™¦î™§î™¨î™©î™ªî™«î™¬î™­î™®î™¯î™°î™±î™²î™³î™´î™µî™¶î™·î™¸î™¹î™ºî™»î™¼î™½î™¾î™¿ +îšîš‚îšîšŽîšîšîš‘îšîšžîšŸîš îš¡îš¢îš£îš¤îš¥îš¦îš§îš¨îš©îšªîš«îš¬îš­îš®îš¯îš°îš±îš²îš³îš´îšµîš¶îš·îš¸îš¹îšºîš»îš¼îš½îš¾îš¿ +î›î›‚î›î›Žî›î›î›‘î›î›žî›Ÿî› î›¡î›¢î›£î›¤î›¥î›¦î›§î›¨î›©î›ªî›«î›¬î›­î›®î›¯î›°î›±î›²î›³î›´î›µî›¶î›·î›¸î›¹î›ºî›»î›¼î›½î›¾î›¿ +îœîœ‚îœîœŽîœîœîœ‘îœîœžîœŸîœ îœ¡îœ¢îœ£îœ¤îœ¥îœ¦îœ§îœ¨îœ©îœªîœ«îœ¬îœ­îœ®îœ¯îœ°îœ±îœ²îœ³îœ´îœµîœ¶îœ·îœ¸îœ¹îœºîœ»îœ¼îœ½îœ¾îœ¿ +î€îî‚îƒî„î…î†î‡îˆî‰îŠî‹îŒîîŽîîî‘î’î“î”î•î–î—î˜î™îšî›îœîîžîŸî î¡î¢î£î¤î¥î¦î§î¨î©îªî«î¬î­î®î¯î°î±î²î³î´îµî¶î·î¸î¹îºî»î¼î½î¾î¿ +îžîž‚îžîžŽîžîžîž‘îžîžžîžŸîž îž¡îž¢îž£îž¤îž¥îž¦îž§îž¨îž©îžªîž«îž¬îž­îž®îž¯îž°îž±îž²îž³îž´îžµîž¶îž·îž¸îž¹îžºîž»îž¼îž½îž¾îž¿ +îŸîŸ‚îŸîŸŽîŸîŸîŸ‘îŸîŸžîŸŸîŸ îŸ¡îŸ¢îŸ£îŸ¤îŸ¥îŸ¦îŸ§îŸ¨îŸ©îŸªîŸ«îŸ¬îŸ­îŸ®îŸ¯îŸ°îŸ±îŸ²îŸ³îŸ´îŸµîŸ¶îŸ·îŸ¸îŸ¹îŸºîŸ»îŸ¼îŸ½îŸ¾îŸ¿ +î €î î ‚î î Žî î î ‘î î žî Ÿî  î ¡î ¢î £î ¤î ¥î ¦î §î ¨î ©î ªî «î ¬î ­î ®î ¯î °î ±î ²î ³î ´î µî ¶î ·î ¸î ¹î ºî »î ¼î ½î ¾î ¿ +î¡€î¡î¡‚î¡î¡Žî¡î¡î¡‘î¡î¡žî¡Ÿî¡ î¡¡î¡¢î¡£î¡¤î¡¥î¡¦î¡§î¡¨î¡©î¡ªî¡«î¡¬î¡­î¡®î¡¯î¡°î¡±î¡²î¡³î¡´î¡µî¡¶î¡·î¡¸î¡¹î¡ºî¡»î¡¼î¡½î¡¾î¡¿ +î¢î¢‚î¢î¢Žî¢î¢î¢‘î¢î¢žî¢Ÿî¢ î¢¡î¢¢î¢£î¢¤î¢¥î¢¦î¢§î¢¨î¢©î¢ªî¢«î¢¬î¢­î¢®î¢¯î¢°î¢±î¢²î¢³î¢´î¢µî¢¶î¢·î¢¸î¢¹î¢ºî¢»î¢¼î¢½î¢¾î¢¿ +î£î£‚î£î£Žî£î£î£‘î£î£žî£Ÿî£ î£¡î£¢î££î£¤î£¥î£¦î£§î£¨î£©î£ªî£«î£¬î£­î£®î£¯î£°î£±î£²î£³î£´î£µî£¶î£·î£¸î£¹î£ºî£»î£¼î£½î£¾î£¿ +î¤î¤‚î¤î¤Žî¤î¤î¤‘î¤î¤žî¤Ÿî¤ î¤¡î¤¢î¤£î¤¤î¤¥î¤¦î¤§î¤¨î¤©î¤ªî¤«î¤¬î¤­î¤®î¤¯î¤°î¤±î¤²î¤³î¤´î¤µî¤¶î¤·î¤¸î¤¹î¤ºî¤»î¤¼î¤½î¤¾î¤¿ +î¥î¥‚î¥î¥Žî¥î¥î¥‘î¥î¥žî¥Ÿî¥ î¥¡î¥¢î¥£î¥¤î¥¥î¥¦î¥§î¥¨î¥©î¥ªî¥«î¥¬î¥­î¥®î¥¯î¥°î¥±î¥²î¥³î¥´î¥µî¥¶î¥·î¥¸î¥¹î¥ºî¥»î¥¼î¥½î¥¾î¥¿ +î¦î¦‚î¦î¦Žî¦î¦î¦‘î¦î¦žî¦Ÿî¦ î¦¡î¦¢î¦£î¦¤î¦¥î¦¦î¦§î¦¨î¦©î¦ªî¦«î¦¬î¦­î¦®î¦¯î¦°î¦±î¦²î¦³î¦´î¦µî¦¶î¦·î¦¸î¦¹î¦ºî¦»î¦¼î¦½î¦¾î¦¿ +î§î§‚î§î§Žî§î§î§‘î§î§žî§Ÿî§ î§¡î§¢î§£î§¤î§¥î§¦î§§î§¨î§©î§ªî§«î§¬î§­î§®î§¯î§°î§±î§²î§³î§´î§µî§¶î§·î§¸î§¹î§ºî§»î§¼î§½î§¾î§¿ +î¨î¨‚î¨î¨Žî¨î¨î¨‘î¨î¨žî¨Ÿî¨ î¨¡î¨¢î¨£î¨¤î¨¥î¨¦î¨§î¨¨î¨©î¨ªî¨«î¨¬î¨­î¨®î¨¯î¨°î¨±î¨²î¨³î¨´î¨µî¨¶î¨·î¨¸î¨¹î¨ºî¨»î¨¼î¨½î¨¾î¨¿ +î©€î©î©‚î©î©Žî©î©î©‘î©î©žî©Ÿî© î©¡î©¢î©£î©¤î©¥î©¦î©§î©¨î©©î©ªî©«î©¬î©­î©®î©¯î©°î©±î©²î©³î©´î©µî©¶î©·î©¸î©¹î©ºî©»î©¼î©½î©¾î©¿ +îªîª‚îªîªŽîªîªîª‘îªîªžîªŸîª îª¡îª¢îª£îª¤îª¥îª¦îª§îª¨îª©îªªîª«îª¬îª­îª®îª¯îª°îª±îª²îª³îª´îªµîª¶îª·îª¸îª¹îªºîª»îª¼îª½îª¾îª¿ +î«€î«î«‚î«î«Žî«î«î«‘î«î«žî«Ÿî« î«¡î«¢î«£î«¤î«¥î«¦î«§î«¨î«©î«ªî««î«¬î«­î«®î«¯î«°î«±î«²î«³î«´î«µî«¶î«·î«¸î«¹î«ºî«»î«¼î«½î«¾î«¿ +î¬î¬‚î¬î¬Žî¬î¬î¬‘î¬î¬žî¬Ÿî¬ î¬¡î¬¢î¬£î¬¤î¬¥î¬¦î¬§î¬¨î¬©î¬ªî¬«î¬¬î¬­î¬®î¬¯î¬°î¬±î¬²î¬³î¬´î¬µî¬¶î¬·î¬¸î¬¹î¬ºî¬»î¬¼î¬½î¬¾î¬¿ +î­€î­î­‚î­î­Žî­î­î­‘î­î­žî­Ÿî­ î­¡î­¢î­£î­¤î­¥î­¦î­§î­¨î­©î­ªî­«î­¬î­­î­®î­¯î­°î­±î­²î­³î­´î­µî­¶î­·î­¸î­¹î­ºî­»î­¼î­½î­¾î­¿ +î®î®‚î®î®Žî®î®î®‘î®î®žî®Ÿî® î®¡î®¢î®£î®¤î®¥î®¦î®§î®¨î®©î®ªî®«î®¬î®­î®®î®¯î®°î®±î®²î®³î®´î®µî®¶î®·î®¸î®¹î®ºî®»î®¼î®½î®¾î®¿ +î¯î¯‚î¯î¯Žî¯î¯î¯‘î¯î¯žî¯Ÿî¯ î¯¡î¯¢î¯£î¯¤î¯¥î¯¦î¯§î¯¨î¯©î¯ªî¯«î¯¬î¯­î¯®î¯¯î¯°î¯±î¯²î¯³î¯´î¯µî¯¶î¯·î¯¸î¯¹î¯ºî¯»î¯¼î¯½î¯¾î¯¿ +î°€î°î°‚î°î°Žî°î°î°‘î°î°žî°Ÿî° î°¡î°¢î°£î°¤î°¥î°¦î°§î°¨î°©î°ªî°«î°¬î°­î°®î°¯î°°î°±î°²î°³î°´î°µî°¶î°·î°¸î°¹î°ºî°»î°¼î°½î°¾î°¿ +î±€î±î±‚î±î±Žî±î±î±‘î±î±žî±Ÿî± î±¡î±¢î±£î±¤î±¥î±¦î±§î±¨î±©î±ªî±«î±¬î±­î±®î±¯î±°î±±î±²î±³î±´î±µî±¶î±·î±¸î±¹î±ºî±»î±¼î±½î±¾î±¿ +î²€î²î²‚î²î²Žî²î²î²‘î²î²žî²Ÿî² î²¡î²¢î²£î²¤î²¥î²¦î²§î²¨î²©î²ªî²«î²¬î²­î²®î²¯î²°î²±î²²î²³î²´î²µî²¶î²·î²¸î²¹î²ºî²»î²¼î²½î²¾î²¿ +î³€î³î³‚î³î³Žî³î³î³‘î³î³žî³Ÿî³ î³¡î³¢î³£î³¤î³¥î³¦î³§î³¨î³©î³ªî³«î³¬î³­î³®î³¯î³°î³±î³²î³³î³´î³µî³¶î³·î³¸î³¹î³ºî³»î³¼î³½î³¾î³¿ +î´€î´î´‚î´î´Žî´î´î´‘î´î´žî´Ÿî´ î´¡î´¢î´£î´¤î´¥î´¦î´§î´¨î´©î´ªî´«î´¬î´­î´®î´¯î´°î´±î´²î´³î´´î´µî´¶î´·î´¸î´¹î´ºî´»î´¼î´½î´¾î´¿ +îµ€îµîµ‚îµîµŽîµîµîµ‘îµîµžîµŸîµ îµ¡îµ¢îµ£îµ¤îµ¥îµ¦îµ§îµ¨îµ©îµªîµ«îµ¬îµ­îµ®îµ¯îµ°îµ±îµ²îµ³îµ´îµµîµ¶îµ·îµ¸îµ¹îµºîµ»îµ¼îµ½îµ¾îµ¿ +î¶î¶‚î¶î¶Žî¶î¶î¶‘î¶î¶žî¶Ÿî¶ î¶¡î¶¢î¶£î¶¤î¶¥î¶¦î¶§î¶¨î¶©î¶ªî¶«î¶¬î¶­î¶®î¶¯î¶°î¶±î¶²î¶³î¶´î¶µî¶¶î¶·î¶¸î¶¹î¶ºî¶»î¶¼î¶½î¶¾î¶¿ +î·€î·î·‚î·î·Žî·î·î·‘î·î·žî·Ÿî· î·¡î·¢î·£î·¤î·¥î·¦î·§î·¨î·©î·ªî·«î·¬î·­î·®î·¯î·°î·±î·²î·³î·´î·µî·¶î··î·¸î·¹î·ºî·»î·¼î·½î·¾î·¿ +î¸î¸‚î¸î¸Žî¸î¸î¸‘î¸î¸žî¸Ÿî¸ î¸¡î¸¢î¸£î¸¤î¸¥î¸¦î¸§î¸¨î¸©î¸ªî¸«î¸¬î¸­î¸®î¸¯î¸°î¸±î¸²î¸³î¸´î¸µî¸¶î¸·î¸¸î¸¹î¸ºî¸»î¸¼î¸½î¸¾î¸¿ +î¹€î¹î¹‚î¹î¹Žî¹î¹î¹‘î¹î¹žî¹Ÿî¹ î¹¡î¹¢î¹£î¹¤î¹¥î¹¦î¹§î¹¨î¹©î¹ªî¹«î¹¬î¹­î¹®î¹¯î¹°î¹±î¹²î¹³î¹´î¹µî¹¶î¹·î¹¸î¹¹î¹ºî¹»î¹¼î¹½î¹¾î¹¿ +îºîº‚îºîºŽîºîºîº‘îºîºžîºŸîº îº¡îº¢îº£îº¤îº¥îº¦îº§îº¨îº©îºªîº«îº¬îº­îº®îº¯îº°îº±îº²îº³îº´îºµîº¶îº·îº¸îº¹îººîº»îº¼îº½îº¾îº¿ +î»î»‚î»î»Žî»î»î»‘î»î»žî»Ÿî» î»¡î»¢î»£î»¤î»¥î»¦î»§î»¨î»©î»ªî»«î»¬î»­î»®î»¯î»°î»±î»²î»³î»´î»µî»¶î»·î»¸î»¹î»ºî»»î»¼î»½î»¾î»¿ +î¼€î¼î¼‚î¼î¼Žî¼î¼î¼‘î¼î¼žî¼Ÿî¼ î¼¡î¼¢î¼£î¼¤î¼¥î¼¦î¼§î¼¨î¼©î¼ªî¼«î¼¬î¼­î¼®î¼¯î¼°î¼±î¼²î¼³î¼´î¼µî¼¶î¼·î¼¸î¼¹î¼ºî¼»î¼¼î¼½î¼¾î¼¿ +î½€î½î½‚î½î½Žî½î½î½‘î½î½žî½Ÿî½ î½¡î½¢î½£î½¤î½¥î½¦î½§î½¨î½©î½ªî½«î½¬î½­î½®î½¯î½°î½±î½²î½³î½´î½µî½¶î½·î½¸î½¹î½ºî½»î½¼î½½î½¾î½¿ +î¾€î¾î¾‚î¾î¾Žî¾î¾î¾‘î¾î¾žî¾Ÿî¾ î¾¡î¾¢î¾£î¾¤î¾¥î¾¦î¾§î¾¨î¾©î¾ªî¾«î¾¬î¾­î¾®î¾¯î¾°î¾±î¾²î¾³î¾´î¾µî¾¶î¾·î¾¸î¾¹î¾ºî¾»î¾¼î¾½î¾¾î¾¿ +î¿€î¿î¿‚î¿î¿Žî¿î¿î¿‘î¿î¿žî¿Ÿî¿ î¿¡î¿¢î¿£î¿¤î¿¥î¿¦î¿§î¿¨î¿©î¿ªî¿«î¿¬î¿­î¿®î¿¯î¿°î¿±î¿²î¿³î¿´î¿µî¿¶î¿·î¿¸î¿¹î¿ºî¿»î¿¼î¿½î¿¾î¿¿ +ï€ï€‚ï€ï€Žï€ï€ï€‘ï€ï€žï€Ÿï€ ï€¡ï€¢ï€£ï€¤ï€¥ï€¦ï€§ï€¨ï€©ï€ªï€«ï€¬ï€­ï€®ï€¯ï€°ï€±ï€²ï€³ï€´ï€µï€¶ï€·ï€¸ï€¹ï€ºï€»ï€¼ï€½ï€¾ï€¿ +ï€ïï‚ïƒï„ï…ï†ï‡ïˆï‰ïŠï‹ïŒïïŽïïï‘ï’ï“ï”ï•ï–ï—ï˜ï™ïšï›ïœïïžïŸï ï¡ï¢ï£ï¤ï¥ï¦ï§ï¨ï©ïªï«ï¬ï­ï®ï¯ï°ï±ï²ï³ï´ïµï¶ï·ï¸ï¹ïºï»ï¼ï½ï¾ï¿ +ï‚€ï‚ï‚ï‚Žï‚ï‚ï‚ +ïƒïƒ‚ïƒïƒŽïƒïƒïƒ‘ïƒïƒžïƒŸïƒ ïƒ¡ïƒ¢ïƒ£ïƒ¤ïƒ¥ïƒ¦ïƒ§ïƒ¨ïƒ©ïƒªïƒ«ïƒ¬ïƒ­ïƒ®ïƒ¯ïƒ°ïƒ±ïƒ²ïƒ³ïƒ´ïƒµïƒ¶ïƒ·ïƒ¸ïƒ¹ïƒºïƒ»ïƒ¼ïƒ½ïƒ¾ïƒ¿ +ï„€ï„ï„ï„Žï„ï„ï„ +ï…€ï…ï…ï…Žï…ï…ï… +ï†ï†‚ï†ï†Žï†ï†ï†‘ï†ï†žï†Ÿï† ï†¡ï†¢ï†£ï†¤ï†¥ï†¦ï†§ï†¨ï†©ï†ªï†«ï†¬ï†­ï†®ï†¯ï†°ï†±ï†²ï†³ï†´ï†µï†¶ï†·ï†¸ï†¹ï†ºï†»ï†¼ï†½ï†¾ï†¿ +ï‡ï‡‚ï‡ï‡Žï‡ï‡ï‡‘ï‡ï‡žï‡Ÿï‡ ï‡¡ï‡¢ï‡£ï‡¤ï‡¥ï‡¦ï‡§ï‡¨ï‡©ï‡ªï‡«ï‡¬ï‡­ï‡®ï‡¯ï‡°ï‡±ï‡²ï‡³ï‡´ï‡µï‡¶ï‡·ï‡¸ï‡¹ï‡ºï‡»ï‡¼ï‡½ï‡¾ï‡¿ +ïˆïˆ‚ïˆïˆŽïˆïˆïˆ‘ïˆïˆžïˆŸïˆ ïˆ¡ïˆ¢ïˆ£ïˆ¤ïˆ¥ïˆ¦ïˆ§ïˆ¨ïˆ©ïˆªïˆ«ïˆ¬ïˆ­ïˆ®ïˆ¯ïˆ°ïˆ±ïˆ²ïˆ³ïˆ´ïˆµïˆ¶ïˆ·ïˆ¸ïˆ¹ïˆºïˆ»ïˆ¼ïˆ½ïˆ¾ïˆ¿ +ï‰ï‰‚ï‰ï‰Žï‰ï‰ï‰‘ï‰ï‰žï‰Ÿï‰ ï‰¡ï‰¢ï‰£ï‰¤ï‰¥ï‰¦ï‰§ï‰¨ï‰©ï‰ªï‰«ï‰¬ï‰­ï‰®ï‰¯ï‰°ï‰±ï‰²ï‰³ï‰´ï‰µï‰¶ï‰·ï‰¸ï‰¹ï‰ºï‰»ï‰¼ï‰½ï‰¾ï‰¿ +ïŠïŠ‚ïŠïŠŽïŠïŠïŠ‘ïŠïŠžïŠŸïŠ ïŠ¡ïŠ¢ïŠ£ïŠ¤ïŠ¥ïŠ¦ïŠ§ïŠ¨ïŠ©ïŠªïŠ«ïŠ¬ïŠ­ïŠ®ïŠ¯ïŠ°ïŠ±ïŠ²ïŠ³ïŠ´ïŠµïŠ¶ïŠ·ïŠ¸ïŠ¹ïŠºïŠ»ïŠ¼ïŠ½ïŠ¾ïŠ¿ +ï‹€ï‹ï‹‚ï‹ï‹Žï‹ï‹ï‹‘ï‹ï‹žï‹Ÿï‹ ï‹¡ï‹¢ï‹£ï‹¤ï‹¥ï‹¦ï‹§ï‹¨ï‹©ï‹ªï‹«ï‹¬ï‹­ï‹®ï‹¯ï‹°ï‹±ï‹²ï‹³ï‹´ï‹µï‹¶ï‹·ï‹¸ï‹¹ï‹ºï‹»ï‹¼ï‹½ï‹¾ï‹¿ +ïŒïŒ‚ïŒïŒŽïŒïŒïŒ‘ïŒïŒžïŒŸïŒ ïŒ¡ïŒ¢ïŒ£ïŒ¤ïŒ¥ïŒ¦ïŒ§ïŒ¨ïŒ©ïŒªïŒ«ïŒ¬ïŒ­ïŒ®ïŒ¯ïŒ°ïŒ±ïŒ²ïŒ³ïŒ´ïŒµïŒ¶ïŒ·ïŒ¸ïŒ¹ïŒºïŒ»ïŒ¼ïŒ½ïŒ¾ïŒ¿ +ï€ïï‚ïƒï„ï…ï†ï‡ïˆï‰ïŠï‹ïŒïïŽïïï‘ï’ï“ï”ï•ï–ï—ï˜ï™ïšï›ïœïïžïŸï ï¡ï¢ï£ï¤ï¥ï¦ï§ï¨ï©ïªï«ï¬ï­ï®ï¯ï°ï±ï²ï³ï´ïµï¶ï·ï¸ï¹ïºï»ï¼ï½ï¾ï¿ +ïŽïŽ‚ïŽïŽŽïŽïŽïŽ‘ïŽïŽžïŽŸïŽ ïŽ¡ïŽ¢ïŽ£ïŽ¤ïŽ¥ïŽ¦ïŽ§ïŽ¨ïŽ©ïŽªïŽ«ïŽ¬ïŽ­ïŽ®ïŽ¯ïŽ°ïŽ±ïŽ²ïŽ³ïŽ´ïŽµïŽ¶ïŽ·ïŽ¸ïŽ¹ïŽºïŽ»ïŽ¼ïŽ½ïŽ¾ïŽ¿ +ï€ïï‚ïƒï„ï…ï†ï‡ïˆï‰ïŠï‹ïŒïïŽïïï‘ï’ï“ï”ï•ï–ï—ï˜ï™ïšï›ïœïïžïŸï ï¡ï¢ï£ï¤ï¥ï¦ï§ï¨ï©ïªï«ï¬ï­ï®ï¯ï°ï±ï²ï³ï´ïµï¶ï·ï¸ï¹ïºï»ï¼ï½ï¾ï¿ +ï€ïï‚ïƒï„ï…ï†ï‡ïˆï‰ïŠï‹ïŒïïŽïïï‘ï’ï“ï”ï•ï–ï—ï˜ï™ïšï›ïœïïžïŸï ï¡ï¢ï£ï¤ï¥ï¦ï§ï¨ï©ïªï«ï¬ï­ï®ï¯ï°ï±ï²ï³ï´ïµï¶ï·ï¸ï¹ïºï»ï¼ï½ï¾ï¿ +ï‘€ï‘ï‘ï‘Žï‘ï‘ï‘ +ï’€ï’ï’ï’Žï’ï’ï’ +ï“€ï“ï“ï“Žï“ï“ï“ +ï”ï”ï”ï”ï” +ï•€ï•ï•‚ï•ï•Žï•ï•ï•‘ï•ï•žï•Ÿï• ï•¡ï•¢ï•£ï•¤ï•¥ï•¦ï•§ï•¨ï•©ï•ªï•«ï•¬ï•­ï•®ï•¯ï•°ï•±ï•²ï•³ï•´ï•µï•¶ï•·ï•¸ï•¹ï•ºï•»ï•¼ï•½ï•¾ï•¿ +ï–€ï–ï–ï–Žï–ï–ï– +ï—€ï—ï—ï—Žï—ï—ï— +ï˜ï˜‚ï˜ï˜Žï˜ï˜ï˜‘ï˜ï˜žï˜Ÿï˜ ï˜¡ï˜¢ï˜£ï˜¤ï˜¥ï˜¦ï˜§ï˜¨ï˜©ï˜ªï˜«ï˜¬ï˜­ï˜®ï˜¯ï˜°ï˜±ï˜²ï˜³ï˜´ï˜µï˜¶ï˜·ï˜¸ï˜¹ï˜ºï˜»ï˜¼ï˜½ï˜¾ï˜¿ +ï™ï™‚ï™ï™Žï™ï™ï™‘ï™ï™žï™Ÿï™ ï™¡ï™¢ï™£ï™¤ï™¥ï™¦ï™§ï™¨ï™©ï™ªï™«ï™¬ï™­ï™®ï™¯ï™°ï™±ï™²ï™³ï™´ï™µï™¶ï™·ï™¸ï™¹ï™ºï™»ï™¼ï™½ï™¾ï™¿ +ïšïš‚ïšïšŽïšïšïš‘ïšïšžïšŸïš ïš¡ïš¢ïš£ïš¤ïš¥ïš¦ïš§ïš¨ïš©ïšªïš«ïš¬ïš­ïš®ïš¯ïš°ïš±ïš²ïš³ïš´ïšµïš¶ïš·ïš¸ïš¹ïšºïš»ïš¼ïš½ïš¾ïš¿ +ï›ï›‚ï›ï›Žï›ï›ï›‘ï›ï›žï›Ÿï› ï›¡ï›¢ï›£ï›¤ï›¥ï›¦ï›§ï›¨ï›©ï›ªï›«ï›¬ï›­ï›®ï›¯ï›°ï›±ï›²ï›³ï›´ï›µï›¶ï›·ï›¸ï›¹ï›ºï›»ï›¼ï›½ï›¾ï›¿ +ïœïœ‚ïœïœŽïœïœïœ‘ïœïœžïœŸïœ ïœ¡ïœ¢ïœ£ïœ¤ïœ¥ïœ¦ïœ§ïœ¨ïœ©ïœªïœ«ïœ¬ïœ­ïœ®ïœ¯ïœ°ïœ±ïœ²ïœ³ïœ´ïœµïœ¶ïœ·ïœ¸ïœ¹ïœºïœ»ïœ¼ïœ½ïœ¾ïœ¿ +ï€ïï‚ïƒï„ï…ï†ï‡ïˆï‰ïŠï‹ïŒïïŽïïï‘ï’ï“ï”ï•ï–ï—ï˜ï™ïšï›ïœïïžïŸï ï¡ï¢ï£ï¤ï¥ï¦ï§ï¨ï©ïªï«ï¬ï­ï®ï¯ï°ï±ï²ï³ï´ïµï¶ï·ï¸ï¹ïºï»ï¼ï½ï¾ï¿ +ïžïž‚ïžïžŽïžïžïž‘ïžïžžïžŸïž ïž¡ïž¢ïž£ïž¤ïž¥ïž¦ïž§ïž¨ïž©ïžªïž«ïž¬ïž­ïž®ïž¯ïž°ïž±ïž²ïž³ïž´ïžµïž¶ïž·ïž¸ïž¹ïžºïž»ïž¼ïž½ïž¾ïž¿ +ïŸïŸ‚ïŸïŸŽïŸïŸïŸ‘ïŸïŸžïŸŸïŸ ïŸ¡ïŸ¢ïŸ£ïŸ¤ïŸ¥ïŸ¦ïŸ§ïŸ¨ïŸ©ïŸªïŸ«ïŸ¬ïŸ­ïŸ®ïŸ¯ïŸ°ïŸ±ïŸ²ïŸ³ïŸ´ïŸµïŸ¶ïŸ·ïŸ¸ïŸ¹ïŸºïŸ»ïŸ¼ïŸ½ïŸ¾ïŸ¿ +ï €ï ï ‚ï ï Žï ï ï ‘ï ï žï Ÿï  ï ¡ï ¢ï £ï ¤ï ¥ï ¦ï §ï ¨ï ©ï ªï «ï ¬ï ­ï ®ï ¯ï °ï ±ï ²ï ³ï ´ï µï ¶ï ·ï ¸ï ¹ï ºï »ï ¼ï ½ï ¾ï ¿ +ï¡€ï¡ï¡‚ï¡ï¡Žï¡ï¡ï¡‘ï¡ï¡žï¡Ÿï¡ ï¡¡ï¡¢ï¡£ï¡¤ï¡¥ï¡¦ï¡§ï¡¨ï¡©ï¡ªï¡«ï¡¬ï¡­ï¡®ï¡¯ï¡°ï¡±ï¡²ï¡³ï¡´ï¡µï¡¶ï¡·ï¡¸ï¡¹ï¡ºï¡»ï¡¼ï¡½ï¡¾ï¡¿ +ï¢ï¢‚ï¢ï¢Žï¢ï¢ï¢‘ï¢ï¢žï¢Ÿï¢ ï¢¡ï¢¢ï¢£ï¢¤ï¢¥ï¢¦ï¢§ï¢¨ï¢©ï¢ªï¢«ï¢¬ï¢­ï¢®ï¢¯ï¢°ï¢±ï¢²ï¢³ï¢´ï¢µï¢¶ï¢·ï¢¸ï¢¹ï¢ºï¢»ï¢¼ï¢½ï¢¾ï¢¿ +ï£ï£‚ï£ï£Žï£ï£ï£‘ï£ï£žï£Ÿï£ ï£¡ï£¢ï££ï£¤ï£¥ï£¦ï£§ï£¨ï£©ï£ªï£«ï£¬ï£­ï£®ï£¯ï£°ï£±ï£²ï£³ï£´ï£µï£¶ï£·ï£¸ï£¹ï£ºï£»ï£¼ï£½ï£¾ï£¿ + +CJK Compatibility Ideographs (U+F900-U+FAFF): + +豈ï¤ï¤‚賈滑串句龜龜契金喇奈ï¤ï¤Žï¤ï¤ï¤‘裸邏樂洛烙珞落酪駱亂卵ï¤ï¤žï¤Ÿ +鸞嵐濫藍襤拉臘蠟廊朗浪狼郎來冷勞擄櫓爐盧老蘆虜路露魯鷺碌祿綠菉錄 +鹿ï¥ï¥‚弄籠聾牢磊賂雷壘屢樓ï¥ï¥Žï¥ï¥ï¥‘勒肋凜凌稜綾菱陵讀拏樂ï¥ï¥žï¥Ÿ +怒率異北磻便復不泌數索參塞省葉說殺辰沈拾若掠略亮兩凉梁糧良諒量勵 +呂ï¦ï¦‚旅濾礪閭驪麗黎力曆歷ï¦ï¦Žï¦ï¦ï¦‘漣煉璉秊練聯輦蓮連鍊列ï¦ï¦žï¦Ÿ +裂說廉念捻殮簾獵令囹寧嶺怜玲瑩羚聆鈴零靈領例禮醴隸惡了僚寮尿料樂 +燎ï§ï§‚遼龍暈阮劉杻柳流溜琉ï§ï§Žï§ï§ï§‘戮陸倫崙淪輪律慄栗率隆ï§ï§žï§Ÿ +易李梨泥理痢罹裏裡里離匿溺吝燐璘藺隣鱗麟林淋臨立笠粒狀炙識什茶刺 +切ï¨ï¨‚糖宅洞暴輻行降見廓兀ï¨ï¨Žï¨ï¨ï¨‘晴﨓﨔凞猪益礼神祥福靖ï¨ï¨žï¨Ÿ +蘒﨡諸﨣﨤逸都﨧﨨﨩飯飼館鶴郞隷侮僧免勉勤卑喝嘆器塀墨層屮悔慨憎 +ï©€ï©ï©‚暑梅海渚漢煮爫琢碑社ï©ï©Žï©ï©ï©‘禍禎穀突節練縉繁署者臭ï©ï©žï©Ÿ +褐視謁謹賓贈辶逸難響頻恵𤋮舘﩮﩯並况全侀充冀勇勺喝啕喙嗢塚墳奄奔 +婢ïªïª‚廙彩徭惘慎愈憎慠懲戴ïªïªŽïªïªïª‘朗望杖歹殺流滛滋漢瀞煮ïªïªžïªŸ +猪瑱甆画瘝瘟益盛直睊着磌窱節类絛練缾者荒華蝹襁覆視調諸請謁諾諭謹 +ï«€ï«ï«‚遲醙鉶陼難靖韛響頋頻ï«ï«Žï«ï«ï«‘㮝䀘䀹𥉉𥳐𧻓齃龎﫚﫛﫜ï«ï«žï«Ÿ +﫠﫡﫢﫣﫤﫥﫦﫧﫨﫩﫪﫫﫬﫭﫮﫯﫰﫱﫲﫳﫴﫵﫶﫷﫸﫹﫺﫻﫼﫽﫾﫿 + +Alphabetic Presentation Forms (U+FB00-U+FB4F): + +ffï¬ï¬‚ffifflſtst﬇﬈﬉﬊﬋﬌ï¬ï¬Žï¬ï¬ï¬‘﬒ﬓﬔﬕﬖﬗ﬘﬙﬚﬛﬜ï¬â—Œï¬žï¬Ÿï¬ ï¬¡ï¬¢ï¬£ï¬¤ï¬¥ï¬¦ï¬§ï¬¨ï¬©ï¬ªï¬«ï¬¬ï¬­ï¬®ï¬¯ï¬°ï¬±ï¬²ï¬³ï¬´ï¬µï¬¶ï¬·ï¬¸ï¬¹ï¬ºï¬»ï¬¼ï¬½ï¬¾ï¬¿ +ï­€ï­ï­‚ףּפּ﭅צּקּרּשּתּוֹבֿï­ï­Žï­ + +Arabic Presentation Forms-A (U+FB50-U+FDFF): + +ï­ï­‘ﭒﭓﭔﭕﭖﭗﭘﭙﭚﭛﭜï­ï­žï­Ÿï­ ï­¡ï­¢ï­£ï­¤ï­¥ï­¦ï­§ï­¨ï­©ï­ªï­«ï­¬ï­­ï­®ï­¯ï­°ï­±ï­²ï­³ï­´ï­µï­¶ï­·ï­¸ï­¹ï­ºï­»ï­¼ï­½ï­¾ï­¿ï®€ï®ï®‚ﮃﮄﮅﮆﮇﮈﮉﮊﮋﮌï®ï®Žï® +ï®ï®‘ﮒﮓﮔﮕﮖﮗﮘﮙﮚﮛﮜï®ï®žï®Ÿï® ï®¡ï®¢ï®£ï®¤ï®¥ï®¦ï®§ï®¨ï®©ï®ªï®«ï®¬ï®­ï®®ï®¯ï®°ï®±ï®²ï®³ï®´ï®µï®¶ï®·ï®¸ï®¹ï®ºï®»ï®¼ï®½ï®¾ï®¿ï¯€ï¯ï¯‚﯃﯄﯅﯆﯇﯈﯉﯊﯋﯌ï¯ï¯Žï¯ +ï¯ï¯‘﯒ﯓﯔﯕﯖﯗﯘﯙﯚﯛﯜï¯ï¯žï¯Ÿï¯ ï¯¡ï¯¢ï¯£ï¯¤ï¯¥ï¯¦ï¯§ï¯¨ï¯©ï¯ªï¯«ï¯¬ï¯­ï¯®ï¯¯ï¯°ï¯±ï¯²ï¯³ï¯´ï¯µï¯¶ï¯·ï¯¸ï¯¹ï¯ºï¯»ï¯¼ï¯½ï¯¾ï¯¿ï°€ï°ï°‚ﰃﰄﰅﰆﰇﰈﰉﰊﰋﰌï°ï°Žï° +ï°ï°‘ﰒﰓﰔﰕﰖﰗﰘﰙﰚﰛﰜï°ï°žï°Ÿï° ï°¡ï°¢ï°£ï°¤ï°¥ï°¦ï°§ï°¨ï°©ï°ªï°«ï°¬ï°­ï°®ï°¯ï°°ï°±ï°²ï°³ï°´ï°µï°¶ï°·ï°¸ï°¹ï°ºï°»ï°¼ï°½ï°¾ï°¿ï±€ï±ï±‚ﱃﱄﱅﱆﱇﱈﱉﱊﱋﱌï±ï±Žï± +ï±ï±‘ﱒﱓﱔﱕﱖﱗﱘﱙﱚﱛﱜï±ï±žï±Ÿï± ï±¡ï±¢ï±£ï±¤ï±¥ï±¦ï±§ï±¨ï±©ï±ªï±«ï±¬ï±­ï±®ï±¯ï±°ï±±ï±²ï±³ï±´ï±µï±¶ï±·ï±¸ï±¹ï±ºï±»ï±¼ï±½ï±¾ï±¿ï²€ï²ï²‚ﲃﲄﲅﲆﲇﲈﲉﲊﲋﲌï²ï²Žï² +ï²ï²‘ﲒﲓﲔﲕﲖﲗﲘﲙﲚﲛﲜï²ï²žï²Ÿï² ï²¡ï²¢ï²£ï²¤ï²¥ï²¦ï²§ï²¨ï²©ï²ªï²«ï²¬ï²­ï²®ï²¯ï²°ï²±ï²²ï²³ï²´ï²µï²¶ï²·ï²¸ï²¹ï²ºï²»ï²¼ï²½ï²¾ï²¿ï³€ï³ï³‚ﳃﳄﳅﳆﳇﳈﳉﳊﳋﳌï³ï³Žï³ +ï³ï³‘ﳒﳓﳔﳕﳖﳗﳘﳙﳚﳛﳜï³ï³žï³Ÿï³ ï³¡ï³¢ï³£ï³¤ï³¥ï³¦ï³§ï³¨ï³©ï³ªï³«ï³¬ï³­ï³®ï³¯ï³°ï³±ï³²ï³³ï³´ï³µï³¶ï³·ï³¸ï³¹ï³ºï³»ï³¼ï³½ï³¾ï³¿ï´€ï´ï´‚ﴃﴄﴅﴆﴇﴈﴉﴊﴋﴌï´ï´Žï´ +ï´ï´‘ﴒﴓﴔﴕﴖﴗﴘﴙﴚﴛﴜï´ï´žï´Ÿï´ ï´¡ï´¢ï´£ï´¤ï´¥ï´¦ï´§ï´¨ï´©ï´ªï´«ï´¬ï´­ï´®ï´¯ï´°ï´±ï´²ï´³ï´´ï´µï´¶ï´·ï´¸ï´¹ï´ºï´»ï´¼ï´½ï´¾ï´¿ïµ€ïµïµ‚﵃﵄﵅﵆﵇﵈﵉﵊﵋﵌ïµïµŽïµ +ïµïµ‘ﵒﵓﵔﵕﵖﵗﵘﵙﵚﵛﵜïµïµžïµŸïµ ïµ¡ïµ¢ïµ£ïµ¤ïµ¥ïµ¦ïµ§ïµ¨ïµ©ïµªïµ«ïµ¬ïµ­ïµ®ïµ¯ïµ°ïµ±ïµ²ïµ³ïµ´ïµµïµ¶ïµ·ïµ¸ïµ¹ïµºïµ»ïµ¼ïµ½ïµ¾ïµ¿ï¶€ï¶ï¶‚ﶃﶄﶅﶆﶇﶈﶉﶊﶋﶌï¶ï¶Žï¶ +ï¶ï¶‘ﶒﶓﶔﶕﶖﶗﶘﶙﶚﶛﶜï¶ï¶žï¶Ÿï¶ ï¶¡ï¶¢ï¶£ï¶¤ï¶¥ï¶¦ï¶§ï¶¨ï¶©ï¶ªï¶«ï¶¬ï¶­ï¶®ï¶¯ï¶°ï¶±ï¶²ï¶³ï¶´ï¶µï¶¶ï¶·ï¶¸ï¶¹ï¶ºï¶»ï¶¼ï¶½ï¶¾ï¶¿ï·€ï·ï·‚ﷃﷄﷅﷆﷇ﷈﷉﷊﷋﷌ï·ï·Žï· +ï·ï·‘﷒﷓﷔﷕﷖﷗﷘﷙﷚﷛﷜ï·ï·žï·Ÿï· ï·¡ï·¢ï·£ï·¤ï·¥ï·¦ï·§ï·¨ï·©ï·ªï·«ï·¬ï·­ï·®ï·¯ï·°ï·±ï·²ï·³ï·´ï·µï·¶ï··ï·¸ï·¹ï·ºï·»ï·¼ï·½ï·¾ï·¿ + +Variation Selectors (U+FE00-U+FE0F): + +◌︀◌ï¸â—Œï¸‚◌︃◌︄◌︅◌︆◌︇◌︈◌︉◌︊◌︋◌︌◌ï¸â—Œï¸Žâ—Œï¸ + +Free block (U+FE10-U+FE1F): + +ï¸ï¸‘︒︓︔︕︖︗︘︙︚︛︜ï¸ï¸žï¸Ÿ + +Combining Half Marks (U+FE20-U+FE2F): + +◌︠◌︡◌︢◌︧︨︩︪︫︬︭︣︤︥︦︮︯ + +CJK Compatibility Forms (U+FE30-U+FE4F): + +︰︱︲︳︴︵︶︷︸︹︺︻︼︽︾︿﹀ï¹ï¹‚﹃﹄﹅﹆﹇﹈﹉﹊﹋﹌ï¹ï¹Žï¹ + +Small Form Variants (U+FE50-U+FE6F): + +ï¹ï¹‘﹒﹓﹔﹕﹖﹗﹘﹙﹚﹛﹜ï¹ï¹žï¹Ÿï¹ ï¹¡ï¹¢ï¹£ï¹¤ï¹¥ï¹¦ï¹§ï¹¨ï¹©ï¹ªï¹«ï¹¬ï¹­ï¹®ï¹¯ + +Arabic Presentation Forms-B (U+FE70-U+FEFF): + +ﹰﹱﹲﹳﹴ﹵ﹶﹷﹸﹹﹺﹻﹼﹽﹾﹿﺀïºïº‚ﺃﺄﺅﺆﺇﺈﺉﺊﺋﺌïºïºŽïºïºïº‘ﺒﺓﺔﺕﺖﺗﺘﺙﺚﺛﺜïºïºžïºŸïº ïº¡ïº¢ïº£ïº¤ïº¥ïº¦ïº§ïº¨ïº©ïºªïº«ïº¬ïº­ïº®ïº¯ +ﺰﺱﺲﺳﺴﺵﺶﺷﺸﺹﺺﺻﺼﺽﺾﺿﻀï»ï»‚ﻃﻄﻅﻆﻇﻈﻉﻊﻋﻌï»ï»Žï»ï»ï»‘ﻒﻓﻔﻕﻖﻗﻘﻙﻚﻛﻜï»ï»žï»Ÿï» ï»¡ï»¢ï»£ï»¤ï»¥ï»¦ï»§ï»¨ï»©ï»ªï»«ï»¬ï»­ï»®ï»¯ +ﻰﻱﻲﻳﻴﻵﻶﻷﻸﻹﻺﻻﻼ﻽﻾ + +Halfwidth and Fullwidth Forms (U+FF00-U+FFEF): + +ï¼€ï¼ï¼‚#$%&'()*+,ï¼ï¼Žï¼ï¼ï¼‘23456789:;<ï¼ï¼žï¼Ÿ +@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_ +ï½€ï½ï½‚cdefghijklï½ï½Žï½ï½ï½‘rstuvwxyz{|ï½ï½žï½Ÿ +⦆。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタï¾ï¾‚テトナニヌネノハヒフï¾ï¾Žï¾ï¾ï¾‘メモヤユヨラリルレロワï¾ï¾ž +゚ᅠᄀᄁᆪᄂᆬᆭᄃᄄᄅᆰᆱᆲᆳᆴᆵᄚᄆᄇᄈᄡᄉᄊᄋᄌᄍᄎᄏᄐᄑᄒ﾿￀ï¿ï¿‚ᅢᅣᅤᅥᅦ￈￉ᅧᅨᅩï¿ï¿Žï¿ï¿ï¿‘ᅭᅮᅯᅰᅱᅲ￘￙ᅳᅴᅵï¿ï¿ž +￟¢£¬ ̄¦¥₩￧│←↑→↓■○￯ + +Specials (U+FFF0-U+FFFF): + +￰￱￲￳￴￵￶￷￸�￾￿ diff --git a/busybox-1_37_0/docs/unit-tests.txt b/busybox-1_37_0/docs/unit-tests.txt new file mode 100644 index 000000000..0fb522086 --- /dev/null +++ b/busybox-1_37_0/docs/unit-tests.txt @@ -0,0 +1,50 @@ +Busybox unit test framework +=========================== + +This document describes what you need to do to write test cases using the +Busybox unit test framework. + + +Building unit tests +------------------- + +The framework and all tests are built as a regular Busybox applet if option +CONFIG_UNIT_TEST (found in General Configuration -> Debugging Options) is set. + + +Writing test cases +------------------ + +Unit testing interface can be found in include/bbunit.h. + +Tests can be placed in any .c file in Busybox tree - preferably right next to +the functions they test. Test cases should be enclosed within an #if, and +should start with BBUNIT_DEFINE_TEST macro and end with BBUNIT_ENDTEST within +the test curly brackets. If an assertion fails the test ends immediately, ie. +the following assertions will not be reached. Any code placed after +BBUNIT_ENDTEST is executed regardless of the test result. Here's an example: + +#if ENABLE_UNIT_TEST + +BBUNIT_DEFINE_TEST(test_name) +{ + int *i; + + i = malloc(sizeof(int)); + BBUNIT_ASSERT_NOTNULL(i); + *i = 2; + BBUNIT_ASSERT_EQ((*i)*(*i), 4); + + BBUNIT_ENDTEST; + + free(i); +} + +#endif /* ENABLE_UNIT_TEST */ + + +Running the unit test suite +--------------------------- + +To run the tests you can either directly run 'busybox unit' or use 'make test' +to run both the unit tests (if compiled) and regular test suite. diff --git a/busybox-1_37_0/e2fsprogs/Config.src b/busybox-1_37_0/e2fsprogs/Config.src new file mode 100644 index 000000000..ad15f470c --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/Config.src @@ -0,0 +1,43 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Linux Ext2 FS Progs" + +INSERT + +### config E2FSCK +### bool "e2fsck" +### default y +### help +### e2fsck is used to check Linux second extended file systems (ext2fs). +### e2fsck also supports ext2 filesystems countaining a journal (ext3). +### The normal compat symlinks 'fsck.ext2' and 'fsck.ext3' are also +### provided. + +### config MKE2FS +### bool "mke2fs" +### default y +### help +### mke2fs is used to create an ext2/ext3 filesystem. The normal compat +### symlinks 'mkfs.ext2' and 'mkfs.ext3' are also provided. + +### config E2LABEL +### bool "e2label" +### default y +### depends on TUNE2FS +### help +### e2label will display or change the filesystem label on the ext2 +### filesystem located on device. + +### NB: this one is now provided by util-linux/volume_id/* +### config FINDFS +### bool "findfs" +### default y +### depends on TUNE2FS +### help +### findfs will search the disks in the system looking for a filesystem +### which has a label matching label or a UUID equal to uuid. + +endmenu diff --git a/busybox-1_37_0/e2fsprogs/Kbuild.src b/busybox-1_37_0/e2fsprogs/Kbuild.src new file mode 100644 index 000000000..6b4fb7470 --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/Kbuild.src @@ -0,0 +1,9 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +lib-y:= + +INSERT diff --git a/busybox-1_37_0/e2fsprogs/README b/busybox-1_37_0/e2fsprogs/README new file mode 100644 index 000000000..eb158e588 --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/README @@ -0,0 +1,12 @@ +Authors and contributors of original e2fsprogs: + +Remy Card +Theodore Ts'o +Stephen C. Tweedie +Andreas Gruenbacher, +Kaz Kylheku +F.W. ten Wolde +Jeremy Fitzhardinge +M.J.E. Mol +Miquel van Smoorenburg +Uwe Ohse diff --git a/busybox-1_37_0/e2fsprogs/chattr.c b/busybox-1_37_0/e2fsprogs/chattr.c new file mode 100644 index 000000000..5dec3253b --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/chattr.c @@ -0,0 +1,260 @@ +/* vi: set sw=4 ts=4: */ +/* + * chattr.c - Change file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU General + * Public License + */ +//config:config CHATTR +//config: bool "chattr (4.1 kb)" +//config: default y +//config: help +//config: chattr changes the file attributes on a second extended file system. + +//applet:IF_CHATTR(APPLET_NOEXEC(chattr, chattr, BB_DIR_BIN, BB_SUID_DROP, chattr)) + +//kbuild:lib-$(CONFIG_CHATTR) += chattr.o e2fs_lib.o + +//usage:#define chattr_trivial_usage +//usage: "[-R] [-v VERSION] [-p PROJID] [-+=AacDdijsStTu] FILE..." +//usage:#define chattr_full_usage "\n\n" +//usage: "Change ext2 file attributes\n" +//usage: "\n -R Recurse" +//usage: "\n -v NUM Set version/generation number" +//usage: "\n -p NUM Set project number" +//-V, -f accepted but ignored +//usage: "\nModifiers:" +//usage: "\n -,+,= Remove/add/set attributes" +//usage: "\nAttributes:" +//usage: "\n A No atime" +//usage: "\n a Append only" +//usage: "\n C No copy-on-write" +//usage: "\n c Compressed" +//usage: "\n D Synchronous dir updates" +//usage: "\n d Don't backup with dump" +//usage: "\n E Encrypted" +//usage: "\n e File uses extents" +//usage: "\n F Case-insensitive dir" +//usage: "\n I Indexed dir" +//usage: "\n i Immutable" +//usage: "\n j Write data to journal first" +//usage: "\n N File is stored in inode" +//usage: "\n P Hierarchical project ID dir" +//usage: "\n S Synchronous file updates" +//usage: "\n s Zero storage when deleted" +//usage: "\n T Top of dir hierarchy" +//usage: "\n t Don't tail-merge with other files" +//usage: "\n u Allow undelete" +//usage: "\n V Verity" + +#include "libbb.h" +#include "e2fs_lib.h" + +#define OPT_ADD (1 << 0) +#define OPT_REM (1 << 1) +#define OPT_SET (1 << 2) +#define OPT_SET_VER (1 << 3) +#define OPT_SET_PROJ (1 << 4) + +struct globals { + unsigned version; + unsigned af; + unsigned rf; + int flags; + uint32_t projid; + smallint recursive; +}; + +static unsigned long get_flag(char c) +{ + const char *fp = strchr(e2attr_flags_sname_chattr, c); + if (fp) + return e2attr_flags_value_chattr[fp - e2attr_flags_sname_chattr]; + bb_show_usage(); +} + +static char** decode_arg(char **argv, struct globals *gp) +{ + unsigned *fl; + const char *arg = *argv; + char opt = *arg; + + fl = &gp->af; + if (opt == '-') { + /* gp->flags |= OPT_REM; - WRONG, it can be an option */ + /* testcase: chattr =ae -R FILE should not complain "= is incompatible with - and +" */ + /* (and should not read flags, with =FLAGS they can be just set directly) */ + fl = &gp->rf; + } else if (opt == '+') { + gp->flags |= OPT_ADD; + } else { /* if (opt == '=') */ + gp->flags |= OPT_SET; + } + + while (*++arg) { + if (opt == '-') { +//e2fsprogs-1.43.1 accepts: +// "-RRR", "-RRRv VER" and even "-ARRRva VER" and "-vvv V1 V2 V3" +// but not "-vVER". +// IOW: options are parsed as part of "remove attrs" strings, +// if "v" is seen, next argv[] is VER, even if more opts/attrs follow in this argv[]! + if (*arg == 'R') { + gp->recursive = 1; + continue; + } + if (*arg == 'V') { + /*"verbose and print program version" (nop for now) */; + continue; + } + if (*arg == 'f') { + /*"suppress most error messages" (nop) */; + continue; + } + if (*arg == 'v') { + if (!*++argv) + bb_show_usage(); + gp->version = xatou(*argv); + gp->flags |= OPT_SET_VER; + continue; + } + if (*arg == 'p') { + if (!*++argv) + bb_show_usage(); + gp->projid = xatou32(*argv); + gp->flags |= OPT_SET_PROJ; + continue; + } + /* not a known option, try as an attribute */ + gp->flags |= OPT_REM; + } + *fl |= get_flag(*arg); /* aborts on bad flag letter */ + } + + return argv; +} + +static void change_attributes(const char *name, struct globals *gp); + +static int FAST_FUNC chattr_dir_proc(const char *dir_name, struct dirent *de, void *gp) +{ +//TODO: use de->d_type (if it's not DT_UNKNOWN) to skip !(REG || DIR || LNK) entries without lstat? + + char *path = concat_subpath_file(dir_name, de->d_name); + /* path is NULL if de->d_name is "." or "..", else... */ + if (path) { + change_attributes(path, gp); + free(path); + } + return 0; +} + +static void change_attributes(const char *name, struct globals *gp) +{ + unsigned fsflags; + int fd; + struct stat st; + + if (lstat(name, &st) != 0) { + bb_perror_msg("can't stat '%s'", name); + return; + } + + /* Don't try to open device files, fifos etc. We probably + * ought to display an error if the file was explicitly given + * on the command line (whether or not recursive was + * requested). */ + if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode) && !S_ISDIR(st.st_mode)) + return; + + /* There is no way to run needed ioctls on a symlink. + * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink, + * but ioctls fail on such a fd (tried on 4.12.0 kernel). + * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks. + */ + fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW); + if (fd >= 0) { + int r; + + if (gp->flags & OPT_SET_VER) { + r = ioctl(fd, EXT2_IOC_SETVERSION, &gp->version); + if (r != 0) + bb_perror_msg("setting %s on %s", "version", name); + } + + if (gp->flags & OPT_SET_PROJ) { + struct ext2_fsxattr fsxattr; + r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr); + /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */ + if (r != 0) { + bb_perror_msg("getting %s on %s", "project ID", name); + } else { + fsxattr.fsx_projid = gp->projid; + r = ioctl(fd, EXT2_IOC_FSSETXATTR, &fsxattr); + if (r != 0) + bb_perror_msg("setting %s on %s", "project ID", name); + } + } + + if (gp->flags & OPT_SET) { + fsflags = gp->af; + } else { + r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags); + if (r != 0) { + bb_perror_msg("getting %s on %s", "flags", name); + goto skip_setflags; + } + /*if (gp->flags & OPT_REM) - not needed, rf is zero otherwise */ + fsflags &= ~gp->rf; + /*if (gp->flags & OPT_ADD) - not needed, af is zero otherwise */ + fsflags |= gp->af; +// What is this? And why it's not done for SET case? + if (!S_ISDIR(st.st_mode)) + fsflags &= ~EXT2_DIRSYNC_FL; + } + r = ioctl(fd, EXT2_IOC_SETFLAGS, &fsflags); + if (r != 0) + bb_perror_msg("setting %s on %s", "flags", name); + skip_setflags: + close(fd); + } + + if (gp->recursive && S_ISDIR(st.st_mode)) + iterate_on_dir(name, chattr_dir_proc, gp); +} + +int chattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int chattr_main(int argc UNUSED_PARAM, char **argv) +{ + struct globals g; + + memset(&g, 0, sizeof(g)); + + /* parse the args */ + for (;;) { + char *arg = *++argv; + if (!arg) + bb_show_usage(); + if (arg[0] != '-' && arg[0] != '+' && arg[0] != '=') + break; + + argv = decode_arg(argv, &g); + } + /* note: on loop exit, remaining argv[] is never empty */ + + /* run sanity checks on all the arguments given us */ + if ((g.flags & OPT_SET) && (g.flags & (OPT_ADD|OPT_REM))) + bb_simple_error_msg_and_die("= is incompatible with - and +"); + if (g.rf & g.af) + bb_simple_error_msg_and_die("can't set and unset a flag"); + if (!g.flags) + bb_simple_error_msg_and_die("must use -v, -p, =, - or +"); + + /* now run chattr on all the files passed to us */ + do change_attributes(*argv, &g); while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/e2fsprogs/e2fs_lib.c b/busybox-1_37_0/e2fsprogs/e2fs_lib.c new file mode 100644 index 000000000..9b68d8901 --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/e2fs_lib.c @@ -0,0 +1,111 @@ +/* vi: set sw=4 ts=4: */ +/* + * See README for additional information + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" +#include "e2fs_lib.h" + +/* Print file attributes on an ext2 file system */ +const uint32_t e2attr_flags_value[] ALIGN4 = { +#ifdef ENABLE_COMPRESSION + EXT2_COMPRBLK_FL, + EXT2_DIRTY_FL, + EXT2_NOCOMPR_FL, +#endif + EXT2_SECRM_FL, + EXT2_UNRM_FL, + EXT2_SYNC_FL, + EXT2_DIRSYNC_FL, + EXT2_IMMUTABLE_FL, + EXT2_APPEND_FL, + EXT2_NODUMP_FL, + EXT2_NOATIME_FL, + EXT2_COMPR_FL, + EXT2_ECOMPR_FL, + EXT3_JOURNAL_DATA_FL, + EXT2_INDEX_FL, + EXT2_NOTAIL_FL, + EXT2_TOPDIR_FL, + EXT2_EXTENT_FL, + EXT2_NOCOW_FL, + EXT2_CASEFOLD_FL, + EXT2_INLINE_DATA_FL, + EXT2_PROJINHERIT_FL, + EXT2_VERITY_FL, +}; + +const char e2attr_flags_sname[] ALIGN1 = +#ifdef ENABLE_COMPRESSION + "BZX" +#endif + "suSDiadAcEjItTeCFNPV"; + +static const char e2attr_flags_lname[] ALIGN1 = +#ifdef ENABLE_COMPRESSION + "Compressed_File" "\0" + "Compressed_Dirty_File" "\0" + "Compression_Raw_Access" "\0" +#endif + "Secure_Deletion" "\0" + "Undelete" "\0" + "Synchronous_Updates" "\0" + "Synchronous_Directory_Updates" "\0" + "Immutable" "\0" + "Append_Only" "\0" + "No_Dump" "\0" + "No_Atime" "\0" + "Compression_Requested" "\0" + "Encrypted" "\0" + "Journaled_Data" "\0" + "Indexed_directory" "\0" + "No_Tailmerging" "\0" + "Top_of_Directory_Hierarchies" "\0" + "Extents" "\0" + "No_COW" "\0" + "Casefold" "\0" + "Inline_Data" "\0" + "Project_Hierarchy" "\0" + "Verity" "\0" + /* Another trailing NUL is added by compiler */; + +void print_e2flags_long(unsigned flags) +{ + const uint32_t *fv; + const char *fn; + int first = 1; + + fv = e2attr_flags_value; + fn = e2attr_flags_lname; + do { + if (flags & *fv) { + if (!first) + fputs(", ", stdout); + fputs(fn, stdout); + first = 0; + } + fv++; + fn += strlen(fn) + 1; + } while (*fn); + if (first) + fputs("---", stdout); +} + +void print_e2flags(unsigned flags) +{ + const uint32_t *fv; + const char *fn; + + fv = e2attr_flags_value; + fn = e2attr_flags_sname; + do { + char c = '-'; + if (flags & *fv) + c = *fn; + putchar(c); + fv++; + fn++; + } while (*fn); +} diff --git a/busybox-1_37_0/e2fsprogs/e2fs_lib.h b/busybox-1_37_0/e2fsprogs/e2fs_lib.h new file mode 100644 index 000000000..bab447a94 --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/e2fs_lib.h @@ -0,0 +1,31 @@ +/* vi: set sw=4 ts=4: */ +/* + * See README for additional information + * + * This file can be redistributed under the terms of the GNU Library General + * Public License + */ + +/* Constants and structures */ +#include "bb_e2fs_defs.h" + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +/* Print file attributes on an ext2 file system */ +void print_e2flags_long(unsigned flags); +void print_e2flags(unsigned flags); + +extern const uint32_t e2attr_flags_value[]; +extern const char e2attr_flags_sname[]; + +/* If you plan to ENABLE_COMPRESSION, see e2fs_lib.c and chattr.c - */ +/* make sure that chattr doesn't accept bad options! */ +#ifdef ENABLE_COMPRESSION +#define e2attr_flags_value_chattr (&e2attr_flags_value[5]) +#define e2attr_flags_sname_chattr (&e2attr_flags_sname[5]) +#else +#define e2attr_flags_value_chattr (&e2attr_flags_value[1]) +#define e2attr_flags_sname_chattr (&e2attr_flags_sname[1]) +#endif + +POP_SAVED_FUNCTION_VISIBILITY diff --git a/busybox-1_37_0/e2fsprogs/fsck.c b/busybox-1_37_0/e2fsprogs/fsck.c new file mode 100644 index 000000000..fd4ea737c --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/fsck.c @@ -0,0 +1,1115 @@ +/* vi: set sw=4 ts=4: */ +/* + * fsck --- A generic, parallelizing front-end for the fsck program. + * It will automatically try to run fsck programs in parallel if the + * devices are on separate spindles. It is based on the same ideas as + * the generic front end for fsck by David Engel and Fred van Kempen, + * but it has been completely rewritten from scratch to support + * parallel execution. + * + * Written by Theodore Ts'o, + * + * Miquel van Smoorenburg (miquels@drinkel.ow.org) 20-Oct-1994: + * o Changed -t fstype to behave like with mount when -A (all file + * systems) or -M (like mount) is specified. + * o fsck looks if it can find the fsck.type program to decide + * if it should ignore the fs type. This way more fsck programs + * can be added without changing this front-end. + * o -R flag skip root file system. + * + * Copyright (C) 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, + * 2001, 2002, 2003, 2004, 2005 by Theodore Ts'o. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +/* All filesystem specific hooks have been removed. + * If filesystem cannot be determined, we will execute + * "fsck.auto". Currently this also happens if you specify + * UUID=xxx or LABEL=xxx as an object to check. + * Detection code for that is also probably has to be in fsck.auto. + * + * In other words, this is _really_ is just a driver program which + * spawns actual fsck.something for each filesystem to check. + * It doesn't guess filesystem types from on-disk format. + */ +//config:config FSCK +//config: bool "fsck (7.6 kb)" +//config: default y +//config: help +//config: fsck is used to check and optionally repair one or more filesystems. +//config: In actuality, fsck is simply a front-end for the various file system +//config: checkers (fsck.fstype) available under Linux. + +//applet:IF_FSCK(APPLET(fsck, BB_DIR_SBIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_FSCK) += fsck.o + +//usage:#define fsck_trivial_usage +//usage: "[-ANPRTV] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]..." +//usage:#define fsck_full_usage "\n\n" +//usage: "Check and repair filesystems\n" +//usage: "\n -A Walk /etc/fstab and check all filesystems" +//usage: "\n -N Don't execute, just show what would be done" +//usage: "\n -P With -A, check filesystems in parallel" +//usage: "\n -R With -A, skip the root filesystem" +//usage: "\n -T Don't show title on startup" +//usage: "\n -V Verbose" +//DO_PROGRESS_INDICATOR is off: +////usage: "\n -C FD Write status information to specified file descriptor" +//usage: "\n -t TYPE List of filesystem types to check" + +#include "libbb.h" +#include "common_bufsiz.h" + +/* "progress indicator" code is somewhat buggy and ext[23] specific. + * We should be filesystem agnostic. IOW: there should be a well-defined + * API for fsck.something, NOT ad-hoc hacks in generic fsck. */ +#define DO_PROGRESS_INDICATOR 0 + +/* fsck 1.41.4 (27-Jan-2009) manpage says: + * 0 - No errors + * 1 - File system errors corrected + * 2 - System should be rebooted + * 4 - File system errors left uncorrected + * 8 - Operational error + * 16 - Usage or syntax error + * 32 - Fsck canceled by user request + * 128 - Shared library error + */ +#define EXIT_OK 0 +#define EXIT_NONDESTRUCT 1 +#define EXIT_DESTRUCT 2 +#define EXIT_UNCORRECTED 4 +#define EXIT_ERROR 8 +#define EXIT_USAGE 16 +#define FSCK_CANCELED 32 /* Aborted with a signal or ^C */ + +/* + * Internal structure for mount table entries. + */ +struct fs_info { + struct fs_info *next; + char *device; + char *mountpt; + char *type; + char *opts; + int passno; + int flags; +}; + +#define FLAG_DONE 1 +#define FLAG_PROGRESS 2 +/* + * Structure to allow exit codes to be stored + */ +struct fsck_instance { + struct fsck_instance *next; + int pid; + int flags; +#if DO_PROGRESS_INDICATOR + time_t start_time; +#endif + char *prog; + char *device; + char *base_device; /* /dev/hda for /dev/hdaN etc */ +}; + +static const char ignored_types[] ALIGN1 = + "ignore\0" + "iso9660\0" + "nfs\0" + "proc\0" + "sw\0" + "swap\0" + "tmpfs\0" + "devpts\0"; + +#if 0 +static const char really_wanted[] ALIGN1 = + "minix\0" + "ext2\0" + "ext3\0" + "jfs\0" + "reiserfs\0" + "xiafs\0" + "xfs\0"; +#endif + +#define BASE_MD "/dev/md" + +struct globals { + char **args; + int num_args; + int verbose; + +#define FS_TYPE_FLAG_NORMAL 0 +#define FS_TYPE_FLAG_OPT 1 +#define FS_TYPE_FLAG_NEGOPT 2 + char **fs_type_list; + uint8_t *fs_type_flag; + smallint fs_type_negated; + + smallint noexecute; + smallint serialize; + smallint skip_root; + /* smallint like_mount; */ + smallint parallel_root; + smallint force_all_parallel; + smallint kill_sent; + +#if DO_PROGRESS_INDICATOR + smallint progress; + int progress_fd; +#endif + + int num_running; + int max_running; + char *fstype; + struct fs_info *filesys_info; + struct fs_info *filesys_last; + struct fsck_instance *instance_list; +} FIX_ALIASING; +#define G (*(struct globals*)bb_common_bufsiz1) +#define INIT_G() do { \ + setup_common_bufsiz(); \ + BUILD_BUG_ON(sizeof(G) > COMMON_BUFSIZE); \ +} while (0) + +/* + * Return the "base device" given a particular device; this is used to + * assure that we only fsck one partition on a particular drive at any + * one time. Otherwise, the disk heads will be seeking all over the + * place. If the base device cannot be determined, return NULL. + * + * The base_device() function returns an allocated string which must + * be freed. + */ +#if ENABLE_FEATURE_DEVFS +/* + * Required for the uber-silly devfs /dev/ide/host1/bus2/target3/lun3 + * pathames. + */ +static const char *const devfs_hier[] ALIGN_PTR = { + "host", "bus", "target", "lun", NULL +}; +#endif + +static char *base_device(const char *device) +{ + char *str, *cp; +#if ENABLE_FEATURE_DEVFS + const char *const *hier; + const char *disk; + int len; +#endif + str = xstrdup(device); + + /* Skip over "/dev/"; if it's not present, give up */ + cp = skip_dev_pfx(str); + if (cp == str) + goto errout; + + /* + * For md devices, we treat them all as if they were all + * on one disk, since we don't know how to parallelize them. + */ + if (cp[0] == 'm' && cp[1] == 'd') { + cp[2] = 0; + return str; + } + + /* Handle DAC 960 devices */ + if (is_prefixed_with(cp, "rd/")) { + cp += 3; + if (cp[0] != 'c' || !isdigit(cp[1]) + || cp[2] != 'd' || !isdigit(cp[3])) + goto errout; + cp[4] = 0; + return str; + } + + /* Now let's handle /dev/hd* and /dev/sd* devices.... */ + if ((cp[0] == 'h' || cp[0] == 's') && cp[1] == 'd') { + cp += 2; + /* If there's a single number after /dev/hd, skip it */ + if (isdigit(*cp)) + cp++; + /* What follows must be an alpha char, or give up */ + if (!isalpha(*cp)) + goto errout; + cp[1] = 0; + return str; + } + +#if ENABLE_FEATURE_DEVFS + /* Now let's handle devfs (ugh) names */ + len = 0; + if (is_prefixed_with(cp, "ide/")) + len = 4; + if (is_prefixed_with(cp, "scsi/")) + len = 5; + if (len) { + cp += len; + /* + * Now we proceed down the expected devfs hierarchy. + * i.e., .../host1/bus2/target3/lun4/... + * If we don't find the expected token, followed by + * some number of digits at each level, abort. + */ + for (hier = devfs_hier; *hier; hier++) { + cp = is_prefixed_with(cp, *hier); + if (!cp) + goto errout; + while (*cp != '/' && *cp != '\0') { + if (!isdigit(*cp)) + goto errout; + cp++; + } +//FIXME: what if *cp = '\0' now? cp++ moves past it!!! + cp++; + } + cp[-1] = '\0'; + return str; + } + + /* Now handle devfs /dev/disc or /dev/disk names */ + disk = NULL; + if (is_prefixed_with(cp, "discs/")) + disk = "disc"; + else if (is_prefixed_with(cp, "disks/")) + disk = "disk"; + if (disk) { + cp += 6; + cp = is_prefixed_with(cp, disk); + if (!cp) + goto errout; + while (*cp != '/' && *cp != '\0') { + if (!isdigit(*cp)) + goto errout; + cp++; + } + *cp = '\0'; + return str; + } +#endif + errout: + free(str); + return NULL; +} + +static void free_instance(struct fsck_instance *p) +{ + free(p->prog); + free(p->device); + free(p->base_device); + free(p); +} + +static struct fs_info *create_fs_device(const char *device, const char *mntpnt, + const char *type, const char *opts, + int passno) +{ + struct fs_info *fs; + + fs = xzalloc(sizeof(*fs)); + fs->device = xstrdup(device); + fs->mountpt = xstrdup(mntpnt); + if (strchr(type, ',')) + type = (char *)"auto"; + fs->type = xstrdup(type); + fs->opts = xstrdup(opts ? opts : ""); + fs->passno = passno < 0 ? 1 : passno; + /*fs->flags = 0; */ + /*fs->next = NULL; */ + + if (!G.filesys_info) + G.filesys_info = fs; + else + G.filesys_last->next = fs; + G.filesys_last = fs; + + return fs; +} + +/* Load the filesystem database from /etc/fstab */ +static void load_fs_info(const char *filename) +{ + FILE *fstab; + struct mntent mte; + char buf[1024]; + + fstab = setmntent(filename, "r"); + if (!fstab) { + bb_perror_msg("can't read '%s'", filename); + return; + } + + // Loop through entries + while (getmntent_r(fstab, &mte, buf, sizeof(buf))) { + //bb_error_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir, + // mte.mnt_type, mte.mnt_opts, + // mte.mnt_passno); + create_fs_device(mte.mnt_fsname, mte.mnt_dir, + mte.mnt_type, mte.mnt_opts, + mte.mnt_passno); + } + endmntent(fstab); +} + +/* Lookup filesys in /etc/fstab and return the corresponding entry. */ +static struct fs_info *lookup(char *filesys) +{ + struct fs_info *fs; + + for (fs = G.filesys_info; fs; fs = fs->next) { + if (strcmp(filesys, fs->device) == 0 + || (fs->mountpt && strcmp(filesys, fs->mountpt) == 0) + ) + break; + } + + return fs; +} + +#if DO_PROGRESS_INDICATOR +static int progress_active(void) +{ + struct fsck_instance *inst; + + for (inst = G.instance_list; inst; inst = inst->next) { + if (inst->flags & FLAG_DONE) + continue; + if (inst->flags & FLAG_PROGRESS) + return 1; + } + return 0; +} +#endif + + +/* + * Send a signal to all outstanding fsck child processes + */ +static void kill_all_if_got_signal(void) +{ + struct fsck_instance *inst; + + if (!bb_got_signal || G.kill_sent) + return; + + for (inst = G.instance_list; inst; inst = inst->next) { + if (inst->flags & FLAG_DONE) + continue; + kill(inst->pid, SIGTERM); + } + G.kill_sent = 1; +} + +/* + * Wait for one child process to exit; when it does, unlink it from + * the list of executing child processes, free, and return its exit status. + * If there is no exited child, return -1. + */ +static int wait_one(int flags) +{ + int status; + int exitcode; + struct fsck_instance *inst, *prev; + pid_t pid; + + if (!G.instance_list) + return -1; + /* if (G.noexecute) { already returned -1; } */ + + while (1) { + pid = waitpid(-1, &status, flags); + kill_all_if_got_signal(); + if (pid == 0) /* flags == WNOHANG and no children exited */ + return -1; + if (pid < 0) { + if (errno == EINTR) + continue; + if (errno == ECHILD) { /* paranoia */ + bb_simple_error_msg("wait: no more children"); + return -1; + } + bb_simple_perror_msg("wait"); + continue; + } + prev = NULL; + inst = G.instance_list; + do { + if (inst->pid == pid) + goto child_died; + prev = inst; + inst = inst->next; + } while (inst); + } + child_died: + + exitcode = WEXITSTATUS(status); + if (WIFSIGNALED(status)) { + unsigned sig; + sig = WTERMSIG(status); + exitcode = EXIT_UNCORRECTED; + if (sig != SIGINT) { + printf("Warning: %s %s terminated " + "by signal %u\n", + inst->prog, inst->device, sig); + exitcode = EXIT_ERROR; + } + } + +#if DO_PROGRESS_INDICATOR + if (progress && (inst->flags & FLAG_PROGRESS) && !progress_active()) { + struct fsck_instance *inst2; + for (inst2 = G.instance_list; inst2; inst2 = inst2->next) { + if (inst2->flags & FLAG_DONE) + continue; + if (strcmp(inst2->type, "ext2") != 0 + && strcmp(inst2->type, "ext3") != 0 + ) { + continue; + } + /* ext[23], we will send USR1 + * (request to start displaying progress bar) + * + * If we've just started the fsck, wait a tiny + * bit before sending the kill, to give it + * time to set up the signal handler + */ + if (inst2->start_time >= time(NULL) - 1) + sleep1(); + kill(inst2->pid, SIGUSR1); + inst2->flags |= FLAG_PROGRESS; + break; + } + } +#endif + + if (prev) + prev->next = inst->next; + else + G.instance_list = inst->next; + if (G.verbose > 1) + printf("Finished with %s (exit status %u)\n", + inst->device, exitcode); + G.num_running--; + free_instance(inst); + + return exitcode; +} + +/* + * Wait until all executing child processes have exited; return the + * logical OR of all of their exit code values. + */ +#define FLAG_WAIT_ALL 0 +#define FLAG_WAIT_ATLEAST_ONE WNOHANG +static int wait_many(int flags) +{ + int exit_status; + int global_status = 0; + int wait_flags = 0; + + while ((exit_status = wait_one(wait_flags)) != -1) { + global_status |= exit_status; + wait_flags |= flags; + } + return global_status; +} + +/* + * Execute a particular fsck program, and link it into the list of + * child processes we are waiting for. + */ +static void execute(const char *type, const char *device, + const char *mntpt /*, int interactive */) +{ + int i; + struct fsck_instance *inst; + pid_t pid; + + G.args[0] = xasprintf("fsck.%s", type); + +#if DO_PROGRESS_INDICATOR + if (progress && !progress_active()) { + if (strcmp(type, "ext2") == 0 + || strcmp(type, "ext3") == 0 + ) { + G.args[XXX] = xasprintf("-C%d", progress_fd); /* 1 */ + inst->flags |= FLAG_PROGRESS; + } + } +#endif + + G.args[G.num_args - 2] = (char*)device; + /* G.args[G.num_args - 1] = NULL; - already is */ + + if (G.verbose || G.noexecute) { + printf("[%s (%d) -- %s]", G.args[0], G.num_running, + mntpt ? mntpt : device); + for (i = 0; G.args[i]; i++) + printf(" %s", G.args[i]); + bb_putchar('\n'); + } + + /* Fork and execute the correct program. */ + pid = -1; + if (!G.noexecute) { + pid = spawn(G.args); + if (pid < 0) + bb_simple_perror_msg(G.args[0]); + } + +#if DO_PROGRESS_INDICATOR + free(G.args[XXX]); +#endif + + /* No child, so don't record an instance */ + if (pid <= 0) { + free(G.args[0]); + return; + } + + inst = xzalloc(sizeof(*inst)); + inst->pid = pid; + inst->prog = G.args[0]; + inst->device = xstrdup(device); + inst->base_device = base_device(device); +#if DO_PROGRESS_INDICATOR + inst->start_time = time(NULL); +#endif + + /* Add to the list of running fsck's. + * (was adding to the end, but adding to the front is simpler...) */ + inst->next = G.instance_list; + G.instance_list = inst; +} + +/* + * Run the fsck program on a particular device + * + * If the type is specified using -t, and it isn't prefixed with "no" + * (as in "noext2") and only one filesystem type is specified, then + * use that type regardless of what is specified in /etc/fstab. + * + * If the type isn't specified by the user, then use either the type + * specified in /etc/fstab, or "auto". + */ +static void fsck_device(struct fs_info *fs /*, int interactive */) +{ + const char *type; + + if (strcmp(fs->type, "auto") != 0) { + type = fs->type; + if (G.verbose > 2) + printf("using filesystem type '%s' %s\n", + type, "from fstab"); + } else if (G.fstype + && (G.fstype[0] != 'n' || G.fstype[1] != 'o') /* != "no" */ + && !is_prefixed_with(G.fstype, "opts=") + && !is_prefixed_with(G.fstype, "loop") + && !strchr(G.fstype, ',') + ) { + type = G.fstype; + if (G.verbose > 2) + printf("using filesystem type '%s' %s\n", + type, "from -t"); + } else { + type = "auto"; + if (G.verbose > 2) + printf("using filesystem type '%s' %s\n", + type, "(default)"); + } + + G.num_running++; + execute(type, fs->device, fs->mountpt /*, interactive */); +} + +/* + * Returns TRUE if a partition on the same disk is already being + * checked. + */ +static int device_already_active(char *device) +{ + struct fsck_instance *inst; + char *base; + + if (G.force_all_parallel) + return 0; + +#ifdef BASE_MD + /* Don't check a soft raid disk with any other disk */ + if (G.instance_list + && (is_prefixed_with(G.instance_list->device, BASE_MD) + || is_prefixed_with(device, BASE_MD)) + ) { + return 1; + } +#endif + + base = base_device(device); + /* + * If we don't know the base device, assume that the device is + * already active if there are any fsck instances running. + */ + if (!base) + return (G.instance_list != NULL); + + for (inst = G.instance_list; inst; inst = inst->next) { + if (!inst->base_device || strcmp(base, inst->base_device) == 0) { + free(base); + return 1; + } + } + + free(base); + return 0; +} + +/* + * This function returns true if a particular option appears in a + * comma-delimited options list + */ +static int opt_in_list(char *opt, char *optlist) +{ + char *s; + int len; + + if (!optlist) + return 0; + + len = strlen(opt); + s = optlist - 1; + while (1) { + s = strstr(s + 1, opt); + if (!s) + return 0; + /* neither "opt.." nor "xxx,opt.."? */ + if (s != optlist && s[-1] != ',') + continue; + /* neither "..opt" nor "..opt,xxx"? */ + if (s[len] != '\0' && s[len] != ',') + continue; + return 1; + } +} + +/* See if the filesystem matches the criteria given by the -t option */ +static int fs_match(struct fs_info *fs) +{ + int n, ret, checked_type; + char *cp; + + if (!G.fs_type_list) + return 1; + + ret = 0; + checked_type = 0; + n = 0; + while (1) { + cp = G.fs_type_list[n]; + if (!cp) + break; + switch (G.fs_type_flag[n]) { + case FS_TYPE_FLAG_NORMAL: + checked_type++; + if (strcmp(cp, fs->type) == 0) + ret = 1; + break; + case FS_TYPE_FLAG_NEGOPT: + if (opt_in_list(cp, fs->opts)) + return 0; + break; + case FS_TYPE_FLAG_OPT: + if (!opt_in_list(cp, fs->opts)) + return 0; + break; + } + n++; + } + if (checked_type == 0) + return 1; + + return (G.fs_type_negated ? !ret : ret); +} + +/* Check if we should ignore this filesystem. */ +static int ignore(struct fs_info *fs) +{ + /* + * If the pass number is 0, ignore it. + */ + if (fs->passno == 0) + return 1; + + /* + * If a specific fstype is specified, and it doesn't match, + * ignore it. + */ + if (!fs_match(fs)) + return 1; + + /* Are we ignoring this type? */ + if (index_in_strings(ignored_types, fs->type) >= 0) + return 1; + + /* We can and want to check this file system type. */ + return 0; +} + +/* Check all file systems, using the /etc/fstab table. */ +static int check_all(void) +{ + struct fs_info *fs; + int status = EXIT_OK; + smallint not_done_yet; + smallint pass_done; + int passno; + + if (G.verbose) + puts("Checking all filesystems"); + + /* + * Do an initial scan over the filesystem; mark filesystems + * which should be ignored as done, and resolve any "auto" + * filesystem types (done as a side-effect of calling ignore()). + */ + for (fs = G.filesys_info; fs; fs = fs->next) + if (ignore(fs)) + fs->flags |= FLAG_DONE; + + /* + * Find and check the root filesystem. + */ + if (!G.parallel_root) { + for (fs = G.filesys_info; fs; fs = fs->next) { + if (LONE_CHAR(fs->mountpt, '/')) { + if (!G.skip_root && !ignore(fs)) { + fsck_device(fs /*, 1*/); + status |= wait_many(FLAG_WAIT_ALL); + if (status > EXIT_NONDESTRUCT) + return status; + } + fs->flags |= FLAG_DONE; + break; + } + } + } + /* + * This is for the bone-headed user who has root + * filesystem listed twice. + * "Skip root" will skip _all_ root entries. + */ + if (G.skip_root) + for (fs = G.filesys_info; fs; fs = fs->next) + if (LONE_CHAR(fs->mountpt, '/')) + fs->flags |= FLAG_DONE; + + not_done_yet = 1; + passno = 1; + while (not_done_yet) { + not_done_yet = 0; + pass_done = 1; + + for (fs = G.filesys_info; fs; fs = fs->next) { + if (bb_got_signal) + break; + if (fs->flags & FLAG_DONE) + continue; + /* + * If the filesystem's pass number is higher + * than the current pass number, then we didn't + * do it yet. + */ + if (fs->passno > passno) { + not_done_yet = 1; + continue; + } + /* + * If a filesystem on a particular device has + * already been spawned, then we need to defer + * this to another pass. + */ + if (device_already_active(fs->device)) { + pass_done = 0; + continue; + } + /* + * Spawn off the fsck process + */ + fsck_device(fs /*, G.serialize*/); + fs->flags |= FLAG_DONE; + + /* + * Only do one filesystem at a time, or if we + * have a limit on the number of fsck's extant + * at one time, apply that limit. + */ + if (G.serialize + || (G.num_running >= G.max_running) + ) { + pass_done = 0; + break; + } + } + if (bb_got_signal) + break; + if (G.verbose > 1) + printf("--waiting-- (pass %d)\n", passno); + status |= wait_many(pass_done ? FLAG_WAIT_ALL : + FLAG_WAIT_ATLEAST_ONE); + if (pass_done) { + if (G.verbose > 1) + puts("----------------------------------"); + passno++; + } else + not_done_yet = 1; + } + kill_all_if_got_signal(); + status |= wait_many(FLAG_WAIT_ATLEAST_ONE); + return status; +} + +/* + * Deal with the fsck -t argument. + * Huh, for mount "-t novfat,nfs" means "neither vfat nor nfs"! + * Why here we require "-t novfat,nonfs" ?? + */ +static void compile_fs_type(char *fs_type) +{ + char *s; + int num = 2; + smallint negate; + + s = fs_type; + while ((s = strchr(s, ','))) { + num++; + s++; + } + + G.fs_type_list = xzalloc(num * sizeof(G.fs_type_list[0])); + G.fs_type_flag = xzalloc(num * sizeof(G.fs_type_flag[0])); + G.fs_type_negated = -1; /* not yet known is it negated or not */ + + num = 0; + s = fs_type; + while (1) { + char *comma; + + negate = 0; + if (s[0] == 'n' && s[1] == 'o') { /* "no.." */ + s += 2; + negate = 1; + } else if (s[0] == '!') { + s++; + negate = 1; + } + + if (strcmp(s, "loop") == 0) + /* loop is really short-hand for opts=loop */ + goto loop_special_case; + if (is_prefixed_with(s, "opts=")) { + s += 5; + loop_special_case: + G.fs_type_flag[num] = negate ? FS_TYPE_FLAG_NEGOPT : FS_TYPE_FLAG_OPT; + } else { + if (G.fs_type_negated == -1) + G.fs_type_negated = negate; + if (G.fs_type_negated != negate) + bb_simple_error_msg_and_die( +"either all or none of the filesystem types passed to -t must be prefixed " +"with 'no' or '!'"); + } + comma = strchrnul(s, ','); + G.fs_type_list[num++] = xstrndup(s, comma-s); + if (*comma == '\0') + break; + s = comma + 1; + } +} + +static char **new_args(void) +{ + G.args = xrealloc_vector(G.args, 2, G.num_args); + return &G.args[G.num_args++]; +} + +int fsck_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int fsck_main(int argc UNUSED_PARAM, char **argv) +{ + int i, status; + /*int interactive;*/ + struct fs_info *fs; + const char *fstab; + char *tmp; + char **devices; + int num_devices; + smallint opts_for_fsck; + smallint doall; + smallint notitle; + + INIT_G(); + + /* we want wait() to be interruptible */ + signal_no_SA_RESTART_empty_mask(SIGINT, record_signo); + signal_no_SA_RESTART_empty_mask(SIGTERM, record_signo); + + setbuf(stdout, NULL); + + opts_for_fsck = doall = notitle = 0; + devices = NULL; + num_devices = 0; + new_args(); /* G.args[0] = NULL, will be replaced by fsck. */ + /* G.instance_list = NULL; - in bss, so already zeroed */ + + while (*++argv) { + int j; + int optpos; + char *options; + char *arg = *argv; + + /* "/dev/blk" or "/path" or "UUID=xxx" or "LABEL=xxx" */ + if ((arg[0] == '/' && !opts_for_fsck) || strchr(arg, '=')) { +// FIXME: must check that arg is a blkdev, or resolve +// "/path", "UUID=xxx" or "LABEL=xxx" into block device name +// ("UUID=xxx"/"LABEL=xxx" can probably shifted to fsck.auto duties) + devices = xrealloc_vector(devices, 2, num_devices); + devices[num_devices++] = arg; + continue; + } + + if (arg[0] != '-' || opts_for_fsck) { + *new_args() = arg; + continue; + } + + if (LONE_CHAR(arg + 1, '-')) { /* "--" ? */ + opts_for_fsck = 1; + continue; + } + + optpos = 0; + options = NULL; + for (j = 1; arg[j]; j++) { + switch (arg[j]) { + case 'A': + doall = 1; + break; +#if DO_PROGRESS_INDICATOR + case 'C': + progress = 1; + if (arg[++j]) { /* -Cn */ + progress_fd = xatoi_positive(&arg[j]); + goto next_arg; + } + /* -C n */ + if (!*++argv) + bb_show_usage(); + progress_fd = xatoi_positive(*argv); + goto next_arg; +#endif + case 'V': + G.verbose++; + break; + case 'N': + G.noexecute = 1; + break; + case 'R': + G.skip_root = 1; + break; + case 'T': + notitle = 1; + break; +/* case 'M': + like_mount = 1; + break; */ + case 'P': + G.parallel_root = 1; + break; + case 's': + G.serialize = 1; + break; + case 't': + if (G.fstype) + bb_show_usage(); + if (arg[++j]) + tmp = &arg[j]; + else if (*++argv) + tmp = *argv; + else + bb_show_usage(); + G.fstype = xstrdup(tmp); + compile_fs_type(G.fstype); + goto next_arg; + case '?': + bb_show_usage(); + break; + default: + optpos++; + /* one extra for '\0' */ + options = xrealloc(options, optpos + 2); + options[optpos] = arg[j]; + break; + } + } + next_arg: + if (optpos) { + options[0] = '-'; + options[optpos + 1] = '\0'; + *new_args() = options; + } + } + if (getenv("FSCK_FORCE_ALL_PARALLEL")) + G.force_all_parallel = 1; + tmp = getenv("FSCK_MAX_INST"); + G.max_running = INT_MAX; + if (tmp) + G.max_running = xatoi(tmp); + new_args(); /* G.args[G.num_args - 2] will be replaced by */ + new_args(); /* G.args[G.num_args - 1] is the last, NULL element */ + + if (!notitle) + puts("fsck (busybox "BB_VER")"); + + /* Even plain "fsck /dev/hda1" needs fstab to get fs type, + * so we are scanning it anyway */ + fstab = getenv("FSTAB_FILE"); + if (!fstab) + fstab = "/etc/fstab"; + load_fs_info(fstab); + + /*interactive = (num_devices == 1) | G.serialize;*/ + + if (num_devices == 0) + /*interactive =*/ G.serialize = doall = 1; + if (doall) + return check_all(); + + status = 0; + for (i = 0; i < num_devices; i++) { + if (bb_got_signal) { + kill_all_if_got_signal(); + break; + } + + fs = lookup(devices[i]); + if (!fs) + fs = create_fs_device(devices[i], "", "auto", NULL, -1); + fsck_device(fs /*, interactive */); + + if (G.serialize + || (G.num_running >= G.max_running) + ) { + int exit_status = wait_one(0); + if (exit_status >= 0) + status |= exit_status; + if (G.verbose > 1) + puts("----------------------------------"); + } + } + status |= wait_many(FLAG_WAIT_ALL); + return status; +} diff --git a/busybox-1_37_0/e2fsprogs/lsattr.c b/busybox-1_37_0/e2fsprogs/lsattr.c new file mode 100644 index 000000000..f678f72fb --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/lsattr.c @@ -0,0 +1,153 @@ +/* vi: set sw=4 ts=4: */ +/* + * lsattr.c - List file attributes on an ext2 file system + * + * Copyright (C) 1993, 1994 Remy Card + * Laboratoire MASI, Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * This file can be redistributed under the terms of the GNU General + * Public License + */ +//config:config LSATTR +//config: bool "lsattr (5.7 kb)" +//config: default y +//config: help +//config: lsattr lists the file attributes on a second extended file system. + +//applet:IF_LSATTR(APPLET_NOEXEC(lsattr, lsattr, BB_DIR_BIN, BB_SUID_DROP, lsattr)) +/* ls is NOEXEC, so we should be too! ;) */ + +//kbuild:lib-$(CONFIG_LSATTR) += lsattr.o e2fs_lib.o + +//usage:#define lsattr_trivial_usage +//usage: "[-Radlpv] [FILE]..." +//usage:#define lsattr_full_usage "\n\n" +//usage: "List ext2 file attributes\n" +//usage: "\n -R Recurse" +//usage: "\n -a Include names starting with ." +//usage: "\n -d List directory names, not contents" +// -a,-d text should match ls --help +//usage: "\n -l List long flag names" +//usage: "\n -p List project ID" +//usage: "\n -v List version/generation number" + +#include "libbb.h" +#include "e2fs_lib.h" + +enum { + OPT_RECUR = 1 << 0, + OPT_ALL = 1 << 1, + OPT_DIRS_OPT = 1 << 2, + OPT_PF_LONG = 1 << 3, + OPT_GENERATION = 1 << 4, + OPT_PROJID = 1 << 5, +}; + +static void list_attributes(const char *name) +{ + unsigned fsflags; + int fd, r; + + /* There is no way to run needed ioctls on a symlink. + * open(O_PATH | O_NOFOLLOW) _can_ be used to get a fd referring to the symlink, + * but ioctls fail on such a fd (tried on 4.12.0 kernel). + * e2fsprogs-1.46.2 uses open(O_NOFOLLOW), it fails on symlinks. + */ + fd = open_or_warn(name, O_RDONLY | O_NONBLOCK | O_NOCTTY | O_NOFOLLOW); + if (fd < 0) + return; + + if (option_mask32 & OPT_PROJID) { + struct ext2_fsxattr fsxattr; + r = ioctl(fd, EXT2_IOC_FSGETXATTR, &fsxattr); + /* note: ^^^ may fail in 32-bit userspace on 64-bit kernel (seen on 4.12.0) */ + if (r != 0) + goto read_err; + printf("%5u ", (unsigned)fsxattr.fsx_projid); + } + + if (option_mask32 & OPT_GENERATION) { + unsigned generation; + r = ioctl(fd, EXT2_IOC_GETVERSION, &generation); + if (r != 0) + goto read_err; + printf("%-10u ", generation); + } + + r = ioctl(fd, EXT2_IOC_GETFLAGS, &fsflags); + if (r != 0) + goto read_err; + + close(fd); + + if (option_mask32 & OPT_PF_LONG) { + printf("%-28s ", name); + print_e2flags_long(fsflags); + bb_putchar('\n'); + } else { + print_e2flags(fsflags); + printf(" %s\n", name); + } + + return; + read_err: + bb_perror_msg("reading %s", name); + close(fd); +} + +static int FAST_FUNC lsattr_dir_proc(const char *dir_name, + struct dirent *de, + void *private UNUSED_PARAM) +{ + struct stat st; + char *path; + + path = concat_path_file(dir_name, de->d_name); + + if (lstat(path, &st) != 0) + bb_perror_msg("can't stat '%s'", path); + + else if (de->d_name[0] != '.' || (option_mask32 & OPT_ALL)) { + /* Don't try to open device files, fifos etc */ + if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode) || S_ISDIR(st.st_mode)) + list_attributes(path); + + if (S_ISDIR(st.st_mode) && (option_mask32 & OPT_RECUR) + && !DOT_OR_DOTDOT(de->d_name) + ) { + printf("\n%s:\n", path); + iterate_on_dir(path, lsattr_dir_proc, NULL); + bb_putchar('\n'); + } + } + + free(path); + return 0; +} + +static void lsattr_args(const char *name) +{ + struct stat st; + + if (lstat(name, &st) == -1) { + bb_perror_msg("can't stat '%s'", name); + } else if (S_ISDIR(st.st_mode) && !(option_mask32 & OPT_DIRS_OPT)) { + iterate_on_dir(name, lsattr_dir_proc, NULL); + } else { + list_attributes(name); + } +} + +int lsattr_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int lsattr_main(int argc UNUSED_PARAM, char **argv) +{ + getopt32(argv, "Radlvp"); + argv += optind; + + if (!*argv) + *--argv = (char*)"."; + do lsattr_args(*argv++); while (*argv); + + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/e2fsprogs/tune2fs.c b/busybox-1_37_0/e2fsprogs/tune2fs.c new file mode 100644 index 000000000..f7fcd88bf --- /dev/null +++ b/busybox-1_37_0/e2fsprogs/tune2fs.c @@ -0,0 +1,102 @@ +/* vi: set sw=4 ts=4: */ +/* + * tune2fs: utility to modify EXT2 filesystem + * + * Busybox'ed (2009) by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +//config:config TUNE2FS +//config: bool "tune2fs (4.4 kb)" +//config: default n # off: it is too limited compared to upstream version +//config: help +//config: tune2fs allows the system administrator to adjust various tunable +//config: filesystem parameters on Linux ext2/ext3 filesystems. + +//applet:IF_TUNE2FS(APPLET_NOEXEC(tune2fs, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, tune2fs)) + +//TODO alias to "tune2fs -L LABEL": //applet:IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) + +//kbuild:lib-$(CONFIG_TUNE2FS) += tune2fs.o + +//usage:#define tune2fs_trivial_usage +//usage: "[-c MAX_MOUNT_COUNT] " +////usage: "[-e errors-behavior] [-g group] " +//usage: "[-i DAYS] " +////usage: "[-j] [-J journal-options] [-l] [-s sparse-flag] " +////usage: "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " +////usage: "[-r reserved-blocks-count] [-u user] " +//usage: "[-C MOUNT_COUNT] " +//usage: "[-L LABEL] " +////usage: "[-M last-mounted-dir] [-O [^]feature[,...]] " +////usage: "[-T last-check-time] [-U UUID] " +//usage: "BLOCKDEV" +//usage: +//usage:#define tune2fs_full_usage "\n\n" +//usage: "Adjust filesystem options on ext[23] filesystems" + +#include "libbb.h" +#include +#include "bb_e2fs_defs.h" + +enum { + OPT_L = 1 << 0, // label + OPT_c = 1 << 1, // max mount count + OPT_i = 1 << 2, // check interval + OPT_C = 1 << 3, // current mount count +}; + +int tune2fs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int tune2fs_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + const char *label, *str_c, *str_i, *str_C; + struct ext2_super_block *sb; + int fd; + + opts = getopt32(argv, "^" "L:c:i:C:" "\0" "=1", &label, &str_c, &str_i, &str_C); + if (!opts) + bb_show_usage(); + argv += optind; // argv[0] -- device + + // read superblock + fd = xopen(argv[0], O_RDWR); + xlseek(fd, 1024, SEEK_SET); + sb = xzalloc(1024); + xread(fd, sb, 1024); + + // mangle superblock + //STORE_LE(sb->s_wtime, time(NULL)); - why bother? + + if (opts & OPT_C) { + int n = xatoi_range(str_C, 1, 0xfffe); + STORE_LE(sb->s_mnt_count, (unsigned)n); + } + + // set the label + if (opts & OPT_L) + safe_strncpy((char *)sb->s_volume_name, label, sizeof(sb->s_volume_name)); + + if (opts & OPT_c) { + int n = xatoi_range(str_c, -1, 0xfffe); + if (n == 0) + n = -1; + STORE_LE(sb->s_max_mnt_count, (unsigned)n); + } + + if (opts & OPT_i) { + unsigned n = xatou_range(str_i, 0, (unsigned)0xffffffff / (24*60*60)) * 24*60*60; + STORE_LE(sb->s_checkinterval, n); + } + + // write superblock + xlseek(fd, 1024, SEEK_SET); + xwrite(fd, sb, 1024); + + if (ENABLE_FEATURE_CLEAN_UP) { + free(sb); + } + + xclose(fd); + return EXIT_SUCCESS; +} diff --git a/busybox-1_37_0/editors/Config.src b/busybox-1_37_0/editors/Config.src new file mode 100644 index 000000000..3b2e4a6c0 --- /dev/null +++ b/busybox-1_37_0/editors/Config.src @@ -0,0 +1,18 @@ +# +# For a description of the syntax of this configuration file, +# see docs/Kconfig-language.txt. +# + +menu "Editors" + +INSERT + +config FEATURE_ALLOW_EXEC + bool "Allow vi and awk to execute shell commands" + default y + depends on VI || AWK + help + Enables vi and awk features which allow user to execute + shell commands (using system() C call). + +endmenu diff --git a/busybox-1_37_0/editors/Kbuild.src b/busybox-1_37_0/editors/Kbuild.src new file mode 100644 index 000000000..6b4fb7470 --- /dev/null +++ b/busybox-1_37_0/editors/Kbuild.src @@ -0,0 +1,9 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# +# Licensed under GPLv2, see file LICENSE in this source tree. + +lib-y:= + +INSERT diff --git a/busybox-1_37_0/editors/awk.c b/busybox-1_37_0/editors/awk.c new file mode 100644 index 000000000..64e752f4b --- /dev/null +++ b/busybox-1_37_0/editors/awk.c @@ -0,0 +1,3893 @@ +/* vi: set sw=4 ts=4: */ +/* + * awk implementation for busybox + * + * Copyright (C) 2002 by Dmitry Zakharov + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config AWK +//config: bool "awk (24 kb)" +//config: default y +//config: help +//config: Awk is used as a pattern scanning and processing language. +//config: +//config:config FEATURE_AWK_LIBM +//config: bool "Enable math functions (requires libm)" +//config: default y +//config: depends on AWK +//config: help +//config: Enable math functions of the Awk programming language. +//config: NOTE: This requires libm to be present for linking. +//config: +//config:config FEATURE_AWK_GNU_EXTENSIONS +//config: bool "Enable a few GNU extensions" +//config: default y +//config: depends on AWK +//config: help +//config: Enable a few features from gawk: +//config: * command line option -e AWK_PROGRAM +//config: * simultaneous use of -f and -e on the command line. +//config: This enables the use of awk library files. +//config: Example: awk -f mylib.awk -e '{print myfunction($1);}' ... + +//applet:IF_AWK(APPLET_NOEXEC(awk, awk, BB_DIR_USR_BIN, BB_SUID_DROP, awk)) + +//kbuild:lib-$(CONFIG_AWK) += awk.o + +//usage:#define awk_trivial_usage +//usage: "[OPTIONS] [AWK_PROGRAM] [FILE]..." +//usage:#define awk_full_usage "\n\n" +//usage: " -v VAR=VAL Set variable" +//usage: "\n -F SEP Use SEP as field separator" +//usage: "\n -f/-E FILE Read program from FILE" +//usage: IF_FEATURE_AWK_GNU_EXTENSIONS( +//usage: "\n -e AWK_PROGRAM" +//usage: ) + +#include "libbb.h" +#include "xregex.h" +#include + +/* This is a NOEXEC applet. Be very careful! */ + + +/* If you comment out one of these below, it will be #defined later + * to perform debug printfs to stderr: */ +#define debug_printf_walker(...) do {} while (0) +#define debug_printf_eval(...) do {} while (0) +#define debug_printf_parse(...) do {} while (0) + +#ifndef debug_printf_walker +# define debug_printf_walker(...) (fprintf(stderr, __VA_ARGS__)) +#endif +#ifndef debug_printf_eval +# define debug_printf_eval(...) (fprintf(stderr, __VA_ARGS__)) +#endif +#ifndef debug_printf_parse +# define debug_printf_parse(...) (fprintf(stderr, __VA_ARGS__)) +#else +# define debug_parse_print_tc(...) ((void)0) +#endif + + +/* "+": stop on first non-option: + * $ awk 'BEGIN { for(i=1; i >> */ +#define TC_UOPPOST (1 << 4) /* unary postfix operator ++ -- */ +#define TC_UOPPRE1 (1 << 5) /* unary prefix operator ++ -- $ */ +#define TC_BINOPX (1 << 6) /* two-opnd operator */ +#define TC_IN (1 << 7) /* 'in' */ +#define TC_COMMA (1 << 8) /* , */ +#define TC_PIPE (1 << 9) /* input redirection pipe | */ +#define TC_UOPPRE2 (1 << 10) /* unary prefix operator + - ! */ +#define TC_ARRTERM (1 << 11) /* ] */ +#define TC_LBRACE (1 << 12) /* { */ +#define TC_RBRACE (1 << 13) /* } */ +#define TC_SEMICOL (1 << 14) /* ; */ +#define TC_NEWLINE (1 << 15) +#define TC_STATX (1 << 16) /* ctl statement (for, next...) */ +#define TC_WHILE (1 << 17) /* 'while' */ +#define TC_ELSE (1 << 18) /* 'else' */ +#define TC_BUILTIN (1 << 19) +/* This costs ~50 bytes of code. + * A separate class to support deprecated "length" form. If we don't need that + * (i.e. if we demand that only "length()" with () is valid), then TC_LENGTH + * can be merged with TC_BUILTIN: + */ +#define TC_LENGTH (1 << 20) /* 'length' */ +#define TC_GETLINE (1 << 21) /* 'getline' */ +#define TC_FUNCDECL (1 << 22) /* 'function' 'func' */ +#define TC_BEGIN (1 << 23) /* 'BEGIN' */ +#define TC_END (1 << 24) /* 'END' */ +#define TC_EOF (1 << 25) +#define TC_VARIABLE (1 << 26) /* name */ +#define TC_ARRAY (1 << 27) /* name[ */ +#define TC_FUNCTION (1 << 28) /* name( */ +#define TC_STRING (1 << 29) /* "..." */ +#define TC_NUMBER (1 << 30) + +#ifndef debug_parse_print_tc +static void debug_parse_print_tc(uint32_t n) +{ + if (n & TC_LPAREN ) debug_printf_parse(" LPAREN" ); + if (n & TC_RPAREN ) debug_printf_parse(" RPAREN" ); + if (n & TC_REGEXP ) debug_printf_parse(" REGEXP" ); + if (n & TC_OUTRDR ) debug_printf_parse(" OUTRDR" ); + if (n & TC_UOPPOST ) debug_printf_parse(" UOPPOST" ); + if (n & TC_UOPPRE1 ) debug_printf_parse(" UOPPRE1" ); + if (n & TC_BINOPX ) debug_printf_parse(" BINOPX" ); + if (n & TC_IN ) debug_printf_parse(" IN" ); + if (n & TC_COMMA ) debug_printf_parse(" COMMA" ); + if (n & TC_PIPE ) debug_printf_parse(" PIPE" ); + if (n & TC_UOPPRE2 ) debug_printf_parse(" UOPPRE2" ); + if (n & TC_ARRTERM ) debug_printf_parse(" ARRTERM" ); + if (n & TC_LBRACE ) debug_printf_parse(" LBRACE" ); + if (n & TC_RBRACE ) debug_printf_parse(" RBRACE" ); + if (n & TC_SEMICOL ) debug_printf_parse(" SEMICOL" ); + if (n & TC_NEWLINE ) debug_printf_parse(" NEWLINE" ); + if (n & TC_STATX ) debug_printf_parse(" STATX" ); + if (n & TC_WHILE ) debug_printf_parse(" WHILE" ); + if (n & TC_ELSE ) debug_printf_parse(" ELSE" ); + if (n & TC_BUILTIN ) debug_printf_parse(" BUILTIN" ); + if (n & TC_LENGTH ) debug_printf_parse(" LENGTH" ); + if (n & TC_GETLINE ) debug_printf_parse(" GETLINE" ); + if (n & TC_FUNCDECL) debug_printf_parse(" FUNCDECL"); + if (n & TC_BEGIN ) debug_printf_parse(" BEGIN" ); + if (n & TC_END ) debug_printf_parse(" END" ); + if (n & TC_EOF ) debug_printf_parse(" EOF" ); + if (n & TC_VARIABLE) debug_printf_parse(" VARIABLE"); + if (n & TC_ARRAY ) debug_printf_parse(" ARRAY" ); + if (n & TC_FUNCTION) debug_printf_parse(" FUNCTION"); + if (n & TC_STRING ) debug_printf_parse(" STRING" ); + if (n & TC_NUMBER ) debug_printf_parse(" NUMBER" ); +} +#endif + +/* combined token classes ("token [class] sets") */ +#define TS_UOPPRE (TC_UOPPRE1 | TC_UOPPRE2) + +#define TS_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) +//#define TS_UNARYOP (TS_UOPPRE | TC_UOPPOST) +#define TS_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ + | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ + | TC_LPAREN | TC_STRING | TC_NUMBER) + +#define TS_LVALUE (TC_VARIABLE | TC_ARRAY) +#define TS_STATEMNT (TC_STATX | TC_WHILE) + +/* word tokens, cannot mean something else if not expected */ +#define TS_WORD (TC_IN | TS_STATEMNT | TC_ELSE \ + | TC_BUILTIN | TC_LENGTH | TC_GETLINE \ + | TC_FUNCDECL | TC_BEGIN | TC_END) + +/* discard newlines after these */ +#define TS_NOTERM (TS_BINOP | TC_COMMA | TC_LBRACE | TC_RBRACE \ + | TC_SEMICOL | TC_NEWLINE) + +/* what can expression begin with */ +#define TS_OPSEQ (TS_OPERAND | TS_UOPPRE | TC_REGEXP) +/* what can group begin with */ +#define TS_GRPSEQ (TS_OPSEQ | TS_STATEMNT \ + | TC_SEMICOL | TC_NEWLINE | TC_LBRACE) + +/* if previous token class is CONCAT_L and next is CONCAT_R, concatenation */ +/* operator is inserted between them */ +#define TS_CONCAT_L (TC_VARIABLE | TC_ARRTERM | TC_RPAREN \ + | TC_STRING | TC_NUMBER | TC_UOPPOST \ + | TC_LENGTH) +#define TS_CONCAT_R (TS_OPERAND | TS_UOPPRE) + +#define OF_RES1 0x010000 /* evaluate(left_node) */ +#define OF_RES2 0x020000 /* evaluate(right_node) */ +#define OF_STR1 0x040000 /* ...and use its string value */ +#define OF_STR2 0x080000 /* ...and use its string value */ +#define OF_NUM1 0x100000 /* ...and use its numeric value */ +#define OF_REQUIRED 0x200000 /* left_node must not be NULL */ +#define OF_CHECKED 0x400000 /* range pattern flip-flop bit */ + +/* combined operator flags */ +#define xx 0 +#define xV OF_RES2 +#define xS (OF_RES2 | OF_STR2) +#define Vx OF_RES1 +#define Rx OF_REQUIRED +#define VV (OF_RES1 | OF_RES2) +#define Nx (OF_RES1 | OF_NUM1) +#define NV (OF_RES1 | OF_NUM1 | OF_RES2) +#define Sx (OF_RES1 | OF_STR1) +#define SV (OF_RES1 | OF_STR1 | OF_RES2) +#define SS (OF_RES1 | OF_STR1 | OF_RES2 | OF_STR2) + +#define OPCLSMASK 0xFF00 +#define OPNMASK 0x007F + +/* operator precedence is the highest byte (even: r->l, odd: l->r grouping) + * (for builtins the byte has a different meaning) + */ +#undef P +#undef PRIMASK +#undef PRIMASK2 +#define PRIMASK 0x7F000000 +#define PRIMASK2 0x7E000000 +/* Smaller 'x' means _higher_ operator precedence */ +#define PRECEDENCE(x) (x << 24) +#define P(x) PRECEDENCE(x) +#define LOWEST_PRECEDENCE PRIMASK + +/* Operation classes */ +#define SHIFT_TIL_THIS 0x0600 +#define RECUR_FROM_THIS 0x1000 +enum { + OC_DELETE = 0x0100, OC_EXEC = 0x0200, OC_NEWSOURCE = 0x0300, + OC_PRINT = 0x0400, OC_PRINTF = 0x0500, OC_WALKINIT = 0x0600, + + OC_BR = 0x0700, OC_BREAK = 0x0800, OC_CONTINUE = 0x0900, + OC_EXIT = 0x0a00, OC_NEXT = 0x0b00, OC_NEXTFILE = 0x0c00, + OC_TEST = 0x0d00, OC_WALKNEXT = 0x0e00, + + OC_BINARY = 0x1000, OC_BUILTIN = 0x1100, OC_COLON = 0x1200, + OC_COMMA = 0x1300, OC_COMPARE = 0x1400, OC_CONCAT = 0x1500, + OC_FBLTIN = 0x1600, OC_FIELD = 0x1700, OC_FNARG = 0x1800, + OC_FUNC = 0x1900, OC_GETLINE = 0x1a00, OC_IN = 0x1b00, + OC_LAND = 0x1c00, OC_LOR = 0x1d00, OC_MATCH = 0x1e00, + OC_MOVE = 0x1f00, OC_PGETLINE = 0x2000, OC_REGEXP = 0x2100, + OC_REPLACE = 0x2200, OC_RETURN = 0x2300, OC_SPRINTF = 0x2400, + OC_TERNARY = 0x2500, OC_UNARY = 0x2600, OC_VAR = 0x2700, + OC_CONST = 0x2800, OC_DONE = 0x2900, + + ST_IF = 0x3000, ST_DO = 0x3100, ST_FOR = 0x3200, + ST_WHILE = 0x3300 +}; + +/* simple builtins */ +enum { + F_in, F_rn, F_co, F_ex, F_lg, F_si, F_sq, F_sr, + F_ti, F_le, F_sy, F_ff, F_cl +}; + +/* builtins */ +enum { + B_a2, B_ix, B_ma, B_sp, B_ss, B_ti, B_mt, B_lo, B_up, + B_ge, B_gs, B_su, + B_an, B_co, B_ls, B_or, B_rs, B_xo, +}; + +/* tokens and their corresponding info values */ + +#define NTC "\377" /* switch to next token class (tc<<1) */ +#define NTCC '\377' + +static const char tokenlist[] ALIGN1 = + "\1(" NTC /* TC_LPAREN */ + "\1)" NTC /* TC_RPAREN */ + "\1/" NTC /* TC_REGEXP */ + "\2>>" "\1>" "\1|" NTC /* TC_OUTRDR */ + "\2++" "\2--" NTC /* TC_UOPPOST */ + "\2++" "\2--" "\1$" NTC /* TC_UOPPRE1 */ + "\2==" "\1=" "\2+=" "\2-=" /* TC_BINOPX */ + "\2*=" "\2/=" "\2%=" "\2^=" + "\1+" "\1-" "\3**=" "\2**" + "\1/" "\1%" "\1^" "\1*" + "\2!=" "\2>=" "\2<=" "\1>" + "\1<" "\2!~" "\1~" "\2&&" + "\2||" "\1?" "\1:" NTC + "\2in" NTC /* TC_IN */ + "\1," NTC /* TC_COMMA */ + "\1|" NTC /* TC_PIPE */ + "\1+" "\1-" "\1!" NTC /* TC_UOPPRE2 */ + "\1]" NTC /* TC_ARRTERM */ + "\1{" NTC /* TC_LBRACE */ + "\1}" NTC /* TC_RBRACE */ + "\1;" NTC /* TC_SEMICOL */ + "\1\n" NTC /* TC_NEWLINE */ + "\2if" "\2do" "\3for" "\5break" /* TC_STATX */ + "\10continue" "\6delete" "\5print" + "\6printf" "\4next" "\10nextfile" + "\6return" "\4exit" NTC + "\5while" NTC /* TC_WHILE */ + "\4else" NTC /* TC_ELSE */ + "\3and" "\5compl" "\6lshift" "\2or" /* TC_BUILTIN */ + "\6rshift" "\3xor" + "\5close" "\6system" "\6fflush" "\5atan2" + "\3cos" "\3exp" "\3int" "\3log" + "\4rand" "\3sin" "\4sqrt" "\5srand" + "\6gensub" "\4gsub" "\5index" /* "\6length" was here */ + "\5match" "\5split" "\7sprintf" "\3sub" + "\6substr" "\7systime" "\10strftime" "\6mktime" + "\7tolower" "\7toupper" NTC + "\6length" NTC /* TC_LENGTH */ + "\7getline" NTC /* TC_GETLINE */ + "\4func" "\10function" NTC /* TC_FUNCDECL */ + "\5BEGIN" NTC /* TC_BEGIN */ + "\3END" /* TC_END */ + /* compiler adds trailing "\0" */ + ; + +static const uint32_t tokeninfo[] ALIGN4 = { + 0, /* ( */ + 0, /* ) */ +#define TI_REGEXP OC_REGEXP + TI_REGEXP, /* / */ + /* >> > | */ + xS|'a', xS|'w', xS|'|', + /* ++ -- */ + OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', +#define TI_PREINC (OC_UNARY|xV|P(9)|'P') +#define TI_PREDEC (OC_UNARY|xV|P(9)|'M') + /* ++ -- $ */ + TI_PREINC, TI_PREDEC, OC_FIELD|xV|P(5), + /* == = += -= */ + OC_COMPARE|VV|P(39)|5, OC_MOVE|VV|P(74), OC_REPLACE|NV|P(74)|'+', OC_REPLACE|NV|P(74)|'-', + /* *= /= %= ^= (^ is exponentiation, NOT xor) */ + OC_REPLACE|NV|P(74)|'*', OC_REPLACE|NV|P(74)|'/', OC_REPLACE|NV|P(74)|'%', OC_REPLACE|NV|P(74)|'&', + /* + - **= ** */ + OC_BINARY|NV|P(29)|'+', OC_BINARY|NV|P(29)|'-', OC_REPLACE|NV|P(74)|'&', OC_BINARY|NV|P(15)|'&', + /* / % ^ * */ + OC_BINARY|NV|P(25)|'/', OC_BINARY|NV|P(25)|'%', OC_BINARY|NV|P(15)|'&', OC_BINARY|NV|P(25)|'*', + /* != >= <= > */ + OC_COMPARE|VV|P(39)|4, OC_COMPARE|VV|P(39)|3, OC_COMPARE|VV|P(39)|0, OC_COMPARE|VV|P(39)|1, +#define TI_LESS (OC_COMPARE|VV|P(39)|2) + /* < !~ ~ && */ + TI_LESS, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), +#define TI_TERNARY (OC_TERNARY|Vx|P(64)|'?') +#define TI_COLON (OC_COLON|xx|P(67)|':') + /* || ? : */ + OC_LOR|Vx|P(59), TI_TERNARY, TI_COLON, +#define TI_IN (OC_IN|SV|P(49)) + TI_IN, +#define TI_COMMA (OC_COMMA|SS|P(80)) + TI_COMMA, +#define TI_PGETLINE (OC_PGETLINE|SV|P(37)) + TI_PGETLINE, /* | */ + /* + - ! */ + OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', + 0, /* ] */ + 0, /* { */ + 0, /* } */ + 0, /* ; */ + 0, /* \n */ + ST_IF, ST_DO, ST_FOR, OC_BREAK, + OC_CONTINUE, OC_DELETE|Rx, OC_PRINT, + OC_PRINTF, OC_NEXT, OC_NEXTFILE, + OC_RETURN|Vx, OC_EXIT|Nx, + ST_WHILE, + 0, /* else */ +// OC_B's are builtins with enforced minimum number of arguments (two upper bits). +// Highest byte bit pattern: nn s3s2s1 v3v2v1 +// nn - min. number of args, sN - resolve Nth arg to string, vN - resolve to var +// OC_F's are builtins with zero or one argument. +// |Rx| enforces that arg is present for: system, close, cos, sin, exp, int, log, sqrt +// Check for no args is present in builtins' code (not in this table): rand, systime +// Have one _optional_ arg: fflush, srand, length +#define OC_B OC_BUILTIN +#define OC_F OC_FBLTIN +#define A1 P(0x40) /*one arg*/ +#define A2 P(0x80) /*two args*/ +#define A3 P(0xc0) /*three args*/ +#define __v P(1) +#define _vv P(3) +#define __s__v P(9) +#define __s_vv P(0x0b) +#define __svvv P(0x0f) +#define _ss_vv P(0x1b) +#define _s_vv_ P(0x16) +#define ss_vv_ P(0x36) + OC_B|B_an|_vv|A2, OC_B|B_co|__v|A1, OC_B|B_ls|_vv|A2, OC_B|B_or|_vv|A2, // and compl lshift or + OC_B|B_rs|_vv|A2, OC_B|B_xo|_vv|A2, // rshift xor + OC_F|F_cl|Sx|Rx, OC_F|F_sy|Sx|Rx, OC_F|F_ff|Sx, OC_B|B_a2|_vv|A2, // close system fflush atan2 + OC_F|F_co|Nx|Rx, OC_F|F_ex|Nx|Rx, OC_F|F_in|Nx|Rx, OC_F|F_lg|Nx|Rx, // cos exp int log + OC_F|F_rn, OC_F|F_si|Nx|Rx, OC_F|F_sq|Nx|Rx, OC_F|F_sr|Nx, // rand sin sqrt srand + OC_B|B_ge|_s_vv_|A3,OC_B|B_gs|ss_vv_|A2,OC_B|B_ix|_ss_vv|A2, // gensub gsub index /*length was here*/ + OC_B|B_ma|__s__v|A2,OC_B|B_sp|__s_vv|A2,OC_SPRINTF, OC_B|B_su|ss_vv_|A2,// match split sprintf sub + OC_B|B_ss|__svvv|A2,OC_F|F_ti, OC_B|B_ti|__s_vv, OC_B|B_mt|__s_vv|A1,// substr systime strftime mktime + OC_B|B_lo|__s__v|A1,OC_B|B_up|__s__v|A1, // tolower toupper + OC_F|F_le|Sx, // length + OC_GETLINE|SV, // getline + 0, 0, // func function + 0, // BEGIN + 0 // END +#undef A1 +#undef A2 +#undef A3 +#undef OC_B +#undef OC_F +}; + +/* gawk 5.1.1 manpage says the precedence of comparisons and assignments are as follows: + * ...... + * < > <= >= == != + * ~ !~ + * in + * && + * || + * ?: + * = += -= *= /= %= ^= + * But there are some abnormalities: + * awk 'BEGIN { print v=3==3,v }' - ok: + * 1 1 + * awk 'BEGIN { print 3==v=3,v }' - wrong, (3==v)=3 is not a valid assignment: + * 1 3 + * This also unexpectedly works: echo "foo" | awk '$1==$1="foo" {print $1}' + * More than one comparison op fails to parse: + * awk 'BEGIN { print 3==3==3 }' - syntax error (wrong, should work) + * awk 'BEGIN { print 3==3!=3 }' - syntax error (wrong, should work) + * + * The ternary a?b:c works as follows in gawk: "a" can't be assignment + * ("= has lower precedence than ?") but inside "b" or "c", assignment + * is higher precedence: + * awk 'BEGIN { u=v=w=1; print u=0?v=4:w=5; print u,v,w }' + * 5 + * 5 1 5 + * This differs from C and shell's "test" rules for ?: which have implicit () + * around "b" in ?:, but not around "c" - they would barf on "w=5" above. + * gawk allows nesting of ?: - this works: + * u=0?v=4?5:6:w=7?8:9 means u=0?(v=4?5:6):(w=7?8:9) + * bbox is buggy here, requires parens: "u=0?(v=4):(w=5)" + */ + +/* internal variable names and their initial values */ +/* asterisk marks SPECIAL vars; $ is just no-named Field0 */ +enum { + CONVFMT, OFMT, FS, OFS, + ORS, RS, RT, FILENAME, + SUBSEP, F0, ARGIND, ARGC, + ARGV, ERRNO, FNR, NR, + NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS +}; + +static const char vNames[] ALIGN1 = + "CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0" + "ORS\0" "RS\0*" "RT\0" "FILENAME\0" + "SUBSEP\0" "$\0*" "ARGIND\0" "ARGC\0" + "ARGV\0" "ERRNO\0" "FNR\0" "NR\0" + "NF\0*" "IGNORECASE\0*" "ENVIRON\0" "\0"; + +static const char vValues[] ALIGN1 = + "%.6g\0" "%.6g\0" " \0" " \0" + "\n\0" "\n\0" "\0" "\0" + "\034\0" "\0" "\377"; +#define str_percent_dot_6g vValues + +/* hash size may grow to these values */ +#define FIRST_PRIME 61 +static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 }; + + +/* Globals. Split in two parts so that first one is addressed + * with (mostly short) negative offsets. + * NB: it's unsafe to put members of type "double" + * into globals2 (gcc may fail to align them). + */ +struct globals { + double t_double; + chain beginseq, mainseq, endseq; + chain *seq; + node *break_ptr, *continue_ptr; + xhash *ahash; /* argument names, used only while parsing function bodies */ + xhash *fnhash; /* function names, used only in parsing stage */ + xhash *vhash; /* variables and arrays */ + //xhash *fdhash; /* file objects, used only in execution stage */ + //we are reusing ahash as fdhash, via define (see later) + const char *g_progname; + int g_lineno; + int num_fields; /* number of existing $N's */ + unsigned num_alloc_fields; /* current size of Fields[] */ + /* NB: Fields[0] corresponds to $1, not to $0 */ + var *Fields; + char *g_pos; + char g_saved_ch; + smallint got_program; + smallint icase; + smallint exiting; + smallint nextrec; + smallint nextfile; + smallint is_f0_split; + smallint t_rollback; + + /* former statics from various functions */ + smallint next_token__concat_inserted; + uint32_t next_token__save_tclass; + uint32_t next_token__save_info; +}; +struct globals2 { + uint32_t t_info; /* often used */ + uint32_t t_tclass; + char *t_string; + int t_lineno; + + var *intvar[NUM_INTERNAL_VARS]; /* often used */ + + rstream iF; + + /* former statics from various functions */ + char *split_f0__fstrings; + + unsigned next_input_file__argind; + smallint next_input_file__input_file_seen; + + smalluint exitcode; + + unsigned evaluate__seed; + var *evaluate__fnargs; + regex_t evaluate__sreg; + + var ptest__tmpvar; + var awk_printf__tmpvar; + var as_regex__tmpvar; + var exit__tmpvar; + var main__tmpvar; + + tsplitter exec_builtin__tspl; + + /* biggest and least used members go last */ + tsplitter fsplitter, rsplitter; + + char g_buf[MAXVARFMT + 1]; +}; +#define G1 (ptr_to_globals[-1]) +#define G (*(struct globals2 *)ptr_to_globals) +/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */ +//char G1size[sizeof(G1)]; // 0x70 +//char Gsize[sizeof(G)]; // 0x2f8 +/* Trying to keep most of members accessible with short offsets: */ +//char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; // 0x7c +#define t_double (G1.t_double ) +#define beginseq (G1.beginseq ) +#define mainseq (G1.mainseq ) +#define endseq (G1.endseq ) +#define seq (G1.seq ) +#define break_ptr (G1.break_ptr ) +#define continue_ptr (G1.continue_ptr) +#define ahash (G1.ahash ) +#define fnhash (G1.fnhash ) +#define vhash (G1.vhash ) +#define fdhash ahash +//^^^^^^^^^^^^^^^^^^ ahash is cleared after every function parsing, +// and ends up empty after parsing phase. Thus, we can simply reuse it +// for fdhash in execution stage. +#define g_progname (G1.g_progname ) +#define g_lineno (G1.g_lineno ) +#define num_fields (G1.num_fields ) +#define num_alloc_fields (G1.num_alloc_fields) +#define Fields (G1.Fields ) +#define g_pos (G1.g_pos ) +#define g_saved_ch (G1.g_saved_ch ) +#define got_program (G1.got_program ) +#define icase (G1.icase ) +#define exiting (G1.exiting ) +#define nextrec (G1.nextrec ) +#define nextfile (G1.nextfile ) +#define is_f0_split (G1.is_f0_split ) +#define t_rollback (G1.t_rollback ) +#define t_info (G.t_info ) +#define t_tclass (G.t_tclass ) +#define t_string (G.t_string ) +#define t_lineno (G.t_lineno ) +#define intvar (G.intvar ) +#define iF (G.iF ) +#define fsplitter (G.fsplitter ) +#define rsplitter (G.rsplitter ) +#define g_buf (G.g_buf ) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS((char*)xzalloc(sizeof(G1)+sizeof(G)) + sizeof(G1)); \ + t_tclass = TC_NEWLINE; \ + G.evaluate__seed = 1; \ +} while (0) + +static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string"; +static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token"; +static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero"; +static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier"; +static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments"; +static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array"; +static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error"; +static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function"; +static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; +static const char EMSG_NEGATIVE_FIELD[] ALIGN1 = "Access to negative field"; + +static int awk_exit(void) NORETURN; + +static void syntax_error(const char *message) NORETURN; +static void syntax_error(const char *message) +{ + bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message); +} + +/* ---- hash stuff ---- */ + +static unsigned hashidx(const char *name) +{ + unsigned idx = 0; + + while (*name) + idx = *name++ + (idx << 6) - idx; + return idx; +} + +/* create new hash */ +static xhash *hash_init(void) +{ + xhash *newhash; + + newhash = xzalloc(sizeof(*newhash)); + newhash->csize = FIRST_PRIME; + newhash->items = xzalloc(FIRST_PRIME * sizeof(newhash->items[0])); + + return newhash; +} + +static void hash_clear(xhash *hash) +{ + unsigned i; + hash_item *hi, *thi; + + for (i = 0; i < hash->csize; i++) { + hi = hash->items[i]; + while (hi) { + thi = hi; + hi = hi->next; +//FIXME: this assumes that it's a hash of *variables*: + free(thi->data.v.string); + free(thi); + } + hash->items[i] = NULL; + } + hash->glen = hash->nel = 0; +} + +#if 0 //UNUSED +static void hash_free(xhash *hash) +{ + hash_clear(hash); + free(hash->items); + free(hash); +} +#endif + +/* find item in hash, return ptr to data, NULL if not found */ +static NOINLINE void *hash_search3(xhash *hash, const char *name, unsigned idx) +{ + hash_item *hi; + + hi = hash->items[idx % hash->csize]; + while (hi) { + if (strcmp(hi->name, name) == 0) + return &hi->data; + hi = hi->next; + } + return NULL; +} + +static void *hash_search(xhash *hash, const char *name) +{ + return hash_search3(hash, name, hashidx(name)); +} + +/* grow hash if it becomes too big */ +static void hash_rebuild(xhash *hash) +{ + unsigned newsize, i, idx; + hash_item **newitems, *hi, *thi; + + if (hash->nprime == ARRAY_SIZE(PRIMES)) + return; + + newsize = PRIMES[hash->nprime++]; + newitems = xzalloc(newsize * sizeof(newitems[0])); + + for (i = 0; i < hash->csize; i++) { + hi = hash->items[i]; + while (hi) { + thi = hi; + hi = thi->next; + idx = hashidx(thi->name) % newsize; + thi->next = newitems[idx]; + newitems[idx] = thi; + } + } + + free(hash->items); + hash->csize = newsize; + hash->items = newitems; +} + +/* find item in hash, add it if necessary. Return ptr to data */ +static void *hash_find(xhash *hash, const char *name) +{ + hash_item *hi; + unsigned idx; + int l; + + idx = hashidx(name); + hi = hash_search3(hash, name, idx); + if (!hi) { + if (++hash->nel > hash->csize * 8) + hash_rebuild(hash); + + l = strlen(name) + 1; + hi = xzalloc(sizeof(*hi) + l); + strcpy(hi->name, name); + + idx = idx % hash->csize; + hi->next = hash->items[idx]; + hash->items[idx] = hi; + hash->glen += l; + } + return &hi->data; +} + +#define findvar(hash, name) ((var*) hash_find((hash), (name))) +#define newvar(name) ((var*) hash_find(vhash, (name))) +#define newfile(name) ((rstream*)hash_find(fdhash, (name))) +#define newfunc(name) ((func*) hash_find(fnhash, (name))) + +static void hash_remove(xhash *hash, const char *name) +{ + hash_item *hi, **phi; + + phi = &hash->items[hashidx(name) % hash->csize]; + while (*phi) { + hi = *phi; + if (strcmp(hi->name, name) == 0) { + hash->glen -= (strlen(name) + 1); + hash->nel--; + *phi = hi->next; + free(hi); + break; + } + phi = &hi->next; + } +} + +/* ------ some useful functions ------ */ + +static char *skip_spaces(char *p) +{ + for (;;) { + if (*p == '\\' && p[1] == '\n') { + p++; + t_lineno++; + } else if (*p != ' ' && *p != '\t') { + break; + } + p++; + } + return p; +} + +/* returns old *s, advances *s past word and terminating NUL */ +static char *nextword(char **s) +{ + char *p = *s; + char *q = p; + while (*q++ != '\0') + continue; + *s = q; + return p; +} + +static char nextchar(char **s) +{ + char c, *pps; + again: + c = *(*s)++; + pps = *s; + if (c == '\\') + c = bb_process_escape_sequence((const char**)s); + /* Example awk statement: + * s = "abc\"def" + * we must treat \" as " + */ + if (c == '\\' && *s == pps) { /* unrecognized \z? */ + c = *(*s); /* yes, fetch z */ + if (c) { /* advance unless z = NUL */ + (*s)++; + if (c == '\n') /* \? eat it */ + goto again; + } + } + return c; +} + +/* TODO: merge with strcpy_and_process_escape_sequences()? + */ +static void unescape_string_in_place(char *s1) +{ + char *s = s1; + while ((*s1 = nextchar(&s)) != '\0') + s1++; +} + +static ALWAYS_INLINE int isalnum_(int c) +{ + return (isalnum(c) || c == '_'); +} + +static double my_strtod(char **pp) +{ + char *cp = *pp; + return strtod(cp, pp); +} +#if ENABLE_DESKTOP +static double my_strtod_or_hexoct(char **pp) +{ + char *cp = *pp; + if (cp[0] == '0') { + /* Might be hex or octal integer: 0x123abc or 07777 */ + char c = (cp[1] | 0x20); + if (c == 'x' || isdigit(cp[1])) { + unsigned long long ull = strtoull(cp, pp, 0); + if (c == 'x') + return ull; + c = **pp; + if (!isdigit(c) && c != '.') + return ull; + /* else: it may be a floating number. Examples: + * 009.123 (*pp points to '9') + * 000.123 (*pp points to '.') + * fall through to strtod. + */ + } + } + return strtod(cp, pp); +} +#else +# define my_strtod_or_hexoct(p) my_strtod(p) +#endif + +/* -------- working with variables (set/get/copy/etc) -------- */ + +static const char *fmt_num(const char *format, double n) +{ + if (n == (long long)n) { + snprintf(g_buf, MAXVARFMT, "%lld", (long long)n); + } else { + const char *s = format; + char c; + + do { c = *s; } while (c && *++s); + if (strchr("diouxX", c)) { + snprintf(g_buf, MAXVARFMT, format, (int)n); + } else if (strchr("eEfFgGaA", c)) { + snprintf(g_buf, MAXVARFMT, format, n); + } else { + syntax_error(EMSG_INV_FMT); + } + } + return g_buf; +} + +static xhash *iamarray(var *a) +{ + while (a->type & VF_CHILD) + a = a->x.parent; + + if (!(a->type & VF_ARRAY)) { + a->type |= VF_ARRAY; + a->x.array = hash_init(); + } + return a->x.array; +} + +#define clear_array(array) hash_clear(array) + +/* clear a variable */ +static var *clrvar(var *v) +{ + if (!(v->type & VF_FSTR)) + free(v->string); + + v->type &= VF_DONTTOUCH; + v->type |= VF_DIRTY; + v->string = NULL; + return v; +} + +static void handle_special(var *); + +/* assign string value to variable */ +static var *setvar_p(var *v, char *value) +{ + clrvar(v); + v->string = value; + handle_special(v); + return v; +} + +/* same as setvar_p but make a copy of string */ +static var *setvar_s(var *v, const char *value) +{ + return setvar_p(v, (value && *value) ? xstrdup(value) : NULL); +} + +static var *setvar_sn(var *v, const char *value, int len) +{ + return setvar_p(v, (value && *value && len > 0) ? xstrndup(value, len) : NULL); +} + +/* same as setvar_s but sets USER flag */ +static var *setvar_u(var *v, const char *value) +{ + v = setvar_s(v, value); + v->type |= VF_USER; + return v; +} + +/* set array element to user string */ +static void setari_u(var *a, int idx, const char *s) +{ + var *v; + + v = findvar(iamarray(a), itoa(idx)); + setvar_u(v, s); +} + +/* assign numeric value to variable */ +static var *setvar_i(var *v, double value) +{ + clrvar(v); + v->type |= VF_NUMBER; + v->number = value; + handle_special(v); + return v; +} + +static void setvar_ERRNO(void) +{ + setvar_i(intvar[ERRNO], errno); +} + +static const char *getvar_s(var *v) +{ + /* if v is numeric and has no cached string, convert it to string */ + if ((v->type & (VF_NUMBER | VF_CACHED)) == VF_NUMBER) { + const char *convfmt = str_percent_dot_6g; /* "%.6g" */ + /* Get CONVFMT, unless we already recursed on it: + * someone might try to cause stack overflow by setting + * CONVFMT=9 (a numeric, not string, value) + */ + if (v != intvar[CONVFMT]) + convfmt = getvar_s(intvar[CONVFMT]); + /* Convert the value */ + v->string = xstrdup(fmt_num(convfmt, v->number)); + v->type |= VF_CACHED; + } + return (v->string == NULL) ? "" : v->string; +} + +static double getvar_i(var *v) +{ + char *s; + + if ((v->type & (VF_NUMBER | VF_CACHED)) == 0) { + v->number = 0; + s = v->string; + if (s && *s) { + debug_printf_eval("getvar_i: '%s'->", s); + v->number = my_strtod(&s); + /* ^^^ hex/oct NOT allowed here! */ + debug_printf_eval("%f (s:'%s')\n", v->number, s); + if (v->type & VF_USER) { +//TODO: skip_spaces() also skips backslash+newline, is it intended here? + s = skip_spaces(s); + if (*s != '\0') + v->type &= ~VF_USER; + } + } else { + debug_printf_eval("getvar_i: '%s'->zero\n", s); + v->type &= ~VF_USER; + } + v->type |= VF_CACHED; + } + debug_printf_eval("getvar_i: %f\n", v->number); + return v->number; +} + +/* Used for operands of bitwise ops */ +static unsigned long getvar_i_int(var *v) +{ + double d = getvar_i(v); + + /* Casting doubles to longs is undefined for values outside + * of target type range. Try to widen it as much as possible */ + if (d >= 0) + return (unsigned long)d; + /* Why? Think about d == -4294967295.0 (assuming 32bit longs) */ + return - (long) (unsigned long) (-d); +} + +static var *copyvar(var *dest, const var *src) +{ + if (dest != src) { + clrvar(dest); + dest->type |= (src->type & ~(VF_DONTTOUCH | VF_FSTR)); + debug_printf_eval("copyvar: number:%f string:'%s'\n", src->number, src->string); + dest->number = src->number; + if (src->string) + dest->string = xstrdup(src->string); + } + handle_special(dest); + return dest; +} + +static var *incvar(var *v) +{ + return setvar_i(v, getvar_i(v) + 1.0); +} + +/* return true if v is number or numeric string */ +static int is_numeric(var *v) +{ + getvar_i(v); + return ((v->type ^ VF_DIRTY) & (VF_NUMBER | VF_USER | VF_DIRTY)); +} + +/* return 1 when value of v corresponds to true, 0 otherwise */ +static int istrue(var *v) +{ + if (is_numeric(v)) + return (v->number != 0); + return (v->string && v->string[0]); +} + +/* ------- awk program text parsing ------- */ + +/* Parse next token pointed by global pos, place results into global t_XYZ variables. + * If token isn't expected, print error message and die. + * Return token class (also store it in t_tclass). + */ +static uint32_t next_token(uint32_t expected) +{ +#define concat_inserted (G1.next_token__concat_inserted) +#define save_tclass (G1.next_token__save_tclass) +#define save_info (G1.next_token__save_info) + + char *p; + const char *tl; + const uint32_t *ti; + uint32_t tc, last_token_class; + + last_token_class = t_tclass; /* t_tclass is initialized to TC_NEWLINE */ + + debug_printf_parse("%s() expected(%x):", __func__, expected); + debug_parse_print_tc(expected); + debug_printf_parse("\n"); + + if (t_rollback) { + debug_printf_parse("%s: using rolled-back token\n", __func__); + t_rollback = FALSE; + } else if (concat_inserted) { + debug_printf_parse("%s: using concat-inserted token\n", __func__); + concat_inserted = FALSE; + t_tclass = save_tclass; + t_info = save_info; + } else { + p = g_pos; + if (g_saved_ch != '\0') { + *p = g_saved_ch; + g_saved_ch = '\0'; + } + readnext: + p = skip_spaces(p); + g_lineno = t_lineno; + if (*p == '#') + while (*p != '\n' && *p != '\0') + p++; + + if (*p == '\0') { + tc = TC_EOF; + debug_printf_parse("%s: token found: TC_EOF\n", __func__); + } else if (*p == '"') { + /* it's a string */ + char *s = t_string = ++p; + while (*p != '"') { + char *pp; + if (*p == '\0' || *p == '\n') + syntax_error(EMSG_UNEXP_EOS); + pp = p; + *s++ = nextchar(&pp); + p = pp; + } + p++; + *s = '\0'; + tc = TC_STRING; + debug_printf_parse("%s: token found:'%s' TC_STRING\n", __func__, t_string); + } else if ((expected & TC_REGEXP) && *p == '/') { + /* it's regexp */ + char *s = t_string = ++p; + while (*p != '/') { + if (*p == '\0' || *p == '\n') + syntax_error(EMSG_UNEXP_EOS); + *s = *p++; + if (*s++ == '\\') { + char *pp = p; + s[-1] = bb_process_escape_sequence((const char **)&pp); + if (*p == '\\') + *s++ = '\\'; + if (pp == p) + *s++ = *p++; + else + p = pp; + } + } + p++; + *s = '\0'; + tc = TC_REGEXP; + debug_printf_parse("%s: token found:'%s' TC_REGEXP\n", __func__, t_string); + + } else if (*p == '.' || isdigit(*p)) { + /* it's a number */ + char *pp = p; + t_double = my_strtod_or_hexoct(&pp); + /* ^^^ awk only allows hex/oct consts in _program_, not in _input_ */ + p = pp; + if (*p == '.') + syntax_error(EMSG_UNEXP_TOKEN); + tc = TC_NUMBER; + debug_printf_parse("%s: token found:%f TC_NUMBER\n", __func__, t_double); + } else { + char *end_of_name; + + if (*p == '\n') + t_lineno++; + + /* search for something known */ + tl = tokenlist; + tc = 0x00000001; + ti = tokeninfo; + while (*tl) { + int l = (unsigned char) *tl++; + if (l == (unsigned char) NTCC) { + tc <<= 1; + continue; + } + /* if token class is expected, + * token matches, + * and it's not a longer word, + */ + if ((tc & (expected | TS_WORD | TC_NEWLINE)) + && strncmp(p, tl, l) == 0 + && !((tc & TS_WORD) && isalnum_(p[l])) + ) { + /* then this is what we are looking for */ + t_info = *ti; + debug_printf_parse("%s: token found:'%.*s' t_info:%x\n", __func__, l, p, t_info); + p += l; + goto token_found; + } + ti++; + tl += l; + } + /* not a known token */ + + /* is it a name? (var/array/function) */ + if (!isalnum_(*p)) + syntax_error(EMSG_UNEXP_TOKEN); /* no */ + /* yes */ + t_string = p; + while (isalnum_(*p)) + p++; + end_of_name = p; + + if (last_token_class == TC_FUNCDECL) + /* eat space in "function FUNC (...) {...}" declaration */ + p = skip_spaces(p); + else if (expected & TC_ARRAY) { + /* eat space between array name and [ */ + char *s = skip_spaces(p); + if (*s == '[') /* array ref, not just a name? */ + p = s; + } + /* else: do NOT consume whitespace after variable name! + * gawk allows definition "function FUNC (p) {...}" - note space, + * but disallows the call "FUNC (p)" because it isn't one - + * expression "v (a)" should NOT be parsed as TC_FUNCTION: + * it is a valid concatenation if "v" is a variable, + * not a function name (and type of name is not known at parse time). + */ + + if (*p == '(') { + p++; + tc = TC_FUNCTION; + debug_printf_parse("%s: token found:'%s' TC_FUNCTION\n", __func__, t_string); + } else if (*p == '[') { + p++; + tc = TC_ARRAY; + debug_printf_parse("%s: token found:'%s' TC_ARRAY\n", __func__, t_string); + } else { + tc = TC_VARIABLE; + debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string); + if (end_of_name == p) { + /* there is no space for trailing NUL in t_string! + * We need to save the char we are going to NUL. + * (we'll use it in future call to next_token()) + */ + g_saved_ch = *end_of_name; +// especially pathological example is V="abc"; V.2 - it's V concatenated to .2 +// (it evaluates to "abc0.2"). Because of this case, we can't simply cache +// '.' and analyze it later: we also have to *store it back* in next +// next_token(), in order to give my_strtod() the undamaged ".2" string. + } + } + *end_of_name = '\0'; /* terminate t_string */ + } + token_found: + g_pos = p; + + /* skipping newlines in some cases */ + if ((last_token_class & TS_NOTERM) && (tc & TC_NEWLINE)) + goto readnext; + + /* insert concatenation operator when needed */ + debug_printf_parse("%s: concat_inserted if all nonzero: %x %x %x %x\n", __func__, + (last_token_class & TS_CONCAT_L), (tc & TS_CONCAT_R), (expected & TS_BINOP), + !(last_token_class == TC_LENGTH && tc == TC_LPAREN)); + if ((last_token_class & TS_CONCAT_L) && (tc & TS_CONCAT_R) && (expected & TS_BINOP) + && !(last_token_class == TC_LENGTH && tc == TC_LPAREN) /* but not for "length(..." */ + ) { + concat_inserted = TRUE; + save_tclass = tc; + save_info = t_info; + tc = TC_BINOPX; + t_info = OC_CONCAT | SS | PRECEDENCE(35); + } + + t_tclass = tc; + debug_printf_parse("%s: t_tclass=tc=%x\n", __func__, tc); + } + /* Are we ready for this? */ + if (!(t_tclass & expected)) { + syntax_error((last_token_class & (TC_NEWLINE | TC_EOF)) ? + EMSG_UNEXP_EOS : EMSG_UNEXP_TOKEN); + } + + debug_printf_parse("%s: returning, t_double:%f t_tclass:", __func__, t_double); + debug_parse_print_tc(t_tclass); + debug_printf_parse("\n"); + + return t_tclass; +#undef concat_inserted +#undef save_tclass +#undef save_info +} + +static ALWAYS_INLINE void rollback_token(void) +{ + t_rollback = TRUE; +} + +static node *new_node(uint32_t info) +{ + node *n; + + n = xzalloc(sizeof(node)); + n->info = info; + n->lineno = g_lineno; + return n; +} + +static void mk_re_node(const char *s, node *n, regex_t *re) +{ + n->info = TI_REGEXP; + n->l.re = re; + xregcomp(re, s, REG_EXTENDED); + xregcomp(re + 1, s, REG_EXTENDED | REG_ICASE); +} + +static node *parse_expr(uint32_t); + +static node *parse_lrparen_list(void) +{ + next_token(TC_LPAREN); + return parse_expr(TC_RPAREN); +} + +/* Parse expression terminated by given token, return ptr + * to built subtree. Terminator is eaten by parse_expr */ +static node *parse_expr(uint32_t term_tc) +{ + node sn; + node *cn = &sn; + node *getline_node; + uint32_t tc, expected_tc; + + debug_printf_parse("%s() term_tc(%x):", __func__, term_tc); + debug_parse_print_tc(term_tc); + debug_printf_parse("\n"); + + sn.info = LOWEST_PRECEDENCE; + sn.r.n = sn.a.n = getline_node = NULL; + expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP | term_tc; + + while (!((tc = next_token(expected_tc)) & term_tc)) { + node *vn; + + if (getline_node && (t_info == TI_LESS)) { + /* Attach input redirection (<) to getline node */ + debug_printf_parse("%s: input redir\n", __func__); + cn = getline_node->l.n = new_node(OC_CONCAT | SS | PRECEDENCE(37)); + cn->a.n = getline_node; + expected_tc = TS_OPERAND | TS_UOPPRE; + getline_node = NULL; + continue; + } + if (tc & (TS_BINOP | TC_UOPPOST)) { + debug_printf_parse("%s: TS_BINOP | TC_UOPPOST tc:%x\n", __func__, tc); + /* for binary and postfix-unary operators, jump back over + * previous operators with higher precedence */ + vn = cn; + while (((t_info & PRIMASK) > (vn->a.n->info & PRIMASK2)) + || (t_info == vn->info && t_info == TI_COLON) + ) { + vn = vn->a.n; + if (!vn->a.n) syntax_error(EMSG_UNEXP_TOKEN); + } + if (t_info == TI_TERNARY) /* "?" token */ +//TODO: why? + t_info += PRECEDENCE(6); + cn = vn->a.n->r.n = new_node(t_info); + cn->a.n = vn->a.n; + if (tc & TS_BINOP) { + cn->l.n = vn; + + /* Prevent: + * awk 'BEGIN { "qwe" = 1 }' + * awk 'BEGIN { 7 *= 7 }' + * awk 'BEGIN { length("qwe") = 1 }' + * awk 'BEGIN { (1+1) += 3 }' + */ + /* Assignment? (including *= and friends) */ + if (((t_info & OPCLSMASK) == OC_MOVE) + || ((t_info & OPCLSMASK) == OC_REPLACE) + ) { + debug_printf_parse("%s: MOVE/REPLACE vn->info:%08x\n", __func__, vn->info); + /* Left side is a (variable or array element) + * or function argument + * or $FIELD ? + */ + if ((vn->info & OPCLSMASK) != OC_VAR + && (vn->info & OPCLSMASK) != OC_FNARG + && (vn->info & OPCLSMASK) != OC_FIELD + ) { + syntax_error(EMSG_UNEXP_TOKEN); /* no. bad */ + } + } + + expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; + if (t_info == TI_PGETLINE) { /* "|" token */ + next_token(TC_GETLINE); /* must be folowed by "getline" */ + /* give maximum precedence to this pipe */ + cn->info &= ~PRIMASK; /* sets PRECEDENCE(0) */ + expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; + } + } else { + /* It was an unary postfix operator */ + cn->r.n = vn; + expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; + } + vn->a.n = cn; + continue; + } + /* It wasn't a binary or postfix-unary operator */ + + debug_printf_parse("%s: other, t_info:%x\n", __func__, t_info); + /* for operands and prefix-unary operators, attach them + * to last node */ + vn = cn; + cn = vn->r.n = new_node(t_info); + cn->a.n = vn; + + expected_tc = TS_OPERAND | TS_UOPPRE | TC_REGEXP; + if (t_info == TI_PREINC || t_info == TI_PREDEC) + expected_tc = TS_LVALUE | TC_UOPPRE1; + + if (!(tc & (TS_OPERAND | TC_REGEXP))) + continue; + + debug_printf_parse("%s: TS_OPERAND | TC_REGEXP\n", __func__); + expected_tc = TS_UOPPRE | TC_UOPPOST | TS_BINOP | TS_OPERAND | term_tc; + /* one should be very careful with switch on tclass - + * only simple tclasses should be used (TC_xyz, not TS_xyz) */ + switch (tc) { + var *v; + + case TC_VARIABLE: + case TC_ARRAY: + debug_printf_parse("%s: TC_VARIABLE | TC_ARRAY\n", __func__); + cn->info = OC_VAR; + v = hash_search(ahash, t_string); + if (v != NULL) { + cn->info = OC_FNARG; + cn->l.aidx = v->x.aidx; + } else { + cn->l.v = newvar(t_string); + } + if (tc & TC_ARRAY) { + cn->info |= xS; + cn->r.n = parse_expr(TC_ARRTERM); + } + break; + + case TC_NUMBER: + case TC_STRING: + debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); + cn->info = OC_CONST; + v = cn->l.v = xzalloc(sizeof(var)); + if (tc & TC_NUMBER) { + setvar_i(v, t_double); + } else { + setvar_s(v, t_string); + } + expected_tc &= ~TC_UOPPOST; /* NUM++, "str"++ not allowed */ + break; + + case TC_REGEXP: + debug_printf_parse("%s: TC_REGEXP\n", __func__); + mk_re_node(t_string, cn, xzalloc(sizeof(regex_t)*2)); + break; + + case TC_FUNCTION: + debug_printf_parse("%s: TC_FUNCTION\n", __func__); + cn->info = OC_FUNC; + cn->r.f = newfunc(t_string); + cn->l.n = parse_expr(TC_RPAREN); + break; + + case TC_LPAREN: + debug_printf_parse("%s: TC_LPAREN\n", __func__); + cn = vn->r.n = parse_expr(TC_RPAREN); + if (!cn) + syntax_error("Empty sequence"); + cn->a.n = vn; + break; + + case TC_GETLINE: + /* "getline" is a function, not a statement. + * Works in gawk: + * r = ["SHELL CMD" | ] getline [VAR] [<"FILE"] + * if (getline <"FILE" < 0) print "Can't read FILE" + * while ("SHELL CMD" | getline > 0) ... + * Returns: 1 successful read, 0 EOF, -1 error (sets ERRNO) + */ + debug_printf_parse("%s: TC_GETLINE\n", __func__); + getline_node = cn; + expected_tc = TS_OPERAND | TS_UOPPRE | TS_BINOP | term_tc; + break; + + case TC_BUILTIN: + debug_printf_parse("%s: TC_BUILTIN\n", __func__); + cn->l.n = parse_lrparen_list(); + break; + + case TC_LENGTH: + debug_printf_parse("%s: TC_LENGTH\n", __func__); + tc = next_token(TC_LPAREN /* length(...) */ + | TC_SEMICOL /* length; */ + | TC_NEWLINE /* length */ + | TC_RBRACE /* length } */ + | TC_BINOPX /* length NUM */ + | TC_COMMA /* print length, 1 */ + ); + if (tc != TC_LPAREN) + rollback_token(); + else { + /* It was a "(" token. Handle just like TC_BUILTIN */ + cn->l.n = parse_expr(TC_RPAREN); + } + break; + } + } /* while() */ + + debug_printf_parse("%s() returns %p\n", __func__, sn.r.n); + return sn.r.n; +} + +/* add node to chain. Return ptr to alloc'd node */ +static node *chain_node(uint32_t info) +{ + node *n; + + if (!seq->first) + seq->first = seq->last = new_node(0); + + if (seq->programname != g_progname) { + seq->programname = g_progname; + n = chain_node(OC_NEWSOURCE); + n->l.new_progname = g_progname; + } + + n = seq->last; + n->info = info; + seq->last = n->a.n = new_node(OC_DONE); + + return n; +} + +static void chain_expr(uint32_t info) +{ + node *n; + + n = chain_node(info); + + n->l.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_RBRACE); + if ((info & OF_REQUIRED) && !n->l.n) + syntax_error(EMSG_TOO_FEW_ARGS); + + if (t_tclass & TC_RBRACE) + rollback_token(); +} + +static void chain_group(void); + +static node *chain_loop(node *nn) +{ + node *n, *n2, *save_brk, *save_cont; + + save_brk = break_ptr; + save_cont = continue_ptr; + + n = chain_node(OC_BR | Vx); + continue_ptr = new_node(OC_EXEC); + break_ptr = new_node(OC_EXEC); + chain_group(); + n2 = chain_node(OC_EXEC | Vx); + n2->l.n = nn; + n2->a.n = n; + continue_ptr->a.n = n2; + break_ptr->a.n = n->r.n = seq->last; + + continue_ptr = save_cont; + break_ptr = save_brk; + + return n; +} + +static void chain_until_rbrace(void) +{ + uint32_t tc; + while ((tc = next_token(TS_GRPSEQ | TC_RBRACE)) != TC_RBRACE) { + debug_printf_parse("%s: !TC_RBRACE\n", __func__); + if (tc == TC_NEWLINE) + continue; + rollback_token(); + chain_group(); + } + debug_printf_parse("%s: TC_RBRACE\n", __func__); +} + +/* parse group and attach it to chain */ +static void chain_group(void) +{ + uint32_t tc; + node *n, *n2, *n3; + + do { + tc = next_token(TS_GRPSEQ); + } while (tc == TC_NEWLINE); + + if (tc == TC_LBRACE) { + debug_printf_parse("%s: TC_LBRACE\n", __func__); + chain_until_rbrace(); + return; + } + if (tc & (TS_OPSEQ | TC_SEMICOL)) { + debug_printf_parse("%s: TS_OPSEQ | TC_SEMICOL\n", __func__); + rollback_token(); + chain_expr(OC_EXEC | Vx); + return; + } + + /* TS_STATEMNT */ + debug_printf_parse("%s: TS_STATEMNT(?)\n", __func__); + switch (t_info & OPCLSMASK) { + case ST_IF: + debug_printf_parse("%s: ST_IF\n", __func__); + n = chain_node(OC_BR | Vx); + n->l.n = parse_lrparen_list(); + chain_group(); + n2 = chain_node(OC_EXEC); + n->r.n = seq->last; + if (next_token(TS_GRPSEQ | TC_RBRACE | TC_ELSE) == TC_ELSE) { + chain_group(); + n2->a.n = seq->last; + } else { + rollback_token(); + } + break; + + case ST_WHILE: + debug_printf_parse("%s: ST_WHILE\n", __func__); + n2 = parse_lrparen_list(); + n = chain_loop(NULL); + n->l.n = n2; + break; + + case ST_DO: + debug_printf_parse("%s: ST_DO\n", __func__); + n2 = chain_node(OC_EXEC); + n = chain_loop(NULL); + n2->a.n = n->a.n; + next_token(TC_WHILE); + n->l.n = parse_lrparen_list(); + break; + + case ST_FOR: + debug_printf_parse("%s: ST_FOR\n", __func__); + next_token(TC_LPAREN); + n2 = parse_expr(TC_SEMICOL | TC_RPAREN); + if (t_tclass & TC_RPAREN) { /* for (I in ARRAY) */ + if (!n2 || n2->info != TI_IN) + syntax_error(EMSG_UNEXP_TOKEN); + n = chain_node(OC_WALKINIT | VV); + n->l.n = n2->l.n; + n->r.n = n2->r.n; + n = chain_loop(NULL); + n->info = OC_WALKNEXT | Vx; + n->l.n = n2->l.n; + } else { /* for (;;) */ + n = chain_node(OC_EXEC | Vx); + n->l.n = n2; + n2 = parse_expr(TC_SEMICOL); + n3 = parse_expr(TC_RPAREN); + n = chain_loop(n3); + n->l.n = n2; + if (!n2) + n->info = OC_EXEC; + } + break; + + case OC_PRINT: + case OC_PRINTF: + debug_printf_parse("%s: OC_PRINT[F]\n", __func__); + n = chain_node(t_info); + n->l.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_OUTRDR | TC_RBRACE); + if (t_tclass & TC_OUTRDR) { + n->info |= t_info; + n->r.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_RBRACE); + } + if (t_tclass & TC_RBRACE) + rollback_token(); + break; + + case OC_BREAK: + debug_printf_parse("%s: OC_BREAK\n", __func__); + n = chain_node(OC_EXEC); + if (!break_ptr) + syntax_error("'break' not in a loop"); + n->a.n = break_ptr; + chain_expr(t_info); + break; + + case OC_CONTINUE: + debug_printf_parse("%s: OC_CONTINUE\n", __func__); + n = chain_node(OC_EXEC); + if (!continue_ptr) + syntax_error("'continue' not in a loop"); + n->a.n = continue_ptr; + chain_expr(t_info); + break; + + /* delete, next, nextfile, return, exit */ + default: + debug_printf_parse("%s: default\n", __func__); + chain_expr(t_info); + } +} + +static void parse_program(char *p) +{ + debug_printf_parse("%s()\n", __func__); + + g_pos = p; + t_lineno = 1; + for (;;) { + uint32_t tclass; + + tclass = next_token(TS_OPSEQ | TC_LBRACE | TC_BEGIN | TC_END | TC_FUNCDECL + | TC_EOF | TC_NEWLINE /* but not TC_SEMICOL */); + got_tok: + if (tclass == TC_EOF) { + debug_printf_parse("%s: TC_EOF\n", __func__); + break; + } + if (tclass == TC_NEWLINE) { + debug_printf_parse("%s: TC_NEWLINE\n", __func__); + continue; + } + if (tclass == TC_BEGIN) { + debug_printf_parse("%s: TC_BEGIN\n", __func__); + seq = &beginseq; + /* ensure there is no newline between BEGIN and { */ + next_token(TC_LBRACE); + chain_until_rbrace(); + goto next_tok; + } + if (tclass == TC_END) { + debug_printf_parse("%s: TC_END\n", __func__); + seq = &endseq; + /* ensure there is no newline between END and { */ + next_token(TC_LBRACE); + chain_until_rbrace(); + goto next_tok; + } + if (tclass == TC_FUNCDECL) { + func *f; + + debug_printf_parse("%s: TC_FUNCDECL\n", __func__); + next_token(TC_FUNCTION); + f = newfunc(t_string); + if (f->defined) + syntax_error("Duplicate function"); + f->defined = 1; + //f->body.first = NULL; - already is + //f->nargs = 0; - already is + /* func arg list: comma sep list of args, and a close paren */ + for (;;) { + var *v; + if (next_token(TC_VARIABLE | TC_RPAREN) == TC_RPAREN) { + if (f->nargs == 0) + break; /* func() is ok */ + /* func(a,) is not ok */ + syntax_error(EMSG_UNEXP_TOKEN); + } + v = findvar(ahash, t_string); + v->x.aidx = f->nargs++; + /* Arg followed either by end of arg list or 1 comma */ + if (next_token(TC_COMMA | TC_RPAREN) == TC_RPAREN) + break; + /* it was a comma, we ate it */ + } + seq = &f->body; + /* ensure there is { after "func F(...)" - but newlines are allowed */ + while (next_token(TC_LBRACE | TC_NEWLINE) == TC_NEWLINE) + continue; + chain_until_rbrace(); + hash_clear(ahash); + goto next_tok; + } + seq = &mainseq; + if (tclass & TS_OPSEQ) { + node *cn; + + debug_printf_parse("%s: TS_OPSEQ\n", __func__); + rollback_token(); + cn = chain_node(OC_TEST); + cn->l.n = parse_expr(TC_SEMICOL | TC_NEWLINE | TC_EOF | TC_LBRACE); + if (t_tclass == TC_LBRACE) { + debug_printf_parse("%s: TC_LBRACE\n", __func__); + chain_until_rbrace(); + } else { + /* no action, assume default "{ print }" */ + debug_printf_parse("%s: !TC_LBRACE\n", __func__); + chain_node(OC_PRINT); + } + cn->r.n = mainseq.last; + goto next_tok; + } + /* tclass == TC_LBRACE */ + debug_printf_parse("%s: TC_LBRACE(?)\n", __func__); + chain_until_rbrace(); + next_tok: + /* Same as next_token() at the top of the loop, + TC_SEMICOL */ + tclass = next_token(TS_OPSEQ | TC_LBRACE | TC_BEGIN | TC_END | TC_FUNCDECL + | TC_EOF | TC_NEWLINE | TC_SEMICOL); + /* gawk allows many newlines, but does not allow more than one semicolon: + * BEGIN {...};; + * would complain "each rule must have a pattern or an action part". + * Same message for + * ; BEGIN {...} + */ + if (tclass != TC_SEMICOL) + goto got_tok; /* use this token */ + /* else: loop back - ate the semicolon, get and use _next_ token */ + } /* for (;;) */ +} + +/* -------- program execution part -------- */ + +/* temporary variables allocator */ +static var *nvalloc(int sz) +{ + return xzalloc(sz * sizeof(var)); +} + +static void nvfree(var *v, int sz) +{ + var *p = v; + + while (--sz >= 0) { + if ((p->type & (VF_ARRAY | VF_CHILD)) == VF_ARRAY) { + clear_array(iamarray(p)); + free(p->x.array->items); + free(p->x.array); + } + if (p->type & VF_WALK) { + walker_list *n; + walker_list *w = p->x.walker; + debug_printf_walker("nvfree: freeing walker @%p\n", &p->x.walker); + p->x.walker = NULL; + while (w) { + n = w->prev; + debug_printf_walker(" free(%p)\n", w); + free(w); + w = n; + } + } + clrvar(p); + p++; + } + + free(v); +} + +static node *mk_splitter(const char *s, tsplitter *spl) +{ + regex_t *re; + node *n; + + re = spl->re; + n = &spl->n; + if (n->info == TI_REGEXP) { + regfree(re); + regfree(re + 1); + } + if (s[0] && s[1]) { /* strlen(s) > 1 */ + mk_re_node(s, n, re); + } else { + n->info = (uint32_t) s[0]; + } + + return n; +} + +static var *evaluate(node *, var *); + +/* Use node as a regular expression. Supplied with node ptr and regex_t + * storage space. Return ptr to regex (if result points to preg, it should + * be later regfree'd manually). + */ +static regex_t *as_regex(node *op, regex_t *preg) +{ + int cflags; + const char *s; + + if (op->info == TI_REGEXP) { + return &op->l.re[icase]; + } + + //tmpvar = nvalloc(1); +#define TMPVAR (&G.as_regex__tmpvar) + // We use a single "static" tmpvar (instead of on-stack or malloced one) + // to decrease memory consumption in deeply-recursive awk programs. + // The rule to work safely is to never call evaluate() while our static + // TMPVAR's value is still needed. + s = getvar_s(evaluate(op, TMPVAR)); + + cflags = icase ? REG_EXTENDED | REG_ICASE : REG_EXTENDED; + /* Testcase where REG_EXTENDED fails (unpaired '{'): + * echo Hi | awk 'gsub("@(samp|code|file)\{","");' + * gawk 3.1.5 eats this. We revert to ~REG_EXTENDED + * (maybe gsub is not supposed to use REG_EXTENDED?). + */ + if (regcomp(preg, s, cflags)) { + cflags &= ~REG_EXTENDED; + xregcomp(preg, s, cflags); + } + //nvfree(tmpvar, 1); +#undef TMPVAR + return preg; +} + +/* gradually increasing buffer. + * note that we reallocate even if n == old_size, + * and thus there is at least one extra allocated byte. + */ +static char* qrealloc(char *b, int n, int *size) +{ + if (!b || n >= *size) { + *size = n + (n>>1) + 80; + b = xrealloc(b, *size); + } + return b; +} + +/* resize field storage space */ +static void fsrealloc(int size) +{ + int i, newsize; + + if ((unsigned)size >= num_alloc_fields) { + /* Sanity cap, easier than catering for over/underflows */ + if ((unsigned)size > 0xffffff) + bb_die_memory_exhausted(); + + i = num_alloc_fields; + num_alloc_fields = size + 16; + + newsize = num_alloc_fields * sizeof(Fields[0]); + debug_printf_eval("fsrealloc: xrealloc(%p, %u)\n", Fields, newsize); + Fields = xrealloc(Fields, newsize); + debug_printf_eval("fsrealloc: Fields=%p..%p\n", Fields, (char*)Fields + newsize - 1); + /* ^^^ did Fields[] move? debug aid for L.v getting "upstaged" by R.v in evaluate() */ + + for (; i < num_alloc_fields; i++) { + Fields[i].type = VF_SPECIAL | VF_DIRTY; + Fields[i].string = NULL; + } + } + /* if size < num_fields, clear extra field variables */ + for (i = size; i < num_fields; i++) { + clrvar(Fields + i); + } + num_fields = size; +} + +static int regexec1_nonempty(const regex_t *preg, const char *s, regmatch_t pmatch[]) +{ + int r = regexec(preg, s, 1, pmatch, 0); + if (r == 0 && pmatch[0].rm_eo == 0) { + /* For example, happens when FS can match + * an empty string (awk -F ' *'). Logically, + * this should split into one-char fields. + * However, gawk 5.0.1 searches for first + * _non-empty_ separator string match: + */ + size_t ofs = 0; + do { + ofs++; + if (!s[ofs]) + return REG_NOMATCH; + regexec(preg, s + ofs, 1, pmatch, 0); + } while (pmatch[0].rm_eo == 0); + pmatch[0].rm_so += ofs; + pmatch[0].rm_eo += ofs; + } + return r; +} + +static int awk_split(const char *s, node *spl, char **slist) +{ + int n; + char c[4]; + char *s1; + + /* in worst case, each char would be a separate field */ + *slist = s1 = xzalloc(strlen(s) * 2 + 3); + strcpy(s1, s); + + c[0] = c[1] = (char)spl->info; + c[2] = c[3] = '\0'; + if (*getvar_s(intvar[RS]) == '\0') + c[2] = '\n'; + + n = 0; + if (spl->info == TI_REGEXP) { /* regex split */ + if (!*s) + return n; /* "": zero fields */ + n++; /* at least one field will be there */ + do { + int l; + regmatch_t pmatch[1]; + + l = strcspn(s, c+2); /* len till next NUL or \n */ + if (regexec1_nonempty(&spl->l.re[icase], s, pmatch) == 0 + && pmatch[0].rm_so <= l + ) { + /* if (pmatch[0].rm_eo == 0) ... - impossible */ + l = pmatch[0].rm_so; + n++; /* we saw yet another delimiter */ + } else { + pmatch[0].rm_eo = l; + if (s[l]) + pmatch[0].rm_eo++; + } + s1 = mempcpy(s1, s, l); + *s1++ = '\0'; + s += pmatch[0].rm_eo; + } while (*s); + + /* echo a-- | awk -F-- '{ print NF, length($NF), $NF }' + * should print "2 0 ": + */ + *s1 = '\0'; + + return n; + } + if (c[0] == '\0') { /* null split */ + while (*s) { + *s1++ = *s++; + *s1++ = '\0'; + n++; + } + return n; + } + if (c[0] != ' ') { /* single-character split */ + if (icase) { + c[0] = toupper(c[0]); + c[1] = tolower(c[1]); + } + if (*s1) + n++; + while ((s1 = strpbrk(s1, c)) != NULL) { + *s1++ = '\0'; + n++; + } + return n; + } + /* space split: "In the special case that FS is a single space, + * fields are separated by runs of spaces and/or tabs and/or newlines" + */ + while (*s) { + /* s = skip_whitespace(s); -- WRONG (also skips \v \f \r) */ + while (*s == ' ' || *s == '\t' || *s == '\n') + s++; + if (!*s) + break; + n++; + while (*s && !(*s == ' ' || *s == '\t' || *s == '\n')) + *s1++ = *s++; + *s1++ = '\0'; + } + return n; +} + +static void split_f0(void) +{ +/* static char *fstrings; */ +#define fstrings (G.split_f0__fstrings) + + int i, n; + char *s; + + if (is_f0_split) + return; + + is_f0_split = TRUE; + free(fstrings); + fsrealloc(0); + n = awk_split(getvar_s(intvar[F0]), &fsplitter.n, &fstrings); + fsrealloc(n); + s = fstrings; + for (i = 0; i < n; i++) { + Fields[i].string = nextword(&s); + Fields[i].type |= (VF_FSTR | VF_USER | VF_DIRTY); + } + + /* set NF manually to avoid side effects */ + clrvar(intvar[NF]); + intvar[NF]->type = VF_NUMBER | VF_SPECIAL; + intvar[NF]->number = num_fields; +#undef fstrings +} + +/* perform additional actions when some internal variables changed */ +static void handle_special(var *v) +{ + int n; + char *b; + const char *sep, *s; + int sl, l, len, i, bsize; + + if (!(v->type & VF_SPECIAL)) + return; + + if (v == intvar[NF]) { + n = (int)getvar_i(v); + if (n < 0) + syntax_error("NF set to negative value"); + fsrealloc(n); + + /* recalculate $0 */ + sep = getvar_s(intvar[OFS]); + sl = strlen(sep); + b = NULL; + len = 0; + for (i = 0; i < n; i++) { + s = getvar_s(&Fields[i]); + l = strlen(s); + if (b) { + memcpy(b+len, sep, sl); + len += sl; + } + b = qrealloc(b, len+l+sl, &bsize); + memcpy(b+len, s, l); + len += l; + } + if (b) + b[len] = '\0'; + setvar_p(intvar[F0], b); + is_f0_split = TRUE; + + } else if (v == intvar[F0]) { + is_f0_split = FALSE; + + } else if (v == intvar[FS]) { + /* + * The POSIX-2008 standard says that changing FS should have no effect on the + * current input line, but only on the next one. The language is: + * + * > Before the first reference to a field in the record is evaluated, the record + * > shall be split into fields, according to the rules in Regular Expressions, + * > using the value of FS that was current at the time the record was read. + * + * So, split up current line before assignment to FS: + */ + split_f0(); + + mk_splitter(getvar_s(v), &fsplitter); + } else if (v == intvar[RS]) { + mk_splitter(getvar_s(v), &rsplitter); + } else if (v == intvar[IGNORECASE]) { + icase = istrue(v); + } else { /* $n */ + n = getvar_i(intvar[NF]); + setvar_i(intvar[NF], n > v-Fields ? n : v-Fields+1); + /* right here v is invalid. Just to note... */ + } +} + +/* step through func/builtin/etc arguments */ +static node *nextarg(node **pn) +{ + node *n; + + n = *pn; + if (n && n->info == TI_COMMA) { + *pn = n->r.n; + n = n->l.n; + } else { + *pn = NULL; + } + return n; +} + +static void hashwalk_init(var *v, xhash *array) +{ + hash_item *hi; + unsigned i; + walker_list *w; + walker_list *prev_walker; + + if (v->type & VF_WALK) { + prev_walker = v->x.walker; + } else { + v->type |= VF_WALK; + prev_walker = NULL; + } + debug_printf_walker("hashwalk_init: prev_walker:%p\n", prev_walker); + + w = v->x.walker = xzalloc(sizeof(*w) + array->glen + 1); /* why + 1? */ + debug_printf_walker(" walker@%p=%p\n", &v->x.walker, w); + w->cur = w->end = w->wbuf; + w->prev = prev_walker; + for (i = 0; i < array->csize; i++) { + hi = array->items[i]; + while (hi) { + w->end = stpcpy(w->end, hi->name) + 1; + hi = hi->next; + } + } +} + +static int hashwalk_next(var *v) +{ + walker_list *w = v->x.walker; + + if (w->cur >= w->end) { + walker_list *prev_walker = w->prev; + + debug_printf_walker("end of iteration, free(walker@%p:%p), prev_walker:%p\n", &v->x.walker, w, prev_walker); + free(w); + v->x.walker = prev_walker; + return FALSE; + } + + setvar_s(v, nextword(&w->cur)); + return TRUE; +} + +/* evaluate node, return 1 when result is true, 0 otherwise */ +static int ptest(node *pattern) +{ + // We use a single "static" tmpvar (instead of on-stack or malloced one) + // to decrease memory consumption in deeply-recursive awk programs. + // The rule to work safely is to never call evaluate() while our static + // TMPVAR's value is still needed. + return istrue(evaluate(pattern, &G.ptest__tmpvar)); +} + +/* read next record from stream rsm into a variable v */ +static int awk_getline(rstream *rsm, var *v) +{ + char *b; + regmatch_t pmatch[1]; + int p, pp; + int fd, so, eo, retval, rp; + char *m, *s; + + debug_printf_eval("entered %s()\n", __func__); + + /* we're using our own buffer since we need access to accumulating + * characters + */ + fd = fileno(rsm->F); + m = rsm->buffer; + if (!m) + m = qrealloc(m, 256, &rsm->size); + p = rsm->pos; + rp = 0; + pp = 0; + + do { + b = m + rsm->adv; + so = eo = p; + retval = 1; + if (p > 0) { + char c = (char) rsplitter.n.info; + if (rsplitter.n.info == TI_REGEXP) { + if (regexec(&rsplitter.n.l.re[icase], + b, 1, pmatch, 0) == 0 + ) { + so = pmatch[0].rm_so; + eo = pmatch[0].rm_eo; + if (b[eo] != '\0') + break; + } + } else if (c != '\0') { + s = strchr(b+pp, c); + if (!s) + s = memchr(b+pp, '\0', p - pp); + if (s) { + so = eo = s-b; + eo++; + break; + } + } else { + while (b[rp] == '\n') + rp++; + s = strstr(b+rp, "\n\n"); + if (s) { + so = eo = s-b; + while (b[eo] == '\n') + eo++; + if (b[eo] != '\0') + break; + } + } + } + + if (rsm->adv > 0) { + memmove(m, m+rsm->adv, p+1); + b = m; + rsm->adv = 0; + } + + b = m = qrealloc(m, p+128, &rsm->size); + pp = p; + p += safe_read(fd, b+p, rsm->size - p - 1); + if (p < pp) { + p = 0; + retval = 0; + setvar_ERRNO(); + } + b[p] = '\0'; + } while (p > pp); + + if (p == 0) { + retval--; + } else { + setvar_sn(v, b+rp, so-rp); + v->type |= VF_USER; + setvar_sn(intvar[RT], b+so, eo-so); + } + + rsm->buffer = m; + rsm->adv += eo; + rsm->pos = p - eo; + + debug_printf_eval("returning from %s(): %d\n", __func__, retval); + + return retval; +} + +/* formatted output into an allocated buffer, return ptr to buffer */ +#if !ENABLE_FEATURE_AWK_GNU_EXTENSIONS +# define awk_printf(a, b) awk_printf(a) +#endif +static char *awk_printf(node *n, size_t *len) +{ + char *b; + char *fmt, *f; + size_t i; + + //tmpvar = nvalloc(1); +#define TMPVAR (&G.awk_printf__tmpvar) + // We use a single "static" tmpvar (instead of on-stack or malloced one) + // to decrease memory consumption in deeply-recursive awk programs. + // The rule to work safely is to never call evaluate() while our static + // TMPVAR's value is still needed. + fmt = f = xstrdup(getvar_s(evaluate(nextarg(&n), TMPVAR))); + // ^^^^^^^^^ here we immediately strdup() the value, so the later call + // to evaluate() potentially recursing into another awk_printf() can't + // mangle the value. + + b = NULL; + i = 0; + while (1) { /* "print one format spec" loop */ + char *s; + char c; + char sv; + var *arg; + size_t slen; + + /* Find end of the next format spec, or end of line */ + s = f; + while (1) { + c = *f; + if (!c) /* no percent chars found at all */ + goto nul; + f++; + if (c == '%') + break; + } + /* we are past % in "....%..." */ + c = *f; + if (!c) /* "....%" */ + goto nul; + if (c == '%') { /* "....%%...." */ + slen = f - s; + s = xstrndup(s, slen); + f++; + goto append; /* print "....%" part verbatim */ + } + while (1) { + if (isalpha(c)) + break; + if (c == '*') /* gawk supports %*d and %*.*f, we don't... */ + syntax_error("%*x formats are not supported"); + c = *++f; + if (!c) { /* "....%...." and no letter found after % */ + /* Example: awk 'BEGIN { printf "^^^%^^^\n"; }' */ + nul: + slen = f - s; + goto tail; /* print remaining string, exit loop */ + } + } + /* we are at A in "....%...A..." */ + + arg = evaluate(nextarg(&n), TMPVAR); + + /* Result can be arbitrarily long. Example: + * printf "%99999s", "BOOM" + */ + sv = *++f; + *f = '\0'; + if (c == 'c') { + char cc = is_numeric(arg) ? getvar_i(arg) : *getvar_s(arg); + char *r = xasprintf(s, cc ? cc : '^' /* else strlen will be wrong */); + slen = strlen(r); + if (cc == '\0') /* if cc is NUL, re-format the string with it */ + sprintf(r, s, cc); + s = r; + } else { + if (c == 's') { + s = xasprintf(s, getvar_s(arg)); + } else { + double d = getvar_i(arg); + if (strchr("diouxX", c)) { +//TODO: make it wider here (%x -> %llx etc)? +//Can even print the value into a temp string with %.0f, +//then replace diouxX with s and print that string. +//This will correctly print even very large numbers, +//but some replacements are not equivalent: +//%09d -> %09s: breaks zero-padding; +//%+d -> %+s: won't prepend +; etc + s = xasprintf(s, (int)d); + } else if (strchr("eEfFgGaA", c)) { + s = xasprintf(s, d); + } else { + /* gawk 5.1.1 printf("%W") prints "%W", does not error out */ + s = xstrndup(s, f - s); + } + } + slen = strlen(s); + } + *f = sv; + append: + if (i == 0) { + b = s; + i = slen; + continue; + } + tail: + b = xrealloc(b, i + slen + 1); + strcpy(b + i, s); + i += slen; + if (!c) /* s is NOT allocated and this is the last part of string? */ + break; + free(s); + } + + free(fmt); + //nvfree(tmpvar, 1); +#undef TMPVAR + +#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS + if (len) + *len = i; +#endif + return b; +} + +/* Common substitution routine. + * Replace (nm)'th substring of (src) that matches (rn) with (repl), + * store result into (dest), return number of substitutions. + * If nm = 0, replace all matches. + * If src or dst is NULL, use $0. + * If subexp != 0, enable subexpression matching (\0-\9). + */ +static int awk_sub(node *rn, const char *repl, int nm, var *src, var *dest /*,int subexp*/) +{ + char *resbuf; + const char *sp; + int match_no, residx, replen, resbufsize; + int regexec_flags; + regmatch_t pmatch[10]; + regex_t sreg, *regex; + /* True only if called to implement gensub(): */ + int subexp = (src != dest); +#if defined(REG_STARTEND) + const char *src_string; + size_t src_strlen; + regexec_flags = REG_STARTEND; +#else + regexec_flags = 0; +#endif + resbuf = NULL; + residx = 0; + match_no = 0; + regex = as_regex(rn, &sreg); + sp = getvar_s(src ? src : intvar[F0]); +#if defined(REG_STARTEND) + src_string = sp; + src_strlen = strlen(src_string); +#endif + replen = strlen(repl); + for (;;) { + int so, eo; + +#if defined(REG_STARTEND) +// REG_STARTEND: "This flag is a BSD extension, not present in POSIX" + size_t start_ofs = sp - src_string; + pmatch[0].rm_so = start_ofs; + pmatch[0].rm_eo = src_strlen; + if (regexec(regex, src_string, 10, pmatch, regexec_flags) != 0) + break; + eo = pmatch[0].rm_eo - start_ofs; + so = pmatch[0].rm_so - start_ofs; +#else +// BUG: +// gsub(/\= nm) { + const char *s; + int bslash; + + /* replace */ + residx -= (eo - so); + bslash = 0; + for (s = repl; *s; s++) { + char c = *s; + if (c == '\\' && s[1]) { + bslash ^= 1; + if (bslash) + continue; + } + if ((!bslash && c == '&') + || (subexp && bslash && c >= '0' && c <= '9') + ) { + int n, j = 0; + if (c != '&') { + j = c - '0'; + } + n = pmatch[j].rm_eo - pmatch[j].rm_so; + resbuf = qrealloc(resbuf, residx + replen + n, &resbufsize); + memcpy(resbuf + residx, sp + pmatch[j].rm_so - start_ofs, n); + residx += n; + } else + resbuf[residx++] = c; + bslash = 0; + } + } + + sp += eo; + if (match_no == nm) + break; + if (eo == so) { + /* Empty match (e.g. "b*" will match anywhere). + * Advance by one char. */ + /* Subtle: this is safe only because + * qrealloc allocated at least one extra byte */ + resbuf[residx] = *sp; + if (*sp == '\0') + goto ret; + sp++; + residx++; + } + regexec_flags |= REG_NOTBOL; + } + + resbuf = qrealloc(resbuf, residx + strlen(sp), &resbufsize); + strcpy(resbuf + residx, sp); + ret: + //bb_error_msg("end sp:'%s'%p", sp,sp); + setvar_p(dest ? dest : intvar[F0], resbuf); + if (regex == &sreg) + regfree(regex); + return match_no; +} + +static NOINLINE int do_mktime(const char *ds) +{ + struct tm then; + int count; + + /*memset(&then, 0, sizeof(then)); - not needed */ + then.tm_isdst = -1; /* default is unknown */ + + /* manpage of mktime says these fields are ints, + * so we can sscanf stuff directly into them */ + count = sscanf(ds, "%u %u %u %u %u %u %d", + &then.tm_year, &then.tm_mon, &then.tm_mday, + &then.tm_hour, &then.tm_min, &then.tm_sec, + &then.tm_isdst); + + if (count < 6 + || (unsigned)then.tm_mon < 1 + || (unsigned)then.tm_year < 1900 + ) { + return -1; + } + + then.tm_mon -= 1; + then.tm_year -= 1900; + + return mktime(&then); +} + +/* Reduce stack usage in exec_builtin() by keeping match() code separate */ +static NOINLINE var *do_match(node *an1, const char *as0) +{ + regmatch_t pmatch[1]; + regex_t sreg, *re; + int n, start, len; + + re = as_regex(an1, &sreg); + n = regexec(re, as0, 1, pmatch, 0); + if (re == &sreg) + regfree(re); + start = 0; + len = -1; + if (n == 0) { + start = pmatch[0].rm_so + 1; + len = pmatch[0].rm_eo - pmatch[0].rm_so; + } + setvar_i(newvar("RLENGTH"), len); + return setvar_i(newvar("RSTART"), start); +} + +/* Reduce stack usage in evaluate() by keeping builtins' code separate */ +static NOINLINE var *exec_builtin(node *op, var *res) +{ +#define tspl (G.exec_builtin__tspl) + + var *tmpvars; + node *an[4]; + var *av[4]; + const char *as[4]; + node *spl; + uint32_t isr, info; + int nargs; + time_t tt; + int i, l, ll, n; + + tmpvars = nvalloc(4); +#define TMPVAR0 (tmpvars) +#define TMPVAR1 (tmpvars + 1) +#define TMPVAR2 (tmpvars + 2) +#define TMPVAR3 (tmpvars + 3) +#define TMPVAR(i) (tmpvars + (i)) + isr = info = op->info; + op = op->l.n; + + av[2] = av[3] = NULL; + for (i = 0; i < 4 && op; i++) { + an[i] = nextarg(&op); + if (isr & 0x09000000) { + av[i] = evaluate(an[i], TMPVAR(i)); + if (isr & 0x08000000) + as[i] = getvar_s(av[i]); + } + isr >>= 1; + } + + nargs = i; + if ((uint32_t)nargs < (info >> 30)) + syntax_error(EMSG_TOO_FEW_ARGS); + + info &= OPNMASK; + switch (info) { + + case B_a2: + if (ENABLE_FEATURE_AWK_LIBM) + setvar_i(res, atan2(getvar_i(av[0]), getvar_i(av[1]))); + else + syntax_error(EMSG_NO_MATH); + break; + + case B_sp: { + char *s, *s1; + + if (nargs > 2) { + spl = (an[2]->info == TI_REGEXP) ? an[2] + : mk_splitter(getvar_s(evaluate(an[2], TMPVAR2)), &tspl); + } else { + spl = &fsplitter.n; + } + + n = awk_split(as[0], spl, &s); + s1 = s; + clear_array(iamarray(av[1])); + for (i = 1; i <= n; i++) + setari_u(av[1], i, nextword(&s)); + free(s1); + setvar_i(res, n); + break; + } + + case B_ss: { + l = strlen(as[0]); + i = getvar_i(av[1]) - 1; + if (i > l) + i = l; + if (i < 0) + i = 0; + n = (nargs > 2) ? getvar_i(av[2]) : l-i; + if (n < 0) + n = 0; + setvar_sn(res, as[0]+i, n); + break; + } + + /* Bitwise ops must assume that operands are unsigned. GNU Awk 3.1.5: + * awk '{ print or(-1,1) }' gives "4.29497e+09", not "-2.xxxe+09" */ + case B_an: + setvar_i(res, getvar_i_int(av[0]) & getvar_i_int(av[1])); + break; + + case B_co: + setvar_i(res, ~getvar_i_int(av[0])); + break; + + case B_ls: + setvar_i(res, getvar_i_int(av[0]) << getvar_i_int(av[1])); + break; + + case B_or: + setvar_i(res, getvar_i_int(av[0]) | getvar_i_int(av[1])); + break; + + case B_rs: + setvar_i(res, getvar_i_int(av[0]) >> getvar_i_int(av[1])); + break; + + case B_xo: + setvar_i(res, getvar_i_int(av[0]) ^ getvar_i_int(av[1])); + break; + + case B_lo: + case B_up: { + char *s, *s1; + s1 = s = xstrdup(as[0]); + while (*s1) { + //*s1 = (info == B_up) ? toupper(*s1) : tolower(*s1); + if ((unsigned char)((*s1 | 0x20) - 'a') <= ('z' - 'a')) + *s1 = (info == B_up) ? (*s1 & 0xdf) : (*s1 | 0x20); + s1++; + } + setvar_p(res, s); + break; + } + + case B_ix: + n = 0; + ll = strlen(as[1]); + l = strlen(as[0]) - ll; + if (ll > 0 && l >= 0) { + if (!icase) { + char *s = strstr(as[0], as[1]); + if (s) + n = (s - as[0]) + 1; + } else { + /* this piece of code is terribly slow and + * really should be rewritten + */ + for (i = 0; i <= l; i++) { + if (strncasecmp(as[0]+i, as[1], ll) == 0) { + n = i+1; + break; + } + } + } + } + setvar_i(res, n); + break; + + case B_ti: + if (nargs > 1) + tt = getvar_i(av[1]); + else + time(&tt); + i = strftime(g_buf, MAXVARFMT, + ((nargs > 0) ? as[0] : "%a %b %d %H:%M:%S %Z %Y"), + localtime(&tt)); + setvar_sn(res, g_buf, i); + break; + + case B_mt: + setvar_i(res, do_mktime(as[0])); + break; + + case B_ma: + res = do_match(an[1], as[0]); + break; + + case B_ge: /* gensub(regex, repl, matchnum, string) */ + awk_sub(an[0], as[1], /*matchnum:*/getvar_i(av[2]), /*src:*/av[3], /*dst:*/res/*, TRUE*/); + break; + + case B_gs: /* gsub(regex, repl, string) */ + setvar_i(res, awk_sub(an[0], as[1], /*matchnum:all*/0, /*src:*/av[2], /*dst:*/av[2]/*, FALSE*/)); + break; + + case B_su: /* sub(regex, repl, string) */ + setvar_i(res, awk_sub(an[0], as[1], /*matchnum:first*/1, /*src:*/av[2], /*dst:*/av[2]/*, FALSE*/)); + break; + } + + nvfree(tmpvars, 4); +#undef TMPVAR0 +#undef TMPVAR1 +#undef TMPVAR2 +#undef TMPVAR3 +#undef TMPVAR + + return res; +#undef tspl +} + +/* if expr looks like "var=value", perform assignment and return 1, + * otherwise return 0 */ +static int try_to_assign(const char *expr) +{ + char *exprc, *val; + + val = (char*)endofname(expr); + if (val == (char*)expr || *val != '=') { + return FALSE; + } + + exprc = xstrdup(expr); + val = exprc + (val - expr); + *val++ = '\0'; + + unescape_string_in_place(val); + setvar_u(newvar(exprc), val); + free(exprc); + return TRUE; +} + +/* switch to next input file */ +static int next_input_file(void) +{ +#define input_file_seen (G.next_input_file__input_file_seen) +#define argind (G.next_input_file__argind) + const char *fname; + + if (iF.F) { + fclose(iF.F); + iF.F = NULL; + iF.pos = iF.adv = 0; + } + + for (;;) { + /* GNU Awk 5.1.1 does not _read_ ARGIND (but does read ARGC). + * It only sets ARGIND to 1, 2, 3... for every command-line filename + * (VAR=VAL params cause a gap in numbering). + * If there are none and stdin is used, then ARGIND is not modified: + * if it is set by e.g. 'BEGIN { ARGIND="foo" }', that value will + * still be there. + */ + argind++; + if (argind >= getvar_i(intvar[ARGC])) { + if (input_file_seen) + return FALSE; + fname = "-"; + iF.F = stdin; + break; + } + fname = getvar_s(findvar(iamarray(intvar[ARGV]), utoa(argind))); + if (fname && *fname) { + if (got_program != 2) { /* there was no -E option */ + /* "If a filename on the command line has the form + * var=val it is treated as a variable assignment" + */ + if (try_to_assign(fname)) + continue; + } + iF.F = xfopen_stdin(fname); + setvar_i(intvar[ARGIND], argind); + break; + } + } + + setvar_s(intvar[FILENAME], fname); + input_file_seen = TRUE; + return TRUE; +#undef argind +#undef input_file_seen +} + +/* + * Evaluate node - the heart of the program. Supplied with subtree + * and "res" variable to assign the result to if we evaluate an expression. + * If node refers to e.g. a variable or a field, no assignment happens. + * Return ptr to the result (which may or may not be the "res" variable!) + */ +#define XC(n) ((n) >> 8) + +static var *evaluate(node *op, var *res) +{ +/* This procedure is recursive so we should count every byte */ +#define fnargs (G.evaluate__fnargs) +/* seed is initialized to 1 */ +#define seed (G.evaluate__seed) +#define sreg (G.evaluate__sreg) + + var *tmpvars; + + if (!op) + return setvar_s(res, NULL); + + debug_printf_eval("entered %s()\n", __func__); + + tmpvars = nvalloc(2); +#define TMPVAR0 (tmpvars) +#define TMPVAR1 (tmpvars + 1) + + while (op) { + struct { + var *v; + const char *s; + } L = L; /* for compiler */ + struct { + var *v; + const char *s; + } R = R; + double L_d = L_d; + uint32_t opinfo; + int opn; + node *op1; + var *old_Fields_ptr; + + opinfo = op->info; + opn = (opinfo & OPNMASK); + g_lineno = op->lineno; + op1 = op->l.n; + debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); + + /* execute inevitable things */ + old_Fields_ptr = NULL; + if (opinfo & OF_RES1) { + if ((opinfo & OF_REQUIRED) && !op1) + syntax_error(EMSG_TOO_FEW_ARGS); + L.v = evaluate(op1, TMPVAR0); + /* Does L.v point to $n variable? */ + if ((size_t)(L.v - Fields) < num_alloc_fields) { + /* yes, remember where Fields[] is */ + old_Fields_ptr = Fields; + } + if (opinfo & OF_NUM1) { + L_d = getvar_i(L.v); + debug_printf_eval("L_d:%f\n", L_d); + } + } + /* NB: if both L and R are $NNNs, and right one is large, + * then at this pint L.v points to Fields[NNN1], second + * evaluate() below reallocates and moves (!) Fields[], + * R.v points to Fields[NNN2] but L.v now points to freed mem! + * (Seen trying to evaluate "$444 $44444") + */ + if (opinfo & OF_RES2) { + R.v = evaluate(op->r.n, TMPVAR1); + /* Seen in $5=$$5=$0: + * Evaluation of R.v ($$5=$0 expression) + * made L.v ($5) invalid. It's detected here. + */ + if (old_Fields_ptr) { + //if (old_Fields_ptr != Fields) + // debug_printf_eval("L.v moved\n"); + L.v = Fields + (L.v - old_Fields_ptr); + } + if (opinfo & OF_STR2) { + R.s = getvar_s(R.v); + debug_printf_eval("R.s:'%s'\n", R.s); + } + } + /* Get L.s _after_ R.v is evaluated: it may have realloc'd L.v + * so we must get the string after "old_Fields_ptr" correction + * above. Testcase: x = (v = "abc", gsub("b", "X", v)); + */ + if (opinfo & OF_RES1) { + if (opinfo & OF_STR1) { + L.s = getvar_s(L.v); + debug_printf_eval("L.s:'%s'\n", L.s); + } + } + + debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); + switch (XC(opinfo & OPCLSMASK)) { + + /* -- iterative node type -- */ + + /* test pattern */ + case XC( OC_TEST ): + debug_printf_eval("TEST\n"); + if (op1->info == TI_COMMA) { + /* it's range pattern */ + if ((opinfo & OF_CHECKED) || ptest(op1->l.n)) { + op->info |= OF_CHECKED; + if (ptest(op1->r.n)) + op->info &= ~OF_CHECKED; + op = op->a.n; + } else { + op = op->r.n; + } + } else { + op = ptest(op1) ? op->a.n : op->r.n; + } + break; + + /* just evaluate an expression, also used as unconditional jump */ + case XC( OC_EXEC ): + debug_printf_eval("EXEC\n"); + break; + + /* branch, used in if-else and various loops */ + case XC( OC_BR ): + debug_printf_eval("BR\n"); + op = istrue(L.v) ? op->a.n : op->r.n; + break; + + /* initialize for-in loop */ + case XC( OC_WALKINIT ): + debug_printf_eval("WALKINIT\n"); + hashwalk_init(L.v, iamarray(R.v)); + break; + + /* get next array item */ + case XC( OC_WALKNEXT ): + debug_printf_eval("WALKNEXT\n"); + op = hashwalk_next(L.v) ? op->a.n : op->r.n; + break; + + case XC( OC_PRINT ): + debug_printf_eval("PRINT /\n"); + case XC( OC_PRINTF ): + debug_printf_eval("PRINTF\n"); + { + FILE *F = stdout; + + if (op->r.n) { + rstream *rsm = newfile(R.s); + if (!rsm->F) { + if (opn == '|') { + rsm->F = popen(R.s, "w"); + if (rsm->F == NULL) + bb_simple_perror_msg_and_die("popen"); + rsm->is_pipe = 1; + } else { + rsm->F = xfopen(R.s, opn=='w' ? "w" : "a"); + } + } + F = rsm->F; + } + + /* Can't just check 'opinfo == OC_PRINT' here, parser ORs + * additional bits to opinfos of print/printf with redirects + */ + if ((opinfo & OPCLSMASK) == OC_PRINT) { + if (!op1) { + fputs(getvar_s(intvar[F0]), F); + } else { + for (;;) { + var *v = evaluate(nextarg(&op1), TMPVAR0); + if (v->type & VF_NUMBER) { + fputs(fmt_num(getvar_s(intvar[OFMT]), getvar_i(v)), + F); + } else { + fputs(getvar_s(v), F); + } + if (!op1) + break; + fputs(getvar_s(intvar[OFS]), F); + } + } + fputs(getvar_s(intvar[ORS]), F); + } else { /* PRINTF */ + IF_FEATURE_AWK_GNU_EXTENSIONS(size_t len;) + char *s = awk_printf(op1, &len); +#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS + fwrite(s, len, 1, F); +#else + fputs(s, F); +#endif + free(s); + } + fflush(F); + break; + } + + case XC( OC_DELETE ): + debug_printf_eval("DELETE\n"); + { + /* "delete" is special: + * "delete array[var--]" must evaluate index expr only once. + */ + uint32_t info = op1->info & OPCLSMASK; + var *v; + + if (info == OC_VAR) { + v = op1->l.v; + } else if (info == OC_FNARG) { + v = &fnargs[op1->l.aidx]; + } else { + syntax_error(EMSG_NOT_ARRAY); + } + if (op1->r.n) { /* array ref? */ + const char *s; + s = getvar_s(evaluate(op1->r.n, TMPVAR0)); + hash_remove(iamarray(v), s); + } else { + clear_array(iamarray(v)); + } + break; + } + + case XC( OC_NEWSOURCE ): + debug_printf_eval("NEWSOURCE\n"); + g_progname = op->l.new_progname; + break; + + case XC( OC_RETURN ): + debug_printf_eval("RETURN\n"); + copyvar(res, L.v); + break; + + case XC( OC_NEXTFILE ): + debug_printf_eval("NEXTFILE\n"); + nextfile = TRUE; + case XC( OC_NEXT ): + debug_printf_eval("NEXT\n"); + nextrec = TRUE; + case XC( OC_DONE ): + debug_printf_eval("DONE\n"); + clrvar(res); + break; + + case XC( OC_EXIT ): + debug_printf_eval("EXIT\n"); + if (op1) + G.exitcode = (int)L_d; + awk_exit(); + + /* -- recursive node type -- */ + + case XC( OC_CONST ): + debug_printf_eval("CONST "); + case XC( OC_VAR ): + debug_printf_eval("VAR\n"); + L.v = op->l.v; + if (L.v == intvar[NF]) + split_f0(); + goto v_cont; + + case XC( OC_FNARG ): + debug_printf_eval("FNARG[%d]\n", op->l.aidx); + L.v = &fnargs[op->l.aidx]; + v_cont: + res = op->r.n ? findvar(iamarray(L.v), R.s) : L.v; + break; + + case XC( OC_IN ): + debug_printf_eval("IN\n"); + setvar_i(res, hash_search(iamarray(R.v), L.s) ? 1 : 0); + break; + + case XC( OC_REGEXP ): + debug_printf_eval("REGEXP\n"); + op1 = op; + L.s = getvar_s(intvar[F0]); + goto re_cont; + + case XC( OC_MATCH ): + debug_printf_eval("MATCH\n"); + op1 = op->r.n; + re_cont: + { + regex_t *re = as_regex(op1, &sreg); + int i = regexec(re, L.s, 0, NULL, 0); + if (re == &sreg) + regfree(re); + setvar_i(res, (i == 0) ^ (opn == '!')); + } + break; + + case XC( OC_MOVE ): + debug_printf_eval("MOVE\n"); + /* make sure that we never return a temp var */ + if (L.v == TMPVAR0) + L.v = res; + /* if source is a temporary string, just relink it to dest */ + if (R.v == TMPVAR1 + && !(R.v->type & VF_NUMBER) + /* Why check !NUMBER? if R.v is a number but has cached R.v->string, + * L.v ends up a string, which is wrong */ + /*&& R.v->string - always not NULL (right?) */ + ) { + res = setvar_p(L.v, R.v->string); /* avoids strdup */ + R.v->string = NULL; + } else { + res = copyvar(L.v, R.v); + } + break; + + case XC( OC_TERNARY ): + debug_printf_eval("TERNARY\n"); + if (op->r.n->info != TI_COLON) + syntax_error(EMSG_POSSIBLE_ERROR); + res = evaluate(istrue(L.v) ? op->r.n->l.n : op->r.n->r.n, res); + break; + + case XC( OC_FUNC ): { + var *argvars, *sv_fnargs; + const char *sv_progname; + int nargs, i; + + debug_printf_eval("FUNC\n"); + + if (!op->r.f->defined) + syntax_error(EMSG_UNDEF_FUNC); + + /* The body might be empty, still has to eval the args */ + nargs = op->r.f->nargs; + argvars = nvalloc(nargs); + i = 0; + while (op1) { + var *arg = evaluate(nextarg(&op1), TMPVAR0); + if (i == nargs) { + /* call with more arguments than function takes. + * (gawk warns: "warning: function 'f' called with more arguments than declared"). + * They are still evaluated, but discarded: */ + clrvar(arg); + continue; + } + copyvar(&argvars[i], arg); + argvars[i].type |= VF_CHILD; + argvars[i].x.parent = arg; + i++; + } + + sv_fnargs = fnargs; + sv_progname = g_progname; + + fnargs = argvars; + res = evaluate(op->r.f->body.first, res); + nvfree(argvars, nargs); + + g_progname = sv_progname; + fnargs = sv_fnargs; + + break; + } + + case XC( OC_GETLINE ): + debug_printf_eval("GETLINE /\n"); + case XC( OC_PGETLINE ): + debug_printf_eval("PGETLINE\n"); + { + rstream *rsm; + int i; + + if (op1) { + rsm = newfile(L.s); + if (!rsm->F) { + /* NB: can't use "opinfo == TI_PGETLINE", would break "cmd" | getline */ + if ((opinfo & OPCLSMASK) == OC_PGETLINE) { + rsm->F = popen(L.s, "r"); + rsm->is_pipe = TRUE; + } else { + rsm->F = fopen_for_read(L.s); /* not xfopen! */ + } + } + } else { + if (!iF.F) + next_input_file(); + rsm = &iF; + } + + if (!rsm->F) { + setvar_ERRNO(); + setvar_i(res, -1); + break; + } + + if (!op->r.n) + R.v = intvar[F0]; + + i = awk_getline(rsm, R.v); + if (i > 0 && !op1) { + incvar(intvar[FNR]); + incvar(intvar[NR]); + } + setvar_i(res, i); + break; + } + + /* simple builtins */ + case XC( OC_FBLTIN ): { + double R_d = R_d; /* for compiler */ + debug_printf_eval("FBLTIN\n"); + + if (op1 && op1->info == TI_COMMA) + /* Simple builtins take one arg maximum */ + syntax_error("Too many arguments"); + + switch (opn) { + case F_in: + R_d = (long long)L_d; + break; + + case F_rn: /*rand*/ + if (op1) + syntax_error("Too many arguments"); + { +#if RAND_MAX >= 0x7fffffff + uint32_t u = ((uint32_t)rand() << 16) ^ rand(); + uint64_t v = ((uint64_t)rand() << 32) | u; + /* the above shift+or is optimized out on 32-bit arches */ +# if RAND_MAX > 0x7fffffff + v &= 0x7fffffffffffffffULL; +# endif + R_d = (double)v / 0x8000000000000000ULL; +#else +# error Not implemented for this value of RAND_MAX +#endif + break; + } + case F_co: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = cos(L_d); + break; + } + + case F_ex: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = exp(L_d); + break; + } + + case F_lg: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = log(L_d); + break; + } + + case F_si: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sin(L_d); + break; + } + + case F_sq: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sqrt(L_d); + break; + } + + syntax_error(EMSG_NO_MATH); + break; + + case F_sr: + R_d = (double)seed; + seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); + srand(seed); + break; + + case F_ti: /*systime*/ + if (op1) + syntax_error("Too many arguments"); + R_d = time(NULL); + break; + + case F_le: + debug_printf_eval("length: L.s:'%s'\n", L.s); + if (!op1) { + L.s = getvar_s(intvar[F0]); + debug_printf_eval("length: L.s='%s'\n", L.s); + } + else if (L.v->type & VF_ARRAY) { + R_d = L.v->x.array->nel; + debug_printf_eval("length: array_len:%d\n", L.v->x.array->nel); + break; + } + R_d = strlen(L.s); + break; + + case F_sy: + fflush_all(); + R_d = (ENABLE_FEATURE_ALLOW_EXEC && L.s && *L.s) + ? (system(L.s) >> 8) : 0; + break; + + case F_ff: + if (!op1) { + fflush(stdout); + } else if (L.s && *L.s) { + rstream *rsm = newfile(L.s); + fflush(rsm->F); + } else { + fflush_all(); + } + break; + + case F_cl: { + rstream *rsm; + int err = 0; + rsm = (rstream *)hash_search(fdhash, L.s); + debug_printf_eval("OC_FBLTIN close: op1:%p s:'%s' rsm:%p\n", op1, L.s, rsm); + if (rsm) { + debug_printf_eval("OC_FBLTIN F_cl " + "rsm->is_pipe:%d, ->F:%p\n", + rsm->is_pipe, rsm->F); + /* Can be NULL if open failed. Example: + * getline line <"doesnt_exist"; + * close("doesnt_exist"); <--- here rsm->F is NULL + */ + if (rsm->F) + err = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); + free(rsm->buffer); + hash_remove(fdhash, L.s); + } else { + err = -1; + /* gawk 'BEGIN { print close(""); print ERRNO }' + * -1 + * close of redirection that was never opened + */ + errno = ENOENT; + } + if (err) + setvar_ERRNO(); + R_d = (double)err; + break; + } + } /* switch */ + setvar_i(res, R_d); + break; + } + + case XC( OC_BUILTIN ): + debug_printf_eval("BUILTIN\n"); + res = exec_builtin(op, res); + break; + + case XC( OC_SPRINTF ): + debug_printf_eval("SPRINTF\n"); + setvar_p(res, awk_printf(op1, NULL)); + break; + + case XC( OC_UNARY ): + debug_printf_eval("UNARY\n"); + { + double Ld, R_d; + + Ld = R_d = getvar_i(R.v); + switch (opn) { + case 'P': + Ld = ++R_d; + goto r_op_change; + case 'p': + R_d++; + goto r_op_change; + case 'M': + Ld = --R_d; + goto r_op_change; + case 'm': + R_d--; + r_op_change: + setvar_i(R.v, R_d); + break; + case '!': + Ld = !istrue(R.v); + break; + case '-': + Ld = -R_d; + break; + } + setvar_i(res, Ld); + break; + } + + case XC( OC_FIELD ): + debug_printf_eval("FIELD\n"); + { + int i = (int)getvar_i(R.v); + if (i < 0) + syntax_error(EMSG_NEGATIVE_FIELD); + if (i == 0) { + res = intvar[F0]; + } else { + split_f0(); + if (i > num_fields) + fsrealloc(i); + res = &Fields[i - 1]; + } + break; + } + + /* concatenation (" ") and index joining (",") */ + case XC( OC_CONCAT ): + debug_printf_eval("CONCAT /\n"); + case XC( OC_COMMA ): { + const char *sep = ""; + debug_printf_eval("COMMA\n"); + if (opinfo == TI_COMMA) + sep = getvar_s(intvar[SUBSEP]); + setvar_p(res, xasprintf("%s%s%s", L.s, sep, R.s)); + break; + } + + case XC( OC_LAND ): + debug_printf_eval("LAND\n"); + setvar_i(res, istrue(L.v) ? ptest(op->r.n) : 0); + break; + + case XC( OC_LOR ): + debug_printf_eval("LOR\n"); + setvar_i(res, istrue(L.v) ? 1 : ptest(op->r.n)); + break; + + case XC( OC_BINARY ): + debug_printf_eval("BINARY /\n"); + case XC( OC_REPLACE ): + debug_printf_eval("REPLACE\n"); + { + double R_d = getvar_i(R.v); + debug_printf_eval("R_d:%f opn:%c\n", R_d, opn); + switch (opn) { + case '+': + L_d += R_d; + break; + case '-': + L_d -= R_d; + break; + case '*': + L_d *= R_d; + break; + case '/': + if (R_d == 0) + syntax_error(EMSG_DIV_BY_ZERO); + L_d /= R_d; + break; + case '&': + if (ENABLE_FEATURE_AWK_LIBM) + L_d = pow(L_d, R_d); + else + syntax_error(EMSG_NO_MATH); + break; + case '%': + if (R_d == 0) + syntax_error(EMSG_DIV_BY_ZERO); + L_d -= (long long)(L_d / R_d) * R_d; + break; + } + debug_printf_eval("BINARY/REPLACE result:%f\n", L_d); + res = setvar_i(((opinfo & OPCLSMASK) == OC_BINARY) ? res : L.v, L_d); + break; + } + + case XC( OC_COMPARE ): { + int i = i; /* for compiler */ + double Ld; + debug_printf_eval("COMPARE\n"); + + if (is_numeric(L.v) && is_numeric(R.v)) { + Ld = getvar_i(L.v) - getvar_i(R.v); + } else { + const char *l = getvar_s(L.v); + const char *r = getvar_s(R.v); + Ld = icase ? strcasecmp(l, r) : strcmp(l, r); + } + switch (opn & 0xfe) { + case 0: + i = (Ld > 0); + break; + case 2: + i = (Ld >= 0); + break; + case 4: + i = (Ld == 0); + break; + } + debug_printf_eval("COMPARE result: %d\n", (i == 0) ^ (opn & 1)); + setvar_i(res, (i == 0) ^ (opn & 1)); + break; + } + + default: + syntax_error(EMSG_POSSIBLE_ERROR); + } /* switch */ + + if ((opinfo & OPCLSMASK) <= SHIFT_TIL_THIS) + op = op->a.n; + if ((opinfo & OPCLSMASK) >= RECUR_FROM_THIS) + break; + if (nextrec) + break; + } /* while (op) */ + + nvfree(tmpvars, 2); +#undef TMPVAR0 +#undef TMPVAR1 + + debug_printf_eval("returning from %s(): %p\n", __func__, res); + return res; +#undef fnargs +#undef seed +#undef sreg +} + +static int awk_exit(void) +{ + unsigned i; + + if (!exiting) { + exiting = TRUE; + nextrec = FALSE; + evaluate(endseq.first, &G.exit__tmpvar); + } + + /* waiting for children */ + for (i = 0; i < fdhash->csize; i++) { + hash_item *hi; + hi = fdhash->items[i]; + while (hi) { + if (hi->data.rs.F && hi->data.rs.is_pipe) + pclose(hi->data.rs.F); + hi = hi->next; + } + } + + exit(G.exitcode); +} + +int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int awk_main(int argc UNUSED_PARAM, char **argv) +{ + int ch; + int i; + + INIT_G(); + + /* Undo busybox.c, or else strtod may eat ','! This breaks parsing: + * $1,$2 == '$1,' '$2', NOT '$1' ',' '$2' */ + if (ENABLE_LOCALE_SUPPORT) + setlocale(LC_NUMERIC, "C"); + + /* initialize variables */ + vhash = hash_init(); + { + char *vnames = (char *)vNames; /* cheat */ + char *vvalues = (char *)vValues; + for (i = 0; *vnames; i++) { + var *v; + intvar[i] = v = newvar(nextword(&vnames)); + if (*vvalues != '\377') + setvar_s(v, nextword(&vvalues)); + else + setvar_i(v, 0); + + if (*vnames == '*') { + v->type |= VF_SPECIAL; + vnames++; + } + } + } + + handle_special(intvar[FS]); + handle_special(intvar[RS]); + + /* Huh, people report that sometimes environ is NULL. Oh well. */ + if (environ) { + char **envp; + for (envp = environ; *envp; envp++) { + /* environ is writable, thus we don't strdup it needlessly */ + char *s = *envp; + char *s1 = strchr(s, '='); + if (s1) { + *s1 = '\0'; + /* Both findvar and setvar_u take const char* + * as 2nd arg -> environment is not trashed */ + setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1); + *s1 = '='; + } + } + } + + fnhash = hash_init(); + ahash = hash_init(); + + /* Cannot use getopt32: need to preserve order of -e / -f / -E / -i */ + while ((ch = getopt(argc, argv, OPTSTR_AWK)) >= 0) { + switch (ch) { + case 'F': + unescape_string_in_place(optarg); + setvar_s(intvar[FS], optarg); + break; + case 'v': + if (!try_to_assign(optarg)) + bb_show_usage(); + break; +//TODO: implement -i LIBRARY, it is easy-ish + case 'E': + case 'f': { + int fd; + char *s; + g_progname = optarg; + fd = xopen_stdin(g_progname); + s = xmalloc_read(fd, NULL); /* it's NUL-terminated */ + if (!s) + bb_perror_msg_and_die("read error from '%s'", g_progname); + close(fd); + parse_program(s); + free(s); + got_program = 1; + if (ch == 'E') { + got_program = 2; + goto stop_option_parsing; + } + break; + } +#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS + case 'e': + g_progname = "cmd. line"; + parse_program(optarg); + got_program = 1; + break; +#endif + case 'W': + bb_simple_error_msg("warning: option -W is ignored"); + break; + default: +//bb_error_msg("ch:%d", ch); + bb_show_usage(); + } + } + stop_option_parsing: + + argv += optind; + //argc -= optind; + + if (!got_program) { + if (!*argv) + bb_show_usage(); + g_progname = "cmd. line"; + parse_program(*argv++); + } + + /* Free unused parse structures */ + //hash_free(fnhash); // ~250 bytes when empty, used only for function names + //^^^^^^^^^^^^^^^^^ does not work, hash_clear() inside SEGVs + // (IOW: hash_clear() assumes it's a hash of variables. fnhash is not). + free(fnhash->items); + free(fnhash); + fnhash = NULL; // debug + //hash_free(ahash); // empty after parsing, will reuse as fdhash instead of freeing + + /* Parsing done, on to executing */ + + /* fill in ARGV array */ + setari_u(intvar[ARGV], 0, "awk"); + i = 0; + while (*argv) + setari_u(intvar[ARGV], ++i, *argv++); + setvar_i(intvar[ARGC], i + 1); + + //fdhash = ahash; // done via define + newfile("/dev/stdin")->F = stdin; + newfile("/dev/stdout")->F = stdout; + newfile("/dev/stderr")->F = stderr; + + evaluate(beginseq.first, &G.main__tmpvar); + if (!mainseq.first && !endseq.first) + awk_exit(); + + /* input file could already be opened in BEGIN block */ + if (!iF.F) + goto next_file; /* no, it wasn't, go try opening */ + /* Iterate over input files */ + for (;;) { + nextfile = FALSE; + setvar_i(intvar[FNR], 0); + + while ((i = awk_getline(&iF, intvar[F0])) > 0) { + nextrec = FALSE; + incvar(intvar[NR]); + incvar(intvar[FNR]); + evaluate(mainseq.first, &G.main__tmpvar); + + if (nextfile) + break; + } + if (i < 0) + syntax_error(strerror(errno)); + next_file: + if (!next_input_file()) + break; + } + + awk_exit(); + /*return 0;*/ +} diff --git a/busybox-1_37_0/editors/cmp.c b/busybox-1_37_0/editors/cmp.c new file mode 100644 index 000000000..54f347508 --- /dev/null +++ b/busybox-1_37_0/editors/cmp.c @@ -0,0 +1,166 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini cmp implementation for busybox + * + * Copyright (C) 2000,2001 by Matt Kraai + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +//config:config CMP +//config: bool "cmp (5.3 kb)" +//config: default y +//config: help +//config: cmp is used to compare two files and returns the result +//config: to standard output. + +//applet:IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CMP) += cmp.o + +//usage:#define cmp_trivial_usage +//usage: "[-ls] [-n NUM] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" +//usage:#define cmp_full_usage "\n\n" +//usage: "Compare FILE1 with FILE2 (or stdin)\n" +//usage: "\n -l Write the byte numbers (decimal) and values (octal)" +//usage: "\n for all differing bytes" +//usage: "\n -s Quiet" +//usage: "\n -n NUM Compare at most NUM bytes" + +/* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ +/* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ + +#include "libbb.h" + +static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n"; +static const char fmt_differ[] ALIGN1 = "%s %s differ: char %"OFF_FMT"u, line %u\n"; +// This fmt_l_opt uses gnu-isms. SUSv3 would be "%.0s%.0s%"OFF_FMT"u %o %o\n" +static const char fmt_l_opt[] ALIGN1 = "%.0s%.0s%"OFF_FMT"u %3o %3o\n"; + +#define OPT_STR "sln:+" +#define CMP_OPT_s (1<<0) +#define CMP_OPT_l (1<<1) +#define CMP_OPT_n (1<<2) + +int cmp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int cmp_main(int argc UNUSED_PARAM, char **argv) +{ + FILE *fp1, *fp2, *outfile = stdout; + const char *filename1, *filename2 = "-"; + off_t skip1 = 0, skip2 = 0, char_pos = 0; + int line_pos = 1; /* Hopefully won't overflow... */ + const char *fmt; + int c1, c2; + unsigned opt; + int retval = 0; + int max_count = -1; + +#if !ENABLE_LONG_OPTS + opt = getopt32(argv, "^" + OPT_STR + "\0" "-1" + IF_DESKTOP(":?4") + IF_NOT_DESKTOP(":?2") + ":l--s:s--l", + &max_count + ); +#else + static const char cmp_longopts[] ALIGN1 = + "bytes\0" Required_argument "n" + "quiet\0" No_argument "s" + "silent\0" No_argument "s" + "verbose\0" No_argument "l" + ; + opt = getopt32long(argv, "^" + OPT_STR + "\0" "-1" + IF_DESKTOP(":?4") + IF_NOT_DESKTOP(":?2") + ":l--s:s--l", + cmp_longopts, + &max_count + ); +#endif + argv += optind; + + filename1 = *argv; + if (*++argv) { + filename2 = *argv; + if (ENABLE_DESKTOP && *++argv) { + skip1 = XATOOFF(*argv); + if (*++argv) { + skip2 = XATOOFF(*argv); + } + } + } + + xfunc_error_retval = 2; /* missing file results in exitcode 2 */ + if (opt & CMP_OPT_s) + logmode = 0; /* -s suppresses open error messages */ + fp1 = xfopen_stdin(filename1); + fp2 = xfopen_stdin(filename2); + if (fp1 == fp2) { /* Paranoia check... stdin == stdin? */ + /* Note that we don't bother reading stdin. Neither does gnu wc. + * But perhaps we should, so that other apps down the chain don't + * get the input. Consider 'echo hello | (cmp - - && cat -)'. + */ + return 0; + } + logmode = LOGMODE_STDIO; + + if (opt & CMP_OPT_l) + fmt = fmt_l_opt; + else + fmt = fmt_differ; + + if (ENABLE_DESKTOP) { + while (skip1) { getc(fp1); skip1--; } + while (skip2) { getc(fp2); skip2--; } + } + do { + if (max_count >= 0 && --max_count < 0) + break; + c1 = getc(fp1); + c2 = getc(fp2); + ++char_pos; + if (c1 != c2) { /* Remember: a read error may have occurred. */ + retval = 1; /* But assume the files are different for now. */ + if (c2 == EOF) { + /* We know that fp1 isn't at EOF or in an error state. But to + * save space below, things are setup to expect an EOF in fp1 + * if an EOF occurred. So, swap things around. + */ + fp1 = fp2; + filename1 = filename2; + c1 = c2; + } + if (c1 == EOF) { + die_if_ferror(fp1, filename1); + fmt = fmt_eof; /* Well, no error, so it must really be EOF. */ + outfile = stderr; + /* There may have been output to stdout (option -l), so + * make sure we fflush before writing to stderr. */ + fflush_all(); + } + if (!(opt & CMP_OPT_s)) { + if (opt & CMP_OPT_l) { + line_pos = c1; /* line_pos is unused in the -l case. */ + } + fprintf(outfile, fmt, filename1, filename2, char_pos, line_pos, c2); + if (opt) { /* This must be -l since not -s. */ + /* If we encountered an EOF, + * the while check will catch it. */ + continue; + } + } + break; + } + if (c1 == '\n') { + ++line_pos; + } + } while (c1 != EOF); + + die_if_ferror(fp1, filename1); + die_if_ferror(fp2, filename2); + + fflush_stdout_and_exit(retval); +} diff --git a/busybox-1_37_0/editors/diff.c b/busybox-1_37_0/editors/diff.c new file mode 100644 index 000000000..1adc4cbc7 --- /dev/null +++ b/busybox-1_37_0/editors/diff.c @@ -0,0 +1,1058 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini diff implementation for busybox, adapted from OpenBSD diff. + * + * Copyright (C) 2010 by Matheus Izvekov + * Copyright (C) 2006 by Robert Sullivan + * Copyright (c) 2003 Todd C. Miller + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* + * The following code uses an algorithm due to Harold Stone, + * which finds a pair of longest identical subsequences in + * the two files. + * + * The major goal is to generate the match vector J. + * J[i] is the index of the line in file1 corresponding + * to line i in file0. J[i] = 0 if there is no + * such line in file1. + * + * Lines are hashed so as to work in core. All potential + * matches are located by sorting the lines of each file + * on the hash (called "value"). In particular, this + * collects the equivalence classes in file1 together. + * Subroutine equiv replaces the value of each line in + * file0 by the index of the first element of its + * matching equivalence in (the reordered) file1. + * To save space equiv squeezes file1 into a single + * array member in which the equivalence classes + * are simply concatenated, except that their first + * members are flagged by changing sign. + * + * Next the indices that point into member are unsorted into + * array class according to the original order of file0. + * + * The cleverness lies in routine stone. This marches + * through the lines of file0, developing a vector klist + * of "k-candidates". At step i a k-candidate is a matched + * pair of lines x,y (x in file0, y in file1) such that + * there is a common subsequence of length k + * between the first i lines of file0 and the first y + * lines of file1, but there is no such subsequence for + * any smaller y. x is the earliest possible mate to y + * that occurs in such a subsequence. + * + * Whenever any of the members of the equivalence class of + * lines in file1 matable to a line in file0 has serial number + * less than the y of some k-candidate, that k-candidate + * with the smallest such y is replaced. The new + * k-candidate is chained (via pred) to the current + * k-1 candidate so that the actual subsequence can + * be recovered. When a member has serial number greater + * that the y of all k-candidates, the klist is extended. + * At the end, the longest subsequence is pulled out + * and placed in the array J by unravel + * + * With J in hand, the matches there recorded are + * checked against reality to assure that no spurious + * matches have crept in due to hashing. If they have, + * they are broken, and "jackpot" is recorded--a harmless + * matter except that a true match for a spuriously + * mated line may now be unnecessarily reported as a change. + * + * Much of the complexity of the program comes simply + * from trying to minimize core utilization and + * maximize the range of doable problems by dynamically + * allocating what is needed and reusing what is not. + * The core requirements for problems larger than somewhat + * are (in words) 2*length(file0) + length(file1) + + * 3*(number of k-candidates installed), typically about + * 6n words for files of length n. + */ +//config:config DIFF +//config: bool "diff (13 kb)" +//config: default y +//config: help +//config: diff compares two files or directories and outputs the +//config: differences between them in a form that can be given to +//config: the patch command. +//config: +//config:config FEATURE_DIFF_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on DIFF && LONG_OPTS +//config: +//config:config FEATURE_DIFF_DIR +//config: bool "Enable directory support" +//config: default y +//config: depends on DIFF +//config: help +//config: This option enables support for directory and subdirectory +//config: comparison. + +//applet:IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_DIFF) += diff.o + +//usage:#define diff_trivial_usage +//usage: "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" +//usage:#define diff_full_usage "\n\n" +//usage: "Compare files line by line and output the differences between them.\n" +//usage: "This implementation supports unified diffs only.\n" +//usage: "\n -a Treat all files as text" +//usage: "\n -b Ignore changes in the amount of whitespace" +//usage: "\n -B Ignore changes whose lines are all blank" +//usage: "\n -d Try hard to find a smaller set of changes" +//usage: "\n -i Ignore case differences" +//usage: "\n -L Use LABEL instead of the filename in the unified header" +//usage: "\n -N Treat absent files as empty" +//usage: "\n -q Output only whether files differ" +//usage: "\n -r Recurse" +//usage: "\n -S Start with FILE when comparing directories" +//usage: "\n -T Make tabs line up by prefixing a tab when necessary" +//usage: "\n -s Report when two files are the same" +//usage: "\n -t Expand tabs to spaces in output" +//usage: "\n -U Output LINES lines of context" +//usage: "\n -w Ignore all whitespace" + +#include "libbb.h" +#include "common_bufsiz.h" + +#if 0 +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg_error_msg(...) ((void)0) +#endif + +enum { /* print_status() and diffreg() return values */ + STATUS_SAME, /* files are the same */ + STATUS_DIFFER, /* files differ */ + STATUS_BINARY, /* binary files differ */ +}; + +enum { /* Commandline flags */ + FLAG_a, + FLAG_b, + FLAG_d, + FLAG_i, + FLAG_L, /* never used, handled by getopt32 */ + FLAG_N, + FLAG_q, + FLAG_r, + FLAG_s, + FLAG_S, /* never used, handled by getopt32 */ + FLAG_t, + FLAG_T, + FLAG_U, /* never used, handled by getopt32 */ + FLAG_w, + FLAG_u, /* ignored, this is the default */ + FLAG_p, /* not implemented */ + FLAG_B, + FLAG_E, /* not implemented */ +}; +#define FLAG(x) (1 << FLAG_##x) + +/* We cache file position to avoid excessive seeking */ +typedef struct FILE_and_pos_t { + FILE *ft_fp; + off_t ft_pos; +} FILE_and_pos_t; + +struct globals { + smallint exit_status; + int opt_U_context; + const char *other_dir; + char *label[2]; + struct stat stb[2]; +}; +#define G (*ptr_to_globals) +#define exit_status (G.exit_status ) +#define opt_U_context (G.opt_U_context ) +#define label (G.label ) +#define stb (G.stb ) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + opt_U_context = 3; \ +} while (0) + +typedef int token_t; + +enum { + /* Public */ + TOK_EMPTY = 1 << 9, /* Line fully processed, you can proceed to the next */ + TOK_EOF = 1 << 10, /* File ended */ + /* Private (Only to be used by read_token() */ + TOK_EOL = 1 << 11, /* we saw EOL (sticky) */ + TOK_SPACE = 1 << 12, /* used -b code, means we are skipping spaces */ + SHIFT_EOF = (sizeof(token_t)*8 - 8) - 1, + CHAR_MASK = 0x1ff, /* 8th bit is used to distinguish EOF from 0xff */ +}; + +/* Restores full EOF from one 8th bit: */ +//#define TOK2CHAR(t) (((t) << SHIFT_EOF) >> SHIFT_EOF) +/* We don't really need the above, we only need to have EOF != any_real_char: */ +#define TOK2CHAR(t) ((t) & CHAR_MASK) + +static void seek_ft(FILE_and_pos_t *ft, off_t pos) +{ + if (ft->ft_pos != pos) { + ft->ft_pos = pos; + fseeko(ft->ft_fp, pos, SEEK_SET); + } +} + +/* Reads tokens from given fp, handling -b and -w flags + * The user must reset tok every line start + */ +static int read_token(FILE_and_pos_t *ft, token_t tok) +{ + tok |= TOK_EMPTY; + while (!(tok & TOK_EOL)) { + bool is_space; + int t; + + t = fgetc(ft->ft_fp); + if (t != EOF) + ft->ft_pos++; + is_space = (t == EOF || isspace(t)); + + /* If t == EOF (-1), set both TOK_EOF and TOK_EOL */ + tok |= (t & (TOK_EOF + TOK_EOL)); + /* Only EOL? */ + if (t == '\n') + tok |= TOK_EOL; + + if (option_mask32 & FLAG(i)) /* Handcoded tolower() */ + t = (t >= 'A' && t <= 'Z') ? t - ('A' - 'a') : t; + + if ((option_mask32 & FLAG(w)) && is_space) + continue; + + /* Trim char value to low 9 bits */ + t &= CHAR_MASK; + + if (option_mask32 & FLAG(b)) { + /* Was prev char whitespace? */ + if (tok & TOK_SPACE) { /* yes */ + if (is_space) /* this one too, ignore it */ + continue; + tok &= ~TOK_SPACE; + } else if (is_space) { + /* 1st whitespace char. + * Set TOK_SPACE and replace char by ' ' */ + t = TOK_SPACE + ' '; + } + } + /* Clear EMPTY */ + tok &= ~(TOK_EMPTY + CHAR_MASK); + /* Assign char value (low 9 bits) and maybe set TOK_SPACE */ + tok |= t; + break; + } +#if 0 + bb_error_msg("fp:%p tok:%x '%c'%s%s%s%s", fp, tok, tok & 0xff + , tok & TOK_EOF ? " EOF" : "" + , tok & TOK_EOL ? " EOL" : "" + , tok & TOK_EMPTY ? " EMPTY" : "" + , tok & TOK_SPACE ? " SPACE" : "" + ); +#endif + return tok; +} + +struct cand { + int x; + int y; + int pred; +}; + +static int search(const int *c, int k, int y, const struct cand *list) +{ + int i, j; + + if (list[c[k]].y < y) /* quick look for typical case */ + return k + 1; + + for (i = 0, j = k + 1;;) { + const int l = (i + j) >> 1; + if (l > i) { + const int t = list[c[l]].y; + if (t > y) + j = l; + else if (t < y) + i = l; + else + return l; + } else + return l + 1; + } +} + +static void stone(const int *a, int n, const int *b, int *J, int pref) +{ + const unsigned isq = isqrt(n); + const unsigned bound = + (option_mask32 & FLAG(d)) ? UINT_MAX : MAX(256, isq); + int clen = 1; + int clistlen = 100; + int k = 0; + struct cand *clist = xzalloc(clistlen * sizeof(clist[0])); + struct cand cand; + struct cand *q; + int *klist = xzalloc((n + 2) * sizeof(klist[0])); + /*clist[0] = (struct cand){0}; - xzalloc did it */ + /*klist[0] = 0; */ + + for (cand.x = 1; cand.x <= n; cand.x++) { + int j = a[cand.x], oldl = 0; + unsigned numtries = 0; + if (j == 0) + continue; + cand.y = -b[j]; + cand.pred = klist[0]; + do { + int l, tc; + if (cand.y <= clist[cand.pred].y) + continue; + l = search(klist, k, cand.y, clist); + if (l != oldl + 1) + cand.pred = klist[l - 1]; + if (l <= k && clist[klist[l]].y <= cand.y) + continue; + if (clen == clistlen) { + clistlen = clistlen * 11 / 10; + clist = xrealloc(clist, clistlen * sizeof(clist[0])); + } + clist[clen] = cand; + tc = klist[l]; + klist[l] = clen++; + if (l <= k) { + cand.pred = tc; + oldl = l; + numtries++; + } else { + k++; + break; + } + } while ((cand.y = b[++j]) > 0 && numtries < bound); + } + /* Unravel */ + for (q = clist + klist[k]; q->y; q = clist + q->pred) + J[q->x + pref] = q->y + pref; + free(klist); + free(clist); +} + +struct line { + /* 'serial' is not used in the beginning, so we reuse it + * to store line offsets, thus reducing memory pressure + */ + union { + unsigned serial; + off_t offset; + }; + unsigned value; +}; + +static void equiv(struct line *a, int n, struct line *b, int m, int *c) +{ + int i = 1, j = 1; + + while (i <= n && j <= m) { + if (a[i].value < b[j].value) + a[i++].value = 0; + else if (a[i].value == b[j].value) + a[i++].value = j; + else + j++; + } + while (i <= n) + a[i++].value = 0; + b[m + 1].value = 0; + j = 0; + while (++j <= m) { + c[j] = -b[j].serial; + while (b[j + 1].value == b[j].value) { + j++; + c[j] = b[j].serial; + } + } + c[j] = -1; +} + +static void unsort(const struct line *f, int l, int *b) +{ + int i; + int *a = xmalloc((l + 1) * sizeof(a[0])); + for (i = 1; i <= l; i++) + a[f[i].serial] = f[i].value; + for (i = 1; i <= l; i++) + b[i] = a[i]; + free(a); +} + +static int line_compar(const void *a, const void *b) +{ +#define l0 ((const struct line*)a) +#define l1 ((const struct line*)b) + int r = l0->value - l1->value; + if (r) + return r; + return l0->serial - l1->serial; +#undef l0 +#undef l1 +} + +static void fetch(FILE_and_pos_t *ft, const off_t *ix, int a, int b, int ch) +{ + int i, j, col; + for (i = a; i <= b; i++) { + seek_ft(ft, ix[i - 1]); + putchar(ch); + if (option_mask32 & FLAG(T)) + putchar('\t'); + for (j = 0, col = 0; j < ix[i] - ix[i - 1]; j++) { + int c = fgetc(ft->ft_fp); + if (c == EOF) { + puts("\n\\ No newline at end of file"); + return; + } + ft->ft_pos++; + if (c == '\t' && (option_mask32 & FLAG(t))) + do putchar(' '); while (++col & 7); + else { + putchar(c); + col++; + } + } + } +} + +/* Creates the match vector J, where J[i] is the index + * of the line in the new file corresponding to the line i + * in the old file. Lines start at 1 instead of 0, that value + * being used instead to denote no corresponding line. + * This vector is dynamically allocated and must be freed by the caller. + * + * * fp is an input parameter, where fp[0] and fp[1] are the open + * old file and new file respectively. + * * nlen is an output variable, where nlen[0] and nlen[1] + * gets the number of lines in the old and new file respectively. + * * ix is an output variable, where ix[0] and ix[1] gets + * assigned dynamically allocated vectors of the offsets of the lines + * of the old and new file respectively. These must be freed by the caller. + */ +static NOINLINE int *create_J(FILE_and_pos_t ft[2], int nlen[2], off_t *ix[2]) +{ + int *J, slen[2], *class, *member; + struct line *nfile[2], *sfile[2]; + int pref = 0, suff = 0, i, j, delta; + + /* Lines of both files are hashed, and in the process + * their offsets are stored in the array ix[fileno] + * where fileno == 0 points to the old file, and + * fileno == 1 points to the new one. + */ + for (i = 0; i < 2; i++) { + unsigned hash; + token_t tok; + size_t sz = 100; + nfile[i] = xmalloc((sz + 3) * sizeof(nfile[i][0])); + /* ft gets here without the correct position, cant use seek_ft */ + ft[i].ft_pos = 0; + fseeko(ft[i].ft_fp, 0, SEEK_SET); + + nlen[i] = 0; + /* We could zalloc nfile, but then zalloc starts showing in gprof at ~1% */ + nfile[i][0].offset = 0; + goto start; /* saves code */ + while (1) { + tok = read_token(&ft[i], tok); + if (!(tok & TOK_EMPTY)) { + /* Hash algorithm taken from Robert Sedgewick, Algorithms in C, 3d ed., p 578. */ + /*hash = hash * 128 - hash + TOK2CHAR(tok); + * gcc insists on optimizing above to "hash * 127 + ...", thus... */ + unsigned o = hash - TOK2CHAR(tok); + hash = hash * 128 - o; /* we want SPEED here */ + continue; + } + if (nlen[i]++ == sz) { + sz = sz * 3 / 2; + nfile[i] = xrealloc(nfile[i], (sz + 3) * sizeof(nfile[i][0])); + } + /* line_compar needs hashes fit into positive int */ + nfile[i][nlen[i]].value = hash & INT_MAX; + /* like ftello(ft[i].ft_fp) but faster (avoids lseek syscall) */ + nfile[i][nlen[i]].offset = ft[i].ft_pos; + if (tok & TOK_EOF) { + /* EOF counts as a token, so we have to adjust it here */ + nfile[i][nlen[i]].offset++; + break; + } +start: + hash = tok = 0; + } + /* Exclude lone EOF line from the end of the file, to make fetch()'s job easier */ + if (nfile[i][nlen[i]].offset - nfile[i][nlen[i] - 1].offset == 1) + nlen[i]--; + /* Now we copy the line offsets into ix */ + ix[i] = xmalloc((nlen[i] + 2) * sizeof(ix[i][0])); + for (j = 0; j < nlen[i] + 1; j++) + ix[i][j] = nfile[i][j].offset; + } + + /* length of prefix and suffix is calculated */ + for (; pref < nlen[0] && pref < nlen[1] && + nfile[0][pref + 1].value == nfile[1][pref + 1].value; + pref++); + for (; suff < nlen[0] - pref && suff < nlen[1] - pref && + nfile[0][nlen[0] - suff].value == nfile[1][nlen[1] - suff].value; + suff++); + /* Arrays are pruned by the suffix and prefix length, + * the result being sorted and stored in sfile[fileno], + * and their sizes are stored in slen[fileno] + */ + for (j = 0; j < 2; j++) { + sfile[j] = nfile[j] + pref; + slen[j] = nlen[j] - pref - suff; + for (i = 0; i <= slen[j]; i++) + sfile[j][i].serial = i; + qsort(sfile[j] + 1, slen[j], sizeof(*sfile[j]), line_compar); + } + /* nfile arrays are reused to reduce memory pressure + * The #if zeroed out section performs the same task as the + * one in the #else section. + * Peak memory usage is higher, but one array copy is avoided + * by not using unsort() + */ +#if 0 + member = xmalloc((slen[1] + 2) * sizeof(member[0])); + equiv(sfile[0], slen[0], sfile[1], slen[1], member); + free(nfile[1]); + + class = xmalloc((slen[0] + 1) * sizeof(class[0])); + for (i = 1; i <= slen[0]; i++) /* Unsorting */ + class[sfile[0][i].serial] = sfile[0][i].value; + free(nfile[0]); +#else + member = (int *)nfile[1]; + equiv(sfile[0], slen[0], sfile[1], slen[1], member); + member = xrealloc(member, (slen[1] + 2) * sizeof(member[0])); + + class = (int *)nfile[0]; + unsort(sfile[0], slen[0], (int *)nfile[0]); + class = xrealloc(class, (slen[0] + 2) * sizeof(class[0])); +#endif + J = xmalloc((nlen[0] + 2) * sizeof(J[0])); + /* The elements of J which fall inside the prefix and suffix regions + * are marked as unchanged, while the ones which fall outside + * are initialized with 0 (no matches), so that function stone can + * then assign them their right values + */ + for (i = 0, delta = nlen[1] - nlen[0]; i <= nlen[0]; i++) + J[i] = i <= pref ? i : + i > (nlen[0] - suff) ? (i + delta) : 0; + /* Here the magic is performed */ + stone(class, slen[0], member, J, pref); + J[nlen[0] + 1] = nlen[1] + 1; + + free(class); + free(member); + + /* Both files are rescanned, in an effort to find any lines + * which, due to limitations intrinsic to any hashing algorithm, + * are different but ended up confounded as the same + */ + for (i = 1; i <= nlen[0]; i++) { + if (!J[i]) + continue; + + seek_ft(&ft[0], ix[0][i - 1]); + seek_ft(&ft[1], ix[1][J[i] - 1]); + + for (j = J[i]; i <= nlen[0] && J[i] == j; i++, j++) { + token_t tok0 = 0, tok1 = 0; + do { + tok0 = read_token(&ft[0], tok0); + tok1 = read_token(&ft[1], tok1); + + if (((tok0 ^ tok1) & TOK_EMPTY) != 0 /* one is empty (not both) */ + || (!(tok0 & TOK_EMPTY) && TOK2CHAR(tok0) != TOK2CHAR(tok1)) + ) { + J[i] = 0; /* Break the correspondence */ + } + } while (!(tok0 & tok1 & TOK_EMPTY)); + } + } + + return J; +} + +static bool diff(FILE* fp[2], char *file[2]) +{ + int nlen[2]; + off_t *ix[2]; + FILE_and_pos_t ft[2]; + typedef struct { int a, b; } vec_t[2]; + vec_t *vec = NULL; + int i = 1, j, k, idx = -1; + bool anychange = false; + int *J; + + ft[0].ft_fp = fp[0]; + ft[1].ft_fp = fp[1]; + /* note that ft[i].ft_pos is unintitalized, create_J() + * must not assume otherwise */ + J = create_J(ft, nlen, ix); + + do { + bool nonempty = false; + + while (1) { + vec_t v; + + for (v[0].a = i; v[0].a <= nlen[0] && J[v[0].a] == J[v[0].a - 1] + 1; v[0].a++) + continue; + v[1].a = J[v[0].a - 1] + 1; + + for (v[0].b = v[0].a - 1; v[0].b < nlen[0] && !J[v[0].b + 1]; v[0].b++) + continue; + v[1].b = J[v[0].b + 1] - 1; + /* + * Indicate that there is a difference between lines a and b of the 'from' file + * to get to lines c to d of the 'to' file. If a is greater than b then there + * are no lines in the 'from' file involved and this means that there were + * lines appended (beginning at b). If c is greater than d then there are + * lines missing from the 'to' file. + */ + if (v[0].a <= v[0].b || v[1].a <= v[1].b) { + /* + * If this change is more than 'context' lines from the + * previous change, dump the record and reset it. + */ + int ct = (2 * opt_U_context) + 1; + if (idx >= 0 + && v[0].a > vec[idx][0].b + ct + && v[1].a > vec[idx][1].b + ct + ) { + break; + } + + for (j = 0; j < 2; j++) + for (k = v[j].a; k <= v[j].b; k++) + nonempty |= (ix[j][k] - ix[j][k - 1] != 1); + + vec = xrealloc_vector(vec, 6, ++idx); + memcpy(vec[idx], v, sizeof(v)); + } + + i = v[0].b + 1; + if (i > nlen[0]) + break; + J[v[0].b] = v[1].b; + } + if (idx < 0 || ((option_mask32 & FLAG(B)) && !nonempty)) + goto cont; + if (!(option_mask32 & FLAG(q))) { + int lowa; + vec_t span, *cvp = vec; + + if (!anychange) { + /* Print the context/unidiff header first time through */ + printf("--- %s\n", label[0] ? label[0] : file[0]); + printf("+++ %s\n", label[1] ? label[1] : file[1]); + } + + printf("@@"); + for (j = 0; j < 2; j++) { + int a = span[j].a = MAX(1, (*cvp)[j].a - opt_U_context); + int b = span[j].b = MIN(nlen[j], vec[idx][j].b + opt_U_context); + + printf(" %c%d", j ? '+' : '-', MIN(a, b)); + if (a == b) + continue; + printf(",%d", (a < b) ? b - a + 1 : 0); + } + puts(" @@"); + /* + * Output changes in "unified" diff format--the old and new lines + * are printed together. + */ + for (lowa = span[0].a; ; lowa = (*cvp++)[0].b + 1) { + bool end = cvp > &vec[idx]; + fetch(&ft[0], ix[0], lowa, end ? span[0].b : (*cvp)[0].a - 1, ' '); + if (end) + break; + for (j = 0; j < 2; j++) + fetch(&ft[j], ix[j], (*cvp)[j].a, (*cvp)[j].b, j ? '+' : '-'); + } + } + anychange = true; + cont: + idx = -1; + } while (i <= nlen[0]); + + free(vec); + free(ix[0]); + free(ix[1]); + free(J); + return anychange; +} + +static int diffreg(char *file[2]) +{ + FILE *fp[2]; + bool binary = false, differ = false; + int status = STATUS_SAME, i; + + fp[0] = stdin; + fp[1] = stdin; + for (i = 0; i < 2; i++) { + int fd = STDIN_FILENO; + if (!LONE_DASH(file[i])) { + if (!(option_mask32 & FLAG(N))) { + fd = open_or_warn(file[i], O_RDONLY); + if (fd == -1) + goto out; + } else { + /* -N: if some file does not exist compare it like empty */ + fd = open(file[i], O_RDONLY); + if (fd == -1) + fd = xopen("/dev/null", O_RDONLY); + } + } + /* Our diff implementation is using seek. + * When we meet non-seekable file, we must make a temp copy. + */ + if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { + char name[] = "/tmp/difXXXXXX"; + int fd_tmp = xmkstemp(name); + + unlink(name); + if (bb_copyfd_eof(fd, fd_tmp) < 0) + xfunc_die(); + if (fd != STDIN_FILENO) + close(fd); + fd = fd_tmp; + xlseek(fd, 0, SEEK_SET); + } + fp[i] = fdopen(fd, "r"); + } + + setup_common_bufsiz(); + while (1) { + const size_t sz = COMMON_BUFSIZE / 2; + char *const buf0 = bb_common_bufsiz1; + char *const buf1 = buf0 + sz; + int j, k; + i = fread(buf0, 1, sz, fp[0]); + j = fread(buf1, 1, sz, fp[1]); + if (i != j) { + differ = true; + i = MIN(i, j); + } + if (i == 0) + break; + for (k = 0; k < i; k++) { + if (!buf0[k] || !buf1[k]) + binary = true; + if (buf0[k] != buf1[k]) + differ = true; + } + } + if (differ) { + if (binary && !(option_mask32 & FLAG(a))) + status = STATUS_BINARY; + else if (diff(fp, file)) + status = STATUS_DIFFER; + } + if (status != STATUS_SAME) + exit_status |= 1; +out: + fclose_if_not_stdin(fp[0]); + fclose_if_not_stdin(fp[1]); + + return status; +} + +static void print_status(int status, char *path[2]) +{ + switch (status) { + case STATUS_BINARY: + case STATUS_DIFFER: + if ((option_mask32 & FLAG(q)) || status == STATUS_BINARY) + printf("Files %s and %s differ\n", path[0], path[1]); + break; + case STATUS_SAME: + if (option_mask32 & FLAG(s)) + printf("Files %s and %s are identical\n", path[0], path[1]); + break; + } +} + +#if ENABLE_FEATURE_DIFF_DIR +struct dlist { + size_t len; + int s, e; + char **dl; +}; + +/* This function adds a filename to dl, the directory listing. */ +static int FAST_FUNC add_to_dirlist(struct recursive_state *state, + const char *filename, + struct stat *sb UNUSED_PARAM) +{ + struct dlist *const l = state->userData; + const char *file = filename + l->len; + while (*file == '/') + file++; + l->dl = xrealloc_vector(l->dl, 6, l->e); + l->dl[l->e] = xstrdup(file); + l->e++; + return TRUE; +} + +/* If recursion is not set, this function adds the directory + * to the list and prevents recursive_action from recursing into it. + */ +static int FAST_FUNC skip_dir(struct recursive_state *state, + const char *filename, + struct stat *sb) +{ + if (!(option_mask32 & FLAG(r)) && state->depth) { + add_to_dirlist(state, filename, sb); + return SKIP; + } + if (!(option_mask32 & FLAG(N))) { + /* -r without -N: no need to recurse into dirs + * which do not exist on the "other side". + * Testcase: diff -r /tmp / + * (it would recurse deep into /proc without this code) */ + struct dlist *const l = state->userData; + filename += l->len; + if (filename[0]) { + struct stat osb; + char *othername = concat_path_file(G.other_dir, filename); + int r = stat(othername, &osb); + free(othername); + if (r != 0 || !S_ISDIR(osb.st_mode)) { + /* other dir doesn't have similarly named + * directory, don't recurse; return 1 upon + * exit, just like diffutils' diff */ + exit_status |= 1; + return SKIP; + } + } + } + return TRUE; +} + +static void diffdir(char *p[2], const char *s_start) +{ + struct dlist list[2]; + int i; + + memset(&list, 0, sizeof(list)); + for (i = 0; i < 2; i++) { + /*list[i].s = list[i].e = 0; - memset did it */ + /*list[i].dl = NULL; */ + + G.other_dir = p[1 - i]; + /* We need to trim root directory prefix. + * Using list.len to specify its length, + * add_to_dirlist will remove it. */ + list[i].len = strlen(p[i]); + recursive_action(p[i], ACTION_RECURSE | ACTION_FOLLOWLINKS, + add_to_dirlist, skip_dir, &list[i]); + /* Sort dl alphabetically. + * GNU diff does this ignoring any number of trailing dots. + * We don't, so for us dotted files almost always are + * first on the list. + */ + qsort_string_vector(list[i].dl, list[i].e); + /* If -S was set, find the starting point. */ + if (!s_start) + continue; + while (list[i].s < list[i].e && strcmp(list[i].dl[list[i].s], s_start) < 0) + list[i].s++; + } + /* Now that both dirlist1 and dirlist2 contain sorted directory + * listings, we can start to go through dirlist1. If both listings + * contain the same file, then do a normal diff. Otherwise, behaviour + * is determined by whether the -N flag is set. */ + while (1) { + char *dp[2]; + int pos; + int k; + + dp[0] = list[0].s < list[0].e ? list[0].dl[list[0].s] : NULL; + dp[1] = list[1].s < list[1].e ? list[1].dl[list[1].s] : NULL; + if (!dp[0] && !dp[1]) + break; + pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1])); + k = pos > 0; + if (pos && !(option_mask32 & FLAG(N))) { + printf("Only in %s: %s\n", p[k], dp[k]); + exit_status |= 1; + } else { + char *fullpath[2], *path[2]; /* if -N */ + + for (i = 0; i < 2; i++) { + if (pos == 0 || i == k) { + path[i] = fullpath[i] = concat_path_file(p[i], dp[i]); + stat(fullpath[i], &stb[i]); + } else { + fullpath[i] = concat_path_file(p[i], dp[1 - i]); + path[i] = (char *)bb_dev_null; + } + } + if (pos) + stat(fullpath[k], &stb[1 - k]); + + if (S_ISDIR(stb[0].st_mode) && S_ISDIR(stb[1].st_mode)) + printf("Common subdirectories: %s and %s\n", fullpath[0], fullpath[1]); + else if (!S_ISREG(stb[0].st_mode) && !S_ISDIR(stb[0].st_mode)) + printf("File %s is not a regular file or directory and was skipped\n", fullpath[0]); + else if (!S_ISREG(stb[1].st_mode) && !S_ISDIR(stb[1].st_mode)) + printf("File %s is not a regular file or directory and was skipped\n", fullpath[1]); + else if (S_ISDIR(stb[0].st_mode) != S_ISDIR(stb[1].st_mode)) { + if (S_ISDIR(stb[0].st_mode)) + printf("File %s is a %s while file %s is a %s\n", fullpath[0], "directory", fullpath[1], "regular file"); + else + printf("File %s is a %s while file %s is a %s\n", fullpath[0], "regular file", fullpath[1], "directory"); + } else + print_status(diffreg(path), fullpath); + + free(fullpath[0]); + free(fullpath[1]); + } + free(dp[k]); + list[k].s++; + if (pos == 0) { + free(dp[1 - k]); + list[1 - k].s++; + } + } + if (ENABLE_FEATURE_CLEAN_UP) { + free(list[0].dl); + free(list[1].dl); + } +} +#endif + +#if ENABLE_FEATURE_DIFF_LONG_OPTIONS +static const char diff_longopts[] ALIGN1 = + "ignore-case\0" No_argument "i" + "ignore-tab-expansion\0" No_argument "E" + "ignore-space-change\0" No_argument "b" + "ignore-all-space\0" No_argument "w" + "ignore-blank-lines\0" No_argument "B" + "text\0" No_argument "a" + "unified\0" Required_argument "U" + "label\0" Required_argument "L" + "show-c-function\0" No_argument "p" + "brief\0" No_argument "q" + "expand-tabs\0" No_argument "t" + "initial-tab\0" No_argument "T" + "recursive\0" No_argument "r" + "new-file\0" No_argument "N" + "report-identical-files\0" No_argument "s" + "starting-file\0" Required_argument "S" + "minimal\0" No_argument "d" + ; +# define GETOPT32 getopt32long +# define LONGOPTS ,diff_longopts +#else +# define GETOPT32 getopt32 +# define LONGOPTS +#endif + +int diff_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int diff_main(int argc UNUSED_PARAM, char **argv) +{ + int gotstdin = 0, i; + char *file[2], *s_start = NULL; + llist_t *L_arg = NULL; + + INIT_G(); + + /* exactly 2 params; collect multiple -L