From: jk7744.park Date: Sat, 24 Oct 2015 06:54:41 +0000 (+0900) Subject: tizen 2.4 release X-Git-Tag: accepted/tizen/2.4/mobile/20151029.040634 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Ftags%2Faccepted%2Ftizen%2F2.4%2Fmobile%2F20151029.040634;p=external%2Fbusybox.git tizen 2.4 release --- diff --git a/.gitignore b/.gitignore index 7d2cca6..0a0c65b 100644 --- a/.gitignore +++ b/.gitignore @@ -18,6 +18,7 @@ Config.in # Normal output # /busybox +/busybox_old /busybox_unstripped* # diff --git a/Config.in b/Config.in index fe64f2b..2c4be2e 100644 --- a/Config.in +++ b/Config.in @@ -47,6 +47,17 @@ config USE_PORTABLE_CODE compiler other than gcc. If you do use gcc, this option may needlessly increase code size. +config PLATFORM_LINUX + bool "Enable Linux-specific applets and features" + default y + help + For the most part, busybox requires only POSIX compatibility + from the target system, but some applets and features use + Linux-specific interfaces. + + Answering 'N' here will disable such applets and hide the + corresponding configuration options. + choice prompt "Buffer allocation policy" default FEATURE_BUFFERS_USE_MALLOC @@ -72,20 +83,21 @@ config FEATURE_BUFFERS_GO_IN_BSS endchoice config SHOW_USAGE - bool "Show terse applet usage messages" + bool "Show applet usage messages" default y help - All BusyBox applets will show help messages when invoked with - wrong arguments. You can turn off printing these terse usage - messages if you say no here. - This will save you up to 7k. + Enabling this option, BusyBox applets will show terse help messages + when invoked with wrong arguments. + If you do not want to show any (helpful) usage message when + issuing wrong command syntax, you can say 'N' here, + saving approximately 7k. config FEATURE_VERBOSE_USAGE bool "Show verbose applet usage messages" default y depends on SHOW_USAGE help - All BusyBox applets will show more verbose help messages when + All BusyBox applets will show verbose help messages when busybox is invoked with --help. This will add a lot of text to the busybox binary. In the default configuration, this will add about 13k, but it can add much more depending on your configuration. @@ -95,8 +107,8 @@ config FEATURE_COMPRESS_USAGE default y depends on SHOW_USAGE help - Store usage messages in compressed form, uncompress them on-the-fly - when --help is called. + Store usage messages in .bz compressed form, uncompress them + on-the-fly when --help is called. If you have a really tiny busybox with few applets enabled (and bunzip2 isn't one of them), the overhead of the decompressor might @@ -112,6 +124,14 @@ config FEATURE_INSTALLER busybox at runtime to create hard links or symlinks for all the applets that are compiled into busybox. +config INSTALL_NO_USR + bool "Don't use /usr" + default n + help + Disable use of /usr. busybox --install and "make install" + will install applets only to /bin and /sbin, + never to /usr/bin or /usr/sbin. + config LOCALE_SUPPORT bool "Enable locale support (system needs locale for this to work)" default n @@ -141,12 +161,13 @@ config UNICODE_USING_LOCALE Internal implementation is smaller. config FEATURE_CHECK_UNICODE_IN_ENV - bool "Check $LANG environment variable" + bool "Check $LC_ALL, $LC_CTYPE and $LANG environment variables" default n depends on UNICODE_SUPPORT && !UNICODE_USING_LOCALE help With this option on, Unicode support is activated - only if LANG variable has the value of the form "xxxx.utf8" + only if locale-related variables have the value of the form + "xxxx.utf8" Otherwise, Unicode support will be always enabled and active. @@ -229,8 +250,9 @@ config UNICODE_PRESERVE_BROKEN default n depends on UNICODE_SUPPORT help - With this option on, invalid UTF-8 bytes are not substituted - with the selected substitution character. + With this option on, on line-editing input (such as used by shells) + invalid UTF-8 bytes are not substituted with the selected + substitution character. For example, this means that entering 'l', 's', ' ', 0xff, [Enter] at shell prompt will list file named 0xff (single char name with char value 255), not file named '?'. @@ -276,7 +298,7 @@ config FEATURE_UTMP config FEATURE_WTMP bool "Support wtmp file" default y - select FEATURE_UTMP + depends on FEATURE_UTMP help The file /var/run/wtmp is used to track when users have logged into and logged out of the system. @@ -289,35 +311,69 @@ config FEATURE_PIDFILE default y help This option makes some applets (e.g. crond, syslogd, inetd) write - a pidfile in /var/run. Some applications rely on them. + a pidfile at the configured PID_FILE_PATH. It has no effect + on applets which require pidfiles to run. + +config PID_FILE_PATH + string "Path to directory for pidfile" + default "/var/run" + depends on FEATURE_PIDFILE + help + This is the default path where pidfiles are created. Applets which + allow you to set the pidfile path on the command line will override + this value. The option has no effect on applets that require you to + specify a pidfile path. config FEATURE_SUID bool "Support for SUID/SGID handling" default y help With this option you can install the busybox binary belonging - to root with the suid bit set, and it will automatically drop - priviledges for applets that don't need root access. + to root with the suid bit set, enabling some applets to perform + root-level operations even when run by ordinary users + (for example, mounting of user mounts in fstab needs this). + + Busybox will automatically drop privileges for applets + that don't need root access. If you are really paranoid and don't want to do this, build two busybox binaries with different applets in them (and the appropriate symlinks pointing to each binary), and only set the suid bit on the - one that needs it. The applets currently marked to need the suid bit - are: + one that needs it. + + The applets which require root rights (need suid bit or + to be run by root) and will refuse to execute otherwise: + crontab, login, passwd, su, vlock, wall. - crontab, dnsd, findfs, ipcrm, ipcs, login, passwd, ping, su, - traceroute, vlock. + The applets which will use root rights if they have them + (via suid bit, or because run by root), but would try to work + without root right nevertheless: + findfs, ping[6], traceroute[6], mount. + + Note that if you DONT select this option, but DO make busybox + suid root, ALL applets will run under root, which is a huge + security hole (think "cp /some/file /etc/passwd"). config FEATURE_SUID_CONFIG bool "Runtime SUID/SGID configuration via /etc/busybox.conf" - default y if FEATURE_SUID + default y depends on FEATURE_SUID help Allow the SUID / SGID state of an applet to be determined at runtime by checking /etc/busybox.conf. (This is sort of a poor man's sudo.) The format of this file is as follows: - = [Ssx-][Ssx-][x-] (|).(|) + APPLET = [Ssx-][Ssx-][x-] [USER.GROUP] + + s: USER or GROUP is allowed to execute APPLET. + APPLET will run under USER or GROUP + (reagardless of who's running it). + S: USER or GROUP is NOT allowed to execute APPLET. + APPLET will run under USER or GROUP. + This option is not very sensical. + x: USER/GROUP/others are allowed to execute APPLET. + No UID/GID change will be done when it is run. + -: USER/GROUP/others are not allowed to execute APPLET. An example might help: @@ -327,7 +383,8 @@ config FEATURE_SUID_CONFIG su = ssx # exactly the same mount = sx- root.disk # applet mount can be run by root and members - # of group disk and runs with euid=0 + # of group disk (but not anyone else) + # and runs with euid=0 (egid is not changed) cp = --- # disable applet cp for everyone @@ -353,6 +410,7 @@ config FEATURE_SUID_CONFIG_QUIET config SELINUX bool "Support NSA Security Enhanced Linux" default n + select PLATFORM_LINUX help Enable support for SELinux in applets ls, ps, and id. Also provide the option of compiling in SELinux applets. @@ -433,7 +491,10 @@ config PIE default n depends on !STATIC help - (TODO: what is it and why/when is it useful?) + Hardened code option. PIE binaries are loaded at a different + address at each invocation. This has some overhead, + particularly on x86-32 which is short on registers. + Most people will leave this set to 'N'. config NOMMU @@ -530,7 +591,6 @@ config FEATURE_SHARED_BUSYBOX config LFS bool "Build with Large File Support (for accessing files > 2 GB)" default y - select FDISK_SUPPORT_LARGE_DISKS help If you want to build BusyBox with large file support, then enable this option. This will have no effect if your kernel or your C @@ -552,12 +612,39 @@ config CROSS_COMPILER_PREFIX Native builds leave this empty. +config SYSROOT + string "Path to sysroot" + default "" + help + If you want to build BusyBox with a cross compiler, then you + might also need to specify where /usr/include and /usr/lib + will be found. + + For example, BusyBox can be built against an installed + Android NDK, platform version 9, for ARM ABI with + + CONFIG_SYSROOT=/opt/android-ndk/platforms/android-9/arch-arm + + Native builds leave this empty. + config EXTRA_CFLAGS string "Additional CFLAGS" default "" help Additional CFLAGS to pass to the compiler verbatim. +config EXTRA_LDFLAGS + string "Additional LDFLAGS" + default "" + help + Additional LDFLAGS to pass to the linker verbatim. + +config EXTRA_LDLIBS + string "Additional LDLIBS" + default "" + help + Additional LDLIBS to pass to the linker with -l. + endmenu menu 'Debugging Options' @@ -634,25 +721,15 @@ config EFENCE endchoice -### config PARSE -### bool "Uniform config file parser debugging applet: parse" - endmenu -menu 'Installation Options' - -config INSTALL_NO_USR - bool "Don't use /usr" - default n - help - Disable use of /usr. Don't activate this option if you don't know - that you really want this behaviour. +menu 'Installation Options ("make install" behavior)' choice - prompt "Applets links" + prompt "What kind of applet links to install" default INSTALL_APPLET_SYMLINKS help - Choose how you install applets links. + Choose what kind of links to applets are created by "make install". config INSTALL_APPLET_SYMLINKS bool "as soft-links" @@ -674,10 +751,10 @@ config INSTALL_APPLET_SCRIPT_WRAPPERS config INSTALL_APPLET_DONT bool "not installed" - depends on FEATURE_INSTALLER || FEATURE_SH_STANDALONE || FEATURE_PREFER_APPLETS help - Do not install applet links. Useful when using the -install feature - or a standalone shell for rescue purposes. + Do not install applet links. Useful when you plan to use + busybox --install for installing links, or plan to use + a standalone shell and thus don't need applet links. endchoice @@ -701,8 +778,8 @@ config INSTALL_SH_APPLET_HARDLINK config INSTALL_SH_APPLET_SCRIPT_WRAPPER bool "as script wrapper" help - Install /bin/sh applet as script wrapper that call the busybox - binary. + Install /bin/sh applet as script wrapper that calls + the busybox binary. endchoice diff --git a/INSTALL b/INSTALL index ec2b028..750cfc4 100644 --- a/INSTALL +++ b/INSTALL @@ -47,8 +47,11 @@ 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 or not. If you do not have /proc, then point that config option +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: ==================== @@ -70,7 +73,9 @@ 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). +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 @@ -97,7 +102,7 @@ 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 standaone install capability into the busybox base applet, +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). diff --git a/LICENSE b/LICENSE index 0e32274..6f50a71 100644 --- a/LICENSE +++ b/LICENSE @@ -346,515 +346,3 @@ 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. - - - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 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. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations -below. - - When we speak of free software, we are referring to freedom of use, -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 and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it -becomes a de-facto standard. To achieve this, non-free programs must -be allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, 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 library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete 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 distribute a copy of this License along with the -Library. - - 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 Library or any portion -of it, thus forming a work based on the Library, 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) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -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 Library, 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 Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you 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. - - If distribution of 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 satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at least - three years, to give the same user the materials specified in - Subsection 6a, above, for a charge no more than the cost of - performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be 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. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library 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. - - 9. 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 Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -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 with -this License. - - 11. 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 Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library 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 Library. - -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. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library 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. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser 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 Library -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 Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -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 - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "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 -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. 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 LIBRARY 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 -LIBRARY (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 LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), 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 Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms -of the ordinary General Public License). - - To apply these terms, attach the following notices to the library. -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 library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; 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. - -You should also get your employer (if you work as a programmer) or -your school, if any, to sign a "copyright disclaimer" for the library, -if necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James - Random Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! - - diff --git a/Makefile b/Makefile index 03e9885..33d59e3 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ VERSION = 1 -PATCHLEVEL = 17 +PATCHLEVEL = 22 SUBLEVEL = 1 EXTRAVERSION = NAME = Unnamed @@ -297,6 +297,7 @@ 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 @@ -433,7 +434,12 @@ ifeq ($(config-targets),1) -include $(srctree)/arch/$(ARCH)/Makefile export KBUILD_DEFCONFIG -config %config: scripts_basic outputmakefile gen_build_files FORCE +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 @@ -459,7 +465,7 @@ core-y := \ libs-y := \ archival/ \ - archival/libunarchive/ \ + archival/libarchive/ \ console-tools/ \ coreutils/ \ coreutils/libcoreutils/ \ @@ -837,7 +843,7 @@ export CPPFLAGS_busybox.lds += -P -C -U$(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 + cmd_gen_bbconfigopts = $(srctree)/scripts/mkconfigs include/bbconfigopts.h include/bbconfigopts_bz2.h quiet_cmd_split_autoconf = SPLIT include/autoconf.h -> include/config/* cmd_split_autoconf = scripts/basic/split-include include/autoconf.h include/config #bbox# piggybacked generation of few .h files @@ -958,10 +964,14 @@ CLEAN_FILES += busybox busybox_unstripped* busybox.links \ # 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/autoconf.h \ include/bbconfigopts.h \ + include/bbconfigopts_bz2.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 @@ -986,7 +996,7 @@ clean: archclean $(clean-dirs) PHONY += doc-clean doc-clean: rm-files := docs/busybox.pod \ - docs/BusyBox.html docs/BusyBox.1 docs/BusyBox.txt + docs/BusyBox.html docs/busybox.1 docs/BusyBox.txt doc-clean: $(call cmd,rmfiles) @@ -1003,8 +1013,8 @@ $(mrproper-dirs): 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 + @find . -name Config.src | sed 's/.src$$/.in/' | xargs -r rm -f + @find . -name Kbuild.src | sed 's/.src$$//' | xargs -r rm -f # distclean # @@ -1033,7 +1043,7 @@ rpm: FORCE # Brief documentation of the typical targets used # --------------------------------------------------------------------------- -boards := $(wildcard $(srctree)/arch/$(ARCH)/configs/*_defconfig) +boards := $(wildcard $(srctree)/configs/*_defconfig) boards := $(notdir $(boards)) -include $(srctree)/Makefile.help @@ -1122,15 +1132,6 @@ clean: $(clean-dirs) -o -name '.*.d' -o -name '.*.tmp' -o -name '*.mod.c' \) \ -type f -print | xargs rm -f -help: - @echo ' Building external modules.' - @echo ' Syntax: make -C path/to/kernel/src M=$$PWD target' - @echo '' - @echo ' modules - default target, build the module(s)' - @echo ' modules_install - install the module' - @echo ' clean - remove generated files in module directory only' - @echo '' - # Dummies... PHONY += prepare scripts prepare: ; @@ -1285,9 +1286,13 @@ endif $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) # Modules -/ %/: prepare scripts FORCE +%/: 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) diff --git a/Makefile.custom b/Makefile.custom index 01d69dd..8c95ef2 100644 --- a/Makefile.custom +++ b/Makefile.custom @@ -3,7 +3,12 @@ # ========================================================================== busybox.links: $(srctree)/applets/busybox.mkll $(objtree)/include/autoconf.h include/applets.h - $(Q)-$(SHELL) $^ >$@ + $(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_SYMLINKS),y) @@ -69,6 +74,10 @@ release: distclean -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 {} \; ; \ @@ -107,7 +116,7 @@ bigdata: busybox_unstripped # Documentation Targets .PHONY: doc -doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html +doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html # FIXME: Doesn't belong here cmd_doc = @@ -125,6 +134,7 @@ docs/busybox.pod: $(srctree)/docs/busybox_header.pod \ $(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 @@ -134,10 +144,10 @@ docs/BusyBox.txt: docs/busybox.pod $(Q)-mkdir -p docs $(Q)-pod2text $< > $@ -docs/BusyBox.1: docs/busybox.pod +docs/busybox.1: docs/busybox.pod $(disp_doc) $(Q)-mkdir -p docs - $(Q)-pod2man --center=BusyBox --release="version $(KERNELVERSION)" $< > $@ + $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ docs/BusyBox.html: docs/busybox.net/BusyBox.html $(disp_doc) diff --git a/Makefile.flags b/Makefile.flags index 1ffa738..307afa7 100644 --- a/Makefile.flags +++ b/Makefile.flags @@ -4,7 +4,7 @@ BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) export BB_VER -SKIP_STRIP = n +SKIP_STRIP ?= n # -std=gnu99 needed for [U]LLONG_MAX on some systems CPPFLAGS += $(call cc-option,-std=gnu99,) @@ -25,6 +25,7 @@ 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 @@ -52,20 +53,23 @@ CFLAGS += $(call cc-option,-fno-builtin-strlen -finline-limit=0 -fomit-frame-poi CFLAGS += $(call cc-option,-fno-guess-branch-probability,) CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,) CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,) +# 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,) # 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,-Os,) +CFLAGS += $(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,-Os,) +CFLAGS += $(call cc-option,-Os,$(call cc-option,-O2,)) endif endif @@ -74,6 +78,12 @@ 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) @@ -85,6 +95,7 @@ endif ifeq ($(CONFIG_STATIC),y) CFLAGS_busybox += -static +PKG_CONFIG_FLAGS += --static endif ifeq ($(CONFIG_PIE),y) @@ -97,14 +108,40 @@ 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 + +# 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;}' >crypttest.c; $(CC) $(CFLAGS) -lcrypt -o /dev/null crypttest.c >/dev/null 2>&1 && echo "y"; rm crypttest.c) +ifeq ($(CRYPT_AVAILABLE),y) LDLIBS += m crypt +else +LDLIBS += m +endif ifeq ($(CONFIG_PAM),y) -LDLIBS += pam pam_misc +# libpam uses libpthread, so for static builds busybox must be linked to +# libpthread. On some platforms that requires an explicit -lpthread, so +# it should be in LDLIBS. For non-static builds, scripts/trylink will +# take care of removing -lpthread if possible. (Not bothering to check +# CONFIG_STATIC because even in a non-static build it could be that the +# only libpam available is libpam.a, so -lpthread could still be +# needed.) +LDLIBS += pam pam_misc pthread endif ifeq ($(CONFIG_SELINUX),y) -LDLIBS += selinux sepol +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_EFENCE),y) @@ -115,10 +152,6 @@ ifeq ($(CONFIG_DMALLOC),y) LDLIBS += dmalloc endif -ifeq ($(CONFIG_SYSLOGD),y) -LDLIBS += systemd-daemon -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. @@ -129,6 +162,16 @@ ifneq (,$(findstring $(W_ELF2FLT),$(LDFLAGS) $(CFLAGS_busybox))) SKIP_STRIP = y endif +ifneq ($(CONFIG_EXTRA_LDFLAGS),) +EXTRA_LDFLAGS += $(strip $(subst ",,$(CONFIG_EXTRA_LDFLAGS))) +#")) +endif + +ifneq ($(CONFIG_EXTRA_LDLIBS),) +LDLIBS += $(strip $(subst ",,$(CONFIG_EXTRA_LDLIBS))) +#")) +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!) diff --git a/Makefile.help b/Makefile.help index 999d029..119dd6f 100644 --- a/Makefile.help +++ b/Makefile.help @@ -25,6 +25,10 @@ help: @echo ' You can use these commands if the commands on the host' @echo ' is unusable. Afterwards use it like:' @echo ' make SED="$(objtree)/sed"' + @$(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' diff --git a/README b/README index 3a9d849..b940e35 100644 --- a/README +++ b/README @@ -44,7 +44,7 @@ Using busybox: 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 builtin applets without needing them to be + 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.) @@ -80,7 +80,7 @@ Downloading the current source code: 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 subversion changelog. + what happened is the git changelog. Note: if you want to compile busybox in a busybox environment you must select CONFIG_DESKTOP. @@ -169,7 +169,7 @@ Portability: 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 suprised if it doesn't work out of the box. If + 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. diff --git a/TODO b/TODO index 6f8cd8a..dcf48c2 100644 --- a/TODO +++ b/TODO @@ -2,6 +2,8 @@ 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 @@ -82,7 +84,7 @@ Rob Landley suggested this: initramfs Busybox should have a sample initramfs build script. This depends on - bbsh, mdev, and switch_root. + shell, mdev, and switch_root. mkdep Write a mkdep that doesn't segfault if there's a directory it doesn't @@ -125,20 +127,6 @@ patch 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 ---- -stty / catv - stty's visible() function and catv's guts are identical. Merge them into - an appropriate libbb function. ---- -struct suffix_mult - Several duplicate users of: grep -r "1024\*1024" * -B2 -A1 - Merge to a single size_suffixes[] in libbb. - Users: head tail od_bloaty hexdump and (partially as it wouldn't hurt) svlogd ---- -tail - ./busybox tail -f foo.c~ TODO - should not print fmt=header_fmt for subsequent date >> TODO; i.e. only - fmt+ if another (not the current) file did change Architectural issues: @@ -232,8 +220,6 @@ Minor stuff: See grep -r strtod Alot of duplication that wants cleanup. --- - in_ether duplicated in network/{interface,ifconfig}.c ---- unify progress_meter. wget, flash_eraseall, pipe_progress, fbsplash, setfiles. --- support start-stop-daemon -d diff --git a/applets/.gitignore b/applets/.gitignore index cc932fc..459938d 100644 --- a/applets/.gitignore +++ b/applets/.gitignore @@ -1,2 +1,3 @@ /applet_tables /usage +/usage_pod diff --git a/applets/Kbuild.src b/applets/Kbuild.src index 31fee8d..b612399 100644 --- a/applets/Kbuild.src +++ b/applets/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. obj-y := obj-y += applets.o @@ -42,3 +42,6 @@ quiet_cmd_gen_applet_tables = GEN include/applet_tables.h include/applet_tables.h: applets/applet_tables $(call cmd,gen_applet_tables) + +include/NUM_APPLETS.h: applets/applet_tables + $(call cmd,gen_applet_tables) diff --git a/applets/applet_tables.c b/applets/applet_tables.c index 338dc20..94b974e 100644 --- a/applets/applet_tables.c +++ b/applets/applet_tables.c @@ -5,15 +5,21 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPLv2, see file License in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ - +#include +#include +#include #include #include #include +#include + +#undef ARRAY_SIZE +#define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) #include "../include/autoconf.h" -#include "../include/busybox.h" +#include "../include/applet_metadata.h" struct bb_applet { const char *name; @@ -47,7 +53,7 @@ int main(int argc, char **argv) { int i; int ofs; - unsigned MAX_APPLET_NAME_LEN = 1; +// unsigned MAX_APPLET_NAME_LEN = 1; qsort(applets, NUM_APPLETS, sizeof(applets[0]), cmp_name); @@ -75,7 +81,7 @@ int main(int argc, char **argv) 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].name); + printf("#define SINGLE_APPLET_MAIN %s_main\n", applets[0].main); } printf("\n"); @@ -83,8 +89,8 @@ int main(int argc, char **argv) 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); +// if (MAX_APPLET_NAME_LEN < strlen(applets[i].name)) +// MAX_APPLET_NAME_LEN = strlen(applets[i].name); } printf(";\n\n"); @@ -124,8 +130,8 @@ int main(int argc, char **argv) printf("};\n"); #endif //printf("#endif /* SKIP_definitions */\n"); - printf("\n"); - printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); +// printf("\n"); +// printf("#define MAX_APPLET_NAME_LEN %u\n", MAX_APPLET_NAME_LEN); if (argv[2]) { char line_old[80]; diff --git a/applets/applets.c b/applets/applets.c index 6a39962..98c2b44 100644 --- a/applets/applets.c +++ b/applets/applets.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPLv2, see file License in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "busybox.h" diff --git a/applets/busybox.mkll b/applets/busybox.mkll index 6d61f7e..68dbf21 100755 --- a/applets/busybox.mkll +++ b/applets/busybox.mkll @@ -14,7 +14,7 @@ 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,8) + dir=substr($2,7) gsub("_","/",dir) if(dir=="/ROOT") dir="" file=$3 diff --git a/applets/busybox.mksuid b/applets/busybox.mksuid new file mode 100755 index 0000000..6492c07 --- /dev/null +++ b/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/applets/individual.c b/applets/individual.c index 341f4d1..4c468df 100644 --- a/applets/individual.c +++ b/applets/individual.c @@ -2,7 +2,7 @@ * * Copyright 2005 Rob Landley $prefix$i - chmod +x $prefix/$i + rm -f "$prefix/$i" + echo "#!/bin/busybox" >"$prefix/$i" + chmod +x "$prefix/$i" fi - echo " $prefix$i" + echo " $prefix/$i" else if [ "$2" = "--hardlinks" ]; then bb_path="$prefix/bin/busybox" @@ -89,20 +92,20 @@ for i in $h; do /sbin) bb_path="../bin/busybox" ;; - /usr/bin|/usr/sbin) + /usr/bin | /usr/sbin) bb_path="../../bin/busybox" ;; *) - echo "Unknown installation directory: $appdir" - exit 1 + echo "Unknown installation directory: $appdir" + exit 1 ;; esac fi - if [ "$noclobber" = "0" ] || [ ! -e "$prefix$i" ]; then - echo " $prefix$i -> $bb_path" - ln $linkopts $bb_path $prefix$i || exit 1 + if [ "$noclobber" = "0" ] || [ ! -e "$prefix/$i" ]; then + echo " $prefix/$i -> $bb_path" + ln $linkopts "$bb_path" "$prefix/$i" || exit 1 else - echo " $prefix$i already exists" + echo " $prefix/$i already exists" fi fi done diff --git a/applets/usage.c b/applets/usage.c index 46adbf4..94520ff 100644 --- a/applets/usage.c +++ b/applets/usage.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2008 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include #include diff --git a/applets/usage_compressed b/applets/usage_compressed index e1fd0d9..fb6e1c2 100755 --- a/applets/usage_compressed +++ b/applets/usage_compressed @@ -9,14 +9,21 @@ 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 -t x1 \ +"$loc/usage" | od -v -b \ | $SED -e 's/^[^ ]*//' \ -e 's/ //g' \ -e '/^$/d' \ - -e 's/\(..\)/\\x\1/g' \ + -e 's/\(...\)/\\\1/g' \ -e 's/^/"/' \ -e 's/$/" \\/' echo '' @@ -32,11 +39,11 @@ echo '#define PACKED_USAGE \' ## -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 -t x1 \ +"$loc/usage" | bzip2 -1 | $DD bs=2 skip=1 2>/dev/null | od -v -b \ | $SED -e 's/^[^ ]*//' \ -e 's/ //g' \ -e '/^$/d' \ - -e 's/\(..\)/0x\1,/g' \ + -e 's/\(...\)/0\1,/g' \ -e 's/$/ \\/' echo '' diff --git a/applets/usage_pod.c b/applets/usage_pod.c index 85a2a8e..0b1c4aa 100644 --- a/applets/usage_pod.c +++ b/applets/usage_pod.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2009 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include #include @@ -31,8 +31,8 @@ #include "usage.h" #define MAKE_USAGE(aname, usage) { aname, usage }, static struct usage_data { - const char *aname; - const char *usage; + const char *aname; + const char *usage; } usage_array[] = { #include "applets.h" }; diff --git a/applets_sh/README b/applets_sh/README new file mode 100644 index 0000000..9dcd38a --- /dev/null +++ b/applets_sh/README @@ -0,0 +1,5 @@ +This directory contains examples of applets implemented as shell scripts. + +So far these scripts are not hooked to the build system and are not +installed by "make install". If you want to use them, +you need to install them by hand. diff --git a/applets_sh/dos2unix b/applets_sh/dos2unix new file mode 100755 index 0000000..0fd5206 --- /dev/null +++ b/applets_sh/dos2unix @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/\r$//' "$@" diff --git a/applets_sh/nologin b/applets_sh/nologin new file mode 100755 index 0000000..3768eaa --- /dev/null +++ b/applets_sh/nologin @@ -0,0 +1,4 @@ +#!/bin/sh +cat /etc/nologin.txt 2>/dev/null || echo "This account is not available" +sleep 5 +exit 1 diff --git a/applets_sh/tac b/applets_sh/tac new file mode 100755 index 0000000..c5a8e39 --- /dev/null +++ b/applets_sh/tac @@ -0,0 +1,7 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +for i in "$@" +do +sed -e '1!G;h;$!d' "$i" +done diff --git a/applets_sh/unix2dos b/applets_sh/unix2dos new file mode 100755 index 0000000..70e0429 --- /dev/null +++ b/applets_sh/unix2dos @@ -0,0 +1,5 @@ +#!/bin/sh +# TODO: use getopt to avoid parsing options as filenames, +# and to support -- and --help +[ $# -ne 0 ] && DASH_I=-i +sed $DASH_I -e 's/$/\r/' "$@" diff --git a/archival/Config.src b/archival/Config.src index 9a84fd6..76635ba 100644 --- a/archival/Config.src +++ b/archival/Config.src @@ -5,8 +5,6 @@ menu "Archival Utilities" -INSERT - config FEATURE_SEAMLESS_XZ bool "Make tar, rpm, modprobe etc understand .xz data" default y @@ -32,348 +30,11 @@ config FEATURE_SEAMLESS_GZ Make tar, rpm, modprobe etc understand .gz data. config FEATURE_SEAMLESS_Z - bool "Make tar and gunzip understand .Z data" - default n - help - Make tar and gunzip understand .Z data. - -config AR - bool "ar" - default n # needs to be improved to be able to replace binutils ar - help - ar is an archival utility program used to create, modify, and - extract contents from archives. An archive is a single file holding - a collection of other files in a structure that makes it possible to - retrieve the original individual files (called archive members). - The original files' contents, mode (permissions), timestamp, owner, - and group are preserved in the archive, and can be restored on - extraction. - - The stored filename is limited to 15 characters. (for more information - see long filename support). - ar has 60 bytes of overheads for every stored file. - - This implementation of ar can extract archives, it cannot create or - modify them. - On an x86 system, the ar applet adds about 1K. - - Unless you have a specific application which requires ar, you should - probably say N here. - -config FEATURE_AR_LONG_FILENAMES - bool "Support for long filenames (not needed for debs)" - default y - depends on AR - help - By default the ar format can only store the first 15 characters - of the filename, this option removes that limitation. - It supports the GNU ar long filename method which moves multiple long - filenames into a the data section of a new ar entry. - -config FEATURE_AR_CREATE - bool "Support archive creation" - default y - depends on AR - help - This enables archive creation (-c and -r) with busybox ar. - -config BUNZIP2 - bool "bunzip2" - default y - help - bunzip2 is a compression utility using the Burrows-Wheeler block - sorting text compression algorithm, and Huffman coding. Compression - is generally considerably better than that achieved by more - conventional LZ77/LZ78-based compressors, and approaches the - performance of the PPM family of statistical compressors. - - Unless you have a specific application which requires bunzip2, you - should probably say N here. - -config BZIP2 - bool "bzip2" - default y - help - bzip2 is a compression utility using the Burrows-Wheeler block - sorting text compression algorithm, and Huffman coding. Compression - is generally considerably better than that achieved by more - conventional LZ77/LZ78-based compressors, and approaches the - performance of the PPM family of statistical compressors. - - Unless you have a specific application which requires bzip2, you - should probably say N here. - -config CPIO - bool "cpio" - default y - help - cpio is an archival utility program used to create, modify, and - extract contents from archives. - cpio has 110 bytes of overheads for every stored file. - - This implementation of cpio can extract cpio archives created in the - "newc" or "crc" format, it cannot create or modify them. - - Unless you have a specific application which requires cpio, you - should probably say N here. - -config FEATURE_CPIO_O - bool "Support for archive creation" - default y - depends on CPIO - help - This implementation of cpio can create cpio archives in the "newc" - format only. - -config FEATURE_CPIO_P - bool "Support for passthrough mode" - default y - depends on FEATURE_CPIO_O - help - Passthrough mode. Rarely used. - -config DPKG - bool "dpkg" - default n - select FEATURE_SEAMLESS_GZ - help - dpkg is a medium-level tool to install, build, remove and manage - Debian packages. - - This implementation of dpkg has a number of limitations, - you should use the official dpkg if possible. - -config DPKG_DEB - bool "dpkg_deb" - default n - select FEATURE_SEAMLESS_GZ - help - dpkg-deb unpacks and provides information about Debian archives. - - This implementation of dpkg-deb cannot pack archives. - - Unless you have a specific application which requires dpkg-deb, - say N here. - -config FEATURE_DPKG_DEB_EXTRACT_ONLY - bool "Extract only (-x)" - default n - depends on DPKG_DEB - help - This reduces dpkg-deb to the equivalent of - "ar -p data.tar.gz | tar -zx". However it saves space as none - of the extra dpkg-deb, ar or tar options are needed, they are linked - to internally. - -config GUNZIP - bool "gunzip" - default y - help - gunzip is used to decompress archives created by gzip. - You can use the `-t' option to test the integrity of - an archive, without decompressing it. - -config GZIP - bool "gzip" - default y - help - gzip is used to compress files. - It's probably the most widely used UNIX compression program. - -config FEATURE_GZIP_LONG_OPTIONS - bool "Enable long options" - default y - depends on GZIP && LONG_OPTS - help - Enable use of long options, increases size by about 106 Bytes - -config LZOP - bool "lzop" - default y - help - Lzop compression/decompresion. - -config LZOP_COMPR_HIGH - bool "lzop complession levels 7,8,9 (not very useful)" - default n - depends on LZOP - help - High levels (7,8,9) of lzop compression. These levels - are actually slower than gzip at equivalent compression ratios - and take up 3.2K of code. - -config RPM2CPIO - bool "rpm2cpio" - default y - help - Converts an RPM file into a CPIO archive. - -config RPM - bool "rpm" - default y - help - Mini RPM applet - queries and extracts RPM packages. - -config TAR - bool "tar" - default y - help - tar is an archiving program. It's commonly used with gzip to - create compressed archives. It's probably the most widely used - UNIX archive program. - -config FEATURE_TAR_CREATE - bool "Enable archive creation" - default y - depends on TAR - help - If you enable this option you'll be able to create - tar archives using the `-c' option. - -config FEATURE_TAR_AUTODETECT - bool "Autodetect compressed tarballs" - default y - depends on TAR && (FEATURE_SEAMLESS_Z || FEATURE_SEAMLESS_GZ || FEATURE_SEAMLESS_BZ2 || FEATURE_SEAMLESS_LZMA || FEATURE_SEAMLESS_XZ) - help - With this option tar can automatically detect compressed - tarballs. Currently it works only on files (not pipes etc). - -config FEATURE_TAR_FROM - bool "Enable -X (exclude from) and -T (include from) options)" - default y - depends on TAR - help - If you enable this option you'll be able to specify - a list of files to include or exclude from an archive. - -config FEATURE_TAR_OLDGNU_COMPATIBILITY - bool "Support for old tar header format" - default y - depends on TAR || DPKG - help - This option is required to unpack archives created in - the old GNU format; help to kill this old format by - repacking your ancient archives with the new format. - -config FEATURE_TAR_OLDSUN_COMPATIBILITY - bool "Enable untarring of tarballs with checksums produced by buggy Sun tar" - default y - depends on TAR || DPKG - help - This option is required to unpack archives created by some old - version of Sun's tar (it was calculating checksum using signed - arithmetic). It is said to be fixed in newer Sun tar, but "old" - tarballs still exist. - -config FEATURE_TAR_GNU_EXTENSIONS - bool "Support for GNU tar extensions (long filenames)" - default y - depends on TAR || DPKG - help - With this option busybox supports GNU long filenames and - linknames. - -config FEATURE_TAR_LONG_OPTIONS - bool "Enable long options" - default y - depends on TAR && LONG_OPTS - help - Enable use of long options, increases size by about 400 Bytes - -config FEATURE_TAR_TO_COMMAND - bool "Support for writing to an external program" - default y - depends on TAR && FEATURE_TAR_LONG_OPTIONS - help - If you enable this option you'll be able to instruct tar to send - the contents of each extracted file to the standard input of an - external program. - -config FEATURE_TAR_UNAME_GNAME - bool "Enable use of user and group names" - default y - depends on TAR - help - Enables use of user and group names in tar. This affects contents - listings (-t) and preserving permissions when unpacking (-p). - +200 bytes. - -config FEATURE_TAR_NOPRESERVE_TIME - bool "Enable -m (do not preserve time) option" - default y - depends on TAR - help - With this option busybox supports GNU tar -m - (do not preserve time) option. - -config FEATURE_TAR_SELINUX - bool "Support for extracting SELinux labels" + bool "tar, rpm, modprobe etc understand .Z data" default n - depends on TAR && SELINUX help - With this option busybox supports restoring SELinux labels - when extracting files from tar archives. - -config UNCOMPRESS - bool "uncompress" - default n - help - uncompress is used to decompress archives created by compress. - Not much used anymore, replaced by gzip/gunzip. - -config UNLZMA - bool "unlzma" - default y - help - unlzma is a compression utility using the Lempel-Ziv-Markov chain - compression algorithm, and range coding. Compression - is generally considerably better than that achieved by the bzip2 - compressors. - - The BusyBox unlzma applet is limited to de-compression only. - On an x86 system, this applet adds about 4K. - - Unless you have a specific application which requires unlzma, you - should probably say N here. + Make tar, rpm, modprobe etc understand .Z data. -config FEATURE_LZMA_FAST - bool "Optimize unlzma for speed" - default y - depends on UNLZMA - help - This option reduces decompression time by about 25% at the cost of - a 1K bigger binary. - -config LZMA - bool "Provide lzma alias which supports only unpacking" - default y - depends on UNLZMA - help - Enable this option if you want commands like "lzma -d" to work. - IOW: you'll get lzma applet, but it will always require -d option. - -config UNXZ - bool "unxz" - default y - help - unxz is a unlzma successor. - -config XZ - bool "Provide xz alias which supports only unpacking" - default y - depends on UNXZ - help - Enable this option if you want commands like "xz -d" to work. - IOW: you'll get xz applet, but it will always require -d option. - -config UNZIP - bool "unzip" - default y - help - unzip will list or extract files from a ZIP archive, - commonly found on DOS/WIN systems. The default behavior - (with no options) is to extract the archive into the - current directory. Use the `-d' option to extract to a - directory of your choice. +INSERT endmenu diff --git a/archival/Kbuild.src b/archival/Kbuild.src index 076e582..a6fd2ea 100644 --- a/archival/Kbuild.src +++ b/archival/Kbuild.src @@ -2,30 +2,10 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. -libs-y += libunarchive/ +libs-y += libarchive/ lib-y:= INSERT - -lib-$(CONFIG_AR) += ar.o -lib-$(CONFIG_CPIO) += cpio.o -lib-$(CONFIG_DPKG) += dpkg.o -lib-$(CONFIG_DPKG_DEB) += dpkg_deb.o -lib-$(CONFIG_RPM2CPIO) += rpm2cpio.o -lib-$(CONFIG_RPM) += rpm.o -lib-$(CONFIG_TAR) += tar.o -lib-$(CONFIG_UNZIP) += unzip.o - -lib-$(CONFIG_LZOP) += lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o bbunzip.o -lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o -lib-$(CONFIG_GZIP) += gzip.o bbunzip.o -lib-$(CONFIG_BZIP2) += bzip2.o bbunzip.o - -lib-$(CONFIG_UNXZ) += bbunzip.o -lib-$(CONFIG_UNLZMA) += bbunzip.o -lib-$(CONFIG_BUNZIP2) += bbunzip.o -lib-$(CONFIG_GUNZIP) += bbunzip.o -lib-$(CONFIG_UNCOMPRESS) += bbunzip.o diff --git a/archival/ar.c b/archival/ar.c index 1b7b66a..f86c52d 100644 --- a/archival/ar.c +++ b/archival/ar.c @@ -6,7 +6,7 @@ * * Based in part on BusyBox tar, Debian dpkg-deb and GNU ar. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Archive creation support: * Copyright (C) 2010 Nokia Corporation. All rights reserved. @@ -17,8 +17,61 @@ * http://www.unix-systems.org/single_unix_specification_v2/xcu/ar.html */ +//config:config AR +//config: bool "ar" +//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. An archive is a single file holding +//config: a collection of other files in a structure that makes it possible to +//config: retrieve the original individual files (called archive members). +//config: The original files' contents, mode (permissions), timestamp, owner, +//config: and group are preserved in the archive, and can be restored on +//config: extraction. +//config: +//config: The stored filename is limited to 15 characters. (for more information +//config: see long filename support). +//config: ar has 60 bytes of overheads for every stored file. +//config: +//config: This implementation of ar can extract archives, it cannot create or +//config: modify them. +//config: On an x86 system, the ar applet adds about 1K. +//config: +//config: Unless you have a specific application which requires ar, you should +//config: probably say N here. +//config: +//config:config FEATURE_AR_LONG_FILENAMES +//config: bool "Support for 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 + +//usage:#define ar_trivial_usage +//usage: "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES" +//usage:#define ar_full_usage "\n\n" +//usage: "Extract or list FILES from an ar archive\n" +//usage: "\n -o Preserve original dates" +//usage: "\n -p Extract to stdout" +//usage: "\n -t List" +//usage: "\n -x Extract" +//usage: "\n -v Verbose" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "ar.h" #if ENABLE_FEATURE_AR_CREATE @@ -71,7 +124,7 @@ static void output_ar_header(archive_handle_t *handle) } /* - * when replacing files in an existing archive, copy from the the + * 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) @@ -123,8 +176,7 @@ static int write_ar_archive(archive_handle_t *handle) struct stat st; archive_handle_t *out_handle; - if (fstat(handle->src_fd, &st) == -1) - bb_simple_perror_msg_and_die(handle->ar__name); + 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. @@ -180,17 +232,17 @@ static void FAST_FUNC header_verbose_list_ar(const file_header_t *file_header) ); } -#define AR_OPT_VERBOSE (1 << 0) -#define AR_OPT_PRESERVE_DATE (1 << 1) +#define AR_OPT_VERBOSE (1 << 0) +#define AR_OPT_PRESERVE_DATE (1 << 1) /* "ar r" implies create, but warns about it. c suppresses warning. * bbox accepts but ignores it: */ -#define AR_OPT_CREATE (1 << 2) +#define AR_OPT_CREATE (1 << 2) -#define AR_CMD_PRINT (1 << 3) -#define FIRST_CMD AR_CMD_PRINT -#define AR_CMD_LIST (1 << 4) -#define AR_CMD_EXTRACT (1 << 5) -#define AR_CMD_INSERT (1 << 6) +#define AR_CMD_PRINT (1 << 3) +#define FIRST_CMD AR_CMD_PRINT +#define AR_CMD_LIST (1 << 4) +#define AR_CMD_EXTRACT (1 << 5) +#define AR_CMD_INSERT (1 << 6) int ar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ar_main(int argc UNUSED_PARAM, char **argv) diff --git a/archival/bbunzip.c b/archival/bbunzip.c index c1259ac..b3fb90f 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c @@ -1,19 +1,25 @@ /* vi: set sw=4 ts=4: */ /* - * Common code for gunzip-like applets + * Common code for gunzip-like applets * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" +/* lzop_main() uses bbunpack(), need this: */ +//kbuild:lib-$(CONFIG_LZOP) += bbunzip.o + +/* Note: must be kept in sync with archival/lzop.c */ enum { OPT_STDOUT = 1 << 0, OPT_FORCE = 1 << 1, /* only some decompressors: */ OPT_VERBOSE = 1 << 2, - OPT_DECOMPRESS = 1 << 3, - OPT_TEST = 1 << 4, + OPT_QUIET = 1 << 3, + OPT_DECOMPRESS = 1 << 4, + OPT_TEST = 1 << 5, + SEAMLESS_MAGIC = (1 << 31) * SEAMLESS_COMPRESSION, }; static @@ -33,16 +39,16 @@ char* FAST_FUNC append_ext(char *filename, const char *expected_ext) } int FAST_FUNC bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), 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; + IF_DESKTOP(long long) int status = 0; char *filename, *new_name; smallint exitcode = 0; - unpack_info_t info; + transformer_aux_data_t aux; do { /* NB: new_name is *maybe* malloc'ed! */ @@ -54,13 +60,27 @@ int FAST_FUNC bbunpack(char **argv, /* Open src */ if (filename) { - if (stat(filename, &stat_buf) != 0) { - bb_simple_perror_msg(filename); + if (!(option_mask32 & SEAMLESS_MAGIC)) { + if (stat(filename, &stat_buf) != 0) { + err_name: + bb_simple_perror_msg(filename); err: - exitcode = 1; - goto free_name; + exitcode = 1; + goto free_name; + } + if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) + goto err; + } else { + /* "clever zcat" with FILE */ + int fd = open_zipped(filename); + if (fd < 0) + goto err_name; + xmove_fd(fd, STDIN_FILENO); } - if (open_to_or_warn(STDIN_FILENO, filename, O_RDONLY, 0)) + } else + if (option_mask32 & SEAMLESS_MAGIC) { + /* "clever zcat" on stdin */ + if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_detected*/ 0)) goto err; } @@ -68,7 +88,7 @@ int FAST_FUNC bbunpack(char **argv, if (option_mask32 & (OPT_STDOUT|OPT_TEST)) { if (option_mask32 & OPT_TEST) if (open_to_or_warn(STDOUT_FILENO, bb_dev_null, O_WRONLY, 0)) - goto err; + xfunc_die(); filename = NULL; } @@ -93,26 +113,37 @@ int FAST_FUNC bbunpack(char **argv, } /* Check that the input is sane */ - if (isatty(STDIN_FILENO) && (option_mask32 & OPT_FORCE) == 0) { + if (!(option_mask32 & OPT_FORCE) && isatty(STDIN_FILENO)) { bb_error_msg_and_die("compressed data not read from terminal, " "use -f to force it"); } - /* memset(&info, 0, sizeof(info)); */ - info.mtime = 0; /* so far it has one member only */ - status = unpacker(&info); - if (status < 0) - exitcode = 1; - xclose(STDOUT_FILENO); /* with error check! */ + if (!(option_mask32 & SEAMLESS_MAGIC)) { + init_transformer_aux_data(&aux); + aux.check_signature = 1; + status = unpacker(&aux); + 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 & 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 (info.mtime) { + if (aux.mtime != 0) { struct timeval times[2]; - times[1].tv_sec = times[0].tv_sec = info.mtime; + times[1].tv_sec = times[0].tv_sec = aux.mtime; times[1].tv_usec = times[0].tv_usec = 0; /* Note: we closed it first. * On some systems calling utimes @@ -121,28 +152,38 @@ int FAST_FUNC bbunpack(char **argv, utimes(new_name, times); /* ignoring errors */ } - /* Delete _compressed_ file */ + 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 & 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; - /* restore extension (unless tgz -> tar case) */ - if (new_name == filename) - filename[strlen(filename)] = '.'; } xunlink(del); - -#if 0 /* Currently buggy - wrong name: "a.gz: 261% - replaced with a.gz" */ - /* Extreme bloat for gunzip compat */ - if (ENABLE_DESKTOP && (option_mask32 & OPT_VERBOSE) && status >= 0) { - fprintf(stderr, "%s: %u%% - replaced with %s\n", - filename, (unsigned)(stat_buf.st_size*100 / (status+1)), new_name); - } -#endif - free_name: if (new_name != filename) free(new_name); } } while (*argv && *++argv); + if (option_mask32 & OPT_STDOUT) + xclose(STDOUT_FILENO); /* with error check! */ + return exitcode; } @@ -165,20 +206,29 @@ char* FAST_FUNC make_new_name_generic(char *filename, const char *expected_ext) /* * Uncompress applet for busybox (c) 2002 Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * 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 .Z file[s]\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Overwrite" + +//config:config UNCOMPRESS +//config: bool "uncompress" +//config: default n +//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 static -IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_uncompress(transformer_aux_data_t *aux) { - IF_DESKTOP(long long) int status = -1; - - if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) { - bb_error_msg("invalid magic"); - } else { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } - return status; + return unpack_Z_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int uncompress_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uncompress_main(int argc UNUSED_PARAM, char **argv) @@ -206,7 +256,7 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) * 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 tarball for details. + * 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 @@ -214,10 +264,39 @@ int uncompress_main(int argc UNUSED_PARAM, char **argv) * Portions of the lzw code are derived from the public domain 'compress' * written by Spencer Thomas, Joe Orost, James Woods, Jim McKie, Steve Davies, * Ken Turkowski, Dave Mack and Peter Jannesen. - * - * See the license_msg below and the file COPYING for the software license. - * See the file algorithm.doc for the compression algorithms and file formats. */ +//usage:#define gunzip_trivial_usage +//usage: "[-cft] [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 -t Test file 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" +//config: default y +//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. + +//applet:IF_GUNZIP(APPLET(gunzip, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, BB_DIR_BIN, BB_SUID_DROP, zcat)) +//kbuild:lib-$(CONFIG_GZIP) += bbunzip.o +//kbuild:lib-$(CONFIG_GUNZIP) += bbunzip.o #if ENABLE_GUNZIP static char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UNUSED_PARAM) @@ -245,31 +324,9 @@ char* FAST_FUNC make_new_name_gunzip(char *filename, const char *expected_ext UN return filename; } static -IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) +IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(transformer_aux_data_t *aux) { - IF_DESKTOP(long long) int status = -1; - - /* do the decompression, and cleanup */ - if (xread_char(STDIN_FILENO) == 0x1f) { - unsigned char magic2; - - magic2 = xread_char(STDIN_FILENO); - if (ENABLE_FEATURE_SEAMLESS_Z && magic2 == 0x9d) { - status = unpack_Z_stream(STDIN_FILENO, STDOUT_FILENO); - } else if (magic2 == 0x8b) { - status = unpack_gz_stream_with_info(STDIN_FILENO, STDOUT_FILENO, info); - } else { - goto bad_magic; - } - if (status < 0) { - bb_error_msg("error inflating"); - } - } else { - bad_magic: - bb_error_msg("invalid magic"); - /* status is still == -1 */ - } - return status; + return unpack_gz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } /* * Linux kernel build uses gzip -d -n. We accept and ignore it. @@ -287,11 +344,15 @@ IF_DESKTOP(long long) int FAST_FUNC unpack_gunzip(unpack_info_t *info) int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int gunzip_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdtn"); + getopt32(argv, "cfvqdtn"); argv += optind; - /* if called as zcat */ + + /* If called as zcat... + * Normally, "zcat" is just "gunzip -c". + * But if seamless magic is enabled, then we are much more clever. + */ if (applet_name[1] == 'c') - option_mask32 |= OPT_STDOUT; + option_mask32 |= OPT_STDOUT | SEAMLESS_MAGIC; return bbunpack(argv, unpack_gunzip, make_new_name_gunzip, /*unused:*/ NULL); } @@ -302,31 +363,46 @@ int gunzip_main(int argc UNUSED_PARAM, char **argv) * Modified for busybox by Glenn McGrath * Added support output to stdout by Thomas Lundquist * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ //usage:#define bunzip2_trivial_usage -//usage: "[OPTIONS] [FILE]..." +//usage: "[-cf] [FILE]..." //usage:#define bunzip2_full_usage "\n\n" //usage: "Decompress FILEs (or stdin)\n" -//usage: "\nOptions:" //usage: "\n -c Write to stdout" //usage: "\n -f Force" //usage:#define bzcat_trivial_usage -//usage: "FILE" +//usage: "[FILE]..." //usage:#define bzcat_full_usage "\n\n" //usage: "Decompress to stdout" -//applet:IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP, bzcat)) + +//config:config BUNZIP2 +//config: bool "bunzip2" +//config: default y +//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. + +//applet:IF_BUNZIP2(APPLET(bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) +//applet:IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, BB_DIR_USR_BIN, BB_SUID_DROP, bzcat)) +//kbuild:lib-$(CONFIG_BZIP2) += bbunzip.o +//kbuild:lib-$(CONFIG_BUNZIP2) += bbunzip.o #if ENABLE_BUNZIP2 static -IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_bunzip2(transformer_aux_data_t *aux) { - return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO); + return unpack_bz2_stream(aux, STDIN_FILENO, STDOUT_FILENO); } int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bunzip2_main(int argc UNUSED_PARAM, char **argv) { - getopt32(argv, "cfvdt"); + getopt32(argv, "cfvqdt"); argv += optind; if (applet_name[2] == 'c') /* bzcat */ option_mask32 |= OPT_STDOUT; @@ -342,18 +418,90 @@ int bunzip2_main(int argc UNUSED_PARAM, char **argv) * * Based on bunzip.c from busybox * - * Licensed under GPL v2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define unlzma_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define unlzma_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define lzma_trivial_usage +//usage: "-d [-cf] [FILE]..." +//usage:#define lzma_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define lzcat_trivial_usage +//usage: "[FILE]..." +//usage:#define lzcat_full_usage "\n\n" +//usage: "Decompress to stdout" +//usage: +//usage:#define unxz_trivial_usage +//usage: "[-cf] [FILE]..." +//usage:#define unxz_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define xz_trivial_usage +//usage: "-d [-cf] [FILE]..." +//usage:#define xz_full_usage "\n\n" +//usage: "Decompress FILE (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//usage: +//usage:#define xzcat_trivial_usage +//usage: "[FILE]..." +//usage:#define xzcat_full_usage "\n\n" +//usage: "Decompress to stdout" + +//config:config UNLZMA +//config: bool "unlzma" +//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: The BusyBox unlzma applet is limited to decompression only. +//config: On an x86 system, this applet adds about 4K. +//config: +//config:config FEATURE_LZMA_FAST +//config: bool "Optimize unlzma for speed" +//config: default n +//config: depends on UNLZMA +//config: help +//config: This option reduces decompression time by about 25% at the cost of +//config: a 1K bigger binary. +//config: +//config:config LZMA +//config: bool "Provide lzma alias which supports only unpacking" +//config: default y +//config: depends on UNLZMA +//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:IF_UNLZMA(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 #if ENABLE_UNLZMA static -IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unlzma(transformer_aux_data_t *aux) { - return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_lzma_stream(aux, STDIN_FILENO, STDOUT_FILENO); } 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, "cfvdt"); + IF_LZMA(int opts =) getopt32(argv, "cfvqdt"); # if ENABLE_LZMA /* lzma without -d or -t? */ if (applet_name[2] == 'm' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) @@ -369,25 +517,34 @@ int unlzma_main(int argc UNUSED_PARAM, char **argv) #endif +//config:config UNXZ +//config: bool "unxz" +//config: default y +//config: help +//config: unxz is a unlzma successor. +//config: +//config:config XZ +//config: bool "Provide xz alias which supports only unpacking" +//config: default y +//config: depends on UNXZ +//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:IF_UNXZ(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 #if ENABLE_UNXZ static -IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC unpack_unxz(transformer_aux_data_t *aux) { - struct { - uint32_t v1; - uint16_t v2; - } magic; - xread(STDIN_FILENO, &magic, 6); - if (magic.v1 != XZ_MAGIC1a || magic.v2 != XZ_MAGIC2a) { - bb_error_msg("invalid magic"); - return -1; - } - return unpack_xz_stream(STDIN_FILENO, STDOUT_FILENO); + return unpack_xz_stream(aux, STDIN_FILENO, STDOUT_FILENO); } 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, "cfvdt"); + IF_XZ(int opts =) getopt32(argv, "cfvqdt"); # if ENABLE_XZ /* xz without -d or -t? */ if (applet_name[2] == '\0' && !(opts & (OPT_DECOMPRESS|OPT_TEST))) diff --git a/archival/bzip2.c b/archival/bzip2.c index fdb8b93..f7718b4 100644 --- a/archival/bzip2.c +++ b/archival/bzip2.c @@ -7,10 +7,35 @@ * about bzip2 library code. */ +//config:config BZIP2 +//config: bool "bzip2" +//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. + +//applet:IF_BZIP2(APPLET(bzip2, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_BZIP2) += bzip2.o + +//usage:#define bzip2_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define bzip2_full_usage "\n\n" +//usage: "Compress FILEs (or stdin) with bzip2 algorithm\n" +//usage: "\n -1..9 Compression level" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" -#define CONFIG_BZIP2_FEATURE_SPEED 1 +#define CONFIG_BZIP2_FAST 1 /* Speed test: * Compiled with gcc 4.2.1, run on Athlon 64 1800 MHz (512K L2 cache). @@ -18,7 +43,7 @@ * (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 CONFIG_BZIP2_FEATURE_SPEED values on a 11Mb text file: + * Test run of all CONFIG_BZIP2_FAST 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 @@ -33,14 +58,14 @@ /* Takes ~300 bytes, detects corruption caused by bad RAM etc */ #define BZ_LIGHT_DEBUG 0 -#include "bz/bzlib.h" +#include "libarchive/bz/bzlib.h" -#include "bz/bzlib_private.h" +#include "libarchive/bz/bzlib_private.h" -#include "bz/blocksort.c" -#include "bz/bzlib.c" -#include "bz/compress.c" -#include "bz/huffman.c" +#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. @@ -102,7 +127,7 @@ IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, vo } static -IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC compressStream(transformer_aux_data_t *aux UNUSED_PARAM) { IF_DESKTOP(long long) int total; ssize_t count; @@ -128,10 +153,12 @@ IF_DESKTOP(long long) int FAST_FUNC compressStream(unpack_info_t *info UNUSED_PA break; } -#if ENABLE_FEATURE_CLEAN_UP + /* Can't be conditional on ENABLE_FEATURE_CLEAN_UP - + * we are called repeatedly + */ BZ2_bzCompressEnd(strm); free(iobuf); -#endif + return total; } diff --git a/archival/cpio.c b/archival/cpio.c index e0ca7fa..1cce7c8 100644 --- a/archival/cpio.c +++ b/archival/cpio.c @@ -4,15 +4,75 @@ * * Copyright (C) 2001 by Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * 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 - * */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" + +//config:config CPIO +//config: bool "cpio" +//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, it cannot create or modify them. +//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 for 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 for passthrough mode" +//config: default y +//config: depends on FEATURE_CPIO_O +//config: help +//config: Passthrough mode. Rarely used. + +//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]" 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 or list files from a cpio archive" +//usage: IF_FEATURE_CPIO_O(", or" +//usage: "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") +//usage: " using file list on stdin" +//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: "\n -d Make leading directories" +//usage: "\n -m Preserve mtime" +//usage: "\n -v Verbose" +//usage: "\n -u Overwrite" +//usage: "\n -F FILE Input (-t,-i,-p) or output (-o) file" +//usage: IF_FEATURE_CPIO_O( +//usage: "\n -H newc Archive format" +//usage: ) /* GNU cpio 2.9 --help (abridged): @@ -20,7 +80,7 @@ -t, --list List the archive -i, --extract Extract files from an archive -o, --create Create the archive - -p, --pass-through Copy-pass mode [was ist das?!] + -p, --pass-through Copy-pass mode Options valid in any mode: --block-size=SIZE I/O block size = SIZE * 512 bytes @@ -78,27 +138,28 @@ --sparse Write files with blocks of zeros as sparse files -u, --unconditional Replace all files unconditionally */ + enum { - CPIO_OPT_EXTRACT = (1 << 0), - CPIO_OPT_TEST = (1 << 1), - CPIO_OPT_NUL_TERMINATED = (1 << 2), - CPIO_OPT_UNCONDITIONAL = (1 << 3), - CPIO_OPT_VERBOSE = (1 << 4), - CPIO_OPT_CREATE_LEADING_DIR = (1 << 5), - CPIO_OPT_PRESERVE_MTIME = (1 << 6), - CPIO_OPT_DEREF = (1 << 7), - CPIO_OPT_FILE = (1 << 8), + 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), OPTBIT_FILE = 8, 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 ,) - CPIO_OPT_CREATE = IF_FEATURE_CPIO_O((1 << OPTBIT_CREATE )) + 0, - CPIO_OPT_FORMAT = IF_FEATURE_CPIO_O((1 << OPTBIT_FORMAT )) + 0, - CPIO_OPT_PASSTHROUGH = IF_FEATURE_CPIO_P((1 << OPTBIT_PASSTHROUGH)) + 0, - CPIO_OPT_QUIET = IF_LONG_OPTS( (1 << OPTBIT_QUIET )) + 0, - CPIO_OPT_2STDOUT = IF_LONG_OPTS( (1 << OPTBIT_2STDOUT )) + 0, + 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, }; #define OPTION_STR "it0uvdmLF:" @@ -138,7 +199,7 @@ static NOINLINE int cpio_o(void) char *line; struct stat st; - line = (option_mask32 & CPIO_OPT_NUL_TERMINATED) + line = (option_mask32 & OPT_NUL_TERMINATED) ? bb_get_chunk_from_file(stdin, NULL) : xmalloc_fgetline(stdin); @@ -153,7 +214,7 @@ static NOINLINE int cpio_o(void) free(line); continue; } - if ((option_mask32 & CPIO_OPT_DEREF) + if ((option_mask32 & OPT_DEREF) ? stat(name, &st) : lstat(name, &st) ) { @@ -223,24 +284,24 @@ static NOINLINE int cpio_o(void) } bytes += printf("070701" - "%08X%08X%08X%08X%08X%08X%08X" - "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ + "%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'); + (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) { @@ -308,28 +369,24 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) /* -L makes sense only with -o or -p */ #if !ENABLE_FEATURE_CPIO_O - /* no parameters */ - opt_complementary = "=0"; opt = getopt32(argv, OPTION_STR, &cpio_filename); argv += optind; - if (opt & CPIO_OPT_FILE) { /* -F */ + if (opt & OPT_FILE) { /* -F */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } #else - /* _exactly_ one parameter for -p, thus <= 1 param if -p is allowed */ - opt_complementary = ENABLE_FEATURE_CPIO_P ? "?1" : "=0"; opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt); argv += optind; - if ((opt & (CPIO_OPT_FILE|CPIO_OPT_CREATE)) == CPIO_OPT_FILE) { /* -F without -o */ + if ((opt & (OPT_FILE|OPT_CREATE)) == OPT_FILE) { /* -F without -o */ xmove_fd(xopen(cpio_filename, O_RDONLY), STDIN_FILENO); } - if (opt & CPIO_OPT_PASSTHROUGH) { + if (opt & OPT_PASSTHROUGH) { pid_t pid; struct fd_pair pp; if (argv[0] == NULL) bb_show_usage(); - if (opt & CPIO_OPT_CREATE_LEADING_DIR) + if (opt & OPT_CREATE_LEADING_DIR) mkdir(argv[0], 0777); /* Crude existence check: * close(xopen(argv[0], O_RDONLY | O_DIRECTORY)); @@ -358,19 +415,20 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) goto dump; } /* parent */ + USE_FOR_NOMMU(argv[-optind][0] &= 0x7f); /* undo fork_or_rexec() damage */ xchdir(*argv++); close(pp.wr); xmove_fd(pp.rd, STDIN_FILENO); - //opt &= ~CPIO_OPT_PASSTHROUGH; - opt |= CPIO_OPT_EXTRACT; + //opt &= ~OPT_PASSTHROUGH; + opt |= OPT_EXTRACT; goto skip; } /* -o */ - if (opt & CPIO_OPT_CREATE) { + if (opt & OPT_CREATE) { if (cpio_fmt[0] != 'n') /* we _require_ "-H newc" */ bb_show_usage(); - if (opt & CPIO_OPT_FILE) { - xmove_fd(xopen3(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); + if (opt & OPT_FILE) { + xmove_fd(xopen(cpio_filename, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } dump: return cpio_o(); @@ -379,35 +437,35 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) #endif /* One of either extract or test options must be given */ - if ((opt & (CPIO_OPT_TEST | CPIO_OPT_EXTRACT)) == 0) { + if ((opt & (OPT_TEST | OPT_EXTRACT)) == 0) { bb_show_usage(); } - if (opt & CPIO_OPT_TEST) { + if (opt & OPT_TEST) { /* if both extract and test options are given, ignore extract option */ - opt &= ~CPIO_OPT_EXTRACT; + opt &= ~OPT_EXTRACT; archive_handle->action_header = header_list; } - if (opt & CPIO_OPT_EXTRACT) { + if (opt & OPT_EXTRACT) { archive_handle->action_data = data_extract_all; - if (opt & CPIO_OPT_2STDOUT) + if (opt & OPT_2STDOUT) archive_handle->action_data = data_extract_to_stdout; } - if (opt & CPIO_OPT_UNCONDITIONAL) { + if (opt & OPT_UNCONDITIONAL) { archive_handle->ah_flags |= ARCHIVE_UNLINK_OLD; archive_handle->ah_flags &= ~ARCHIVE_EXTRACT_NEWER; } - if (opt & CPIO_OPT_VERBOSE) { + 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 & CPIO_OPT_CREATE_LEADING_DIR) { + if (opt & OPT_CREATE_LEADING_DIR) { archive_handle->ah_flags |= ARCHIVE_CREATE_LEADING_DIRS; } - if (opt & CPIO_OPT_PRESERVE_MTIME) { + if (opt & OPT_PRESERVE_MTIME) { archive_handle->ah_flags |= ARCHIVE_RESTORE_DATE; } @@ -423,7 +481,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv) continue; if (archive_handle->cpio__blocks != (off_t)-1 - && !(opt & CPIO_OPT_QUIET) + && !(opt & OPT_QUIET) ) { fprintf(stderr, "%"OFF_FMT"u blocks\n", archive_handle->cpio__blocks); } diff --git a/archival/dpkg.c b/archival/dpkg.c index 219512b..2893cfc 100644 --- a/archival/dpkg.c +++ b/archival/dpkg.c @@ -12,9 +12,8 @@ * * started life as a busybox implementation of udpkg * - * licensed under gplv2 or later, see file license in this tarball for details. + * 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 @@ -25,12 +24,52 @@ * * bugs that need to be fixed * - (unknown, please let me know when you find any) - * */ +//config:config DPKG +//config: bool "dpkg" +//config: default n +//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 "unarchive.h" +#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. @@ -674,28 +713,21 @@ static unsigned get_status(const unsigned status_node, const int num) static void set_status(const unsigned status_node_num, const char *new_value, const int position) { - const unsigned new_value_len = strlen(new_value); 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); - int want_len = strlen(name_hashtable[want]); - int flag_len = strlen(name_hashtable[flag]); - int status_len = strlen(name_hashtable[status]); char *new_status; switch (position) { case 1: want = new_value_num; - want_len = new_value_len; break; case 2: flag = new_value_num; - flag_len = new_value_len; break; case 3: status = new_value_num; - status_len = new_value_len; break; default: bb_error_msg_and_die("DEBUG ONLY: this shouldnt happen"); @@ -866,7 +898,7 @@ static void write_status_file(deb_file_t **deb_file) write_flag = TRUE; fputs("\n", new_status_file); } - else if (strcmp("config-files", name_hashtable[state_status]) == 0) { + else if (strcmp("config-files", name_hashtable[state_status]) == 0) { /* only change the status line */ while (1) { char *field_name; @@ -939,8 +971,8 @@ static int package_satisfies_dependency(int package, int depend_type) 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"); + 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; } @@ -967,7 +999,7 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count conflicts[conflicts_num] = package_num; conflicts_num++; /* add provides to conflicts list */ - for (j = 0; j < package_hashtable[package_num]->num_of_edges; j++) { + 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, @@ -1006,8 +1038,8 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count if (package_edge->type == EDGE_CONFLICTS) { const unsigned package_num = search_package_hashtable(package_edge->name, - package_edge->version, - package_edge->operator); + 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]); @@ -1067,12 +1099,13 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count if (package_edge->type == EDGE_OR_PRE_DEPENDS || package_edge->type == EDGE_OR_DEPENDS - ) { /* start an EDGE_OR_ list */ + ) { + /* 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 */ + if (number_of_alternatives == 0) { /* not in the middle of an EDGE_OR_ list */ number_of_alternatives = 1; root_of_alternatives = NULL; } @@ -1093,7 +1126,7 @@ static int check_deps(deb_file_t **deb_file, int deb_start /*, int dep_max_count */ 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); + package_edge->type, root_of_alternatives->type); if (package_hashtable[package_num] != NULL) result = !package_satisfies_dependency(package_num, package_edge->type); @@ -1524,8 +1557,8 @@ static char FAST_FUNC filter_rename_config(archive_handle_t *archive_handle) buf = xmalloc(4096); md5_begin(&md5); while ((count = safe_read(fd, buf, 4096)) > 0) - md5_hash(buf, count, &md5); - md5_end(buf, &md5); /* using buf as result storage */ + 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); @@ -1644,20 +1677,25 @@ static void unpack_package(deb_file_t *deb_file) 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? */ - archive_handle->dpkg__sub_archive->ah_flags |= ARCHIVE_UNLINK_OLD; 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 */ - fputs(archive_handle->dpkg__sub_archive->passed->data, out_stream); - fputc('\n', out_stream); - archive_handle->dpkg__sub_archive->passed = archive_handle->dpkg__sub_archive->passed->link; + fprintf(out_stream, "%s\n", filename); + free(filename); } fclose(out_stream); diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c index 45a791b..13f9db9 100644 --- a/archival/dpkg_deb.c +++ b/archival/dpkg_deb.c @@ -2,16 +2,55 @@ /* * dpkg-deb packs, unpacks and provides information about Debian archives. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//config:config DPKG_DEB +//config: bool "dpkg_deb" +//config: default n +//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. +//config: +//config:config FEATURE_DPKG_DEB_EXTRACT_ONLY +//config: bool "Extract only (-x)" +//config: default n +//config: depends on DPKG_DEB +//config: help +//config: This reduces dpkg-deb to the equivalent of +//config: "ar -p data.tar.gz | tar -zx". However it saves space as none +//config: of the extra dpkg-deb, ar or tar options are needed, they are linked +//config: to internally. + +//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 [argument]" +//usage:#define dpkg_deb_full_usage "\n\n" +//usage: "Perform actions on Debian packages (.debs)\n" +//usage: "\n -c List contents of filesystem tree" +//usage: "\n -e Extract control files to [argument] directory" +//usage: "\n -f Display control field name starting with [argument]" +//usage: "\n -x Extract packages filesystem tree to directory" +//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 "unarchive.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 8 -#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 +#define DPKG_DEB_OPT_CONTENTS 1 +#define DPKG_DEB_OPT_CONTROL 2 +#define DPKG_DEB_OPT_FIELD 4 +#define DPKG_DEB_OPT_EXTRACT 8 +#define DPKG_DEB_OPT_EXTRACT_VERBOSE 16 int dpkg_deb_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dpkg_deb_main(int argc, char **argv) diff --git a/archival/gzip.c b/archival/gzip.c index 620897b..1e779c9 100644 --- a/archival/gzip.c +++ b/archival/gzip.c @@ -13,9 +13,8 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - /* big objects in bss: * 00000020 b bl_count * 00000074 b base_length @@ -31,7 +30,6 @@ * 00000480 b static_ltree * 000008f4 b dyn_ltree */ - /* TODO: full support for -v for DESKTOP * "/usr/bin/gzip -v a bogus aa" should say: a: 85.1% -- replaced with a.gz @@ -39,8 +37,52 @@ gzip: bogus: No such file or directory aa: 85.1% -- replaced with aa.gz */ +//config:config GZIP +//config: bool "gzip" +//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: help +//config: Enable use of long options, increases size by about 106 Bytes +//config: +//config:config GZIP_FAST +//config: int "Trade memory for gzip 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 + +//applet:IF_GZIP(APPLET(gzip, BB_DIR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_GZIP) += gzip.o + +//usage:#define gzip_trivial_usage +//usage: "[-cfd] [FILE]..." +//usage:#define gzip_full_usage "\n\n" +//usage: "Compress FILEs (or stdin)\n" +//usage: "\n -d Decompress" +//usage: "\n -c Write to stdout" +//usage: "\n -f Force" +//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 "unarchive.h" +#include "bb_archive.h" /* =========================================================================== @@ -66,9 +108,17 @@ aa: 85.1% -- replaced with aa.gz /* =========================================================================== */ -#define SMALL_MEM +#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 +#ifndef INBUFSIZ # ifdef SMALL_MEM # define INBUFSIZ 0x2000 /* input buffer size */ # else @@ -76,7 +126,7 @@ aa: 85.1% -- replaced with aa.gz # endif #endif -#ifndef OUTBUFSIZ +#ifndef OUTBUFSIZ # ifdef SMALL_MEM # define OUTBUFSIZ 8192 /* output buffer size */ # else @@ -340,7 +390,7 @@ struct globals { ulg bits_sent; /* bit length of the compressed data */ #endif - uint32_t *crc_32_tab; + /*uint32_t *crc_32_tab;*/ uint32_t crc; /* shift register contents */ }; @@ -393,15 +443,9 @@ static void put_32bit(ulg n) * pointer, then initialize the crc shift register contents instead. * Return the current crc in either case. */ -static uint32_t updcrc(uch * s, unsigned n) +static void updcrc(uch * s, unsigned n) { - uint32_t c = G1.crc; - while (n) { - c = G1.crc_32_tab[(uch)(c ^ *s++)] ^ (c >> 8); - n--; - } - G1.crc = c; - return c; + G1.crc = crc32_block_endian0(G1.crc, s, n, global_crc32_table /*G1.crc_32_tab*/); } @@ -1162,7 +1206,7 @@ static void gen_codes(ct_data * tree, int max_code) * must be all ones. */ Assert(code + G2.bl_count[MAX_BITS] - 1 == (1 << MAX_BITS) - 1, - "inconsistent bit counts"); + "inconsistent bit counts"); Tracev((stderr, "\ngen_codes: max_code %d ", max_code)); for (n = 0; n <= max_code; n++) { @@ -1510,9 +1554,9 @@ static int ct_tally(int dist, int lc) } out_length >>= 3; Trace((stderr, - "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", - G2.last_lit, G2.last_dist, in_length, out_length, - 100L - out_length * 100L / in_length)); + "\nlast_lit %u, last_dist %u, in %ld, out ~%ld(%ld%%) ", + G2.last_lit, G2.last_dist, in_length, out_length, + 100L - out_length * 100L / in_length)); if (G2.last_dist < G2.last_lit / 2 && out_length < in_length / 2) return 1; } @@ -1604,9 +1648,9 @@ static ulg flush_block(char *buf, ulg stored_len, int eof) static_lenb = (G2.static_len + 3 + 7) >> 3; Trace((stderr, - "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", - opt_lenb, G2.opt_len, static_lenb, G2.static_len, stored_len, - G2.last_lit, G2.last_dist)); + "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u dist %u ", + opt_lenb, G2.opt_len, static_lenb, G2.static_len, stored_len, + G2.last_lit, G2.last_dist)); if (static_lenb <= opt_lenb) opt_lenb = static_lenb; @@ -1644,7 +1688,7 @@ static ulg flush_block(char *buf, ulg stored_len, int eof) } 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); + max_blindex + 1); compress_block((ct_data *) G2.dyn_ltree, (ct_data *) G2.dyn_dtree); G2.compressed_len += 3 + G2.opt_len; } @@ -1664,7 +1708,7 @@ static ulg flush_block(char *buf, ulg stored_len, int eof) /* =========================================================================== * Update a hash value with the given input byte - * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * 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. */ @@ -1695,7 +1739,7 @@ static ulg flush_block(char *buf, ulg stored_len, int 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 to INSERT_STRING are made with consecutive + * 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) \ @@ -1998,7 +2042,7 @@ static void zip(ulg time_stamp) /* ======================================================================== */ static -IF_DESKTOP(long long) int FAST_FUNC pack_gzip(unpack_info_t *info UNUSED_PARAM) +IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_aux_data_t *aux UNUSED_PARAM) { struct stat s; @@ -2104,8 +2148,8 @@ int gzip_main(int argc UNUSED_PARAM, char **argv) ALLOC(uch, G1.window, 2L * WSIZE); ALLOC(ush, G1.prev, 1L << BITS); - /* Initialise the CRC32 table */ - G1.crc_32_tab = crc32_filltable(NULL, 0); + /* Initialize the CRC32 table */ + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_gzip, append_ext, "gz"); } diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src new file mode 100644 index 0000000..968fdf8 --- /dev/null +++ b/archival/libarchive/Kbuild.src @@ -0,0 +1,83 @@ +# 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_FILES:= \ +\ + data_skip.o \ + data_extract_all.o \ + data_extract_to_stdout.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 \ + get_header_ar.o \ + get_header_tar.o \ + get_header_tar_gz.o \ + get_header_tar_bz2.o \ + get_header_tar_lzma.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 +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_LZOP_COMPR_HIGH) += lzo1x_9x.o +lib-$(CONFIG_BUNZIP2) += open_transformer.o decompress_bunzip2.o +lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.o +lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o +lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o +lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o +lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.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 + +ifneq ($(lib-y),) +lib-y += $(COMMON_FILES) +endif diff --git a/archival/bz/LICENSE b/archival/libarchive/bz/LICENSE similarity index 100% rename from archival/bz/LICENSE rename to archival/libarchive/bz/LICENSE diff --git a/archival/bz/README b/archival/libarchive/bz/README similarity index 100% rename from archival/bz/README rename to archival/libarchive/bz/README diff --git a/archival/bz/blocksort.c b/archival/libarchive/bz/blocksort.c similarity index 99% rename from archival/bz/blocksort.c rename to archival/libarchive/bz/blocksort.c index f70c370..e600cb7 100644 --- a/archival/bz/blocksort.c +++ b/archival/libarchive/bz/blocksort.c @@ -385,7 +385,7 @@ int mainGtU( * but speeds up compression 10% overall */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 +#if CONFIG_BZIP2_FAST >= 1 #define TIMES_8(code) \ code; code; code; code; \ @@ -496,7 +496,7 @@ void mainSimpleSort(uint32_t* ptr, i++; /* 1.5% overall speedup, +290 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 3 +#if CONFIG_BZIP2_FAST >= 3 /*-- copy 2 --*/ if (i > hi) break; v = ptr[i]; @@ -750,7 +750,7 @@ void mainSort(EState* state, j = block[0] << 8; i = nblock - 1; /* 3%, +300 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 +#if CONFIG_BZIP2_FAST >= 2 for (; i >= 3; i -= 4) { quadrant[i] = 0; j = (j >> 8) | (((uint16_t)block[i]) << 8); @@ -787,7 +787,7 @@ void mainSort(EState* state, s = block[0] << 8; i = nblock - 1; -#if CONFIG_BZIP2_FEATURE_SPEED >= 2 +#if CONFIG_BZIP2_FAST >= 2 for (; i >= 3; i -= 4) { s = (s >> 8) | (block[i] << 8); j = ftab[s] - 1; diff --git a/archival/bz/bzlib.c b/archival/libarchive/bz/bzlib.c similarity index 98% rename from archival/bz/bzlib.c rename to archival/libarchive/bz/bzlib.c index 8341794..5f7db74 100644 --- a/archival/bz/bzlib.c +++ b/archival/libarchive/bz/bzlib.c @@ -28,7 +28,7 @@ in the file LICENSE. * 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. + * fixed bzread to correctly handle read requests after EOF. * wrong parameter order in call to bzDecompressInit in * bzBuffToBuffDecompress. Fixed. */ @@ -361,7 +361,6 @@ int BZ2_bzCompress(bz_stream *strm, int action) /*---------------------------------------------------*/ -#if ENABLE_FEATURE_CLEAN_UP static void BZ2_bzCompressEnd(bz_stream *strm) { @@ -372,9 +371,8 @@ void BZ2_bzCompressEnd(bz_stream *strm) free(s->arr2); free(s->ftab); free(s->crc32table); - free(strm->state); + free(s); } -#endif /*---------------------------------------------------*/ diff --git a/archival/bz/bzlib.h b/archival/libarchive/bz/bzlib.h similarity index 100% rename from archival/bz/bzlib.h rename to archival/libarchive/bz/bzlib.h diff --git a/archival/bz/bzlib_private.h b/archival/libarchive/bz/bzlib_private.h similarity index 99% rename from archival/bz/bzlib_private.h rename to archival/libarchive/bz/bzlib_private.h index 6430ce4..43e674b 100644 --- a/archival/bz/bzlib_private.h +++ b/archival/libarchive/bz/bzlib_private.h @@ -183,7 +183,7 @@ typedef struct EState { /* 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 CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 /* second dimension: only 3 needed; 4 makes index calculations faster */ uint32_t sendMTFValues__len_pack[BZ_MAX_ALPHA_SIZE][4]; #endif diff --git a/archival/bz/compress.c b/archival/libarchive/bz/compress.c similarity index 95% rename from archival/bz/compress.c rename to archival/libarchive/bz/compress.c index 640b887..23de9d3 100644 --- a/archival/bz/compress.c +++ b/archival/libarchive/bz/compress.c @@ -61,7 +61,7 @@ void bsFinishWrite(EState* s) /*---------------------------------------------------*/ static /* Helps only on level 5, on other levels hurts. ? */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 ALWAYS_INLINE #endif void bsW(EState* s, int32_t n, uint32_t v) @@ -134,15 +134,14 @@ void generateMTFValues(EState* s) * 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]. + * 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] + * 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 @@ -212,7 +211,6 @@ void generateMTFValues(EState* s) wr++; s->mtfFreq[j+1]++; } - } } @@ -251,9 +249,9 @@ void generateMTFValues(EState* s) static NOINLINE void sendMTFValues(EState* s) { - int32_t v, t, i, j, gs, ge, totc, bt, bc, iter; + int32_t v, t, i, j, gs, ge, bt, bc, iter; int32_t nSelectors, alphaSize, minLen, maxLen, selCtr; - int32_t nGroups, nBytes; + int32_t nGroups; /* * uint8_t len[BZ_N_GROUPS][BZ_MAX_ALPHA_SIZE]; @@ -333,7 +331,7 @@ void sendMTFValues(EState* s) for (v = 0; v < alphaSize; v++) s->rfreq[t][v] = 0; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 /* * Set up an auxiliary length table which is used to fast-track * the common case (nGroups == 6). @@ -347,7 +345,6 @@ void sendMTFValues(EState* s) } #endif nSelectors = 0; - totc = 0; gs = 0; while (1) { /*--- Set group start & end marks. --*/ @@ -363,7 +360,7 @@ void sendMTFValues(EState* s) */ for (t = 0; t < nGroups; t++) cost[t] = 0; -#if CONFIG_BZIP2_FEATURE_SPEED >= 5 +#if CONFIG_BZIP2_FAST >= 5 if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ register uint32_t cost01, cost23, cost45; @@ -413,7 +410,6 @@ void sendMTFValues(EState* s) bt = t; } } - totc += bc; fave[bt]++; s->selector[nSelectors] = bt; nSelectors++; @@ -422,7 +418,7 @@ void sendMTFValues(EState* s) * Increment the symbol frequencies for the selected table. */ /* 1% faster compress. +800 bytes */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 4 +#if CONFIG_BZIP2_FAST >= 4 if (nGroups == 6 && 50 == ge-gs+1) { /*--- fast track the common case ---*/ #define BZ_ITUR(nn) s->rfreq[bt][mtfv[gs + (nn)]]++ @@ -460,7 +456,7 @@ void sendMTFValues(EState* s) } AssertH(nGroups < 8, 3002); - AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); + AssertH(nSelectors < 32768 && nSelectors <= (2 + (900000 / BZ_G_SIZE)), 3003); /*--- Compute MTF values for the selectors. ---*/ { @@ -503,18 +499,17 @@ void sendMTFValues(EState* s) for (i = 0; i < 16; i++) { if (sizeof(long) <= 4) { inUse16 = inUse16*2 + - ((*(uint32_t*)&(s->inUse[i * 16 + 0]) - | *(uint32_t*)&(s->inUse[i * 16 + 4]) - | *(uint32_t*)&(s->inUse[i * 16 + 8]) - | *(uint32_t*)&(s->inUse[i * 16 + 12])) != 0); + ((*(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 + - ((*(uint64_t*)&(s->inUse[i * 16 + 0]) - | *(uint64_t*)&(s->inUse[i * 16 + 8])) != 0); + ((*(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 0]) + | *(bb__aliased_uint64_t*)&(s->inUse[i * 16 + 8])) != 0); } } - nBytes = s->numZ; bsW(s, 16, inUse16); inUse16 <<= (sizeof(int)*8 - 16); /* move 15th bit into sign bit */ @@ -530,7 +525,6 @@ void sendMTFValues(EState* s) } /*--- Now the selectors. ---*/ - nBytes = s->numZ; bsW(s, 3, nGroups); bsW(s, 15, nSelectors); for (i = 0; i < nSelectors; i++) { @@ -540,8 +534,6 @@ void sendMTFValues(EState* s) } /*--- Now the coding tables. ---*/ - nBytes = s->numZ; - for (t = 0; t < nGroups; t++) { int32_t curr = s->len[t][0]; bsW(s, 5, curr); @@ -553,7 +545,6 @@ void sendMTFValues(EState* s) } /*--- And finally, the block data proper ---*/ - nBytes = s->numZ; selCtr = 0; gs = 0; while (1) { diff --git a/archival/bz/huffman.c b/archival/libarchive/bz/huffman.c similarity index 99% rename from archival/bz/huffman.c rename to archival/libarchive/bz/huffman.c index 676b1af..bbec11a 100644 --- a/archival/bz/huffman.c +++ b/archival/libarchive/bz/huffman.c @@ -48,7 +48,7 @@ in the file LICENSE. /* 90 bytes, 0.3% of overall compress speed */ -#if CONFIG_BZIP2_FEATURE_SPEED >= 1 +#if CONFIG_BZIP2_FAST >= 1 /* macro works better than inline (gcc 4.2.1) */ #define DOWNHEAP1(heap, weight, Heap) \ diff --git a/archival/libunarchive/data_align.c b/archival/libarchive/data_align.c similarity index 75% rename from archival/libunarchive/data_align.c rename to archival/libarchive/data_align.c index 0c8542b..a6b84a4 100644 --- a/archival/libunarchive/data_align.c +++ b/archival/libarchive/data_align.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC data_align(archive_handle_t *archive_handle, unsigned boundary) { diff --git a/archival/libunarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c similarity index 86% rename from archival/libunarchive/data_extract_all.c rename to archival/libarchive/data_extract_all.c index 00e67d4..45776dc 100644 --- a/archival/libunarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) { @@ -13,13 +13,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) int res; #if ENABLE_FEATURE_TAR_SELINUX - char *sctx = archive_handle->tar__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif @@ -69,7 +69,9 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } } else if (existing_sb.st_mtime >= file_header->mtime) { - if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + if (!(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) + && !S_ISDIR(file_header->mode) + ) { bb_error_msg("%s not created: newer or " "same age file exists", file_header->name); } @@ -104,15 +106,28 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ + char *dst_name; int flags = O_WRONLY | O_CREAT | O_EXCL; if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) flags = O_WRONLY | O_CREAT | O_TRUNC; - dst_fd = xopen3(file_header->name, + dst_name = file_header->name; +#ifdef ARCHIVE_REPLACE_VIA_RENAME + if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) + /* rpm-style temp file name */ + dst_name = xasprintf("%s;%x", dst_name, (int)getpid()); +#endif + dst_fd = xopen3(dst_name, 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_name, file_header->name); + free(dst_name); + } +#endif break; } case S_IFDIR: diff --git a/archival/libunarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c similarity index 84% rename from archival/libunarchive/data_extract_to_command.c rename to archival/libarchive/data_extract_to_command.c index 95f5bc8..5b32c2e 100644 --- a/archival/libunarchive/data_extract_to_command.c +++ b/archival/libarchive/data_extract_to_command.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" enum { //TAR_FILETYPE, @@ -64,13 +64,13 @@ 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__next_file_sctx; + char *sctx = archive_handle->tar__sctx[PAX_NEXT_FILE]; if (!sctx) - sctx = archive_handle->tar__global_sctx; + sctx = archive_handle->tar__sctx[PAX_GLOBAL]; if (sctx) { /* setfscreatecon is 4 syscalls, avoid if possible */ setfscreatecon(sctx); - free(archive_handle->tar__next_file_sctx); - archive_handle->tar__next_file_sctx = NULL; + free(archive_handle->tar__sctx[PAX_NEXT_FILE]); + archive_handle->tar__sctx[PAX_NEXT_FILE] = NULL; } #endif @@ -99,8 +99,12 @@ void FAST_FUNC data_extract_to_command(archive_handle_t *archive_handle) close(p[1]); xdup2(p[0], STDIN_FILENO); signal(SIGPIPE, SIG_DFL); - execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", archive_handle->tar__to_command, NULL); - bb_perror_msg_and_die("can't execute '%s'", DEFAULT_SHELL); + 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) diff --git a/archival/libunarchive/data_extract_to_stdout.c b/archival/libarchive/data_extract_to_stdout.c similarity index 69% rename from archival/libunarchive/data_extract_to_stdout.c rename to archival/libarchive/data_extract_to_stdout.c index a3efea1..f849f3b 100644 --- a/archival/libunarchive/data_extract_to_stdout.c +++ b/archival/libarchive/data_extract_to_stdout.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC data_extract_to_stdout(archive_handle_t *archive_handle) { diff --git a/archival/libunarchive/data_skip.c b/archival/libarchive/data_skip.c similarity index 65% rename from archival/libunarchive/data_skip.c rename to archival/libarchive/data_skip.c index 06d3dce..588167f 100644 --- a/archival/libunarchive/data_skip.c +++ b/archival/libarchive/data_skip.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC data_skip(archive_handle_t *archive_handle) { diff --git a/archival/libunarchive/decompress_bunzip2.c b/archival/libarchive/decompress_bunzip2.c similarity index 66% rename from archival/libunarchive/decompress_bunzip2.c rename to archival/libarchive/decompress_bunzip2.c index bdbd39a..6396fe4 100644 --- a/archival/libunarchive/decompress_bunzip2.c +++ b/archival/libarchive/decompress_bunzip2.c @@ -6,7 +6,7 @@ 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 tarball for details. + Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -16,10 +16,21 @@ 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_unzip() reversing + 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 @@ -29,7 +40,13 @@ */ #include "libbb.h" -#include "unarchive.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 @@ -41,13 +58,13 @@ /* Status return values */ #define RETVAL_OK 0 -#define RETVAL_LAST_BLOCK (-1) -#define RETVAL_NOT_BZIP_DATA (-2) -#define RETVAL_UNEXPECTED_INPUT_EOF (-3) -#define RETVAL_SHORT_WRITE (-4) -#define RETVAL_DATA_ERROR (-5) -#define RETVAL_OUT_OF_MEMORY (-6) -#define RETVAL_OBSOLETE_INPUT (-7) +#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 @@ -70,38 +87,41 @@ struct bunzip_data { /* I/O tracking data (file handles, buffers, positions, etc.) */ unsigned inbufBitCount, inbufBits; int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/; - unsigned char *inbuf /*,*outbuf*/; + uint8_t *inbuf /*,*outbuf*/; /* State for interrupting output loop */ - int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent; + 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) */ - unsigned *dbuf, dbufSize; + 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]; - unsigned char selectors[32768]; /* nSelectors=15 bits */ - struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ + uint8_t selectors[32768]; /* nSelectors=15 bits */ + struct group_data groups[MAX_GROUPS]; /* Huffman coding tables */ }; /* typedef struct bunzip_data bunzip_data; -- done in .h file */ /* 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 ((int)(bd->inbufBitCount) < bits_wanted) { + while (bit_count < bits_wanted) { /* If we need to read more data from file into byte buffer, do so */ if (bd->inbufPos == bd->inbufCount) { @@ -113,41 +133,47 @@ static unsigned get_bits(bunzip_data *bd, int bits_wanted) } /* Avoid 32-bit overflow (dump bit buffer to top of output) */ - if (bd->inbufBitCount >= 24) { - bits = bd->inbufBits & ((1 << bd->inbufBitCount) - 1); - bits_wanted -= bd->inbufBitCount; + if (bit_count >= 24) { + bits = bd->inbufBits & ((1 << bit_count) - 1); + bits_wanted -= bit_count; bits <<= bits_wanted; - bd->inbufBitCount = 0; + bit_count = 0; } /* Grab next 8 bits of input from buffer. */ bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; + bit_count += 8; } /* Calculate result */ - bd->inbufBitCount -= bits_wanted; - bits |= (bd->inbufBits >> bd->inbufBitCount) & ((1 << bits_wanted) - 1); + bit_count -= bits_wanted; + bd->inbufBitCount = bit_count; + bits |= (bd->inbufBits >> bit_count) & ((1 << bits_wanted) - 1); return bits; } -/* Unpacks the next block and sets up for the inverse burrows-wheeler step. */ +/* Unpacks the next block and sets up for the inverse Burrows-Wheeler step. */ static int get_next_block(bunzip_data *bd) { struct group_data *hufGroup; - int dbufCount, nextSym, dbufSize, groupCount, *base, *limit, selector, - i, j, k, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; - unsigned char uc, symToByte[256], mtfSymbol[256], *selectors; - unsigned *dbuf, origPtr; + int dbufCount, dbufSize, groupCount, *base, *limit, selector, + i, j, t, runPos, symCount, symTotal, nSelectors, byteCount[256]; + int runCnt = runCnt; /* for compiler */ + uint8_t uc, symToByte[256], mtfSymbol[256], *selectors; + uint32_t *dbuf; + unsigned origPtr; dbuf = bd->dbuf; dbufSize = bd->dbufSize; 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) */ @@ -169,16 +195,23 @@ static int get_next_block(bunzip_data *bd) 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. */ - t = get_bits(bd, 16); symTotal = 0; - for (i = 0; i < 16; i++) { - if (t & (1 << (15-i))) { - k = get_bits(bd, 16); - for (j = 0; j < 16; j++) - if (k & (1 << (15-j))) - symToByte[symTotal++] = (16*i) + j; + 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); @@ -189,57 +222,63 @@ static int get_next_block(bunzip_data *bd) 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 < groupCount; i++) mtfSymbol[i] = i; + if (!nSelectors) + return RETVAL_DATA_ERROR; for (i = 0; i < nSelectors; i++) { - + uint8_t tmp_byte; /* Get next value */ - for (j = 0; get_bits(bd, 1); j++) - if (j >= groupCount) return RETVAL_DATA_ERROR; - + int n = 0; + while (get_bits(bd, 1)) { + if (n >= groupCount) return RETVAL_DATA_ERROR; + n++; + } /* Decode MTF to get the next selector */ - uc = mtfSymbol[j]; - for (;j;j--) mtfSymbol[j] = mtfSymbol[j-1]; - mtfSymbol[0] = selectors[i] = uc; + tmp_byte = mtfSymbol[n]; + while (--n >= 0) + mtfSymbol[n + 1] = mtfSymbol[n]; + 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++) { - unsigned char length[MAX_SYMBOLS]; + uint8_t length[MAX_SYMBOLS]; /* 8 bits is ALMOST enough for temp[], see below */ unsigned temp[MAX_HUFCODE_BITS+1]; - int minLen, maxLen, pp; + 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 everys symbol after that. + 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.) */ - t = get_bits(bd, 5) - 1; + len_m1 = get_bits(bd, 5) - 1; for (i = 0; i < symCount; i++) { for (;;) { - if ((unsigned)t > (MAX_HUFCODE_BITS-1)) + 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. */ - k = get_bits(bd, 2); - if (k < 2) { + 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 */ - t += (((k+1) & 2) - 1); + len_m1 += (((two_bits+1) & 2) - 1); } /* Correct for the initial -1, to get the final symbol length */ - length[i] = t + 1; + length[i] = len_m1 + 1; } /* Find largest and smallest lengths in this group */ @@ -265,17 +304,18 @@ static int get_next_block(bunzip_data *bd) /* 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).*/ + entry. We do this again when using them (during symbol decoding). */ base = hufGroup->base - 1; limit = hufGroup->limit - 1; /* Calculate permute[]. Concurently, initialize temp[] and limit[]. */ pp = 0; for (i = minLen; i <= maxLen; i++) { + int k; temp[i] = limit[i] = 0; - for (t = 0; t < symCount; t++) - if (length[t] == i) - hufGroup->permute[pp++] = t; + for (k = 0; k < symCount; k++) + if (length[k] == i) + hufGroup->permute[pp++] = k; } /* Count symbols coded for at each bit length */ @@ -288,8 +328,10 @@ static int get_next_block(bunzip_data *bd) * 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; i++) { - pp += temp[i]; + 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 @@ -299,11 +341,11 @@ static int get_next_block(bunzip_data *bd) don't affect the value>limit[length] comparison. */ limit[i] = (pp << (maxLen - i)) - 1; pp <<= 1; - t += temp[i]; - base[i+1] = pp - t; + t += temp_i; + base[++i] = pp - t; } - limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ limit[maxLen] = pp + temp[maxLen] - 1; + limit[maxLen+1] = INT_MAX; /* Sentinel value for reading next sym. */ base[minLen] = 0; } @@ -312,16 +354,17 @@ static int get_next_block(bunzip_data *bd) 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, maybe slower? */ + /*memset(byteCount, 0, sizeof(byteCount)); - smaller, but slower */ for (i = 0; i < 256; i++) { - //byteCount[i] = 0; - mtfSymbol[i] = (unsigned char)i; + byteCount[i] = 0; + mtfSymbol[i] = (uint8_t)i; } /* Loop through compressed symbols. */ runPos = dbufCount = selector = 0; for (;;) { + int nextSym; /* Fetch next Huffman coding group from list. */ symCount = GROUP_SIZE - 1; @@ -329,44 +372,49 @@ static int get_next_block(bunzip_data *bd) hufGroup = bd->groups + selectors[selector++]; base = hufGroup->base - 1; limit = hufGroup->limit - 1; - continue_this_group: + 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 an additional bit at a time, testing + 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. As a further optimization, we do the read - inline (falling back to a call to get_bits if the buffer runs - dry). The following (up to got_huff_bits:) is equivalent to - j = get_bits(bd, hufGroup->maxLen); + valid compressed file. */ - while ((int)(bd->inbufBitCount) < hufGroup->maxLen) { - if (bd->inbufPos == bd->inbufCount) { - j = get_bits(bd, hufGroup->maxLen); - goto got_huff_bits; - } - bd->inbufBits = (bd->inbufBits << 8) | bd->inbuf[bd->inbufPos++]; - bd->inbufBitCount += 8; - }; - bd->inbufBitCount -= hufGroup->maxLen; - j = (bd->inbufBits >> bd->inbufBitCount) & ((1 << hufGroup->maxLen) - 1); - - got_huff_bits: - - /* Figure how how many bits are in next symbol and unget extras */ + 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 (j > limit[i]) ++i; - bd->inbufBitCount += (hufGroup->maxLen - i); + 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) */ - if (i > hufGroup->maxLen) + nextSym = (nextSym >> j) - base[i]; + if ((unsigned)nextSym >= MAX_SYMBOLS) return RETVAL_DATA_ERROR; - j = (j >> (hufGroup->maxLen - i)) - base[i]; - if ((unsigned)j >= MAX_SYMBOLS) - return RETVAL_DATA_ERROR; - nextSym = hufGroup->permute[j]; + 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, @@ -375,9 +423,9 @@ static int get_next_block(bunzip_data *bd) if ((unsigned)nextSym <= SYMBOL_RUNB) { /* RUNA or RUNB */ /* If this is the start of a new run, zero out counter */ - if (!runPos) { + if (runPos == 0) { runPos = 1; - t = 0; + runCnt = 0; } /* Neat trick that saves 1 symbol: instead of or-ing 0 or 1 at @@ -387,7 +435,7 @@ static int get_next_block(bunzip_data *bd) 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. */ - t += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ + runCnt += (runPos << nextSym); /* +runPos if RUNA; +2*runPos if RUNB */ if (runPos < dbufSize) runPos <<= 1; goto end_of_huffman_loop; } @@ -396,13 +444,17 @@ static int get_next_block(bunzip_data *bd) 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) { + if (runPos != 0) { + uint8_t tmp_byte; + if (dbufCount + runCnt > dbufSize) { + dbg("dbufCount:%d+runCnt:%d %d > dbufSize:%d RETVAL_DATA_ERROR", + dbufCount, runCnt, dbufCount + runCnt, dbufSize); + return RETVAL_DATA_ERROR; + } + tmp_byte = symToByte[mtfSymbol[0]]; + byteCount[tmp_byte] += runCnt; + while (--runCnt >= 0) dbuf[dbufCount++] = (uint32_t)tmp_byte; runPos = 0; - if (dbufCount + t >= dbufSize) return RETVAL_DATA_ERROR; - - uc = symToByte[mtfSymbol[0]]; - byteCount[uc] += t; - while (t--) dbuf[dbufCount++] = uc; } /* Is this the terminating symbol? */ @@ -431,12 +483,12 @@ static int get_next_block(bunzip_data *bd) /* We have our literal byte. Save it into dbuf. */ byteCount[uc]++; - dbuf[dbufCount++] = (unsigned)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--) goto continue_this_group; + if (--symCount >= 0) goto continue_this_group; } /* At this point, we've read all the Huffman-coded symbols (and repeated @@ -449,26 +501,28 @@ static int get_next_block(bunzip_data *bd) /* Turn byteCount into cumulative occurrence counts of 0 to n-1. */ j = 0; for (i = 0; i < 256; i++) { - k = j + byteCount[i]; + int tmp_count = j + byteCount[i]; byteCount[i] = j; - j = k; + j = tmp_count; } /* Figure out what order dbuf would be in if we sorted it. */ for (i = 0; i < dbufCount; i++) { - uc = (unsigned char)(dbuf[i] & 0xff); - dbuf[byteCount[uc]] |= (i << 8); - byteCount[uc]++; + 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; - bd->writePos = dbuf[origPtr]; - bd->writeCurrent = (unsigned char)(bd->writePos & 0xff); - bd->writePos >>= 8; + tmp = dbuf[origPtr]; + bd->writeCurrent = (uint8_t)tmp; + bd->writePos = (tmp >> 8); bd->writeRunCountdown = 5; } bd->writeCount = dbufCount; @@ -476,70 +530,84 @@ static int get_next_block(bunzip_data *bd) return RETVAL_OK; } -/* Undo burrows-wheeler transform on intermediate buffer to produce output. +/* 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) */ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) { - const unsigned *dbuf; - int pos, current, previous, gotcount; + const uint32_t *dbuf; + int pos, current, previous; + uint32_t CRC; - /* If last read was short due to end of file, return last block now */ - if (bd->writeCount < 0) return bd->writeCount; + /* If we already have error/end indicator, return it */ + if (bd->writeCount < 0) + return bd->writeCount; - gotcount = 0; 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, snapshot state and return */ - if (gotcount >= len) { - bd->writePos = pos; - bd->writeCurrent = current; - bd->writeCopies++; - return len; + /* 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[gotcount++] = current; - bd->writeCRC = (bd->writeCRC << 8) - ^ bd->crc32Table[(bd->writeCRC >> 24) ^ current]; + *outbuf++ = current; + CRC = (CRC << 8) ^ bd->crc32Table[(CRC >> 24) ^ current]; /* Loop now if we're outputting multiple copies of this byte */ if (bd->writeCopies) { - --bd->writeCopies; - continue; + /* 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--) break; + 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 = pos & 0xff; + 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) { + 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; @@ -551,30 +619,42 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* Subtract the 1 copy we'd output anyway to get extras */ --bd->writeCopies; } - } + } /* for(;;) */ - /* Decompression of this block completed successfully */ - bd->writeCRC = ~bd->writeCRC; - bd->totalCRC = ((bd->totalCRC << 1) | (bd->totalCRC >> 31)) ^ bd->writeCRC; + /* 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 (bd->writeCRC != bd->headerCRC) { + /* 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 */ - /* (previous is just a convenient unused temp variable here) */ - previous = get_next_block(bd); - if (previous) { - bd->writeCount = previous; - return (previous != RETVAL_LAST_BLOCK) ? previous : gotcount; + { + int r = get_next_block(bd); + if (r) { /* error/end */ + bd->writeCount = r; + return (r != RETVAL_LAST_BLOCK) ? r : len; + } } - bd->writeCRC = ~0; + + 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 @@ -584,8 +664,8 @@ int FAST_FUNC read_bunzip(bunzip_data *bd, char *outbuf, int len) /* 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! */ -int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, - int len) +int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, + const void *inbuf, int len) { bunzip_data *bd; unsigned i; @@ -606,9 +686,11 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *in if (-1 == in_fd) { /* in this case, bd->inbuf is read-only */ bd->inbuf = (void*)inbuf; /* cast away const-ness */ - bd->inbufCount = len; - } else - bd->inbuf = (unsigned char *)(bd + 1); + } 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); @@ -632,7 +714,7 @@ int FAST_FUNC start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *in bd->dbufSize = 100000 * (i - h0); /* Cannot use xmalloc - may leak bd in NOFORK case! */ - bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int)); + bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(bd->dbuf[0])); if (!bd->dbuf) { free(bd); xfunc_die(); @@ -649,57 +731,82 @@ void FAST_FUNC dealloc_bunzip(bunzip_data *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(int src_fd, int dst_fd) +unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) - char *outbuf; bunzip_data *bd; + char *outbuf; int i; + unsigned len; + + if (check_signature16(aux, src_fd, BZIP2_MAGIC)) + return -1; outbuf = xmalloc(IOBUF_SIZE); - i = start_bunzip(&bd, src_fd, NULL, 0); - if (!i) { - for (;;) { - i = read_bunzip(bd, outbuf, IOBUF_SIZE); - if (i <= 0) break; - if (i != full_write(dst_fd, outbuf, i)) { - i = RETVAL_SHORT_WRITE; - break; + len = 0; + while (1) { /* "Process one BZ... stream" loop */ + + i = start_bunzip(&bd, 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 != full_write(dst_fd, outbuf, i)) { + bb_error_msg("short write"); + i = RETVAL_SHORT_WRITE; + goto release_mem; + } + IF_DESKTOP(total_written += i;) } - IF_DESKTOP(total_written += i;) } - } - - /* Check CRC and release memory */ - if (i == RETVAL_LAST_BLOCK) { + 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_error_msg("CRC error"); - } else { - i = RETVAL_OK; + break; } - } else if (i == RETVAL_SHORT_WRITE) { - bb_error_msg("short write"); - } else { - bb_error_msg("bunzip error %d", i); + + /* 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(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; } -IF_DESKTOP(long long) int FAST_FUNC -unpack_bz2_stream_prime(int src_fd, int dst_fd) -{ - uint16_t magic2; - xread(src_fd, &magic2, 2); - if (magic2 != BZIP2_MAGIC) { - bb_error_msg_and_die("invalid magic"); - } - return unpack_bz2_stream(src_fd, dst_fd); -} - #ifdef TESTING static char *const bunzip_errors[] = { @@ -711,10 +818,9 @@ static char *const bunzip_errors[] = { /* Dumb little test thing, decompress stdin to stdout */ int main(int argc, char **argv) { - int i; char c; - int i = unpack_bz2_stream_prime(0, 1); + int i = unpack_bz2_stream(0, 1); if (i < 0) fprintf(stderr, "%s\n", bunzip_errors[-i]); else if (read(STDIN_FILENO, &c, 1)) diff --git a/archival/libunarchive/decompress_unzip.c b/archival/libarchive/decompress_gunzip.c similarity index 96% rename from archival/libunarchive/decompress_unzip.c rename to archival/libarchive/decompress_gunzip.c index bccd026..7c6f38e 100644 --- a/archival/libunarchive/decompress_unzip.c +++ b/archival/libarchive/decompress_gunzip.c @@ -30,12 +30,12 @@ * * See the file algorithm.doc for the compression algorithms and file formats. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" typedef struct huft_t { unsigned char e; /* number of extra bits or operation */ @@ -293,8 +293,8 @@ static unsigned fill_bitbuffer(STATE_PARAM unsigned bitbuffer, unsigned *current * m: maximum lookup bits, returns actual */ static int huft_build(const unsigned *b, const unsigned n, - const unsigned s, const unsigned short *d, - const unsigned char *e, huft_t **t, unsigned *m) + const unsigned s, const unsigned short *d, + const unsigned char *e, huft_t **t, unsigned *m) { unsigned a; /* counter for codes of length k */ unsigned c[BMAX + 1]; /* bit length count table */ @@ -336,7 +336,7 @@ static int huft_build(const unsigned *b, const unsigned n, } /* Find minimum and maximum length, bound *m by those */ - for (j = 1; (c[j] == 0) && (j <= BMAX); j++) + for (j = 1; (j <= BMAX) && (c[j] == 0); j++) continue; k = j; /* minimum code length */ for (i = BMAX; (c[i] == 0) && i; i--) @@ -925,10 +925,7 @@ static int inflate_block(STATE_PARAM smallint *e) /* Two callsites, both in inflate_get_next_window */ static void calculate_gunzip_crc(STATE_PARAM_ONLY) { - unsigned n; - for (n = 0; n < gunzip_outbuf_count; n++) { - gunzip_crc = gunzip_crc_table[((int) gunzip_crc ^ (gunzip_window[n])) & 0xff] ^ (gunzip_crc >> 8); - } + gunzip_crc = crc32_block_endian0(gunzip_crc, gunzip_window, gunzip_outbuf_count, gunzip_crc_table); gunzip_bytes_out += gunzip_outbuf_count; } @@ -1037,22 +1034,22 @@ inflate_unzip_internal(STATE_PARAM int in, int out) /* For unzip */ IF_DESKTOP(long long) int FAST_FUNC -inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out) +inflate_unzip(transformer_aux_data_t *aux, int in, int out) { IF_DESKTOP(long long) int n; DECLARE_STATE; ALLOC_STATE; - to_read = compr_size; + to_read = aux->bytes_in; // bytebuffer_max = 0x8000; bytebuffer_offset = 4; bytebuffer = xmalloc(bytebuffer_max); n = inflate_unzip_internal(PASS_STATE in, out); free(bytebuffer); - res->crc = gunzip_crc; - res->bytes_out = gunzip_bytes_out; + aux->crc32 = gunzip_crc; + aux->bytes_out = gunzip_bytes_out; DEALLOC_STATE; return n; } @@ -1110,7 +1107,7 @@ static uint32_t buffer_read_le_u32(STATE_PARAM_ONLY) return res; } -static int check_header_gzip(STATE_PARAM unpack_info_t *info) +static int check_header_gzip(STATE_PARAM transformer_aux_data_t *aux) { union { unsigned char raw[8]; @@ -1172,8 +1169,8 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } } - if (info) - info->mtime = SWAP_LE32(header.formatted.mtime); + if (aux) + aux->mtime = SWAP_LE32(header.formatted.mtime); /* Read the header checksum */ if (header.formatted.flags & 0x02) { @@ -1185,33 +1182,58 @@ static int check_header_gzip(STATE_PARAM unpack_info_t *info) } IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) +unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { uint32_t v32; - IF_DESKTOP(long long) int n; + IF_DESKTOP(long long) int total, n; DECLARE_STATE; - n = 0; +#if !ENABLE_FEATURE_SEAMLESS_Z + if (check_signature16(aux, src_fd, GZIP_MAGIC)) + return -1; +#else + if (aux && aux->check_signature) { + uint16_t magic2; + + if (full_read(src_fd, &magic2, 2) != 2) { + bad_magic: + bb_error_msg("invalid magic"); + return -1; + } + if (magic2 == COMPRESS_MAGIC) { + aux->check_signature = 0; + return unpack_Z_stream(aux, src_fd, dst_fd); + } + 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 = in; + gunzip_src_fd = src_fd; again: - if (!check_header_gzip(PASS_STATE info)) { + if (!check_header_gzip(PASS_STATE aux)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } - n += inflate_unzip_internal(PASS_STATE in, out); - if (n < 0) + + n = inflate_unzip_internal(PASS_STATE src_fd, dst_fd); + if (n < 0) { + total = -1; goto ret; + } + total += n; if (!top_up(PASS_STATE 8)) { bb_error_msg("corrupted data"); - n = -1; + total = -1; goto ret; } @@ -1219,7 +1241,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((~gunzip_crc) != v32) { bb_error_msg("crc error"); - n = -1; + total = -1; goto ret; } @@ -1227,7 +1249,7 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) v32 = buffer_read_le_u32(PASS_STATE_ONLY); if ((uint32_t)gunzip_bytes_out != v32) { bb_error_msg("incorrect length"); - n = -1; + total = -1; } if (!top_up(PASS_STATE 2)) @@ -1245,11 +1267,5 @@ unpack_gz_stream_with_info(int in, int out, unpack_info_t *info) ret: free(bytebuffer); DEALLOC_STATE; - return n; -} - -IF_DESKTOP(long long) int FAST_FUNC -unpack_gz_stream(int in, int out) -{ - return unpack_gz_stream_with_info(in, out, NULL); + return total; } diff --git a/archival/libunarchive/decompress_uncompress.c b/archival/libarchive/decompress_uncompress.c similarity index 85% rename from archival/libunarchive/decompress_uncompress.c rename to archival/libarchive/decompress_uncompress.c index 1ff89ce..53c2708 100644 --- a/archival/libunarchive/decompress_uncompress.c +++ b/archival/libarchive/decompress_uncompress.c @@ -25,14 +25,14 @@ */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" /* Default input buffer size */ -#define IBUFSIZ 2048 +#define IBUFSIZ 2048 /* Default output buffer size */ -#define OBUFSIZ 2048 +#define OBUFSIZ 2048 /* Defines for third byte of header */ #define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ @@ -73,12 +73,11 @@ */ IF_DESKTOP(long long) int FAST_FUNC -unpack_Z_stream(int fd_in, int fd_out) +unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) IF_DESKTOP(long long) int retval = -1; unsigned char *stackp; - long code; int finchar; long oldcode; long incode; @@ -103,16 +102,19 @@ unpack_Z_stream(int fd_in, int fd_out) /* block compress mode -C compatible with 2.0 */ int block_mode; /* = BLOCK_MODE; */ + if (check_signature16(aux, src_fd, COMPRESS_MAGIC)) + return -1; + inbuf = xzalloc(IBUFSIZ + 64); outbuf = xzalloc(OBUFSIZ + 2048); - htab = xzalloc(HSIZE); /* wsn't zeroed out before, maybe can xmalloc? */ + htab = xzalloc(HSIZE); /* wasn't zeroed out before, maybe can xmalloc? */ codetab = xzalloc(HSIZE * sizeof(codetab[0])); insize = 0; /* xread isn't good here, we have to return - caller may want * to do some cleanup (e.g. delete incomplete unpacked file etc) */ - if (full_read(fd_in, inbuf, 1) != 1) { + if (full_read(src_fd, inbuf, 1) != 1) { bb_error_msg("short read"); goto err; } @@ -140,8 +142,10 @@ unpack_Z_stream(int fd_in, int fd_out) /* As above, initialize the first 256 entries in the table. */ /*clear_tab_prefixof(); - done by xzalloc */ - for (code = 255; code >= 0; --code) { - tab_suffixof(code) = (unsigned char) code; + { + int i; + for (i = 255; i >= 0; --i) + tab_suffixof(i) = (unsigned char) i; } do { @@ -162,8 +166,9 @@ unpack_Z_stream(int fd_in, int fd_out) } if (insize < (int) (IBUFSIZ + 64) - IBUFSIZ) { - rsize = safe_read(fd_in, inbuf + insize, IBUFSIZ); -//error check?? + rsize = safe_read(src_fd, inbuf + insize, IBUFSIZ); + if (rsize < 0) + bb_error_msg_and_die(bb_msg_read_error); insize += rsize; } @@ -171,6 +176,8 @@ unpack_Z_stream(int fd_in, int fd_out) (insize << 3) - (n_bits - 1)); while (inbits > posbits) { + long code; + if (free_ent > maxcode) { posbits = ((posbits - 1) + @@ -187,14 +194,15 @@ unpack_Z_stream(int fd_in, int fd_out) } { unsigned char *p = &inbuf[posbits >> 3]; - - code = ((((long) (p[0])) | ((long) (p[1]) << 8) | - ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; + code = ((p[0] + | ((long) (p[1]) << 8) + | ((long) (p[2]) << 16)) >> (posbits & 0x7)) & bitmask; } posbits += n_bits; - if (oldcode == -1) { + if (code >= 256) + bb_error_msg_and_die("corrupted data"); /* %ld", code); */ oldcode = code; finchar = (int) oldcode; outbuf[outpos++] = (unsigned char) finchar; @@ -220,15 +228,16 @@ unpack_Z_stream(int fd_in, int fd_out) /* 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)); + insize, posbits, p[-1], p[0], p[1], p[2], p[3], + (posbits & 07)); +*/ bb_error_msg("corrupted data"); goto err; } @@ -238,7 +247,9 @@ unpack_Z_stream(int fd_in, int fd_out) } /* Generate output characters in reverse order */ - while ((long) code >= (long) 256) { + while (code >= 256) { + if (stackp <= &htabof(0)) + bb_error_msg_and_die("corrupted data"); *--stackp = tab_suffixof(code); code = tab_prefixof(code); } @@ -263,8 +274,7 @@ unpack_Z_stream(int fd_in, int fd_out) } if (outpos >= OBUFSIZ) { - full_write(fd_out, outbuf, outpos); -//error check?? + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) outpos = 0; } @@ -278,11 +288,10 @@ unpack_Z_stream(int fd_in, int fd_out) } /* Generate the new entry. */ - code = free_ent; - if (code < maxmaxcode) { - tab_prefixof(code) = (unsigned short) oldcode; - tab_suffixof(code) = (unsigned char) finchar; - free_ent = code + 1; + if (free_ent < maxmaxcode) { + tab_prefixof(free_ent) = (unsigned short) oldcode; + tab_suffixof(free_ent) = (unsigned char) finchar; + free_ent++; } /* Remember previous code. */ @@ -292,8 +301,7 @@ unpack_Z_stream(int fd_in, int fd_out) } while (rsize > 0); if (outpos > 0) { - full_write(fd_out, outbuf, outpos); -//error check?? + xwrite(dst_fd, outbuf, outpos); IF_DESKTOP(total_written += outpos;) } diff --git a/archival/libunarchive/decompress_unlzma.c b/archival/libarchive/decompress_unlzma.c similarity index 95% rename from archival/libunarchive/decompress_unlzma.c rename to archival/libarchive/decompress_unlzma.c index ecda174..ca32bd8 100644 --- a/archival/libunarchive/decompress_unlzma.c +++ b/archival/libarchive/decompress_unlzma.c @@ -6,10 +6,10 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #if ENABLE_FEATURE_LZMA_FAST # define speed_inline ALWAYS_INLINE @@ -45,16 +45,16 @@ typedef struct { #define RC_MODEL_TOTAL_BITS 11 -/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */ -static size_inline void rc_read(rc_t *rc) +/* 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_error_msg_and_die("unexpected EOF"); - rc->ptr = RC_BUFFER; 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() */ @@ -65,6 +65,12 @@ static void rc_do_normalize(rc_t *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) */ @@ -78,15 +84,9 @@ static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */ /* rc->ptr = rc->buffer_end; */ for (i = 0; i < 5; i++) { -#if ENABLE_FEATURE_LZMA_FAST - if (rc->ptr >= rc->buffer_end) - rc_read(rc); - rc->code = (rc->code << 8) | *rc->ptr++; -#else rc_do_normalize(rc); -#endif } - rc->range = 0xFFFFFFFF; + rc->range = 0xffffffff; return rc; } @@ -96,13 +96,6 @@ static ALWAYS_INLINE void rc_free(rc_t *rc) free(rc); } -static ALWAYS_INLINE void rc_normalize(rc_t *rc) -{ - if (rc->range < (1 << RC_TOP_BITS)) { - rc_do_normalize(rc); - } -} - /* rc_is_bit_1 is called 9 times */ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) { @@ -120,7 +113,7 @@ static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p) } /* Called 4 times in unlzma loop */ -static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol) +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; @@ -213,7 +206,7 @@ enum { IF_DESKTOP(long long) int FAST_FUNC -unpack_lzma_stream(int src_fd, int dst_fd) +unpack_lzma_stream(transformer_aux_data_t *aux UNUSED_PARAM, int src_fd, int dst_fd) { IF_DESKTOP(long long total_written = 0;) lzma_header_t header; diff --git a/archival/libunarchive/decompress_unxz.c b/archival/libarchive/decompress_unxz.c similarity index 54% rename from archival/libunarchive/decompress_unxz.c rename to archival/libarchive/decompress_unxz.c index 721acd9..986b7b1 100644 --- a/archival/libunarchive/decompress_unxz.c +++ b/archival/libarchive/decompress_unxz.c @@ -7,10 +7,10 @@ * * This file is: * Copyright (C) 2010 Denys Vlasenko - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #define XZ_FUNC FAST_FUNC #define XZ_EXTERN static @@ -22,54 +22,50 @@ /* We use our own crc32 function */ #define XZ_INTERNAL_CRC32 0 -static uint32_t *crc32_table; static uint32_t xz_crc32(const uint8_t *buf, size_t size, uint32_t crc) { - crc = ~crc; - - while (size != 0) { - crc = crc32_table[*buf++ ^ (crc & 0xFF)] ^ (crc >> 8); - --size; - } - - return ~crc; + return ~crc32_block_endian0(~crc, buf, size, global_crc32_table); } /* We use arch-optimized unaligned accessors */ #define get_unaligned_le32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_LE32(v); }) #define get_unaligned_be32(buf) ({ uint32_t v; move_from_unaligned32(v, buf); SWAP_BE32(v); }) -#define put_unaligned_le32(val, buf) move_to_unaligned16(buf, SWAP_LE32(val)) -#define put_unaligned_be32(val, buf) move_to_unaligned16(buf, SWAP_BE32(val)) +#define put_unaligned_le32(val, buf) move_to_unaligned32(buf, SWAP_LE32(val)) +#define put_unaligned_be32(val, buf) move_to_unaligned32(buf, SWAP_BE32(val)) #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(int src_fd, int dst_fd) +unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) { + enum xz_ret xz_result; struct xz_buf iobuf; struct xz_dec *state; unsigned char *membuf; IF_DESKTOP(long long) int total = 0; - if (!crc32_table) - crc32_table = crc32_filltable(NULL, /*endian:*/ 0); + if (!global_crc32_table) + global_crc32_table = crc32_filltable(NULL, /*endian:*/ 0); memset(&iobuf, 0, sizeof(iobuf)); - /* Preload XZ file signature */ - membuf = (void*) strcpy(xmalloc(2 * BUFSIZ), HEADER_MAGIC); + membuf = xmalloc(2 * BUFSIZ); iobuf.in = membuf; - iobuf.in_size = HEADER_MAGIC_SIZE; iobuf.out = membuf + BUFSIZ; iobuf.out_size = BUFSIZ; + if (!aux || aux->check_signature == 0) { + /* 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) { - enum xz_ret r; - if (iobuf.in_pos == iobuf.in_size) { int rd = safe_read(src_fd, membuf, BUFSIZ); if (rd < 0) { @@ -77,28 +73,57 @@ unpack_xz_stream(int src_fd, int dst_fd) 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) { + 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); - r = xz_dec_run(state, &iobuf); + xz_result = xz_dec_run(state, &iobuf); // bb_error_msg("accept, key); /* Fail if an accept list was specified and the key wasnt in there */ - if ((accept_entry == NULL) && archive_handle->accept) { - return EXIT_FAILURE; + if (archive_handle->accept) { + accept_entry = find_list_entry2(archive_handle->accept, key); + if (!accept_entry) { + return EXIT_FAILURE; + } } /* Accepted */ diff --git a/archival/libunarchive/find_list_entry.c b/archival/libarchive/find_list_entry.c similarity index 91% rename from archival/libunarchive/find_list_entry.c rename to archival/libarchive/find_list_entry.c index bc7bc64..56032c6 100644 --- a/archival/libunarchive/find_list_entry.c +++ b/archival/libarchive/find_list_entry.c @@ -2,12 +2,12 @@ /* * Copyright (C) 2002 by Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include #include "libbb.h" -#include "unarchive.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) diff --git a/archival/libunarchive/get_header_ar.c b/archival/libarchive/get_header_ar.c similarity index 75% rename from archival/libunarchive/get_header_ar.c rename to archival/libarchive/get_header_ar.c index dbc5ec0..c66bb3e 100644 --- a/archival/libunarchive/get_header_ar.c +++ b/archival/libarchive/get_header_ar.c @@ -1,18 +1,26 @@ /* vi: set sw=4 ts=4: */ /* Copyright 2001 Glenn McGrath. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "ar.h" -static unsigned read_num(const char *str, int base) +/* 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 */ - int err = bb_strtou(str, NULL, base); + err = bb_strtou(str, NULL, base); if (err == -1) bb_error_msg_and_die("invalid ar header"); return err; @@ -51,11 +59,13 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) if (ar.formatted.magic[0] != '`' || ar.formatted.magic[1] != '\n') bb_error_msg_and_die("invalid ar header"); - /* FIXME: more thorough routine would be in order here - * (we have something like that in tar) - * but for now we are lax. */ - ar.formatted.magic[0] = '\0'; /* else 4G-2 file will have size="4294967294`\n..." */ - typed->size = size = read_num(ar.formatted.size, 10); + /* + * 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] == '/') { @@ -87,10 +97,10 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) * long filename pseudo file. Thus we decode the rest * after dealing with long filename pseudo file. */ - typed->mode = read_num(ar.formatted.mode, 8); - typed->mtime = read_num(ar.formatted.date, 10); - typed->uid = read_num(ar.formatted.uid, 10); - typed->gid = read_num(ar.formatted.gid, 10); + typed->mode = read_num(ar.formatted.mode, 8, sizeof(ar.formatted.mode)); + 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] == '/') { @@ -98,7 +108,8 @@ char FAST_FUNC get_header_ar(archive_handle_t *archive_handle) /* The number after the '/' indicates the offset in the ar data section * (saved in ar_long_names) that conatains the real filename */ - long_offset = read_num(&ar.formatted.name[1], 10); + long_offset = read_num(&ar.formatted.name[1], 10, + sizeof(ar.formatted.name) - 1); if (long_offset >= ar_long_name_size) { bb_error_msg_and_die("can't resolve long filename"); } diff --git a/archival/libunarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c similarity index 98% rename from archival/libunarchive/get_header_cpio.c rename to archival/libarchive/get_header_cpio.c index 4507d53..1a0058b 100644 --- a/archival/libunarchive/get_header_cpio.c +++ b/archival/libarchive/get_header_cpio.c @@ -1,11 +1,11 @@ /* vi: set sw=4 ts=4: */ /* Copyright 2002 Laurence Anderson * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" typedef struct hardlinks_t { struct hardlinks_t *next; diff --git a/archival/libunarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c similarity index 78% rename from archival/libunarchive/get_header_tar.c rename to archival/libarchive/get_header_tar.c index d5c9235..32f8420 100644 --- a/archival/libunarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -1,23 +1,52 @@ /* vi: set sw=4 ts=4: */ -/* Licensed under GPLv2 or later, see file LICENSE in this tarball for details. +/* Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * FIXME: + * 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: + * References: * GNU tar and star man pages, * Opengroup's ustar interchange format, - * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html + * http://www.opengroup.org/onlinepubs/007904975/utilities/pax.html */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" typedef uint32_t aliased_uint32_t FIX_ALIASING; typedef off_t aliased_off_t FIX_ALIASING; +const char* FAST_FUNC strip_unsafe_prefix(const char *str) +{ + const char *cp = str; + while (1) { + char *cp2; + if (*cp == '/') { + cp++; + continue; + } + if (strncmp(cp, "/../"+1, 3) == 0) { + 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; +} + /* NB: _DESTROYS_ str[len] character! */ static unsigned long long getOctal(char *str, int len) { @@ -50,34 +79,31 @@ static unsigned long long getOctal(char *str, int len) * * NB: tarballs with NEGATIVE unix times encoded that way were seen! */ - v = first; - /* Sign-extend using 6th bit: */ - v <<= sizeof(unsigned long long)*8 - 7; - v = (long long)v >> (sizeof(unsigned long long)*8 - 7); + /* 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) + (unsigned char) *str++; + v = (v << 8) + (uint8_t) *++str; } return v; } #define GET_OCTAL(a) getOctal((a), sizeof(a)) -#if ENABLE_FEATURE_TAR_SELINUX -/* Scan a PAX header 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" -static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, unsigned sz) +/* "global" is 0 or 1 */ +static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int global) { char *buf, *p; - char *result; + unsigned blk_sz; + + blk_sz = (sz + 511) & (~511); + p = buf = xmalloc(blk_sz + 1); + xread(archive_handle->src_fd, buf, blk_sz); + archive_handle->offset += blk_sz; - p = buf = xmalloc(sz + 1); /* prevent bb_strtou from running off the buffer */ buf[sz] = '\0'; - xread(archive_handle->src_fd, buf, sz); - archive_handle->offset += sz; - result = NULL; while (sz != 0) { char *end, *value; unsigned len; @@ -104,19 +130,33 @@ static char *get_selinux_sctx_from_pax_hdr(archive_handle_t *archive_handle, uns * (we do not bother to check that it *was* a newline) */ p[-1] = '\0'; - /* Is it selinux security context? */ value = end + 1; + +#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) { + value += sizeof("path=") - 1; + free(archive_handle->tar__longname); + archive_handle->tar__longname = 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 (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; - result = xstrdup(value); - break; + free(archive_handle->tar__sctx[global]); + archive_handle->tar__sctx[global] = xstrdup(value); + continue; } +#endif } free(buf); - return result; } -#endif char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) { @@ -158,13 +198,13 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) * the message and we don't check whether we indeed * saw zero block directly before this. */ if (i == 0) { - xfunc_error_retval = 0; - short_read: - bb_error_msg_and_die("short read"); + bb_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;) - goto short_read; + bb_error_msg_and_die("short read"); } #else @@ -181,10 +221,10 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) */ while (full_read(archive_handle->src_fd, &tar, 512) == 512) continue; - return EXIT_FAILURE; + return EXIT_FAILURE; /* "end of archive" */ } archive_handle->tar__end = 1; - return EXIT_SUCCESS; + return EXIT_SUCCESS; /* "decoded one header" */ } archive_handle->tar__end = 0; @@ -195,43 +235,18 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) || memcmp(tar.magic, "\0\0\0\0", 5) != 0) ) { #if ENABLE_FEATURE_TAR_AUTODETECT - char FAST_FUNC (*get_header_ptr)(archive_handle_t *); - uint16_t magic2; - autodetect: - magic2 = *(uint16_t*)tar.name; - /* tar gz/bz autodetect: check for gz/bz2 magic. - * If we see the magic, and it is the very first block, - * we can switch to get_header_tar_gz/bz2/lzma(). - * Needs seekable fd. I wish recv(MSG_PEEK) works - * on any fd... */ -# if ENABLE_FEATURE_SEAMLESS_GZ - if (magic2 == GZIP_MAGIC) { - get_header_ptr = get_header_tar_gz; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_BZ2 - if (magic2 == BZIP2_MAGIC - && tar.name[2] == 'h' && isdigit(tar.name[3]) - ) { /* bzip2 */ - get_header_ptr = get_header_tar_bz2; - } else -# endif -# if ENABLE_FEATURE_SEAMLESS_XZ - //TODO: if (magic2 == XZ_MAGIC1)... - //else -# endif - goto err; /* 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; - while (get_header_ptr(archive_handle) == EXIT_SUCCESS) - continue; - return EXIT_FAILURE; + if (setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 0) != 0) err: -#endif /* FEATURE_TAR_AUTODETECT */ + bb_error_msg_and_die("invalid tar magic"); + archive_handle->offset = 0; + goto again_after_align; +#endif bb_error_msg_and_die("invalid tar magic"); } @@ -319,10 +334,20 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* Set bits 12-15 of the files mode */ /* (typeflag was not trashed because chksum does not use getOctal) */ switch (tar.typeflag) { - /* busybox identifies hard links as being regular files with 0 size and a link name */ - case '1': + case '1': /* hardlink */ + /* we mark hardlinks as regular files with zero size and a link name */ file_header->mode |= S_IFREG; - break; + /* 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': @@ -379,12 +404,14 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'S': /* Sparse file */ case 'V': /* Volume header */ #endif -#if !ENABLE_FEATURE_TAR_SELINUX case 'g': /* pax global header */ - case 'x': /* pax extended header */ -#else + 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; + } skip_ext_hdr: -#endif { off_t sz; bb_error_msg("warning: skipping header '%c'", tar.typeflag); @@ -396,18 +423,6 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) /* return get_header_tar(archive_handle); */ goto again_after_align; } -#if ENABLE_FEATURE_TAR_SELINUX - case 'g': /* pax global header */ - case 'x': { /* pax extended header */ - char **pp; - if ((uoff_t)file_header->size > 0xfffff) /* paranoia */ - goto skip_ext_hdr; - pp = (tar.typeflag == 'g') ? &archive_handle->tar__global_sctx : &archive_handle->tar__next_file_sctx; - free(*pp); - *pp = get_selinux_sctx_from_pax_hdr(archive_handle, file_header->size); - goto again; - } -#endif default: bb_error_msg_and_die("unknown typeflag: 0x%x", tar.typeflag); } @@ -422,12 +437,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) p_linkname = NULL; } #endif - if (strncmp(file_header->name, "/../"+1, 3) == 0 - || strstr(file_header->name, "/../") - ) { - bb_error_msg_and_die("name with '..' encountered: '%s'", - file_header->name); - } + + /* Everything up to and including last ".." component is stripped */ + overlapping_strcpy(file_header->name, strip_unsafe_prefix(file_header->name)); /* Strip trailing '/' in directories */ /* Must be done after mode is set as '/' is used to check if it's a directory */ @@ -440,9 +452,11 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) if (cp) *cp = '\0'; archive_handle->action_data(archive_handle); - if (archive_handle->accept || archive_handle->reject) + 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 */ + } else /* Caller isn't interested in list of unpacked files */ free(file_header->name); } else { data_skip(archive_handle); @@ -457,5 +471,5 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) free(file_header->tar__uname); free(file_header->tar__gname); #endif - return EXIT_SUCCESS; + return EXIT_SUCCESS; /* "decoded one header" */ } diff --git a/archival/libunarchive/get_header_tar_bz2.c b/archival/libarchive/get_header_tar_bz2.c similarity index 65% rename from archival/libunarchive/get_header_tar_bz2.c rename to archival/libarchive/get_header_tar_bz2.c index 615bbba..0ee00df 100644 --- a/archival/libunarchive/get_header_tar_bz2.c +++ b/archival/libarchive/get_header_tar_bz2.c @@ -1,17 +1,17 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.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; - open_transformer(archive_handle->src_fd, unpack_bz2_stream_prime, "bunzip2"); + open_transformer_with_sig(archive_handle->src_fd, unpack_bz2_stream, "bunzip2"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/archival/libarchive/get_header_tar_gz.c b/archival/libarchive/get_header_tar_gz.c new file mode 100644 index 0000000..0328434 --- /dev/null +++ b/archival/libarchive/get_header_tar_gz.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" + +char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) +{ + /* Can't lseek over pipes */ + archive_handle->seek = seek_by_read; + + open_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/archival/libunarchive/get_header_tar_lzma.c b/archival/libarchive/get_header_tar_lzma.c similarity index 72% rename from archival/libunarchive/get_header_tar_lzma.c rename to archival/libarchive/get_header_tar_lzma.c index 03b1b79..d565a21 100644 --- a/archival/libunarchive/get_header_tar_lzma.c +++ b/archival/libarchive/get_header_tar_lzma.c @@ -3,18 +3,18 @@ * Small lzma deflate implementation. * Copyright (C) 2006 Aurelien Jacobs * - * Licensed under GPL v2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.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; - open_transformer(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); + open_transformer_with_sig(archive_handle->src_fd, unpack_lzma_stream, "unlzma"); archive_handle->offset = 0; while (get_header_tar(archive_handle) == EXIT_SUCCESS) continue; diff --git a/archival/libunarchive/header_list.c b/archival/libarchive/header_list.c similarity index 66% rename from archival/libunarchive/header_list.c rename to archival/libarchive/header_list.c index b1c425a..0621aa4 100644 --- a/archival/libunarchive/header_list.c +++ b/archival/libarchive/header_list.c @@ -1,9 +1,9 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC header_list(const file_header_t *file_header) { diff --git a/archival/libunarchive/header_skip.c b/archival/libarchive/header_skip.c similarity index 55% rename from archival/libunarchive/header_skip.c rename to archival/libarchive/header_skip.c index a97a9ce..f5987bf 100644 --- a/archival/libunarchive/header_skip.c +++ b/archival/libarchive/header_skip.c @@ -1,9 +1,9 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC header_skip(const file_header_t *file_header UNUSED_PARAM) { diff --git a/archival/libunarchive/header_verbose_list.c b/archival/libarchive/header_verbose_list.c similarity index 93% rename from archival/libunarchive/header_verbose_list.c rename to archival/libarchive/header_verbose_list.c index 3319e63..87dd821 100644 --- a/archival/libunarchive/header_verbose_list.c +++ b/archival/libarchive/header_verbose_list.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC header_verbose_list(const file_header_t *file_header) { diff --git a/archival/libunarchive/init_handle.c b/archival/libarchive/init_handle.c similarity index 82% rename from archival/libunarchive/init_handle.c rename to archival/libarchive/init_handle.c index ff7d484..cbae06a 100644 --- a/archival/libunarchive/init_handle.c +++ b/archival/libarchive/init_handle.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" archive_handle_t* FAST_FUNC init_handle(void) { diff --git a/archival/liblzo.h b/archival/libarchive/liblzo.h similarity index 100% rename from archival/liblzo.h rename to archival/libarchive/liblzo.h diff --git a/archival/lzo1x_1.c b/archival/libarchive/lzo1x_1.c similarity index 100% rename from archival/lzo1x_1.c rename to archival/libarchive/lzo1x_1.c diff --git a/archival/lzo1x_1o.c b/archival/libarchive/lzo1x_1o.c similarity index 100% rename from archival/lzo1x_1o.c rename to archival/libarchive/lzo1x_1o.c diff --git a/archival/lzo1x_9x.c b/archival/libarchive/lzo1x_9x.c similarity index 98% rename from archival/lzo1x_9x.c rename to archival/libarchive/lzo1x_9x.c index 0baed54..2b490ae 100644 --- a/archival/lzo1x_9x.c +++ b/archival/libarchive/lzo1x_9x.c @@ -94,7 +94,7 @@ typedef struct { ( ((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) (* (uint16_t *) &(b[p])) +# define HEAD2(b,p) (* (bb__aliased_uint16_t *) &(b[p])) #else # define HEAD2(b,p) (b[p] ^ ((unsigned)b[p+1]<<8)) #endif @@ -466,7 +466,6 @@ static int find_match(lzo1x_999_t *c, lzo_swd_p s, } s->m_len = 1; - s->m_len = 1; #ifdef SWD_BEST_OFF if (s->use_best_off) memset(s->best_pos, 0, sizeof(s->best_pos)); @@ -644,7 +643,7 @@ static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit) static int min_gain(unsigned ahead, unsigned lit1, - unsigned lit2, int l1, int l2, int l3) + unsigned lit2, int l1, int l2, int l3) { int lazy_match_min_gain = 0; @@ -673,9 +672,8 @@ static int min_gain(unsigned ahead, unsigned lit1, #if defined(SWD_BEST_OFF) static void better_match(const lzo_swd_p swd, - unsigned *m_len, unsigned *m_off) + unsigned *m_len, unsigned *m_off) { - if (*m_len <= M2_MIN_LEN) return; @@ -915,8 +913,8 @@ int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len, 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); + c[compression_level].good_length, + c[compression_level].max_lazy, + c[compression_level].max_chain, + c[compression_level].use_best_off); } diff --git a/archival/lzo1x_c.c b/archival/libarchive/lzo1x_c.c similarity index 99% rename from archival/lzo1x_c.c rename to archival/libarchive/lzo1x_c.c index cc86f74..8c77072 100644 --- a/archival/lzo1x_c.c +++ b/archival/libarchive/lzo1x_c.c @@ -15,7 +15,7 @@ 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License diff --git a/archival/lzo1x_d.c b/archival/libarchive/lzo1x_d.c similarity index 99% rename from archival/lzo1x_d.c rename to archival/libarchive/lzo1x_d.c index 348a855..9bc1270 100644 --- a/archival/lzo1x_d.c +++ b/archival/libarchive/lzo1x_d.c @@ -15,7 +15,7 @@ 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 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c new file mode 100644 index 0000000..4e98264 --- /dev/null +++ b/archival/libarchive/open_transformer.c @@ -0,0 +1,227 @@ +/* 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_aux_data(transformer_aux_data_t *aux) +{ + memset(aux, 0, sizeof(*aux)); +} + +int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) +{ + if (aux && aux->check_signature) { + uint16_t magic2; + if (full_read(src_fd, &magic2, 2) != 2 || magic2 != magic16) { + bb_error_msg("invalid magic"); +#if 0 /* possible future extension */ + if (aux->check_signature > 1) + xfunc_die(); +#endif + return -1; + } + } + return 0; +} + +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 open_transformer(int fd, + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) +) +#else +void FAST_FUNC open_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_aux_data_t aux; + init_transformer_aux_data(&aux); + aux.check_signature = check_signature; + r = transformer(&aux, fd, fd_pipe.wr); + 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. + */ +int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_detected) +{ + union { + uint8_t b[4]; + uint16_t b16[2]; + uint32_t b32[1]; + } magic; + int offset = -2; + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_NOMMU(const char *xformer_prog;) + + /* .gz and .bz2 both have 2-byte signature, and their + * unpack_XXX_stream wants this header skipped. */ + xread(fd, magic.b16, sizeof(magic.b16[0])); + if (ENABLE_FEATURE_SEAMLESS_GZ + && magic.b16[0] == GZIP_MAGIC + ) { + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_BZ2 + && magic.b16[0] == BZIP2_MAGIC + ) { + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + goto found_magic; + } + if (ENABLE_FEATURE_SEAMLESS_XZ + && magic.b16[0] == XZ_MAGIC1 + ) { + offset = -6; + xread(fd, magic.b32, sizeof(magic.b32[0])); + if (magic.b32[0] == XZ_MAGIC2) { + USE_FOR_MMU(xformer = unpack_xz_stream;) + USE_FOR_NOMMU(xformer_prog = "unxz";) + goto found_magic; + } + } + + /* No known magic seen */ + if (fail_if_not_detected) + bb_error_msg_and_die("no gzip" + IF_FEATURE_SEAMLESS_BZ2("/bzip2") + IF_FEATURE_SEAMLESS_XZ("/xz") + " magic"); + xlseek(fd, offset, SEEK_CUR); + return 1; + + found_magic: +# if BB_MMU + open_transformer_with_no_sig(fd, xformer); +# else + /* NOMMU version of open_transformer execs + * an external unzipper that wants + * file position at the start of the file */ + xlseek(fd, offset, SEEK_CUR); + open_transformer_with_sig(fd, xformer, xformer_prog); +# endif + return 0; +} + +int FAST_FUNC open_zipped(const char *fname) +{ + char *sfx; + int fd; + + fd = open(fname, O_RDONLY); + if (fd < 0) + return fd; + + sfx = strrchr(fname, '.'); + if (sfx) { + sfx++; + if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) + /* .lzma has no header/signature, just trust it */ + open_transformer_with_sig(fd, unpack_lzma_stream, "unlzma"); + else + if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) + || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) + || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) + ) { + setup_unzip_on_fd(fd, /*fail_if_not_detected:*/ 1); + } + } + + return fd; +} + +#endif /* SEAMLESS_COMPRESSION */ + +void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) +{ + int fd; + char *image; + + fd = open_zipped(fname); + 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; +} diff --git a/archival/libunarchive/seek_by_jump.c b/archival/libarchive/seek_by_jump.c similarity index 72% rename from archival/libunarchive/seek_by_jump.c rename to archival/libarchive/seek_by_jump.c index 7181cb3..4fcd99a 100644 --- a/archival/libunarchive/seek_by_jump.c +++ b/archival/libarchive/seek_by_jump.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" void FAST_FUNC seek_by_jump(int fd, off_t amount) { diff --git a/archival/libunarchive/seek_by_read.c b/archival/libarchive/seek_by_read.c similarity index 73% rename from archival/libunarchive/seek_by_read.c rename to archival/libarchive/seek_by_read.c index af65e5d..c0fde96 100644 --- a/archival/libunarchive/seek_by_read.c +++ b/archival/libarchive/seek_by_read.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.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. diff --git a/archival/libunarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c similarity index 79% rename from archival/libunarchive/unpack_ar_archive.c rename to archival/libarchive/unpack_ar_archive.c index 300d10e..214d17e 100644 --- a/archival/libunarchive/unpack_ar_archive.c +++ b/archival/libarchive/unpack_ar_archive.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "ar.h" void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive) diff --git a/archival/libunarchive/unxz/README b/archival/libarchive/unxz/README similarity index 97% rename from archival/libunarchive/unxz/README rename to archival/libarchive/unxz/README index f79b0a4..a849120 100644 --- a/archival/libunarchive/unxz/README +++ b/archival/libarchive/unxz/README @@ -7,7 +7,7 @@ XZ Embedded 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. + 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 @@ -55,7 +55,7 @@ Compiler requirements 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, + 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. @@ -93,7 +93,7 @@ BCJ filter support them always #defined doesn't hurt either. #define Instruction set BCJ filter endianness - XZ_DEC_X86 x86 or x86-64 Little endian only + 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 @@ -133,4 +133,3 @@ Specifying the calling convention 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/archival/libunarchive/unxz/xz.h b/archival/libarchive/unxz/xz.h similarity index 96% rename from archival/libunarchive/unxz/xz.h rename to archival/libarchive/unxz/xz.h index c6c071c..e0b22db 100644 --- a/archival/libunarchive/unxz/xz.h +++ b/archival/libarchive/unxz/xz.h @@ -19,6 +19,10 @@ # 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 @@ -70,7 +74,7 @@ enum xz_mode { * @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: This return value is used only if + * 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 @@ -105,7 +109,7 @@ enum xz_mode { * 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 + * 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. @@ -207,8 +211,8 @@ XZ_EXTERN struct xz_dec * XZ_FUNC xz_dec_init( * The possible return values depend on build options and operation mode. * See enum xz_ret for details. * - * NOTE: 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 + * 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 @@ -268,4 +272,9 @@ XZ_EXTERN void XZ_FUNC xz_crc32_init(void); 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/archival/libunarchive/unxz/xz_config.h b/archival/libarchive/unxz/xz_config.h similarity index 100% rename from archival/libunarchive/unxz/xz_config.h rename to archival/libarchive/unxz/xz_config.h diff --git a/archival/libunarchive/unxz/xz_dec_bcj.c b/archival/libarchive/unxz/xz_dec_bcj.c similarity index 92% rename from archival/libunarchive/unxz/xz_dec_bcj.c rename to archival/libarchive/unxz/xz_dec_bcj.c index 09162b5..e0f913a 100644 --- a/archival/libunarchive/unxz/xz_dec_bcj.c +++ b/archival/libarchive/unxz/xz_dec_bcj.c @@ -77,10 +77,13 @@ struct xz_dec_bcj { #ifdef XZ_DEC_X86 /* - * This is macro used to test the most significant byte of a memory address + * This is used to test the most significant byte of a memory address * in an x86 instruction. */ -#define bcj_x86_test_msbyte(b) ((b) == 0x00 || (b) == 0xFF) +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) @@ -443,8 +446,12 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, * 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) { + 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; @@ -467,16 +474,25 @@ XZ_EXTERN enum xz_ret XZ_FUNC xz_dec_bcj_run(struct xz_dec_bcj *s, 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; } /* - * If we have unfiltered data in temp, try to fill 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. + * 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 (s->temp.size > 0) { + 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; diff --git a/archival/libunarchive/unxz/xz_dec_lzma2.c b/archival/libarchive/unxz/xz_dec_lzma2.c similarity index 99% rename from archival/libunarchive/unxz/xz_dec_lzma2.c rename to archival/libarchive/unxz/xz_dec_lzma2.c index da71cb4..3c2dc88 100644 --- a/archival/libunarchive/unxz/xz_dec_lzma2.c +++ b/archival/libarchive/unxz/xz_dec_lzma2.c @@ -407,7 +407,6 @@ static void XZ_FUNC dict_uncompressed( b->out_pos += copy_size; b->in_pos += copy_size; - } } @@ -972,6 +971,9 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( */ 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; @@ -1004,9 +1006,6 @@ XZ_EXTERN NOINLINE enum xz_ret XZ_FUNC xz_dec_lzma2_run( lzma_reset(s); } } else { - if (tmp == 0x00) - return XZ_STREAM_END; - if (tmp > 0x02) return XZ_DATA_ERROR; diff --git a/archival/libunarchive/unxz/xz_dec_stream.c b/archival/libarchive/unxz/xz_dec_stream.c similarity index 100% rename from archival/libunarchive/unxz/xz_dec_stream.c rename to archival/libarchive/unxz/xz_dec_stream.c diff --git a/archival/libunarchive/unxz/xz_lzma2.h b/archival/libarchive/unxz/xz_lzma2.h similarity index 100% rename from archival/libunarchive/unxz/xz_lzma2.h rename to archival/libarchive/unxz/xz_lzma2.h diff --git a/archival/libunarchive/unxz/xz_private.h b/archival/libarchive/unxz/xz_private.h similarity index 100% rename from archival/libunarchive/unxz/xz_private.h rename to archival/libarchive/unxz/xz_private.h diff --git a/archival/libunarchive/unxz/xz_stream.h b/archival/libarchive/unxz/xz_stream.h similarity index 72% rename from archival/libunarchive/unxz/xz_stream.h rename to archival/libarchive/unxz/xz_stream.h index 36f2a7c..66cb5a7 100644 --- a/archival/libunarchive/unxz/xz_stream.h +++ b/archival/libarchive/unxz/xz_stream.h @@ -25,15 +25,20 @@ #define STREAM_HEADER_SIZE 12 -#define HEADER_MAGIC "\3757zXZ\0" +#define HEADER_MAGIC "\3757zXZ" #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 to indicate that the value is unknown. + * 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; diff --git a/archival/libunarchive/Kbuild.src b/archival/libunarchive/Kbuild.src deleted file mode 100644 index a854957..0000000 --- a/archival/libunarchive/Kbuild.src +++ /dev/null @@ -1,61 +0,0 @@ -# Makefile for busybox -# -# Copyright (C) 1999-2004 by Erik Andersen -# -# Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - -lib-y:= - -COMMON_FILES:= \ -\ - data_skip.o \ - data_extract_all.o \ - data_extract_to_stdout.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:= \ - get_header_ar.o \ - unpack_ar_archive.o \ - get_header_tar.o \ - filter_accept_list_reassign.o - -INSERT - -lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o -lib-$(CONFIG_BUNZIP2) += decompress_bunzip2.o -lib-$(CONFIG_UNLZMA) += decompress_unlzma.o -lib-$(CONFIG_UNXZ) += decompress_unxz.o -lib-$(CONFIG_CPIO) += get_header_cpio.o -lib-$(CONFIG_DPKG) += $(DPKG_FILES) -lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES) -lib-$(CONFIG_GUNZIP) += decompress_unzip.o -lib-$(CONFIG_RPM2CPIO) += decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_RPM) += open_transformer.o decompress_unzip.o get_header_cpio.o -lib-$(CONFIG_TAR) += get_header_tar.o -lib-$(CONFIG_UNCOMPRESS) += decompress_uncompress.o -lib-$(CONFIG_UNZIP) += decompress_unzip.o -lib-$(CONFIG_FEATURE_SEAMLESS_Z) += open_transformer.o decompress_uncompress.o -lib-$(CONFIG_FEATURE_SEAMLESS_GZ) += open_transformer.o decompress_unzip.o get_header_tar_gz.o -lib-$(CONFIG_FEATURE_SEAMLESS_BZ2) += open_transformer.o decompress_bunzip2.o get_header_tar_bz2.o -lib-$(CONFIG_FEATURE_SEAMLESS_LZMA) += open_transformer.o decompress_unlzma.o get_header_tar_lzma.o -lib-$(CONFIG_FEATURE_SEAMLESS_XZ) += open_transformer.o decompress_unxz.o -lib-$(CONFIG_FEATURE_COMPRESS_USAGE) += decompress_bunzip2.o -lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o - -ifneq ($(lib-y),) -lib-y += $(COMMON_FILES) -endif diff --git a/archival/libunarchive/get_header_tar_gz.c b/archival/libunarchive/get_header_tar_gz.c deleted file mode 100644 index e88b720..0000000 --- a/archival/libunarchive/get_header_tar_gz.c +++ /dev/null @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" -#include "unarchive.h" - -char FAST_FUNC get_header_tar_gz(archive_handle_t *archive_handle) -{ -#if BB_MMU - unsigned char magic[2]; -#endif - - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - /* Check gzip magic only if open_transformer will invoke unpack_gz_stream (MMU case). - * Otherwise, it will invoke an external helper "gunzip -cf" (NOMMU case) which will - * need the header. */ -#if BB_MMU - xread(archive_handle->src_fd, &magic, 2); - /* Can skip this check, but error message will be less clear */ - if ((magic[0] != 0x1f) || (magic[1] != 0x8b)) { - bb_error_msg_and_die("invalid gzip magic"); - } -#endif - - open_transformer(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/archival/libunarchive/open_transformer.c b/archival/libunarchive/open_transformer.c deleted file mode 100644 index cba049f..0000000 --- a/archival/libunarchive/open_transformer.c +++ /dev/null @@ -1,54 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" -#include "unarchive.h" - -/* transformer(), more than meets the eye */ -/* - * On MMU machine, the transform_prog is removed by macro magic - * in include/unarchive.h. On NOMMU, transformer is removed. - */ -void FAST_FUNC open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd), - const char *transform_prog) -{ - 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 - transformer(fd, fd_pipe.wr); - if (ENABLE_FEATURE_CLEAN_UP) { - close(fd_pipe.wr); /* send EOF */ - close(fd); - } - /* must be _exit! bug was actually seen here */ - _exit(EXIT_SUCCESS); -#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); -} diff --git a/archival/lzop.c b/archival/lzop.c index ab4d34c..5062d93 100644 --- a/archival/lzop.c +++ b/archival/lzop.c @@ -14,7 +14,7 @@ This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License @@ -25,8 +25,53 @@ "Minimalized" for busybox by Alain Knaff */ +//config:config LZOP +//config: bool "lzop" +//config: default y +//config: help +//config: Lzop compression/decompresion. +//config: +//config:config LZOP_COMPR_HIGH +//config: bool "lzop compression levels 7,8,9 (not very useful)" +//config: default n +//config: depends on LZOP +//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:IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, lzopcat)) +//applet:IF_LZOP(APPLET_ODDNAME(unlzop, lzop, BB_DIR_USR_BIN, BB_SUID_DROP, unlzop)) +//kbuild:lib-$(CONFIG_LZOP) += lzop.o + +//usage:#define lzop_trivial_usage +//usage: "[-cfvd123456789CF] [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 -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: "[-vCF] [FILE]..." +//usage:#define lzopcat_full_usage "\n\n" +//usage: " -v Verbose" +//usage: "\n -F Don't store or verify checksum" +//usage: +//usage:#define unlzop_trivial_usage +//usage: "[-cfvCF] [FILE]..." +//usage:#define unlzop_full_usage "\n\n" +//usage: " -c Write to stdout" +//usage: "\n -f Force" +//usage: "\n -v Verbose" +//usage: "\n -F Don't store or verify checksum" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "liblzo_interface.h" /* lzo-2.03/src/lzo_ptr.h */ @@ -91,7 +136,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, 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); +// LZO_UNUSED(wrkmem); *out_len = 0; @@ -176,7 +221,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 2 literals that replace the match */ - copy2(ip-3+1,m_pos,pd(op,m_pos)); + copy2(ip-3+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) @@ -186,7 +231,8 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, *litp = (unsigned char)(lit - 3); o_m1_b++; - *op++ = *m_pos++; *op++ = *m_pos++; + *op++ = *m_pos++; + *op++ = *m_pos++; goto copy_literal_run; } copy_m1: @@ -215,7 +261,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, ) { t = *ip++; /* copy over the 3 literals that replace the match */ - copy3(ip-1-2,m_pos,pd(op,m_pos)); + 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); @@ -264,7 +310,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, 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)); + copy3(ip-3, m_pos, pd(op, m_pos)); o_m3_a++; } /* test if a literal run follows */ @@ -275,7 +321,7 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, /* remove short run */ *litp &= ~3; /* copy over the 3 literals that replace the match */ - copy3(ip-4+1,m_pos,pd(op,m_pos)); + copy3(ip-4+1, m_pos, pd(op, m_pos)); /* move literals 1 byte ahead */ litp += 2; if (lit > 0) @@ -320,11 +366,11 @@ static NOINLINE int lzo1x_optimize(uint8_t *in, unsigned in_len, 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); +// 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)); + (ip < ip_end ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN)); } /**********************************************************************/ @@ -393,7 +439,7 @@ typedef struct header_t { } header_t; struct globals { - const uint32_t *lzo_crc32_table; + /*const uint32_t *lzo_crc32_table;*/ chksum_t chksum_in; chksum_t chksum_out; } FIX_ALIASING; @@ -401,7 +447,7 @@ struct globals { #define INIT_G() do { } while (0) //#define G (*ptr_to_globals) //#define INIT_G() do { -// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); +// SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); //} while (0) @@ -410,25 +456,27 @@ struct globals { //#define LZOP_VERSION_STRING "1.01" //#define LZOP_VERSION_DATE "Apr 27th 2003" -#define OPTION_STRING "cfvdt123456789CF" +#define OPTION_STRING "cfvqdt123456789CF" +/* Note: must be kept in sync with archival/bbunzip.c */ enum { OPT_STDOUT = (1 << 0), OPT_FORCE = (1 << 1), OPT_VERBOSE = (1 << 2), - OPT_DECOMPRESS = (1 << 3), - OPT_TEST = (1 << 4), - OPT_1 = (1 << 5), - OPT_2 = (1 << 6), - OPT_3 = (1 << 7), - OPT_4 = (1 << 8), - OPT_5 = (1 << 9), - OPT_6 = (1 << 10), - OPT_789 = (7 << 11), - OPT_7 = (1 << 11), - OPT_8 = (1 << 12), - OPT_C = (1 << 14), - OPT_F = (1 << 15), + OPT_QUIET = (1 << 3), + OPT_DECOMPRESS = (1 << 4), + OPT_TEST = (1 << 5), + OPT_1 = (1 << 6), + OPT_2 = (1 << 7), + OPT_3 = (1 << 8), + OPT_4 = (1 << 9), + OPT_5 = (1 << 10), + OPT_6 = (1 << 11), + OPT_789 = (7 << 12), + OPT_7 = (1 << 13), + OPT_8 = (1 << 14), + OPT_C = (1 << 15), + OPT_F = (1 << 16), }; /**********************************************************************/ @@ -468,19 +516,10 @@ lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len) static FAST_FUNC uint32_t lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len) { - uint32_t crc; - - if (buf == NULL) - return 0; + //if (buf == NULL) - impossible + // return 0; - crc = ~c; - if (len != 0) do { - crc = G.lzo_crc32_table[(uint8_t)((int)crc ^ *buf)] ^ (crc >> 8); - buf += 1; - len -= 1; - } while (len > 0); - - return ~crc; + return ~crc32_block_endian0(~c, buf, len, global_crc32_table); } /**********************************************************************/ @@ -679,8 +718,7 @@ static NOINLINE smallint lzo_compress(const header_t *h) if (dst_len < src_len) { /* write checksum of compressed block */ if (h->flags & F_ADLER32_C) - write32(lzo_adler32(ADLER32_INIT_VALUE, b2, - dst_len)); + write32(lzo_adler32(ADLER32_INIT_VALUE, b2, dst_len)); if (h->flags & F_CRC32_C) write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len)); /* write compressed block data */ @@ -697,10 +735,16 @@ static NOINLINE smallint lzo_compress(const header_t *h) return ok; } -static void lzo_check(uint32_t FAST_FUNC (*fn)(uint32_t, const uint8_t*, unsigned), - uint32_t ref, uint32_t init, - uint8_t* buf, unsigned len) +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_error_msg_and_die("checksum error"); @@ -747,9 +791,8 @@ static NOINLINE smallint lzo_decompress(const header_t *h) if (dst_len > block_size) { if (b2) { -//FIXME! - b2 = NULL; free(b2); + b2 = NULL; } block_size = dst_len; mcs_block_size = MAX_COMPRESSED_SIZE(block_size); @@ -781,13 +824,13 @@ static NOINLINE smallint lzo_decompress(const header_t *h) if (!(option_mask32 & OPT_F)) { /* verify checksum of compressed block */ if (h->flags & F_ADLER32_C) - lzo_check(lzo_adler32, c_adler32, - ADLER32_INIT_VALUE, - b1, src_len); + lzo_check(ADLER32_INIT_VALUE, + b1, src_len, + lzo_adler32, c_adler32); if (h->flags & F_CRC32_C) - lzo_check(lzo_crc32, c_crc32, - CRC32_INIT_VALUE, - b1, src_len); + lzo_check(CRC32_INIT_VALUE, + b1, src_len, + lzo_crc32, c_crc32); } /* decompress */ @@ -808,11 +851,13 @@ static NOINLINE smallint lzo_decompress(const header_t *h) if (!(option_mask32 & OPT_F)) { /* verify checksum of uncompressed block */ if (h->flags & F_ADLER32_D) - lzo_check(lzo_adler32, d_adler32, ADLER32_INIT_VALUE, - dst, dst_len); + lzo_check(ADLER32_INIT_VALUE, + dst, dst_len, + lzo_adler32, d_adler32); if (h->flags & F_CRC32_D) - lzo_check(lzo_crc32, d_crc32, CRC32_INIT_VALUE, - dst, dst_len); + lzo_check(CRC32_INIT_VALUE, + dst, dst_len, + lzo_crc32, d_crc32); } /* write uncompressed block data */ @@ -1054,7 +1099,7 @@ static char* FAST_FUNC make_new_name_lzop(char *filename, const char *expected_e return xasprintf("%s.lzo", filename); } -static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(unpack_info_t *info UNUSED_PARAM) +static IF_DESKTOP(long long) int FAST_FUNC pack_lzop(transformer_aux_data_t *aux UNUSED_PARAM) { if (option_mask32 & OPT_DECOMPRESS) return do_lzo_decompress(); @@ -1070,9 +1115,9 @@ int lzop_main(int argc UNUSED_PARAM, char **argv) if (applet_name[4] == 'c') option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS); /* unlzop? */ - if (applet_name[0] == 'u') + if (applet_name[4] == 'o') option_mask32 |= OPT_DECOMPRESS; - G.lzo_crc32_table = crc32_filltable(NULL, 0); + global_crc32_table = crc32_filltable(NULL, 0); return bbunpack(argv, pack_lzop, make_new_name_lzop, /*unused:*/ NULL); } diff --git a/archival/rpm.c b/archival/rpm.c index 38ec20e..885eddd 100644 --- a/archival/rpm.c +++ b/archival/rpm.c @@ -4,11 +4,32 @@ * * Copyright (C) 2001,2002 by Laurence Anderson * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config RPM +//config: bool "rpm" +//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 + +//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" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "rpm.h" #define RPM_CHAR_TYPE 1 @@ -67,136 +88,13 @@ typedef struct { uint32_t count; /* 4 byte count */ } rpm_index; -static void *map; -static rpm_index **mytags; -static int tagcount; - -static void extract_cpio(int fd, const char *source_rpm); -static rpm_index **rpm_gettags(int fd, int *num_tags); -static int bsearch_rpmtag(const void *key, const void *item); -static char *rpm_getstr(int tag, int itemindex); -static int rpm_getint(int tag, int itemindex); -static int rpm_getcount(int tag); -static void fileaction_dobackup(char *filename, int fileref); -static void fileaction_setowngrp(char *filename, int fileref); -static void loop_through_files(int filetag, void (*fileaction)(char *filename, int fileref)); - -int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int rpm_main(int argc, char **argv) -{ - int opt = 0, func = 0, rpm_fd, offset; - const int pagesize = getpagesize(); - - 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 */ - 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 list) */ - func |= rpm_query_list; - func |= rpm_query_list_doc; - break; - case 'c': /* List config files in a package (implies list) */ - func |= rpm_query_list; - func |= rpm_query_list_config; - break; - default: - bb_show_usage(); - } - } - argv += optind; - //argc -= optind; - if (!argv[0]) { - bb_show_usage(); - } - - while (*argv) { - const char *source_rpm; - - rpm_fd = xopen(*argv++, O_RDONLY); - mytags = rpm_gettags(rpm_fd, &tagcount); - if (!mytags) - bb_error_msg_and_die("error reading rpm header"); - offset = xlseek(rpm_fd, 0, SEEK_CUR); - /* Mimimum is one page */ - map = mmap(0, offset > pagesize ? (offset + offset % pagesize) : pagesize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); - - source_rpm = rpm_getstr(TAG_SOURCERPM, 0); - - if (func & rpm_install) { - /* 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)) { - if (!(func & (rpm_query_info|rpm_query_list))) { - /* If just a straight query, just give package name */ - printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); - } - if (func & rpm_query_info) { - /* Do the nice printout */ - time_t bdate_time; - struct tm *bdate_ptm; - char bdatestring[50]; - const char *p; - - p = rpm_getstr(TAG_PREFIXS, 0); - if (!p) p = "(not relocateable)"; - printf("Name : %-29sRelocations: %s\n", rpm_getstr(TAG_NAME, 0), p); - p = rpm_getstr(TAG_VENDOR, 0); - if (!p) p = "(none)"; - printf("Version : %-34sVendor: %s\n", rpm_getstr(TAG_VERSION, 0), p); - bdate_time = rpm_getint(TAG_BUILDTIME, 0); - bdate_ptm = localtime(&bdate_time); - strftime(bdatestring, 50, "%a %d %b %Y %T %Z", bdate_ptm); - printf("Release : %-30sBuild Date: %s\n", rpm_getstr(TAG_RELEASE, 0), bdatestring); - printf("Install date: %-30sBuild Host: %s\n", "(not installed)", rpm_getstr(TAG_BUILDHOST, 0)); - printf("Group : %-30sSource RPM: %s\n", rpm_getstr(TAG_GROUP, 0), source_rpm); - printf("Size : %-33dLicense: %s\n", rpm_getint(TAG_SIZE, 0), rpm_getstr(TAG_LICENSE, 0)); - printf("URL : %s\n", rpm_getstr(TAG_URL, 0)); - printf("Summary : %s\n", rpm_getstr(TAG_SUMMARY, 0)); - printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); - } - 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)); - } - } - } - free(mytags); - } - return 0; -} +struct globals { + void *map; + rpm_index **mytags; + int tagcount; +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) static void extract_cpio(int fd, const char *source_rpm) { @@ -219,12 +117,12 @@ static void extract_cpio(int fd, const char *source_rpm) /* compat: overwrite existing files. * try "rpm -i foo.src.rpm" few times in a row - * standard rpm will not complain. - * (TODO? real rpm creates "file;1234" and then renames it) */ - | ARCHIVE_UNLINK_OLD; + */ + | 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_detected: 1*/); + setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_detected:*/ 1); while (get_header_cpio(archive_handle) == EXIT_SUCCESS) continue; } @@ -282,7 +180,7 @@ static int bsearch_rpmtag(const void *key, const void *item) static int rpm_getcount(int tag) { rpm_index **found; - found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found) return 0; return found[0]->count; @@ -291,7 +189,7 @@ static int rpm_getcount(int tag) static char *rpm_getstr(int tag, int itemindex) { rpm_index **found; - found = bsearch(&tag, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return NULL; if (found[0]->type == RPM_STRING_TYPE @@ -299,7 +197,7 @@ static char *rpm_getstr(int tag, int itemindex) || found[0]->type == RPM_STRING_ARRAY_TYPE ) { int n; - char *tmpstr = (char *) map + found[0]->offset; + char *tmpstr = (char *) G.map + found[0]->offset; for (n = 0; n < itemindex; n++) tmpstr = tmpstr + strlen(tmpstr) + 1; return tmpstr; @@ -310,32 +208,25 @@ static char *rpm_getstr(int tag, int itemindex) static int rpm_getint(int tag, int itemindex) { rpm_index **found; - int *tmpint; /* NB: using int8_t* would be easier to code */ + 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, mytags, tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); + found = bsearch(&tag, G.mytags, G.tagcount, sizeof(struct rpmtag *), bsearch_rpmtag); if (!found || itemindex >= found[0]->count) return -1; - tmpint = (int *) ((char *) map + found[0]->offset); - + tmpint = (char *) G.map + found[0]->offset; if (found[0]->type == RPM_INT32_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex*4); - /*return ntohl(*tmpint);*/ - /* int can be != int32_t */ + tmpint += itemindex*4; return ntohl(*(int32_t*)tmpint); } if (found[0]->type == RPM_INT16_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex*2); - /* ??? read int, and THEN ntohs() it?? */ - /*return ntohs(*tmpint);*/ + tmpint += itemindex*2; return ntohs(*(int16_t*)tmpint); } if (found[0]->type == RPM_INT8_TYPE) { - tmpint = (int *) ((char *) tmpint + itemindex); - /* ??? why we don't read byte here??? */ - /*return ntohs(*tmpint);*/ + tmpint += itemindex; return *(int8_t*)tmpint; } return -1; @@ -380,3 +271,134 @@ static void loop_through_files(int filetag, void (*fileaction)(char *filename, i free(filename); } } + +int rpm_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int rpm_main(int argc, char **argv) +{ + int opt, func = 0; + const unsigned pagesize = getpagesize(); + + 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 */ + 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 list) */ + func |= rpm_query_list; + func |= rpm_query_list_doc; + break; + case 'c': /* List config files in a package (implies list) */ + func |= rpm_query_list; + func |= rpm_query_list_config; + break; + default: + bb_show_usage(); + } + } + argv += optind; + //argc -= optind; + if (!argv[0]) { + bb_show_usage(); + } + + while (*argv) { + int rpm_fd; + unsigned mapsize; + const char *source_rpm; + + rpm_fd = xopen(*argv++, O_RDONLY); + G.mytags = rpm_gettags(rpm_fd, &G.tagcount); + if (!G.mytags) + bb_error_msg_and_die("error reading rpm header"); + mapsize = xlseek(rpm_fd, 0, SEEK_CUR); + mapsize = (mapsize + pagesize) & -(int)pagesize; + /* Some NOMMU systems prefer MAP_PRIVATE over MAP_SHARED */ + G.map = mmap(0, mapsize, PROT_READ, MAP_PRIVATE, rpm_fd, 0); +//FIXME: error check? + + source_rpm = rpm_getstr(TAG_SOURCERPM, 0); + + if (func & rpm_install) { + /* 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)) { + if (!(func & (rpm_query_info|rpm_query_list))) { + /* If just a straight query, just give package name */ + printf("%s-%s-%s\n", rpm_getstr(TAG_NAME, 0), rpm_getstr(TAG_VERSION, 0), rpm_getstr(TAG_RELEASE, 0)); + } + 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_getstr(TAG_NAME, 0)); + /* TODO compat: add "Epoch" here */ + printf("%-12s: %s\n", "Version" , rpm_getstr(TAG_VERSION, 0)); + printf("%-12s: %s\n", "Release" , rpm_getstr(TAG_RELEASE, 0)); + /* add "Architecture" */ + printf("%-12s: %s\n", "Install Date", "(not installed)"); + printf("%-12s: %s\n", "Group" , rpm_getstr(TAG_GROUP, 0)); + printf("%-12s: %d\n", "Size" , rpm_getint(TAG_SIZE, 0)); + printf("%-12s: %s\n", "License" , rpm_getstr(TAG_LICENSE, 0)); + /* 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_getstr(TAG_BUILDHOST, 0)); + p = rpm_getstr(TAG_PREFIXS, 0); + printf("%-12s: %s\n", "Relocations" , p ? p : "(not relocatable)"); + /* add "Packager" */ + p = rpm_getstr(TAG_VENDOR, 0); + printf("%-12s: %s\n", "Vendor" , p ? p : "(none)"); + printf("%-12s: %s\n", "URL" , rpm_getstr(TAG_URL, 0)); + printf("%-12s: %s\n", "Summary" , rpm_getstr(TAG_SUMMARY, 0)); + printf("Description :\n%s\n", rpm_getstr(TAG_DESCRIPTION, 0)); + } + 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)); + } + } + } + munmap(G.map, mapsize); + free(G.mytags); + close(rpm_fd); + } + return 0; +} diff --git a/archival/rpm.h b/archival/rpm.h index f7c6fc2..afe2b55 100644 --- a/archival/rpm.h +++ b/archival/rpm.h @@ -4,7 +4,7 @@ * * Copyright (C) 2001 by Laurence Anderson * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* RPM file starts with this struct: */ diff --git a/archival/rpm2cpio.c b/archival/rpm2cpio.c index 5bc50b8..61adde7 100644 --- a/archival/rpm2cpio.c +++ b/archival/rpm2cpio.c @@ -4,10 +4,25 @@ * * Copyright (C) 2001 by Laurence Anderson * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//config:config RPM2CPIO +//config: bool "rpm2cpio" +//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) += rpm2cpio.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" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" #include "rpm.h" enum { rpm_fd = STDIN_FILENO }; @@ -60,54 +75,22 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) /* Skip the main header */ skip_header(); -#if 0 + //if (SEAMLESS_COMPRESSION) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); + /* This works, but doesn't report uncompress errors (they happen in child) */ - setup_unzip_on_fd(rpm_fd /*fail_if_not_detected: 1*/); + setup_unzip_on_fd(rpm_fd, /*fail_if_not_detected:*/ 1); if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) bb_error_msg_and_die("error unpacking"); -#else - /* BLOAT */ - { - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - IF_DESKTOP(long long) int FAST_FUNC (*unpack)(int src_fd, int dst_fd); - - xread(rpm_fd, magic.b16, sizeof(magic.b16[0])); - if (magic.b16[0] == GZIP_MAGIC) { - unpack = unpack_gz_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { - unpack = unpack_bz2_stream; - } else - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - xread(rpm_fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] != XZ_MAGIC2) - goto no_magic; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(rpm_fd, -6, SEEK_CUR); - unpack = unpack_xz_stream; - } else { - no_magic: - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - } - if (unpack(rpm_fd, STDOUT_FILENO) < 0) - bb_error_msg_and_die("error unpacking"); - } -#endif if (ENABLE_FEATURE_CLEAN_UP) { close(rpm_fd); } - return 0; + if (SEAMLESS_COMPRESSION) { + check_errors_in_children(0); + return bb_got_signal; + } + return EXIT_SUCCESS; } diff --git a/archival/tar.c b/archival/tar.c index 5ddff7f..bd61abd 100644 --- a/archival/tar.c +++ b/archival/tar.c @@ -15,17 +15,138 @@ * Copyright (c) 1999 by David I. Bell * Permission is granted to use, distribute, or modify this source, * provided that this copyright notice remains intact. - * Permission to distribute sash derived code under the GPL has been granted. + * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* TODO: security with -C DESTDIR option can be enhanced. + * Consider tar file 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 which contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink + * symlink/evil.py + * + * Untarring it puts evil.py in '/tmp' even if the -C DESTDIR is given. + * This doesn't feel right, and IIRC GNU tar doesn't do that. */ +//config:config TAR +//config: bool "tar" +//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_CREATE +//config: bool "Enable archive creation" +//config: default y +//config: depends on TAR +//config: help +//config: If you enable this option you'll be able to create +//config: tar archives using the `-c' option. +//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 for 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 for GNU tar extensions (long filenames)" +//config: default y +//config: depends on TAR || DPKG +//config: help +//config: With this option busybox supports GNU long filenames and +//config: linknames. +//config: +//config:config FEATURE_TAR_LONG_OPTIONS +//config: bool "Enable long options" +//config: default y +//config: depends on TAR && LONG_OPTS +//config: help +//config: Enable use of long options, increases size by about 400 Bytes +//config: +//config:config FEATURE_TAR_TO_COMMAND +//config: bool "Support for writing to an external program" +//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: Enables 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) option" +//config: default y +//config: depends on TAR +//config: help +//config: With this option busybox supports GNU tar -m +//config: (do not preserve time) option. +//config: +//config:config FEATURE_TAR_SELINUX +//config: bool "Support for 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 "unarchive.h" +#include "bb_archive.h" /* FIXME: Stop using this non-standard feature */ #ifndef FNM_LEADING_DIR # define FNM_LEADING_DIR 0 @@ -41,8 +162,8 @@ #if !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_FEATURE_SEAMLESS_BZ2 /* Do not pass gzip flag to writeTarFile() */ -#define writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude, gzip) \ - writeTarFile(tar_fd, verboseFlag, dereferenceFlag, include, exclude) +#define writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude, gzip) \ + writeTarFile(tar_fd, verboseFlag, recurseFlags, include, exclude) #endif @@ -245,7 +366,8 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, 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 */ - PUT_OCTAL(header.mtime, statbuf->st_mtime); + /* 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)); @@ -297,15 +419,42 @@ static int writeTarHeader(struct TarBallInfo *tbInfo, } else if (S_ISFIFO(statbuf->st_mode)) { header.typeflag = FIFOTYPE; } else if (S_ISREG(statbuf->st_mode)) { - if (sizeof(statbuf->st_size) > 4 - && statbuf->st_size > (off_t)0777777777777LL + /* 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; - PUT_OCTAL(header.size, statbuf->st_size); } else { bb_error_msg("%s: unknown file type", fileName); return FALSE; @@ -378,17 +527,8 @@ static int FAST_FUNC writeFileToTarball(const char *fileName, struct stat *statb DBG("writeFileToTarball('%s')", fileName); - /* Strip leading '/' (must be before memorizing hardlink's name) */ - header_name = fileName; - while (header_name[0] == '/') { - static smallint warned; - - if (!warned) { - bb_error_msg("removing leading '/' from member names"); - warned = 1; - } - header_name++; - } + /* Strip leading '/' and such (must be before memorizing hardlink's name) */ + header_name = strip_unsafe_prefix(fileName); if (header_name[0] == '\0') return TRUE; @@ -529,7 +669,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) xmove_fd(gzipDataPipe.rd, 0); xmove_fd(tar_fd, 1); /* exec gzip/bzip2 program/applet */ - BB_EXECLP(zip_exec, zip_exec, "-f", NULL); + BB_EXECLP(zip_exec, zip_exec, "-f", (char *)0); vfork_exec_errno = errno; _exit(EXIT_FAILURE); } @@ -560,7 +700,7 @@ static void NOINLINE vfork_compressor(int tar_fd, int gzip) /* gcc 4.2.1 inlines it, making code bigger */ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, - int dereferenceFlag, const llist_t *include, + int recurseFlags, const llist_t *include, const llist_t *exclude, int gzip) { int errorFlag = FALSE; @@ -572,8 +712,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, /* Store the stat info for the tarball's file, so * can avoid including the tarball into itself.... */ - if (fstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf) < 0) - bb_perror_msg_and_die("can't stat tar file"); + xfstat(tbInfo.tarFd, &tbInfo.tarFileStatBuf, "can't stat tar file"); #if ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 if (gzip) @@ -584,8 +723,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, /* Read the directory/files and iterate over them one at a time */ while (include) { - if (!recursive_action(include->data, ACTION_RECURSE | - (dereferenceFlag ? ACTION_FOLLOWLINKS : 0), + if (!recursive_action(include->data, recurseFlags, writeFileToTarball, writeFileToTarball, &tbInfo, 0) ) { errorFlag = TRUE; @@ -625,7 +763,7 @@ static NOINLINE int writeTarFile(int tar_fd, int verboseFlag, } #else int writeTarFile(int tar_fd, int verboseFlag, - int dereferenceFlag, const llist_t *include, + int recurseFlags, const llist_t *include, const llist_t *exclude, int gzip); #endif /* FEATURE_TAR_CREATE */ @@ -637,76 +775,32 @@ static llist_t *append_file_list_to_list(llist_t *list) llist_t *newlist = NULL; while (list) { - src_stream = xfopen_for_read(llist_pop(&list)); + 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(&newlist, line); + llist_add_to_end(&newlist, line); } fclose(src_stream); } return newlist; } -#else -# define append_file_list_to_list(x) 0 -#endif - -#if ENABLE_FEATURE_SEAMLESS_Z -static char FAST_FUNC get_header_tar_Z(archive_handle_t *archive_handle) -{ - /* Can't lseek over pipes */ - archive_handle->seek = seek_by_read; - - /* do the decompression, and cleanup */ - if (xread_char(archive_handle->src_fd) != 0x1f - || xread_char(archive_handle->src_fd) != 0x9d - ) { - bb_error_msg_and_die("invalid magic"); - } - - open_transformer(archive_handle->src_fd, unpack_Z_stream, "uncompress"); - archive_handle->offset = 0; - while (get_header_tar(archive_handle) == EXIT_SUCCESS) - continue; - - /* Can only do one file at a time */ - return EXIT_FAILURE; -} -#else -# define get_header_tar_Z NULL -#endif - -#ifdef CHECK_FOR_CHILD_EXITCODE -/* Looks like it isn't needed - tar detects malformed (truncated) - * archive if e.g. bunzip2 fails */ -static int child_error; - -static void handle_SIGCHLD(int status) -{ - /* Actually, 'status' is a signo. We reuse it for other needs */ - - /* Wait for any child without blocking */ - if (wait_any_nohang(&status) < 0) - /* wait failed?! I'm confused... */ - return; - - if (WIFEXITED(status) && WEXITSTATUS(status) == 0) - /* child exited with 0 */ - return; - /* Cannot happen? - if (!WIFSIGNALED(status) && !WIFEXITED(status)) return; */ - child_error = 1; -} #endif //usage:#define tar_trivial_usage -//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" IF_FEATURE_SEAMLESS_GZ("z") -//usage: IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") -//usage: IF_FEATURE_SEAMLESS_Z("Z") IF_FEATURE_TAR_NOPRESERVE_TIME("m") "vO] " -//usage: IF_FEATURE_TAR_FROM("[-X FILE] ") -//usage: "[-f TARFILE] [-C DIR] [FILE]..." +//usage: "-[" IF_FEATURE_TAR_CREATE("c") "xt" +//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: IF_FEATURE_SEAMLESS_LZMA("a") +//usage: IF_FEATURE_TAR_CREATE("h") +//usage: IF_FEATURE_TAR_NOPRESERVE_TIME("m") +//usage: "vO] " +//usage: IF_FEATURE_TAR_FROM("[-X FILE] [-T FILE] ") +//usage: "[-f TARFILE] [-C DIR] [FILE]..." //usage:#define tar_full_usage "\n\n" //usage: IF_FEATURE_TAR_CREATE("Create, extract, ") //usage: IF_NOT_FEATURE_TAR_CREATE("Extract ") @@ -717,22 +811,24 @@ static void handle_SIGCHLD(int status) //usage: ) //usage: "\n x Extract" //usage: "\n t List" -//usage: "\nOptions:" //usage: "\n f Name of TARFILE ('-' for stdin/out)" //usage: "\n C Change to DIR before operation" //usage: "\n v Verbose" +//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: "\n a (De)compress using lzma" //usage: ) -//usage: IF_FEATURE_SEAMLESS_Z( -//usage: "\n Z (De)compress using compress" -//usage: ) //usage: "\n O Extract to stdout" //usage: IF_FEATURE_TAR_CREATE( //usage: "\n h Follow symlinks" @@ -756,6 +852,7 @@ static void handle_SIGCHLD(int status) // o no-same-owner // p same-permissions // k keep-old +// no-recursion // numeric-owner // no-same-permissions // overwrite @@ -772,9 +869,11 @@ enum { IF_FEATURE_TAR_FROM( OPTBIT_INCLUDE_FROM,) IF_FEATURE_TAR_FROM( OPTBIT_EXCLUDE_FROM,) IF_FEATURE_SEAMLESS_GZ( OPTBIT_GZIP ,) - IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) // 16th bit + IF_FEATURE_SEAMLESS_XZ( OPTBIT_XZ ,) // 16th bit + IF_FEATURE_SEAMLESS_Z( OPTBIT_COMPRESS ,) IF_FEATURE_TAR_NOPRESERVE_TIME(OPTBIT_NOPRESERVE_TIME,) #if ENABLE_FEATURE_TAR_LONG_OPTIONS + OPTBIT_NORECURSION, IF_FEATURE_TAR_TO_COMMAND(OPTBIT_2COMMAND ,) OPTBIT_NUMERIC_OWNER, OPTBIT_NOPRESERVE_PERM, @@ -796,12 +895,16 @@ enum { 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_NOPRESERVE_TIME = IF_FEATURE_TAR_NOPRESERVE_TIME((1 << OPTBIT_NOPRESERVE_TIME)) + 0, // m + 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 = @@ -834,12 +937,16 @@ static const char tar_longopts[] ALIGN1 = # 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 # if ENABLE_FEATURE_TAR_NOPRESERVE_TIME "touch\0" No_argument "m" # endif + "no-recursion\0" No_argument "\xfa" # if ENABLE_FEATURE_TAR_TO_COMMAND "to-command\0" Required_argument "\xfb" # endif @@ -860,7 +967,6 @@ static const char tar_longopts[] ALIGN1 = int tar_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int tar_main(int argc UNUSED_PARAM, char **argv) { - char FAST_FUNC (*get_header_ptr)(archive_handle_t *) = get_header_tar; archive_handle_t *tar_handle; char *base_dir = NULL; const char *tar_filename = "-"; @@ -883,8 +989,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) /* Prepend '-' to the first argument if required */ opt_complementary = "--:" // first arg is options "tt:vv:" // count -t,-v - "?:" // bail out with usage instead of error return - "X::T::" // cumulative lists + IF_FEATURE_TAR_FROM("X::T::") // cumulative lists #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM "\xff::" // cumulative lists for --exclude #endif @@ -928,6 +1033,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) IF_FEATURE_SEAMLESS_LZMA("a" ) IF_FEATURE_TAR_FROM( "T:X:") IF_FEATURE_SEAMLESS_GZ( "z" ) + IF_FEATURE_SEAMLESS_XZ( "J" ) IF_FEATURE_SEAMLESS_Z( "Z" ) IF_FEATURE_TAR_NOPRESERVE_TIME("m") , &base_dir // -C dir @@ -957,6 +1063,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) 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) @@ -976,18 +1083,6 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->ah_flags |= ARCHIVE_O_TRUNC; } - if (opt & OPT_GZIP) - get_header_ptr = get_header_tar_gz; - - if (opt & OPT_BZIP2) - get_header_ptr = get_header_tar_bz2; - - if (opt & OPT_LZMA) - get_header_ptr = get_header_tar_lzma; - - if (opt & OPT_COMPRESS) - get_header_ptr = get_header_tar_Z; - if (opt & OPT_NOPRESERVE_TIME) tar_handle->ah_flags &= ~ARCHIVE_RESTORE_DATE; @@ -1038,8 +1133,10 @@ int tar_main(int argc UNUSED_PARAM, char **argv) tar_handle->src_fd = tar_fd; tar_handle->seek = seek_by_read; } else { - if (ENABLE_FEATURE_TAR_AUTODETECT && flags == O_RDONLY) { - get_header_ptr = get_header_tar; + if (ENABLE_FEATURE_TAR_AUTODETECT + && flags == O_RDONLY + && !(opt & OPT_ANY_COMPRESS) + ) { tar_handle->src_fd = open_zipped(tar_filename); if (tar_handle->src_fd < 0) bb_perror_msg_and_die("can't open '%s'", tar_filename); @@ -1052,10 +1149,9 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (base_dir) xchdir(base_dir); -#ifdef CHECK_FOR_CHILD_EXITCODE - /* We need to know whether child (gzip/bzip/etc) exits abnormally */ - signal(SIGCHLD, handle_SIGCHLD); -#endif + //if (SEAMLESS_COMPRESSION || OPT_COMPRESS) + // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ + // signal(SIGCHLD, check_errors_in_children); /* Create an archive */ if (opt & OPT_CREATE) { @@ -1067,13 +1163,47 @@ int tar_main(int argc UNUSED_PARAM, char **argv) zipMode = 2; #endif /* NB: writeTarFile() closes tar_handle->src_fd */ - return writeTarFile(tar_handle->src_fd, verboseFlag, opt & OPT_DEREFERENCE, + return writeTarFile(tar_handle->src_fd, verboseFlag, + (opt & OPT_DEREFERENCE ? ACTION_FOLLOWLINKS : 0) + | (opt & OPT_NORECURSION ? 0 : ACTION_RECURSE), tar_handle->accept, tar_handle->reject, zipMode); } - while (get_header_ptr(tar_handle) == EXIT_SUCCESS) - continue; + if (opt & OPT_ANY_COMPRESS) { + USE_FOR_MMU(IF_DESKTOP(long long) int FAST_FUNC (*xformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd);) + USE_FOR_NOMMU(const char *xformer_prog;) + + if (opt & OPT_COMPRESS) + USE_FOR_MMU(xformer = unpack_Z_stream;) + USE_FOR_NOMMU(xformer_prog = "uncompress";) + if (opt & OPT_GZIP) + USE_FOR_MMU(xformer = unpack_gz_stream;) + USE_FOR_NOMMU(xformer_prog = "gunzip";) + if (opt & OPT_BZIP2) + USE_FOR_MMU(xformer = unpack_bz2_stream;) + USE_FOR_NOMMU(xformer_prog = "bunzip2";) + if (opt & OPT_LZMA) + USE_FOR_MMU(xformer = unpack_lzma_stream;) + USE_FOR_NOMMU(xformer_prog = "unlzma";) + if (opt & OPT_XZ) + USE_FOR_MMU(xformer = unpack_xz_stream;) + USE_FOR_NOMMU(xformer_prog = "unxz";) + + open_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 */ /* Check that every file that should have been extracted was */ while (tar_handle->accept) { @@ -1088,5 +1218,10 @@ int tar_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP /* && tar_handle->src_fd != STDIN_FILENO */) close(tar_handle->src_fd); - return EXIT_SUCCESS; + 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/archival/unzip.c b/archival/unzip.c index 84081c0..fcfc9a4 100644 --- a/archival/unzip.c +++ b/archival/unzip.c @@ -7,20 +7,43 @@ * Loosely based on original busybox unzip applet by Laurence Anderson. * All options and features should work in this version. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * 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 + * + * TODO * Zip64 + other methods */ +//config:config UNZIP +//config: bool "unzip" +//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. Use the `-d' option to extract to a +//config: directory of your choice. + +//applet:IF_UNZIP(APPLET(unzip, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_UNZIP) += unzip.o + +//usage:#define unzip_trivial_usage +//usage: "[-lnopq] 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 -p Print to stdout" +//usage: "\n -q Quiet" +//usage: "\n -x FILE Exclude FILEs" +//usage: "\n -d DIR Extract into DIR" + #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" enum { #if BB_BIG_ENDIAN @@ -151,7 +174,17 @@ enum { zip_fd = 3 }; #if ENABLE_DESKTOP -#define PEEK_FROM_END 16384 +/* 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) + +/* This value means that we failed to find CDF */ +#define BAD_CDF_OFFSET ((uint32_t)0xffffffff) /* NB: does not preserve file position! */ static uint32_t find_cdf_offset(void) @@ -168,6 +201,7 @@ static uint32_t find_cdf_offset(void) xlseek(zip_fd, end, SEEK_SET); full_read(zip_fd, buf, PEEK_FROM_END); + cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; p = buf; while (p <= buf + PEEK_FROM_END - CDE_HEADER_LEN - 4) { if (*p != 'P') { @@ -183,11 +217,17 @@ static uint32_t find_cdf_offset(void) /* we found CDE! */ memcpy(cde_header.raw, p + 1, CDE_HEADER_LEN); FIX_ENDIANNESS_CDE(cde_header); - free(buf); - return cde_header.formatted.cdf_offset; + /* + * I've seen .ZIP files with seemingly valid CDEs + * where cdf_offset points past EOF - ?? + * Ignore such CDEs: + */ + if (cde_header.formatted.cdf_offset < end + (p - buf)) + break; + cde_header.formatted.cdf_offset = BAD_CDF_OFFSET; } - //free(buf); - bb_error_msg_and_die("can't find file table"); + free(buf); + return cde_header.formatted.cdf_offset; }; static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) @@ -199,13 +239,15 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) if (!cdf_offset) cdf_offset = find_cdf_offset(); - xlseek(zip_fd, cdf_offset + 4, SEEK_SET); - xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); - FIX_ENDIANNESS_CDF(*cdf_ptr); - cdf_offset += 4 + CDF_HEADER_LEN - + cdf_ptr->formatted.file_name_length - + cdf_ptr->formatted.extra_field_length - + cdf_ptr->formatted.file_comment_length; + if (cdf_offset != BAD_CDF_OFFSET) { + xlseek(zip_fd, cdf_offset + 4, SEEK_SET); + xread(zip_fd, cdf_ptr->raw, CDF_HEADER_LEN); + FIX_ENDIANNESS_CDF(*cdf_ptr); + cdf_offset += 4 + CDF_HEADER_LEN + + cdf_ptr->formatted.file_name_length + + cdf_ptr->formatted.extra_field_length + + cdf_ptr->formatted.file_comment_length; + } xlseek(zip_fd, org, SEEK_SET); return cdf_offset; @@ -214,8 +256,9 @@ static uint32_t read_next_cdf(uint32_t cdf_offset, cdf_header_t *cdf_ptr) static void unzip_skip(off_t skip) { - if (lseek(zip_fd, skip, SEEK_CUR) == (off_t)-1) - bb_copyfd_exact_size(zip_fd, -1, 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) @@ -223,7 +266,7 @@ static void unzip_create_leading_dirs(const char *fn) /* Create all leading directories */ char *name = xstrdup(fn); if (bb_make_directory(dirname(name), 0777, FILEUTILS_RECUR)) { - bb_error_msg_and_die("exiting"); /* bb_make_directory is noisy */ + xfunc_die(); /* bb_make_directory is noisy */ } free(name); } @@ -237,15 +280,17 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd) bb_copyfd_exact_size(zip_fd, dst_fd, size); } else { /* Method 8 - inflate */ - inflate_unzip_result res; - if (inflate_unzip(&res, zip_header->formatted.cmpsize, zip_fd, dst_fd) < 0) + transformer_aux_data_t aux; + init_transformer_aux_data(&aux); + aux.bytes_in = zip_header->formatted.cmpsize; + if (inflate_unzip(&aux, zip_fd, dst_fd) < 0) bb_error_msg_and_die("inflate error"); /* Validate decompression - crc */ - if (zip_header->formatted.crc32 != (res.crc ^ 0xffffffffL)) { + if (zip_header->formatted.crc32 != (aux.crc32 ^ 0xffffffffL)) { bb_error_msg_and_die("crc error"); } /* Validate decompression - size */ - if (zip_header->formatted.ucmpsize != res.bytes_out) { + if (zip_header->formatted.ucmpsize != aux.bytes_out) { /* Don't die. Who knows, maybe len calculation * was botched somewhere. After all, crc matched! */ bb_error_msg("bad length"); @@ -253,6 +298,14 @@ static void unzip_extract(zip_header_t *zip_header, int dst_fd) } } +static void my_fgets80(char *buf80) +{ + fflush_all(); + if (!fgets(buf80, 80, stdin)) { + bb_perror_msg_and_die("can't read standard input"); + } +} + int unzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int unzip_main(int argc, char **argv) { @@ -263,6 +316,7 @@ int unzip_main(int argc, char **argv) IF_NOT_DESKTOP(const) smallint verbose = 0; smallint listing = 0; smallint overwrite = O_PROMPT; + smallint x_opt_seen; #if ENABLE_DESKTOP uint32_t cdf_offset; #endif @@ -276,8 +330,7 @@ int unzip_main(int argc, char **argv) llist_t *zreject = NULL; char *base_dir = NULL; int i, opt; - int opt_range = 0; - char key_buf[80]; + char key_buf[80]; /* must match size used by my_fgets80 */ struct stat stat_buf; /* -q, -l and -v: UnZip 5.52 of 28 February 2005, by Info-ZIP: @@ -321,82 +374,81 @@ int unzip_main(int argc, char **argv) * 204372 1 file */ + x_opt_seen = 0; /* '-' makes getopt return 1 for non-options */ while ((opt = getopt(argc, argv, "-d:lnopqxv")) != -1) { - switch (opt_range) { - case 0: /* Options */ - switch (opt) { - case 'l': /* List */ - listing = 1; - break; - - case 'n': /* Never overwrite existing files */ - overwrite = O_NEVER; - break; + switch (opt) { + case 'd': /* Extract to base directory */ + base_dir = optarg; + break; - case 'o': /* Always overwrite existing files */ - overwrite = O_ALWAYS; - break; + case 'l': /* List */ + listing = 1; + break; - case 'p': /* Extract files to stdout and fall through to set verbosity */ - dst_fd = STDOUT_FILENO; + case 'n': /* Never overwrite existing files */ + overwrite = O_NEVER; + break; - case 'q': /* Be quiet */ - quiet++; - break; + case 'o': /* Always overwrite existing files */ + overwrite = O_ALWAYS; + break; - case 'v': /* Verbose list */ - IF_DESKTOP(verbose++;) - listing = 1; - break; + case 'p': /* Extract files to stdout and fall through to set verbosity */ + dst_fd = STDOUT_FILENO; - case 1: /* The zip file */ - /* +5: space for ".zip" and NUL */ - src_fn = xmalloc(strlen(optarg) + 5); - strcpy(src_fn, optarg); - opt_range++; - break; + case 'q': /* Be quiet */ + quiet++; + break; - default: - bb_show_usage(); + case 'v': /* Verbose list */ + IF_DESKTOP(verbose++;) + listing = 1; + break; - } + case 'x': + x_opt_seen = 1; break; - case 1: /* Include files */ - if (opt == 1) { + 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 (!x_opt_seen) { + /* Include files */ llist_add_to(&zaccept, optarg); - break; - } - if (opt == 'd') { - base_dir = optarg; - opt_range += 2; - break; - } - if (opt == 'x') { - opt_range++; - break; - } - bb_show_usage(); - - case 2 : /* Exclude files */ - if (opt == 1) { + } else { + /* Exclude files */ llist_add_to(&zreject, optarg); - break; - } - if (opt == 'd') { /* Extract to base directory */ - base_dir = optarg; - opt_range++; - break; } - /* fall through */ + break; default: bb_show_usage(); } } - if (src_fn == NULL) { +#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(); } @@ -407,17 +459,20 @@ int unzip_main(int argc, char **argv) if (overwrite == O_PROMPT) overwrite = O_NEVER; } else { - static const char extn[][5] = {"", ".zip", ".ZIP"}; - int orig_src_fn_len = strlen(src_fn); - int src_fd = -1; + static const char extn[][5] = { ".zip", ".ZIP" }; + char *ext = src_fn + strlen(src_fn); + int src_fd; - for (i = 0; (i < 3) && (src_fd == -1); i++) { - strcpy(src_fn + orig_src_fn_len, extn[i]); + i = 0; + for (;;) { src_fd = open(src_fn, O_RDONLY); - } - if (src_fd == -1) { - src_fn[orig_src_fn_len] = '\0'; - bb_error_msg_and_die("can't open %s, %s.zip, %s.ZIP", src_fn, src_fn, src_fn); + 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); } @@ -504,21 +559,31 @@ int unzip_main(int argc, char **argv) bb_error_msg_and_die("zip flag 1 (encryption) is not supported"); } - { + if (cdf_offset != BAD_CDF_OFFSET) { cdf_header_t cdf_header; cdf_offset = read_next_cdf(cdf_offset, &cdf_header); + /* + * Note: cdf_offset can become BAD_CDF_OFFSET after the above call. + */ if (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) { /* 0x0008 - streaming. [u]cmpsize can be reliably gotten - * only from Central Directory. See unzip_doc.txt */ + * only from Central Directory. See unzip_doc.txt + */ zip_header.formatted.crc32 = cdf_header.formatted.crc32; zip_header.formatted.cmpsize = cdf_header.formatted.cmpsize; zip_header.formatted.ucmpsize = cdf_header.formatted.ucmpsize; } if ((cdf_header.formatted.version_made_by >> 8) == 3) { - /* this archive is created on Unix */ + /* This archive is created on Unix */ dir_mode = file_mode = (cdf_header.formatted.external_file_attributes >> 16); } } + if (cdf_offset == BAD_CDF_OFFSET + && (zip_header.formatted.zip_flags & SWAP_LE16(0x0008)) + ) { + /* If it's a streaming zip, we _require_ CDF */ + bb_error_msg_and_die("can't find file table"); + } #endif /* Read filename */ @@ -583,8 +648,8 @@ int unzip_main(int argc, char **argv) printf(" creating: %s\n", dst_fn); } unzip_create_leading_dirs(dst_fn); - if (bb_make_directory(dst_fn, dir_mode, 0)) { - bb_error_msg_and_die("exiting"); + if (bb_make_directory(dst_fn, dir_mode, FILEUTILS_IGNORE_CHMOD_ERR)) { + xfunc_die(); } } else { if (!S_ISDIR(stat_buf.st_mode)) { @@ -608,9 +673,7 @@ int unzip_main(int argc, char **argv) i = 'y'; } else { printf("replace %s? [y]es, [n]o, [A]ll, [N]one, [r]ename: ", dst_fn); - if (!fgets(key_buf, sizeof(key_buf), stdin)) { - bb_perror_msg_and_die("can't read input"); - } + my_fgets80(key_buf); i = key_buf[0]; } } else { /* File is not regular file */ @@ -651,9 +714,7 @@ int unzip_main(int argc, char **argv) case 'r': /* Prompt for new name */ printf("new name: "); - if (!fgets(key_buf, sizeof(key_buf), stdin)) { - bb_perror_msg_and_die("can't read input"); - } + my_fgets80(key_buf); free(dst_fn); dst_fn = xstrdup(key_buf); chomp(dst_fn); diff --git a/TEST_config_nommu b/configs/TEST_nommu_defconfig similarity index 99% rename from TEST_config_nommu rename to configs/TEST_nommu_defconfig index 911f02f..b45afd9 100644 --- a/TEST_config_nommu +++ b/configs/TEST_nommu_defconfig @@ -79,7 +79,7 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y CONFIG_FEATURE_ETC_NETWORKS=y CONFIG_FEATURE_EDITING=y @@ -189,7 +189,6 @@ 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 @@ -342,7 +341,6 @@ CONFIG_FEATURE_VI_READONLY=y CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y -CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -904,7 +902,6 @@ CONFIG_HUSH_FUNCTIONS=y CONFIG_HUSH_LOCAL=y CONFIG_HUSH_EXPORT_N=y CONFIG_HUSH_RANDOM_SUPPORT=y -CONFIG_LASH=y CONFIG_MSH=y CONFIG_SH_MATH_SUPPORT=y CONFIG_SH_MATH_SUPPORT_64=y diff --git a/TEST_config_noprintf b/configs/TEST_noprintf_defconfig similarity index 99% rename from TEST_config_noprintf rename to configs/TEST_noprintf_defconfig index ba003a1..809b60c 100644 --- a/TEST_config_noprintf +++ b/configs/TEST_noprintf_defconfig @@ -89,7 +89,7 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_EDITING=y @@ -211,7 +211,6 @@ CONFIG_FALSE=y # CONFIG_ID is not set # CONFIG_INSTALL is not set # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set # CONFIG_LN is not set # CONFIG_LOGNAME is not set # CONFIG_LS is not set @@ -347,7 +346,6 @@ CONFIG_FEATURE_VI_MAX_LEN=0 # 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_VI_OPTIMIZE_CURSOR is not set # CONFIG_FEATURE_ALLOW_EXEC is not set # @@ -904,7 +902,6 @@ 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_LASH is not set # CONFIG_MSH is not set # CONFIG_SH_MATH_SUPPORT is not set # CONFIG_SH_MATH_SUPPORT_64 is not set diff --git a/TEST_config_rh9 b/configs/TEST_rh9_defconfig similarity index 99% rename from TEST_config_rh9 rename to configs/TEST_rh9_defconfig index f376cd4..565b826 100644 --- a/TEST_config_rh9 +++ b/configs/TEST_rh9_defconfig @@ -88,7 +88,7 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=2 +CONFIG_MD5_SMALL=1 CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set CONFIG_FEATURE_EDITING=y @@ -200,7 +200,6 @@ 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 @@ -359,7 +358,6 @@ CONFIG_FEATURE_VI_READONLY=y CONFIG_FEATURE_VI_SETOPTS=y CONFIG_FEATURE_VI_SET=y CONFIG_FEATURE_VI_WIN_RESIZE=y -CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -803,6 +801,7 @@ 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 # @@ -917,7 +916,6 @@ CONFIG_HUSH_FUNCTIONS=y CONFIG_HUSH_LOCAL=y CONFIG_HUSH_EXPORT_N=y CONFIG_HUSH_RANDOM_SUPPORT=y -# CONFIG_LASH is not set CONFIG_MSH=y CONFIG_SH_MATH_SUPPORT=y CONFIG_SH_MATH_SUPPORT_64=y diff --git a/debian/config/pkg/udeb b/configs/android2_defconfig similarity index 57% rename from debian/config/pkg/udeb rename to configs/android2_defconfig index 4940749..4dfbdb5 100644 --- a/debian/config/pkg/udeb +++ b/configs/android2_defconfig @@ -1,7 +1,7 @@ +# Run "make android2_defconfig", then "make". # -# Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Tue Nov 9 10:36:38 2010 +# 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 @@ -16,31 +16,33 @@ CONFIG_HAVE_DOT_CONFIG=y # CONFIG_EXTRA_COMPAT is not set # CONFIG_INCLUDE_SUSv2 is not set # CONFIG_USE_PORTABLE_CODE is not set +CONFIG_PLATFORM_LINUX=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_SHOW_USAGE is not set # CONFIG_FEATURE_VERBOSE_USAGE is not set -CONFIG_FEATURE_COMPRESS_USAGE=y +# 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=y +# CONFIG_UNICODE_SUPPORT is not set # CONFIG_UNICODE_USING_LOCALE is not set -CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y -CONFIG_SUBST_WCHAR=63 -CONFIG_LAST_SUPPORTED_WCHAR=767 -CONFIG_UNICODE_COMBINING_WCHARS=y -CONFIG_UNICODE_WIDE_WCHARS=y +# 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=y -CONFIG_FEATURE_DEVPTS=y +# 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=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 @@ -58,8 +60,8 @@ CONFIG_FEATURE_SYSLOG=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_LFS is not set +CONFIG_CROSS_COMPILER_PREFIX="arm-linux-androideabi-" CONFIG_EXTRA_CFLAGS="" # @@ -73,9 +75,8 @@ CONFIG_NO_DEBUG_LIB=y # CONFIG_EFENCE is not set # -# Installation Options +# Installation Options ("make install" behavior) # -# 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 @@ -88,25 +89,29 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=1 +CONFIG_MD5_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_USE_TERMIOS=y +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=15 +CONFIG_FEATURE_EDITING_HISTORY=0 # CONFIG_FEATURE_EDITING_SAVEHISTORY is not set -CONFIG_FEATURE_TAB_COMPLETION=y +# CONFIG_FEATURE_TAB_COMPLETION is not set # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y -CONFIG_FEATURE_EDITING_ASK_TERMINAL=y +# 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_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 -CONFIG_MONOTONIC_SYSCALL=y -CONFIG_IOCTL_HEX2STR_ERROR=y -CONFIG_FEATURE_HWIB=y +# 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 @@ -115,48 +120,48 @@ CONFIG_FEATURE_HWIB=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set +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_FEATURE_SEAMLESS_Z=y CONFIG_AR=y -# 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_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_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y -# CONFIG_GZIP is not set +CONFIG_GZIP=y # 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_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 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_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 is not set +CONFIG_FEATURE_TAR_UNAME_GNAME=y CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # 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 +CONFIG_UNCOMPRESS=y +CONFIG_UNLZMA=y +CONFIG_FEATURE_LZMA_FAST=y +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y +CONFIG_UNZIP=y # # Coreutils @@ -167,58 +172,60 @@ CONFIG_CAT=y # 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 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_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=y +# CONFIG_FEATURE_CHOWN_LONG_OPTIONS is not set CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +CONFIG_CKSUM=y +CONFIG_COMM=y CONFIG_CP=y -CONFIG_FEATURE_CP_LONG_OPTIONS=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 is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y +# CONFIG_DF is not set # CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y -# 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_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_ENV is not set # CONFIG_FEATURE_ENV_LONG_OPTIONS is not set -# CONFIG_EXPAND is not set +CONFIG_EXPAND=y # CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set -CONFIG_EXPR=y -CONFIG_EXPR_MATH_SUPPORT_64=y +# CONFIG_EXPR is not set +# CONFIG_EXPR_MATH_SUPPORT_64 is not set CONFIG_FALSE=y -# CONFIG_FOLD is not set +CONFIG_FOLD=y # CONFIG_FSYNC is not set CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y # CONFIG_HOSTID is not set -CONFIG_ID=y -# CONFIG_INSTALL is not set +CONFIG_INSTALL=y # CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set CONFIG_LN=y # CONFIG_LOGNAME is not set CONFIG_LS=y -# CONFIG_FEATURE_LS_FILETYPES is not set +CONFIG_FEATURE_LS_FILETYPES=y CONFIG_FEATURE_LS_FOLLOWLINKS=y -# CONFIG_FEATURE_LS_RECURSIVE is not set +CONFIG_FEATURE_LS_RECURSIVE=y CONFIG_FEATURE_LS_SORTFILES=y CONFIG_FEATURE_LS_TIMESTAMPS=y CONFIG_FEATURE_LS_USERNAME=y @@ -227,14 +234,14 @@ CONFIG_FEATURE_LS_USERNAME=y CONFIG_MD5SUM=y CONFIG_MKDIR=y # CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set -# CONFIG_MKFIFO is not set +CONFIG_MKFIFO=y CONFIG_MKNOD=y CONFIG_MV=y # 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_NICE=y +CONFIG_NOHUP=y +CONFIG_OD=y +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y CONFIG_READLINK=y @@ -243,42 +250,41 @@ CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y # CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set -# CONFIG_SEQ is not set -# CONFIG_SHA1SUM is not set +CONFIG_SEQ=y +CONFIG_SHA1SUM=y CONFIG_SHA256SUM=y -# CONFIG_SHA512SUM is not set +CONFIG_SHA512SUM=y CONFIG_SLEEP=y -# CONFIG_FEATURE_FANCY_SLEEP is not set -# CONFIG_FEATURE_FLOAT_SLEEP is not set +CONFIG_FEATURE_FANCY_SLEEP=y +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y CONFIG_FEATURE_SORT_BIG=y -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +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 is not set +CONFIG_STTY=y +CONFIG_SUM=y CONFIG_SYNC=y -# CONFIG_TAC is not set +CONFIG_TAC=y CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y -# CONFIG_TEE is not set -# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set -CONFIG_TOUCH=y +CONFIG_TEE=y +CONFIG_FEATURE_TEE_USE_BLOCK_IO=y CONFIG_TRUE=y -CONFIG_TTY=y +# CONFIG_TTY is not set CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set +CONFIG_UNEXPAND=y # CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set CONFIG_UNIQ=y # CONFIG_USLEEP is not set -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set +CONFIG_UUDECODE=y +CONFIG_UUENCODE=y CONFIG_WC=y -# CONFIG_FEATURE_WC_LARGE is not set +CONFIG_FEATURE_WC_LARGE=y # CONFIG_WHO is not set -# CONFIG_WHOAMI is not set -# CONFIG_YES is not set +CONFIG_WHOAMI=y +CONFIG_YES=y # # Common options for cp and mv @@ -303,60 +309,53 @@ CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # 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_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 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_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 is not set -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set +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 is not set -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set +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 is not set -# CONFIG_START_STOP_DAEMON is not set -# CONFIG_FEATURE_START_STOP_DAEMON_FANCY 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 is not set +CONFIG_WHICH=y # # 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=y +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 @@ -364,44 +363,51 @@ CONFIG_FEATURE_VI_MAX_LEN=0 # 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_VI_OPTIMIZE_CURSOR 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=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_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=y +# 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=y -CONFIG_GREP=y -CONFIG_FEATURE_GREP_EGREP_ALIAS=y +# 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 +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 @@ -409,6 +415,9 @@ CONFIG_FEATURE_GREP_EGREP_ALIAS=y # 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 @@ -416,33 +425,33 @@ CONFIG_FEATURE_KILL_DELAY=0 CONFIG_FEATURE_INIT_SCTTY=y CONFIG_FEATURE_INIT_SYSLOG=y CONFIG_FEATURE_EXTRA_QUIET=y -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=y CONFIG_INIT_TERMINAL_TYPE="linux" -CONFIG_HALT=y -# CONFIG_FEATURE_CALL_TELINIT is not set -CONFIG_TELINIT_PATH="" -# CONFIG_MESG is not set +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=y +# CONFIG_USE_BB_PWD_GRP is not set # CONFIG_USE_BB_SHADOW is not set -CONFIG_USE_BB_CRYPT=y +# 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_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 @@ -462,18 +471,18 @@ CONFIG_LAST_SYSTEM_ID=0 # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set -# CONFIG_TUNE2FS is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y # # Linux Module Utilities # CONFIG_MODINFO=y -# 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_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 @@ -495,34 +504,36 @@ CONFIG_MODINFO=y # 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="" +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" # # Linux System Utilities # CONFIG_BLOCKDEV=y -# CONFIG_REV is not set +CONFIG_REV=y # CONFIG_ACPID is not set # CONFIG_FEATURE_ACPID_COMPAT is not set -# CONFIG_BLKID is not set +CONFIG_BLKID=y +# CONFIG_FEATURE_BLKID_TYPE is not set CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y -# 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_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 is not set +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 is not set -# CONFIG_FINDFS is not set -# CONFIG_FLOCK 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 @@ -530,19 +541,19 @@ CONFIG_FREERAMDISK=y # 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_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 is not set -# CONFIG_LSPCI is not set -# CONFIG_LSUSB 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 @@ -552,97 +563,104 @@ CONFIG_FREERAMDISK=y CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_MOUNT=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=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# 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_RDEV=y +CONFIG_READPROFILE=y +CONFIG_RTCWAKE=y +CONFIG_SCRIPT=y +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set # CONFIG_SWITCH_ROOT is not set -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_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 +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_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_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 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_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 is not set -# CONFIG_FEATURE_DC_LIBM 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 is not set +CONFIG_DEVMEM=y # 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_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 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 @@ -655,90 +673,98 @@ CONFIG_FEATURE_LESS_MAXLINES=0 # 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_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 is not set -# CONFIG_MAN 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 is not set +CONFIG_RAIDAUTORUN=y # 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_RX=y +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 is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME 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_FEATURE_IPV6=y +# 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 is not set -CONFIG_ARPING=y +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 is not set +CONFIG_DNSD=y # 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_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=y -# 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_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 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_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 is not set -# CONFIG_FEATURE_IFCONFIG_HW is not set -# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS 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 is not set -CONFIG_IFUPDOWN_IFSTATE_PATH="" -# CONFIG_FEATURE_IFUPDOWN_IP is not set -# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN 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 is not set +CONFIG_FEATURE_IFUPDOWN_IPV4=y # CONFIG_FEATURE_IFUPDOWN_IPV6 is not set -# CONFIG_FEATURE_IFUPDOWN_MAPPING 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 @@ -751,47 +777,38 @@ CONFIG_IP=y CONFIG_FEATURE_IP_ADDRESS=y CONFIG_FEATURE_IP_LINK=y CONFIG_FEATURE_IP_ROUTE=y -# 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_TUNNEL=y +CONFIG_FEATURE_IP_RULE=y +CONFIG_FEATURE_IP_SHORT_FORMS=y # 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_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_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_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_PING is not set -# CONFIG_PING6 is not set -# CONFIG_FEATURE_FANCY_PING is not set -# CONFIG_PSCAN is not set +CONFIG_PSCAN=y CONFIG_ROUTE=y # CONFIG_SLATTACH is not set -# CONFIG_TCPSVD 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=y +# CONFIG_TFTP is not set # CONFIG_TFTPD is not set - -# -# Common options for tftp/tftpd -# -CONFIG_FEATURE_TFTP_GET=y -CONFIG_FEATURE_TFTP_PUT=y +# 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 @@ -800,94 +817,103 @@ CONFIG_FEATURE_TFTP_PUT=y # CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set # CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set # CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG 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_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +# 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=0 +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="" +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 is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +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 +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_SMEMCAP is not set -CONFIG_FREE=y -# CONFIG_FUSER is not set -CONFIG_KILL=y +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_NMETER is not set # CONFIG_PGREP is not set CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set +CONFIG_FEATURE_PIDOF_SINGLE=y +CONFIG_FEATURE_PIDOF_OMIT=y # CONFIG_PKILL is not set -CONFIG_PS=y +# 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_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 is not set +CONFIG_WATCH=y # # Runit Utilities # -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set +CONFIG_RUNSV=y +CONFIG_RUNSVDIR=y # 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_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 @@ -907,23 +933,27 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # # Shells # -CONFIG_ASH=y +# CONFIG_ASH is not set # CONFIG_ASH_BASH_COMPAT is not set -CONFIG_ASH_JOB_CONTROL=y +# CONFIG_ASH_IDLE_TIMEOUT is not set +# CONFIG_ASH_JOB_CONTROL is not set # CONFIG_ASH_ALIAS is not set -CONFIG_ASH_GETOPTS=y -CONFIG_ASH_BUILTIN_ECHO=y -CONFIG_ASH_BUILTIN_PRINTF=y -CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_GETOPTS is not set +# CONFIG_ASH_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF is not set +# CONFIG_ASH_BUILTIN_TEST is not set +# CONFIG_ASH_CMDCMD is not set # CONFIG_ASH_MAIL is not set -CONFIG_ASH_OPTIMIZE_FOR_SIZE=y +# 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 @@ -931,35 +961,36 @@ CONFIG_ASH_OPTIMIZE_FOR_SIZE=y # 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=y +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH is not set +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE 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_LASH is not set -# CONFIG_MSH is not set -CONFIG_SH_MATH_SUPPORT=y -CONFIG_SH_MATH_SUPPORT_64=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 +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # System Logging Utilities # -CONFIG_SYSLOGD=y +# 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=256 +# 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=y +# CONFIG_LOGGER is not set diff --git a/configs/android_defconfig b/configs/android_defconfig new file mode 100644 index 0000000..e35830e --- /dev/null +++ b/configs/android_defconfig @@ -0,0 +1,1028 @@ +# +# 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_PLATFORM_LINUX=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 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 +# CONFIG_FEATURE_HAVE_RPC is not set + +# +# 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_SYSTEMD is not set +# 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_USE_TERMIOS=y +# 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_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set +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 ls, more and telnet +# +CONFIG_FEATURE_AUTOWIDTH=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_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=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_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="/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_SOURCE_ROUTE is not set +# 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_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF is not set +# CONFIG_ASH_BUILTIN_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_MSH 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/packaging/busybox-dahlia.config b/configs/android_ndk_defconfig similarity index 60% rename from packaging/busybox-dahlia.config rename to configs/android_ndk_defconfig index 3b3be76..01cc2dd 100644 --- a/packaging/busybox-dahlia.config +++ b/configs/android_ndk_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Fri Apr 15 11:03:42 2011 +# Busybox version: 1.21.0.git +# Mon May 28 21:51:18 2012 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,9 +12,9 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set -CONFIG_EXTRA_COMPAT=y -CONFIG_INCLUDE_SUSv2=y +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set +# CONFIG_INCLUDE_SUSv2 is not set # CONFIG_USE_PORTABLE_CODE is not set CONFIG_PLATFORM_LINUX=y CONFIG_FEATURE_BUFFERS_USE_MALLOC=y @@ -23,32 +23,33 @@ CONFIG_FEATURE_BUFFERS_USE_MALLOC=y CONFIG_SHOW_USAGE=y CONFIG_FEATURE_VERBOSE_USAGE=y CONFIG_FEATURE_COMPRESS_USAGE=y -# CONFIG_FEATURE_INSTALLER is not set +CONFIG_FEATURE_INSTALLER=y +CONFIG_INSTALL_NO_USR=y # CONFIG_LOCALE_SUPPORT is not set -CONFIG_UNICODE_SUPPORT=y +# CONFIG_UNICODE_SUPPORT is not set # CONFIG_UNICODE_USING_LOCALE is not set -CONFIG_FEATURE_CHECK_UNICODE_IN_ENV=y -CONFIG_SUBST_WCHAR=63 -CONFIG_LAST_SUPPORTED_WCHAR=767 +# 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=y -CONFIG_FEATURE_DEVPTS=y +# CONFIG_FEATURE_DEVPTS is not set # 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_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 -CONFIG_FEATURE_HAVE_RPC=y +# CONFIG_FEATURE_HAVE_RPC is not set # # Build Options @@ -59,9 +60,12 @@ CONFIG_FEATURE_HAVE_RPC=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="" +# 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" +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 @@ -74,9 +78,8 @@ CONFIG_NO_DEBUG_LIB=y # CONFIG_EFENCE is not set # -# Installation Options +# Installation Options ("make install" behavior) # -# 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 @@ -89,25 +92,31 @@ CONFIG_PREFIX="./_install" # # Busybox Library Tuning # +# CONFIG_FEATURE_SYSTEMD is not set +# CONFIG_FEATURE_RTMINMAX is not set CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=0 -CONFIG_FEATURE_FAST_TOP=y +CONFIG_MD5_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_USE_TERMIOS=y +# CONFIG_FEATURE_EDITING is not set +CONFIG_FEATURE_EDITING_MAX_LEN=0 # CONFIG_FEATURE_EDITING_VI is not set -CONFIG_FEATURE_EDITING_HISTORY=15 -CONFIG_FEATURE_EDITING_SAVEHISTORY=y -CONFIG_FEATURE_TAB_COMPLETION=y +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=y -CONFIG_FEATURE_EDITING_ASK_TERMINAL=y +# 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_MONOTONIC_SYSCALL=y -CONFIG_IOCTL_HEX2STR_ERROR=y -CONFIG_FEATURE_HWIB=y +# 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 @@ -129,12 +138,13 @@ 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_DPKG=y +CONFIG_DPKG_DEB=y # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y -CONFIG_FEATURE_GZIP_LONG_OPTIONS=y +# CONFIG_FEATURE_GZIP_LONG_OPTIONS is not set +CONFIG_GZIP_FAST=0 CONFIG_LZOP=y CONFIG_LZOP_COMPR_HIGH=y CONFIG_RPM2CPIO=y @@ -146,8 +156,8 @@ 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_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 @@ -155,8 +165,8 @@ CONFIG_UNCOMPRESS=y CONFIG_UNLZMA=y CONFIG_FEATURE_LZMA_FAST=y CONFIG_LZMA=y -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set +CONFIG_UNXZ=y +CONFIG_XZ=y CONFIG_UNZIP=y # @@ -164,33 +174,41 @@ CONFIG_UNZIP=y # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y -CONFIG_FEATURE_DATE_NANO=y -CONFIG_FEATURE_DATE_COMPAT=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=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=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=y -CONFIG_FEATURE_DF_FANCY=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y CONFIG_DOS2UNIX=y CONFIG_UNIX2DOS=y @@ -199,9 +217,9 @@ 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_FEATURE_ENV_LONG_OPTIONS is not set CONFIG_EXPAND=y -CONFIG_FEATURE_EXPAND_LONG_OPTIONS=y +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set CONFIG_EXPR=y CONFIG_EXPR_MATH_SUPPORT_64=y CONFIG_FALSE=y @@ -209,13 +227,10 @@ 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_FEATURE_INSTALL_LONG_OPTIONS is not set CONFIG_LN=y -CONFIG_LOGNAME=y +# CONFIG_LOGNAME is not set CONFIG_LS=y CONFIG_FEATURE_LS_FILETYPES=y CONFIG_FEATURE_LS_FOLLOWLINKS=y @@ -227,11 +242,11 @@ 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=y +# CONFIG_FEATURE_MKDIR_LONG_OPTIONS is not set CONFIG_MKFIFO=y CONFIG_MKNOD=y CONFIG_MV=y -CONFIG_FEATURE_MV_LONG_OPTIONS=y +# CONFIG_FEATURE_MV_LONG_OPTIONS is not set CONFIG_NICE=y CONFIG_NOHUP=y CONFIG_OD=y @@ -243,7 +258,7 @@ CONFIG_FEATURE_READLINK_FOLLOW=y CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y -CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y +# CONFIG_FEATURE_RMDIR_LONG_OPTIONS is not set CONFIG_SEQ=y CONFIG_SHA1SUM=y CONFIG_SHA256SUM=y @@ -255,8 +270,8 @@ 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_STAT is not set +# CONFIG_FEATURE_STAT_FORMAT is not set CONFIG_STTY=y CONFIG_SUM=y CONFIG_SYNC=y @@ -265,19 +280,17 @@ 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_TTY is not set CONFIG_UNAME=y CONFIG_UNEXPAND=y -CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=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_WHO=y CONFIG_WHOAMI=y CONFIG_YES=y @@ -306,63 +319,51 @@ CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # CONFIG_CHVT=y CONFIG_FGCONSOLE=y -# CONFIG_CLEAR is not set +CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y -CONFIG_KBD_MODE=y -CONFIG_LOADFONT=y +# CONFIG_KBD_MODE is not set +# CONFIG_LOADFONT is not set CONFIG_LOADKMAP=y CONFIG_OPENVT=y -# CONFIG_RESET is not set +CONFIG_RESET=y CONFIG_RESIZE=y CONFIG_FEATURE_RESIZE_PRINT=y CONFIG_SETCONSOLE=y -CONFIG_FEATURE_SETCONSOLE_LONG_OPTIONS=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 - -# -# Common options for loadfont and setfont -# -CONFIG_FEATURE_LOADFONT_PSF2=y -CONFIG_FEATURE_LOADFONT_RAW=y +# CONFIG_FEATURE_LOADFONT_PSF2 is not set +# CONFIG_FEATURE_LOADFONT_RAW is not set # # Debian Utilities # -# CONFIG_MKTEMP is not set CONFIG_MKTEMP=y -# CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set +CONFIG_PIPE_PROGRESS=y +CONFIG_RUN_PARTS=y # 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_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 is not set +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_REGEX_SEARCH is not set CONFIG_FEATURE_VI_USE_SIGNALS=y CONFIG_FEATURE_VI_DOT_CMD=y CONFIG_FEATURE_VI_READONLY=y @@ -370,7 +371,14 @@ 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_OPTIMIZE_CURSOR=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 # @@ -412,81 +420,86 @@ 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_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_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_HALT is not set +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_MESG is not set +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_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=y +CONFIG_INIT_TERMINAL_TYPE="linux" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # -CONFIG_FEATURE_SHADOWPASSWDS=y +# 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_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_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=64900 -CONFIG_DELUSER=y -CONFIG_GETTY=y +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=y -CONFIG_FEATURE_PASSWD_WEAK_CHECK=y +# CONFIG_PASSWD is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set # CONFIG_CRYPTPW is not set -CONFIG_CHPASSWD=y +# 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=y +# CONFIG_VLOCK is not set # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set +CONFIG_CHATTR=y # CONFIG_FSCK is not set -# CONFIG_LSATTR is not set -# CONFIG_TUNE2FS is not set +CONFIG_LSATTR=y +CONFIG_TUNE2FS=y # # Linux Module Utilities # CONFIG_MODINFO=y -# 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=y -CONFIG_RMMOD=y -CONFIG_LSMOD=y -CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y -CONFIG_MODPROBE=y -CONFIG_FEATURE_MODPROBE_BLACKLIST=y -CONFIG_DEPMOD=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 @@ -498,20 +511,27 @@ CONFIG_DEPMOD=y # 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=y -CONFIG_FEATURE_MODUTILS_ALIAS=y -CONFIG_FEATURE_MODUTILS_SYMBOLS=y -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +# 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="/system/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 @@ -526,67 +546,57 @@ CONFIG_FEATURE_FDISK_WRITABLE=y # 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 is not set +CONFIG_FINDFS=y CONFIG_FLOCK=y CONFIG_FREERAMDISK=y -CONFIG_FSCK_MINIX=y +# CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set -CONFIG_MKFS_MINIX=y -CONFIG_FEATURE_MINIX2=y +# CONFIG_MKFS_MINIX is not set +# CONFIG_FEATURE_MINIX2 is not set # CONFIG_MKFS_REISER is not set -CONFIG_MKFS_VFAT=y +# 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=y -CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y -CONFIG_IPCRM=y -CONFIG_IPCS=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 is not set -# CONFIG_LSUSB is not set -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_LSPCI=y +CONFIG_LSUSB=y CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=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_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=y -CONFIG_SWAPONOFF=y -CONFIG_FEATURE_SWAPON_PRI=y +# CONFIG_SETARCH is not set +# CONFIG_SWAPONOFF 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_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 @@ -615,13 +625,31 @@ CONFIG_FEATURE_VOLUMEID_LINUXRAID=y # Miscellaneous Utilities # # CONFIG_CONSPY is not set -CONFIG_UBIATTACH=y -CONFIG_UBIDETACH=y -CONFIG_ADJTIMEX=y -# CONFIG_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 +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=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 @@ -643,28 +671,19 @@ CONFIG_FEATURE_DC_LIBM=y # 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=y -CONFIG_FEATURE_EJECT_SCSI=y +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=y -CONFIG_IONICE=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=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 @@ -676,70 +695,78 @@ 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_MICROCOM is not set +# CONFIG_MOUNTPOINT is not set +# CONFIG_MT is not set CONFIG_RAIDAUTORUN=y -CONFIG_READAHEAD=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=y -CONFIG_FEATURE_TASKSET_FANCY=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=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=y -CONFIG_FEATURE_IPV6=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=y -CONFIG_BRCTL=y -CONFIG_FEATURE_BRCTL_FANCY=y -CONFIG_FEATURE_BRCTL_SHOW=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=y +# CONFIG_ETHER_WAKE is not set CONFIG_FAKEIDENTD=y -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set +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_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=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=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=y +# CONFIG_IFENSLAVE is not set # CONFIG_IFPLUGD is not set CONFIG_IFUPDOWN=y CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" @@ -747,16 +774,16 @@ 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_IPV6 is not set 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_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 @@ -764,7 +791,7 @@ 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_FEATURE_IP_RARE_PROTOCOLS is not set CONFIG_IPADDR=y CONFIG_IPLINK=y CONFIG_IPROUTE=y @@ -772,21 +799,16 @@ 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_FEATURE_IPCALC_LONG_OPTIONS is not set CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y CONFIG_FEATURE_NETSTAT_PRG=y -CONFIG_NSLOOKUP=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -CONFIG_PING6=y -CONFIG_FEATURE_FANCY_PING=y CONFIG_PSCAN=y CONFIG_ROUTE=y -CONFIG_SLATTACH=y +# CONFIG_SLATTACH is not set CONFIG_TCPSVD=y CONFIG_TELNET=y CONFIG_FEATURE_TELNET_TTYPE=y @@ -804,73 +826,86 @@ 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_TFTP_DEBUG is not set CONFIG_TRACEROUTE=y # CONFIG_TRACEROUTE6 is not set CONFIG_FEATURE_TRACEROUTE_VERBOSE=y -CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y -CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG is not set -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_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set +# 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=0 +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_FEATURE_UDHCPC_FAST_REQUEST=y 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_ZCIP=y +# CONFIG_FEATURE_WGET_LONG_OPTIONS is not set +CONFIG_FEATURE_WGET_TIMEOUT=y +# CONFIG_ZCIP is not set # # Print Utilities # -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set +CONFIG_LPD=y +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set +CONFIG_MAKEMIME=y CONFIG_FEATURE_MIME_CHARSET="us-ascii" -# 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_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y CONFIG_SENDMAIL=y # # Process Utilities # -# CONFIG_SMEMCAP is not set +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_UPTIME=y +# CONFIG_FEATURE_UPTIME_UTMP_SUPPORT is not set CONFIG_FREE=y CONFIG_FUSER=y -CONFIG_KILL=y -CONFIG_KILLALL=y +# CONFIG_KILL is not set +# CONFIG_KILLALL is not set # CONFIG_KILLALL5 is not set -CONFIG_NMETER=y -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_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=y -# CONFIG_FEATURE_PS_TIME is not set -# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +# 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 @@ -882,7 +917,6 @@ 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 # @@ -890,7 +924,7 @@ CONFIG_WATCH=y # CONFIG_RUNSV=y CONFIG_RUNSVDIR=y -CONFIG_FEATURE_RUNSVDIR_LOG=y +# CONFIG_FEATURE_RUNSVDIR_LOG is not set CONFIG_SV=y CONFIG_SV_DEFAULT_SERVICE_DIR="/var/service" CONFIG_SVLOGD=y @@ -918,23 +952,27 @@ CONFIG_SOFTLIMIT=y # # Shells # -CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y -CONFIG_ASH_JOB_CONTROL=y -CONFIG_ASH_ALIAS=y -CONFIG_ASH_GETOPTS=y -CONFIG_ASH_BUILTIN_ECHO=y -CONFIG_ASH_BUILTIN_PRINTF=y -CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y +# 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_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF is not set +# CONFIG_ASH_BUILTIN_TEST is not set +# CONFIG_ASH_CMDCMD is not set # CONFIG_ASH_MAIL is not set -CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -CONFIG_ASH_RANDOM_SUPPORT=y -CONFIG_ASH_EXPAND_PRMT=y +# 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 @@ -942,35 +980,36 @@ CONFIG_ASH_EXPAND_PRMT=y # 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=y +# CONFIG_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH is not set +# CONFIG_FEATURE_SH_IS_ASH is not set # CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_NONE 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_LASH is not set -# CONFIG_MSH is not set -CONFIG_SH_MATH_SUPPORT=y -CONFIG_SH_MATH_SUPPORT_64=y -CONFIG_FEATURE_SH_EXTRA_QUIET=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 +# CONFIG_FEATURE_SH_HISTFILESIZE is not set # # 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_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=y +# CONFIG_LOGGER is not set diff --git a/configs/cygwin_defconfig b/configs/cygwin_defconfig new file mode 100644 index 0000000..aa346e3 --- /dev/null +++ b/configs/cygwin_defconfig @@ -0,0 +1,996 @@ +# +# Automatically generated make config: don't edit +# Busybox version: 1.19.0.git +# Sun Jul 10 12:48:50 2011 +# +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_PLATFORM_LINUX=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 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_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_FEATURE_SUID=y +# 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 +# CONFIG_FEATURE_HAVE_RPC is not set + +# +# 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_FEATURE_SYSTEMD is not set +CONFIG_FEATURE_RTMINMAX=y +CONFIG_PASSWORD_MINLEN=6 +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y +# CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_USE_TERMIOS=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_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 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 is not set +# CONFIG_AR is not set +# CONFIG_FEATURE_AR_LONG_FILENAMES is not set +# CONFIG_FEATURE_AR_CREATE is not set +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_FEATURE_DPKG_DEB_EXTRACT_ONLY 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=y +CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y +# CONFIG_FEATURE_TAR_SELINUX is not set +# CONFIG_UNCOMPRESS is not set +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=y +CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_FEATURE_DATE_NANO is not set +CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_ID=y +CONFIG_GROUPS=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_BASE64=y +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=y +CONFIG_FEATURE_DF_FANCY=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_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_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 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=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 ls, more and telnet +# +CONFIG_FEATURE_AUTOWIDTH=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=y +CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y +CONFIG_FEATURE_START_STOP_DAEMON_LONG_OPTIONS=y +CONFIG_WHICH=y + +# +# Editors +# +CONFIG_PATCH=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_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_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_EXTRA_QUIET is not set +# CONFIG_FEATURE_INIT_COREDUMPS is not set +# CONFIG_FEATURE_INITRD is not set +CONFIG_INIT_TERMINAL_TYPE="" +CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y + +# +# Login/Password Management Utilities +# +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y +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_ADDUSER=y +CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +# 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=y +CONFIG_DELGROUP=y +CONFIG_FEATURE_DEL_USER_FROM_GROUP=y +# CONFIG_GETTY is not set +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 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_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_FEATURE_BLKID_TYPE 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 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_FREERAMDISK is not set +CONFIG_FSCK_MINIX=y +# CONFIG_MKFS_EXT2 is not set +# CONFIG_MKFS_MINIX is not set +CONFIG_FEATURE_MINIX2=y +# 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=y +# 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=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 is not set +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 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_SETSERIAL 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_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=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 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=y +CONFIG_FEATURE_LESS_DASHCMD=y +CONFIG_FEATURE_LESS_LINENUMS=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_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_MOUNTPOINT is not set +CONFIG_MT=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_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 is not set +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=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 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=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 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=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_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_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_PSCAN=y +# CONFIG_ROUTE is not set +# 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 is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set +# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 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_FEATURE_UDHCPD_BASE_IP_ON_MAC 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_FEATURE_UDHCP_8021Q is not set +CONFIG_UDHCPC_DEFAULT_SCRIPT="" +CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=0 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="" +CONFIG_UDPSVD=y +# 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=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 is not set +# CONFIG_POWERTOP is not set +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +# CONFIG_FREE is not set +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=y +# CONFIG_FEATURE_PS_TIME is not set +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 is not set +# 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=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_BUILTIN_ECHO=y +CONFIG_ASH_BUILTIN_PRINTF=y +CONFIG_ASH_BUILTIN_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_CTTYHACK is not set +CONFIG_HUSH=y +CONFIG_HUSH_BASH_COMPAT=y +CONFIG_HUSH_BRACE_EXPANSION=y +CONFIG_HUSH_HELP=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_EXPORT_N=y +CONFIG_HUSH_MODE_X=y +# CONFIG_MSH 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_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_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/debian/config/pkg/deb b/configs/freebsd_defconfig similarity index 69% rename from debian/config/pkg/deb rename to configs/freebsd_defconfig index fbd418b..ec3ed03 100644 --- a/debian/config/pkg/deb +++ b/configs/freebsd_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Tue Nov 9 10:34:49 2010 +# Busybox version: 1.18.1 +# Tue Dec 21 19:47:40 2010 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,10 +12,11 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -CONFIG_DESKTOP=y -CONFIG_EXTRA_COMPAT=y +# CONFIG_DESKTOP is not set +# CONFIG_EXTRA_COMPAT is not set CONFIG_INCLUDE_SUSv2=y -# CONFIG_USE_PORTABLE_CODE is not set +CONFIG_USE_PORTABLE_CODE=y +# CONFIG_PLATFORM_LINUX 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 @@ -23,29 +24,30 @@ 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_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=y +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=63 CONFIG_LAST_SUPPORTED_WCHAR=767 -CONFIG_UNICODE_COMBINING_WCHARS=y -CONFIG_UNICODE_WIDE_WCHARS=y +# 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_UTMP=y -CONFIG_FEATURE_WTMP=y +# 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=y -CONFIG_BUSYBOX_EXEC_PATH="/bin/busybox" +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" CONFIG_FEATURE_SYSLOG=y # CONFIG_FEATURE_HAVE_RPC is not set @@ -73,13 +75,12 @@ CONFIG_NO_DEBUG_LIB=y # CONFIG_EFENCE is not set # -# Installation Options +# Installation Options ("make install" behavior) # -# CONFIG_INSTALL_NO_USR is not set -# CONFIG_INSTALL_APPLET_SYMLINKS 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=y +# 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 @@ -89,22 +90,23 @@ CONFIG_PREFIX="./_install" # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=1 -# CONFIG_FEATURE_FAST_TOP is not set +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_USE_TERMIOS=y 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_HISTORY=30 # 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_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=y +# CONFIG_FEATURE_VERBOSE_CP_MESSAGE is not set CONFIG_FEATURE_COPYBUF_KB=4 -CONFIG_MONOTONIC_SYSCALL=y +# CONFIG_MONOTONIC_SYSCALL is not set CONFIG_IOCTL_HEX2STR_ERROR=y CONFIG_FEATURE_HWIB=y @@ -115,18 +117,18 @@ CONFIG_FEATURE_HWIB=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set +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_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_O is not set # CONFIG_FEATURE_CPIO_P is not set # CONFIG_DPKG is not set # CONFIG_DPKG_DEB is not set @@ -134,20 +136,20 @@ CONFIG_FEATURE_CPIO_O=y CONFIG_GUNZIP=y CONFIG_GZIP=y CONFIG_FEATURE_GZIP_LONG_OPTIONS=y -# CONFIG_LZOP is not set +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 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_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_UNAME_GNAME is not set CONFIG_FEATURE_TAR_NOPRESERVE_TIME=y # CONFIG_FEATURE_TAR_SELINUX is not set CONFIG_UNCOMPRESS=y @@ -163,33 +165,34 @@ CONFIG_UNZIP=y # CONFIG_BASENAME=y CONFIG_CAT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y +# CONFIG_DATE is not set +# CONFIG_FEATURE_DATE_ISOFMT is not set # CONFIG_FEATURE_DATE_NANO is not set -CONFIG_FEATURE_DATE_COMPAT=y +# CONFIG_FEATURE_DATE_COMPAT is not set CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +# CONFIG_BASE64 is not set CONFIG_CAL=y -# CONFIG_CATV is not set +CONFIG_CATV=y CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +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 is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y CONFIG_FEATURE_DD_IBS_OBS=y -CONFIG_DF=y -CONFIG_FEATURE_DF_FANCY=y +# CONFIG_DF is not set +# CONFIG_FEATURE_DF_FANCY is not set CONFIG_DIRNAME=y CONFIG_DOS2UNIX=y CONFIG_UNIX2DOS=y @@ -199,19 +202,19 @@ CONFIG_ECHO=y CONFIG_FEATURE_FANCY_ECHO=y CONFIG_ENV=y CONFIG_FEATURE_ENV_LONG_OPTIONS=y -# CONFIG_EXPAND is not set -# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set +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 is not set +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y CONFIG_HOSTID=y CONFIG_ID=y -# CONFIG_INSTALL is not set -# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y CONFIG_LENGTH=y CONFIG_LN=y CONFIG_LOGNAME=y @@ -223,18 +226,18 @@ 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_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_MKNOD is not set CONFIG_MV=y CONFIG_FEATURE_MV_LONG_OPTIONS=y -# CONFIG_NICE is not set -# CONFIG_NOHUP is not set +CONFIG_NICE=y +CONFIG_NOHUP=y CONFIG_OD=y -# CONFIG_PRINTENV is not set +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y CONFIG_READLINK=y @@ -242,24 +245,24 @@ CONFIG_FEATURE_READLINK_FOLLOW=y CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y -CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y -# CONFIG_SEQ is not set +# 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 is not set +CONFIG_FEATURE_FLOAT_SLEEP=y CONFIG_SORT=y CONFIG_FEATURE_SORT_BIG=y -# CONFIG_SPLIT is not set -# CONFIG_FEATURE_SPLIT_FANCY is not set +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 is not set +# CONFIG_STTY is not set +CONFIG_SUM=y CONFIG_SYNC=y -CONFIG_TAC=y +# CONFIG_TAC is not set CONFIG_TAIL=y CONFIG_FEATURE_FANCY_TAIL=y CONFIG_TEE=y @@ -268,15 +271,15 @@ CONFIG_TOUCH=y CONFIG_TRUE=y CONFIG_TTY=y CONFIG_UNAME=y -# CONFIG_UNEXPAND is not set -# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set +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 is not set -CONFIG_WHO=y +CONFIG_FEATURE_WC_LARGE=y +# CONFIG_WHO is not set CONFIG_WHOAMI=y CONFIG_YES=y @@ -298,35 +301,31 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # -CONFIG_CHVT=y +# CONFIG_CHVT is not set # CONFIG_FGCONSOLE is not set CONFIG_CLEAR=y -CONFIG_DEALLOCVT=y -CONFIG_DUMPKMAP=y +# CONFIG_DEALLOCVT is not set +# CONFIG_DUMPKMAP is not set # CONFIG_KBD_MODE is not set -CONFIG_LOADFONT=y -CONFIG_LOADKMAP=y -CONFIG_OPENVT=y +# CONFIG_LOADFONT is not set +# CONFIG_LOADKMAP is not set +# CONFIG_OPENVT is not set CONFIG_RESET=y -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set +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=y +# CONFIG_SETKEYCODES is not set # CONFIG_SETLOGCONS is not set # CONFIG_SHOWKEY is not set - -# -# Common options for loadfont and setfont -# # CONFIG_FEATURE_LOADFONT_PSF2 is not set # CONFIG_FEATURE_LOADFONT_RAW is not set @@ -334,26 +333,26 @@ CONFIG_SETKEYCODES=y # Debian Utilities # CONFIG_MKTEMP=y -# CONFIG_PIPE_PROGRESS is not set +CONFIG_PIPE_PROGRESS=y CONFIG_RUN_PARTS=y CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -CONFIG_START_STOP_DAEMON=y -CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y -CONFIG_FEATURE_START_STOP_DAEMON_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 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=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 @@ -368,7 +367,6 @@ 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_OPTIMIZE_CURSOR=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -392,7 +390,7 @@ CONFIG_FEATURE_FIND_DEPTH=y CONFIG_FEATURE_FIND_PAREN=y CONFIG_FEATURE_FIND_SIZE=y CONFIG_FEATURE_FIND_PRUNE=y -# CONFIG_FEATURE_FIND_DELETE is not set +CONFIG_FEATURE_FIND_DELETE=y CONFIG_FEATURE_FIND_PATH=y CONFIG_FEATURE_FIND_REGEX=y # CONFIG_FEATURE_FIND_CONTEXT is not set @@ -402,10 +400,10 @@ 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 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 +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 @@ -413,6 +411,9 @@ CONFIG_XARGS=y # 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 @@ -422,30 +423,30 @@ CONFIG_FEATURE_KILL_DELAY=0 # CONFIG_FEATURE_EXTRA_QUIET is not set # CONFIG_FEATURE_INIT_COREDUMPS is not set # CONFIG_FEATURE_INITRD is not set -# CONFIG_HALT is not set -# CONFIG_FEATURE_CALL_TELINIT is not set -CONFIG_TELINIT_PATH="" +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 is not set +CONFIG_USE_BB_PWD_GRP=y # CONFIG_USE_BB_SHADOW is not set -CONFIG_USE_BB_CRYPT=y -CONFIG_USE_BB_CRYPT_SHA=y -# 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_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_FIRST_SYSTEM_ID=0 -CONFIG_LAST_SYSTEM_ID=0 +# 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 @@ -465,14 +466,10 @@ CONFIG_LAST_SYSTEM_ID=0 # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set +CONFIG_CHATTR=y # 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 @@ -484,10 +481,6 @@ CONFIG_LAST_SYSTEM_ID=0 # 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 @@ -504,13 +497,13 @@ CONFIG_DEFAULT_DEPMOD_FILE="" # # Linux System Utilities # -CONFIG_BLOCKDEV=y +# 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=y -CONFIG_FEATURE_DMESG_PRETTY=y +# 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 @@ -523,9 +516,10 @@ CONFIG_FDISK_SUPPORT_LARGE_DISKS=y # 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 is not set +CONFIG_FLOCK=y # CONFIG_FREERAMDISK is not set # CONFIG_FSCK_MINIX is not set # CONFIG_MKFS_EXT2 is not set @@ -537,15 +531,15 @@ CONFIG_GETOPT=y CONFIG_FEATURE_GETOPT_LONG=y CONFIG_HEXDUMP=y # CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD 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=y -# CONFIG_LSPCI is not set -# CONFIG_LSUSB 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 @@ -555,67 +549,61 @@ CONFIG_LOSETUP=y # CONFIG_MKSWAP is not set # CONFIG_FEATURE_MKSWAP_UUID is not set CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# 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=y -CONFIG_FEATURE_MOUNT_FSTAB=y +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set # CONFIG_PIVOT_ROOT is not set -CONFIG_RDATE=y +# CONFIG_RDATE is not set # CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set +CONFIG_READPROFILE=y # CONFIG_RTCWAKE is not set # CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y +# CONFIG_SWAPONOFF is not set # CONFIG_FEATURE_SWAPON_PRI is not set # CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y -CONFIG_FEATURE_UMOUNT_ALL=y - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=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 +# 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=y +# 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 @@ -627,12 +615,12 @@ CONFIG_FEATURE_BEEP_LENGTH_MS=0 # 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_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_FEATURE_CROND_DIR="/var/spool/cron" +CONFIG_CRONTAB=y CONFIG_DC=y CONFIG_FEATURE_DC_LIBM=y # CONFIG_DEVFSD is not set @@ -648,17 +636,17 @@ CONFIG_FEATURE_DC_LIBM=y # CONFIG_FLASH_LOCK is not set # CONFIG_FLASH_UNLOCK is not set # CONFIG_FLASH_ERASEALL is not set -CONFIG_IONICE=y +# CONFIG_IONICE is not set # CONFIG_INOTIFYD is not set -CONFIG_LAST=y -CONFIG_FEATURE_LAST_SMALL=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_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 @@ -673,69 +661,71 @@ CONFIG_FEATURE_LESS_MAXLINES=0 # 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_MICROCOM=y # CONFIG_MOUNTPOINT is not set -CONFIG_MT=y +# 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_SETSID=y CONFIG_STRINGS=y # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set -CONFIG_TIME=y -# CONFIG_TIMEOUT is not set -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set +# CONFIG_TIME is not set +CONFIG_TIMEOUT=y +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y # CONFIG_WALL is not set -CONFIG_WATCHDOG=y +# 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=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 is not set -CONFIG_ARPING=y -CONFIG_BRCTL=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 is not set +CONFIG_DNSD=y # 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_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 is not set +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 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=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_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 @@ -754,12 +744,12 @@ CONFIG_IFUPDOWN_IFSTATE_PATH="" # 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_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 @@ -770,29 +760,29 @@ CONFIG_FEATURE_IP_RULE=y CONFIG_IPCALC=y CONFIG_FEATURE_IPCALC_FANCY=y CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y -CONFIG_NAMEIF=y +# CONFIG_NAMEIF is not set # CONFIG_FEATURE_NAMEIF_EXTENDED is not set -CONFIG_NETSTAT=y +# CONFIG_NETSTAT is not set # CONFIG_FEATURE_NETSTAT_WIDE is not set # CONFIG_FEATURE_NETSTAT_PRG is not set -CONFIG_NSLOOKUP=y +# CONFIG_NSLOOKUP is not set # CONFIG_NTPD is not set # CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -CONFIG_PING6=y -CONFIG_FEATURE_FANCY_PING=y -# CONFIG_PSCAN is not set -CONFIG_ROUTE=y +# 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 is not set -# CONFIG_FEATURE_TELNETD_STANDALONE is not set -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set +CONFIG_TELNETD=y +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y CONFIG_TFTP=y -# CONFIG_TFTPD is not set +CONFIG_TFTPD=y # # Common options for tftp/tftpd @@ -802,25 +792,25 @@ 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_TRACEROUTE is not set +# CONFIG_TRACEROUTE6 is not set +# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set # CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE 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=y +# CONFIG_UDHCPD is not set # CONFIG_DHCPRELAY is not set -CONFIG_DUMPLEASES=y +# CONFIG_DUMPLEASES is not set # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set -CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" -CONFIG_UDHCPC=y -CONFIG_FEATURE_UDHCPC_ARPING=y +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=y -CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +# 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 @@ -828,14 +818,15 @@ 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 is not set -# CONFIG_LPQ is not set +CONFIG_LPR=y +CONFIG_LPQ=y # # Mail Utilities @@ -851,26 +842,30 @@ CONFIG_FEATURE_MIME_CHARSET="" # # Process Utilities # -# CONFIG_SMEMCAP is not set -CONFIG_FREE=y +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 is not set +CONFIG_KILLALL5=y # CONFIG_NMETER is not set -# CONFIG_PGREP is not set -CONFIG_PIDOF=y +CONFIG_PGREP=y +# 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_PKILL=y CONFIG_PS=y -# CONFIG_FEATURE_PS_WIDE is not set +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_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 @@ -878,7 +873,7 @@ CONFIG_TOP=y # CONFIG_FEATURE_TOP_SMP_PROCESS is not set # CONFIG_FEATURE_TOPMEM is not set CONFIG_FEATURE_SHOW_THREADS=y -CONFIG_UPTIME=y +# CONFIG_UPTIME is not set CONFIG_WATCH=y # @@ -915,22 +910,25 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # Shells # CONFIG_ASH=y -CONFIG_ASH_BASH_COMPAT=y -CONFIG_ASH_JOB_CONTROL=y -CONFIG_ASH_ALIAS=y -CONFIG_ASH_GETOPTS=y -CONFIG_ASH_BUILTIN_ECHO=y -CONFIG_ASH_BUILTIN_PRINTF=y -CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y -CONFIG_ASH_MAIL=y -CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -CONFIG_ASH_RANDOM_SUPPORT=y -CONFIG_ASH_EXPAND_PRMT=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_BUILTIN_ECHO is not set +# CONFIG_ASH_BUILTIN_PRINTF is not set +# CONFIG_ASH_BUILTIN_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 @@ -938,35 +936,34 @@ CONFIG_ASH_EXPAND_PRMT=y # 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_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH 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_LASH is not set -# CONFIG_MSH is not set CONFIG_SH_MATH_SUPPORT=y CONFIG_SH_MATH_SUPPORT_64=y # CONFIG_FEATURE_SH_EXTRA_QUIET is not set -CONFIG_FEATURE_SH_STANDALONE=y +# CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set -# CONFIG_CTTYHACK is not set # # System Logging Utilities # CONFIG_SYSLOGD=y -# CONFIG_FEATURE_ROTATE_LOGFILE is not set +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=64 +CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 CONFIG_LOGREAD=y -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -CONFIG_FEATURE_KLOGD_KLOGCTL=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/console-tools/Config.src b/console-tools/Config.src index 6e3191a..c657044 100644 --- a/console-tools/Config.src +++ b/console-tools/Config.src @@ -10,6 +10,7 @@ INSERT config CHVT bool "chvt" default y + select PLATFORM_LINUX help This program is used to change to another terminal. Example: chvt 4 (change to terminal /dev/tty4) @@ -17,6 +18,7 @@ config CHVT config FGCONSOLE bool "fgconsole" default y + select PLATFORM_LINUX help This program prints active (foreground) console number. @@ -29,12 +31,14 @@ config CLEAR config DEALLOCVT bool "deallocvt" default y + select PLATFORM_LINUX help This program deallocates unused virtual consoles. config DUMPKMAP bool "dumpkmap" default y + select PLATFORM_LINUX help This program dumps the kernel's keyboard translation table to stdout, in binary format. You can then use loadkmap to load it. @@ -42,18 +46,21 @@ config DUMPKMAP config KBD_MODE bool "kbd_mode" default y + select PLATFORM_LINUX help This program reports and sets keyboard mode. config LOADFONT bool "loadfont" default y + select PLATFORM_LINUX help This program loads a console font from standard input. config LOADKMAP bool "loadkmap" default y + select PLATFORM_LINUX help This program loads a keyboard translation table from standard input. @@ -61,6 +68,7 @@ config LOADKMAP config OPENVT bool "openvt" default y + select PLATFORM_LINUX help This program is used to start a command on an unused virtual terminal. @@ -92,6 +100,7 @@ config FEATURE_RESIZE_PRINT config SETCONSOLE bool "setconsole" default y + select PLATFORM_LINUX help This program redirects the system console to another device, like the current tty while logged in via telnet. @@ -106,6 +115,7 @@ config FEATURE_SETCONSOLE_LONG_OPTIONS config SETFONT bool "setfont" default y + select PLATFORM_LINUX help Allows to load console screen map. Useful for i18n. @@ -127,6 +137,7 @@ config DEFAULT_SETFONT_DIR config SETKEYCODES bool "setkeycodes" default y + select PLATFORM_LINUX help This program loads entries into the kernel's scancode-to-keycode map, allowing unusual keyboards to generate usable keycodes. @@ -134,12 +145,14 @@ config SETKEYCODES config SETLOGCONS bool "setlogcons" default y + select PLATFORM_LINUX help This program redirects the output console of kernel messages. config SHOWKEY bool "showkey" default y + select PLATFORM_LINUX help Shows keys pressed. diff --git a/console-tools/Kbuild.src b/console-tools/Kbuild.src index 17f6606..94de9ad 100644 --- a/console-tools/Kbuild.src +++ b/console-tools/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/console-tools/chvt.c b/console-tools/chvt.c index 977c269..b9c974f 100644 --- a/console-tools/chvt.c +++ b/console-tools/chvt.c @@ -4,8 +4,14 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//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; diff --git a/console-tools/clear.c b/console-tools/clear.c index cac7163..ac22b78 100644 --- a/console-tools/clear.c +++ b/console-tools/clear.c @@ -4,8 +4,14 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define clear_trivial_usage +//usage: "" +//usage:#define clear_full_usage "\n\n" +//usage: "Clear screen" + #include "libbb.h" int clear_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/console-tools/deallocvt.c b/console-tools/deallocvt.c index 0974883..b131c0a 100644 --- a/console-tools/deallocvt.c +++ b/console-tools/deallocvt.c @@ -5,11 +5,16 @@ * Copyright (C) 2003 by Tito Ragusa * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* no options, no getopt */ +//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 */ diff --git a/console-tools/dumpkmap.c b/console-tools/dumpkmap.c index a03b593..bf8d690 100644 --- a/console-tools/dumpkmap.c +++ b/console-tools/dumpkmap.c @@ -4,11 +4,19 @@ * * Copyright (C) Arne Bernin * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * */ /* no options, no getopt */ +//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" /* From */ @@ -28,47 +36,56 @@ int dumpkmap_main(int argc UNUSED_PARAM, char **argv) { struct kbentry ke; int i, j, fd; - RESERVE_CONFIG_BUFFER(flags, MAX_NR_KEYMAPS); +#define flags bb_common_bufsiz1 /* When user accidentally runs "dumpkmap FILE" * instead of "dumpkmap >FILE", we'd dump binary stuff to tty. - * Let's prevent it: */ + * Let's prevent it: + */ if (argv[1]) bb_show_usage(); /* bb_warn_ignoring_args(argv[1]);*/ fd = get_console_fd_or_die(); +#if 0 write(STDOUT_FILENO, "bkeymap", 7); - /* Here we want to set everything to 0 except for indexes: - * [0-2] [4-6] [8-10] [12] */ - memset(flags, 0x00, MAX_NR_KEYMAPS); + * [0-2] [4-6] [8-10] [12] + */ + /*memset(flags, 0x00, MAX_NR_KEYMAPS); - already is */ memset(flags, 0x01, 13); flags[3] = flags[7] = flags[11] = 0; - /* dump flags */ write(STDOUT_FILENO, flags, MAX_NR_KEYMAPS); +#define flags7 flags +#else + /* Same effect */ + /* 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) +#endif - for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { + 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 failed with %s, %s, %p", - (char *)&ke.kb_index, - (char *)&ke.kb_table, - &ke.kb_value) + "ioctl(KDGKBENT{%d,%d}) failed", + j, i) ) { - write(STDOUT_FILENO, (void*)&ke.kb_value, 2); + write(STDOUT_FILENO, &ke.kb_value, 2); } } } } if (ENABLE_FEATURE_CLEAN_UP) { close(fd); - RELEASE_CONFIG_BUFFER(flags); } return EXIT_SUCCESS; } diff --git a/console-tools/fgconsole.c b/console-tools/fgconsole.c index 75fd98f..54355be 100644 --- a/console-tools/fgconsole.c +++ b/console-tools/fgconsole.c @@ -4,9 +4,14 @@ * * Copyright (C) 2010 by Grigory Batalov * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define fgconsole_trivial_usage +//usage: "" +//usage:#define fgconsole_full_usage "\n\n" +//usage: "Get active console" + #include "libbb.h" /* From */ diff --git a/console-tools/kbd_mode.c b/console-tools/kbd_mode.c index e1d8523..1385367 100644 --- a/console-tools/kbd_mode.c +++ b/console-tools/kbd_mode.c @@ -6,8 +6,19 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//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 the keyboard mode\n" +//usage: "\n -a Default (ASCII)" +//usage: "\n -k Medium-raw (keyboard)" +//usage: "\n -s Raw (scancode)" +//usage: "\n -u Unicode (utf-8)" +//usage: "\n -C TTY Affect TTY instead of /dev/tty" + #include "libbb.h" #include @@ -16,9 +27,9 @@ int kbd_mode_main(int argc UNUSED_PARAM, char **argv) { enum { SCANCODE = (1 << 0), - ASCII = (1 << 1), + ASCII = (1 << 1), MEDIUMRAW = (1 << 2), - UNICODE = (1 << 3), + UNICODE = (1 << 3), }; int fd; unsigned opt; diff --git a/console-tools/loadfont.c b/console-tools/loadfont.c index e51142c..032506d 100644 --- a/console-tools/loadfont.c +++ b/console-tools/loadfont.c @@ -7,8 +7,28 @@ * 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 tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//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" +//usage: +//usage:#define setfont_trivial_usage +//usage: "FONT [-m MAPFILE] [-C TTY]" +//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" + #include "libbb.h" #include @@ -136,7 +156,7 @@ static void do_loadfont(int fd, unsigned char *inbuf, int height, int width, int * Example: * At the font position for a capital A-ring glyph, we * may have: - * 00C5,212B,FFFE,0041,030A,FFFF + * 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. */ @@ -159,7 +179,7 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, int glyph; uint16_t unicode; - maxct = tailsz; /* more than enough */ + maxct = tailsz; /* more than enough */ up = xmalloc(maxct * sizeof(*up)); for (glyph = 0; glyph < fontsize; glyph++) { @@ -209,7 +229,7 @@ static void do_loadtable(int fd, unsigned char *inbuf, int tailsz, int fontsize, } /* Note: after PIO_UNIMAPCLR and before PIO_UNIMAP - this printf did not work on many kernels */ + * this printf did not work on many kernels */ advice.advised_hashsize = 0; advice.advised_hashstep = 0; @@ -255,10 +275,10 @@ static void do_load(int fd, unsigned char *buffer, size_t len) } else #endif #if ENABLE_FEATURE_LOADFONT_RAW - if (len == 9780) { /* file with three code pages? */ + if (len == 9780) { /* file with three code pages? */ charsize = height = 16; font += 40; - } else if ((len & 0377) == 0) { /* bare font */ + } else if ((len & 0377) == 0) { /* bare font */ charsize = height = len / 256; } else #endif diff --git a/console-tools/loadkmap.c b/console-tools/loadkmap.c index 8f1a915..66ec3b0 100644 --- a/console-tools/loadkmap.c +++ b/console-tools/loadkmap.c @@ -4,8 +4,18 @@ * * Copyright (C) 1998 Enrique Zanardi * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define loadkmap_trivial_usage +//usage: "< keymap" +//usage:#define loadkmap_full_usage "\n\n" +//usage: "Load a binary keyboard translation table from stdin\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" @@ -38,6 +48,7 @@ int loadkmap_main(int argc UNUSED_PARAM, char **argv) if (argv[1]) bb_show_usage(); /* bb_warn_ignoring_args(argv[1]); */ + fd = get_console_fd_or_die(); /* or maybe: opt = getopt32(argv, "C:", &tty_name); @@ -51,14 +62,24 @@ int loadkmap_main(int argc UNUSED_PARAM, char **argv) xread(STDIN_FILENO, flags, MAX_NR_KEYMAPS); for (i = 0; i < MAX_NR_KEYMAPS; i++) { - if (flags[i] == 1) { - xread(STDIN_FILENO, ibuff, NR_KEYS * sizeof(uint16_t)); - for (j = 0; j < NR_KEYS; j++) { - ke.kb_index = j; - ke.kb_table = i; - ke.kb_value = ibuff[j]; - ioctl(fd, KDSKBENT, &ke); - } + if (flags[i] != 1) + continue; + xread(STDIN_FILENO, ibuff, NR_KEYS * sizeof(uint16_t)); + for (j = 0; j < NR_KEYS; j++) { + ke.kb_index = j; + ke.kb_table = i; + ke.kb_value = ibuff[j]; + /* + * Note: table[idx:0] can contain special value + * K_ALLOCATED (marks allocated tables in kernel). + * dumpkmap saves the value as-is; but attempts + * to load it here fail, since it isn't a valid + * key value: it is K(KT_SPEC,126) == 2<<8 + 126, + * whereas last valid KT_SPEC is + * K_BARENUMLOCK == K(KT_SPEC,19). + * So far we just ignore these errors: + */ + ioctl(fd, KDSKBENT, &ke); } } diff --git a/console-tools/openvt.c b/console-tools/openvt.c index e3ea71b..e523566 100644 --- a/console-tools/openvt.c +++ b/console-tools/openvt.c @@ -5,9 +5,21 @@ * busyboxed by Quy Tonthat * hacked by Tito * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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" @@ -144,9 +156,7 @@ int openvt_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) { argv--; - argv[0] = getenv("SHELL"); - if (!argv[0]) - argv[0] = (char *) DEFAULT_SHELL; + argv[0] = (char *) get_shell_name(); /*argv[1] = NULL; - already is */ } diff --git a/console-tools/reset.c b/console-tools/reset.c index f0ea5cb..65940bd 100644 --- a/console-tools/reset.c +++ b/console-tools/reset.c @@ -5,14 +5,21 @@ * Copyright (C) 1999-2004 by Erik Andersen * Written by Erik Andersen and Kent Robotti * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#include "libbb.h" - /* BTW, which "standard" package has this utility? It doesn't seem * to be ncurses, coreutils, console-tools... then what? */ +//usage:#define reset_trivial_usage +//usage: "" +//usage:#define reset_full_usage "\n\n" +//usage: "Reset the screen" + +#include "libbb.h" + +#define ESC "\033" + #if ENABLE_STTY int stty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; #endif @@ -26,15 +33,15 @@ int reset_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) /* no options, no getopt */ - if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { + if (/*isatty(STDIN_FILENO) &&*/ isatty(STDOUT_FILENO)) { /* See 'man 4 console_codes' for details: * "ESC c" -- Reset - * "ESC ( K" -- Select user mapping - * "ESC [ J" -- Erase to the end of screen + * "ESC ( B" -- Select G0 Character Set (B = US) * "ESC [ 0 m" -- Reset all display attributes + * "ESC [ J" -- Erase to the end of screen * "ESC [ ? 25 h" -- Make cursor visible */ - printf("\033c\033(K\033[J\033[0m\033[?25h"); + printf(ESC"c" ESC"(B" ESC"[0m" ESC"[J" ESC"[?25h"); /* http://bugs.busybox.net/view.php?id=1414: * people want it to reset echo etc: */ #if ENABLE_STTY diff --git a/console-tools/resize.c b/console-tools/resize.c index 828b5bb..4b0d63a 100644 --- a/console-tools/resize.c +++ b/console-tools/resize.c @@ -4,9 +4,15 @@ * * Copyright 2006 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* no options, no getopt */ + +//usage:#define resize_trivial_usage +//usage: "" +//usage:#define resize_full_usage "\n\n" +//usage: "Resize the screen" + #include "libbb.h" #define ESC "\033" @@ -17,7 +23,7 @@ static void onintr(int sig UNUSED_PARAM) { tcsetattr(STDERR_FILENO, TCSANOW, old_termios_p); - exit(EXIT_FAILURE); + _exit(EXIT_FAILURE); } int resize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -53,6 +59,7 @@ int resize_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) */ 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"); diff --git a/console-tools/setconsole.c b/console-tools/setconsole.c index 8ad9948..c0051dc 100644 --- a/console-tools/setconsole.c +++ b/console-tools/setconsole.c @@ -5,9 +5,15 @@ * Copyright (C) 2004,2005 Enrik Berkhan * Copyright (C) 2008 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define setconsole_trivial_usage +//usage: "[-r" IF_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]" +//usage:#define setconsole_full_usage "\n\n" +//usage: "Redirect system console output to DEVICE (default: /dev/tty)\n" +//usage: "\n -r Reset output to /dev/console" + #include "libbb.h" int setconsole_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -34,6 +40,6 @@ int setconsole_main(int argc UNUSED_PARAM, char **argv) device = DEV_CONSOLE; } - xioctl(xopen(device, O_RDONLY), TIOCCONS, NULL); + xioctl(xopen(device, O_WRONLY), TIOCCONS, NULL); return EXIT_SUCCESS; } diff --git a/console-tools/setkeycodes.c b/console-tools/setkeycodes.c index b6a9a32..a6a7c23 100644 --- a/console-tools/setkeycodes.c +++ b/console-tools/setkeycodes.c @@ -6,8 +6,20 @@ * * Adjusted for BusyBox by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define setkeycodes_trivial_usage +//usage: "SCANCODE KEYCODE..." +//usage:#define setkeycodes_full_usage "\n\n" +//usage: "Set entries into the kernel's scancode-to-keycode map,\n" +//usage: "allowing unusual keyboards to generate usable keycodes.\n\n" +//usage: "SCANCODE may be either xx or e0xx (hexadecimal),\n" +//usage: "and KEYCODE is given in decimal." +//usage: +//usage:#define setkeycodes_example_usage +//usage: "$ setkeycodes e030 127\n" + #include "libbb.h" /* From */ diff --git a/console-tools/setlogcons.c b/console-tools/setlogcons.c index dd44591..c76a5a4 100644 --- a/console-tools/setlogcons.c +++ b/console-tools/setlogcons.c @@ -6,9 +6,14 @@ * * Based on setlogcons (kbd-1.12) by Andries E. Brouwer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define setlogcons_trivial_usage +//usage: "N" +//usage:#define setlogcons_full_usage "\n\n" +//usage: "Redirect the kernel output to console N (0 for current)" + #include "libbb.h" int setlogcons_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -17,9 +22,10 @@ int setlogcons_main(int argc UNUSED_PARAM, char **argv) struct { char fn; char subarg; - } arg = { 11, /* redirect kernel messages */ - 0 /* to specified console (current as default) */ - }; + } arg = { + 11, /* redirect kernel messages */ + 0 /* to specified console (current as default) */ + }; if (argv[1]) arg.subarg = xatou_range(argv[1], 0, 63); diff --git a/console-tools/showkey.c b/console-tools/showkey.c index 681114d..69b785e 100644 --- a/console-tools/showkey.c +++ b/console-tools/showkey.c @@ -4,135 +4,147 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//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 -// set raw tty mode -// also used by microcom -// libbb candidates? -static void xget1(int fd, struct termios *t, struct termios *oldt) -{ - tcgetattr(fd, oldt); - *t = *oldt; - cfmakeraw(t); -} - -static int xset1(int fd, struct termios *tio, const char *device) -{ - int ret = tcsetattr(fd, TCSAFLUSH, tio); - - if (ret) { - bb_perror_msg("can't tcsetattr for %s", device); - } - return ret; -} -/* - * GLOBALS - */ 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 kbmode (G.kbmode) +#define tio (G.tio) +#define tio0 (G.tio0) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ } while (0) -static void signal_handler(int signo) +// 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) { - // restore keyboard and console settings - xset1(STDIN_FILENO, &tio0, "stdin"); - xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); - // alarmed? -> exit 0 - exit(SIGALRM == signo); + int ret = tcsetattr(STDIN_FILENO, TCSAFLUSH, t); + if (ret) { + bb_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 + 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"); - INIT_G(); - - // get keyboard settings - xioctl(STDIN_FILENO, KDGKBMODE, &kbmode); - printf("kb mode was %s\n\nPress any keys. Program terminates %s\n\n", - kbmode == K_RAW ? "RAW" : - (kbmode == K_XLATE ? "XLATE" : - (kbmode == K_MEDIUMRAW ? "MEDIUMRAW" : - (kbmode == K_UNICODE ? "UNICODE" : "?UNKNOWN?"))) - , (option_mask32 & OPT_a) ? "when CTRL+D pressed" : "10s after last keypress" - ); // prepare for raw mode - xget1(STDIN_FILENO, &tio, &tio0); + xget1(&tio, &tio0); // put stdin in raw mode - xset1(STDIN_FILENO, &tio, "stdin"); + xset1(&tio); + +#define press_keys "Press any keys, program terminates %s:\r\n\n" if (option_mask32 & OPT_a) { - char c; // just read stdin char by char - while (1 == safe_read(STDIN_FILENO, &c, 1)) { - printf("%3d 0%03o 0x%02x\r\n", c, c, c); + 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 should exit on any signal - bb_signals(BB_FATAL_SIGS, signal_handler); + // 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_recursive_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 (1) { + 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) { - char c = buf[i]; - // show raw scancodes ordered? -> if (option_mask32 & OPT_s) { + // show raw scancodes printf("0x%02x ", buf[i++]); - // show interpreted scancodes (default) ? -> } 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) { + 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 %3d %s", kc, (c & 0x80) ? "release" : "press"); + printf("keycode %3u %s", kc, (c & 0x80) ? "release" : "press"); } } puts("\r"); } + + // restore keyboard mode + xioctl(STDIN_FILENO, KDSKBMODE, (void *)(ptrdiff_t)kbmode); } - // cleanup - signal_handler(SIGALRM); + // restore console settings + xset1(&tio0); - // should never be here! return EXIT_SUCCESS; } diff --git a/coreutils/Config.src b/coreutils/Config.src index d4c9e05..0c44c4b 100644 --- a/coreutils/Config.src +++ b/coreutils/Config.src @@ -269,19 +269,6 @@ config FEATURE_FANCY_HEAD help This enables the head options (-c, -q, and -v). -config HOSTID - bool "hostid" - default y - help - hostid prints the numeric identifier (in hexadecimal) for - the current host. - -config ID - bool "id" - default y - help - id displays the current user and group ID names. - config INSTALL bool "install" default y @@ -295,11 +282,11 @@ config FEATURE_INSTALL_LONG_OPTIONS help Support long options for the install applet. -config LENGTH - bool "length" - default y - help - length is used to print out the length of a specified string. +####config LENGTH +#### bool "length" +#### default y +#### help +#### length is used to print out the length of a specified string. config LN bool "ln" @@ -527,6 +514,12 @@ config SHA512SUM help Compute and check SHA512 message digest +config SHA3SUM + bool "sha3sum" + default y + help + Compute and check SHA3 (512-bit) message digest + config SLEEP bool "sleep" default y @@ -591,6 +584,7 @@ config FEATURE_SPLIT_FANCY config STAT bool "stat" default y + select PLATFORM_LINUX # statfs() help display file or filesystem status. @@ -660,13 +654,6 @@ config FEATURE_TEE_USE_BLOCK_IO help Enable this option for a faster tee, at expense of size. -config TOUCH - bool "touch" - default y - help - touch is used to create or change the access and/or - modification timestamp of specified files. - config TRUE bool "true" default y @@ -737,13 +724,6 @@ config FEATURE_WC_LARGE help Use "unsigned long long" in wc for counter variables. -config WHO - bool "who" - default y - depends on FEATURE_UTMP - help - who is used to show who is logged on. - config WHOAMI bool "whoami" default y @@ -792,13 +772,13 @@ config FEATURE_HUMAN_READABLE help Allow df, du, and ls to have human readable output. -comment "Common options for md5sum, sha1sum, sha256sum, sha512sum" - depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM +comment "Common options for md5sum, sha1sum, sha256sum, sha512sum, sha3sum" + depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM config FEATURE_MD5_SHA1_SUM_CHECK bool "Enable -c, -s and -w options" default y - depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM + depends on MD5SUM || SHA1SUM || SHA256SUM || SHA512SUM || SHA3SUM help Enabling the -c options allows files to be checked against pre-calculated hash values. diff --git a/coreutils/Kbuild.src b/coreutils/Kbuild.src index 1c846a7..ec4ef7d 100644 --- a/coreutils/Kbuild.src +++ b/coreutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. libs-y += libcoreutils/ @@ -35,11 +35,8 @@ lib-$(CONFIG_EXPAND) += expand.o lib-$(CONFIG_FALSE) += false.o lib-$(CONFIG_FOLD) += fold.o lib-$(CONFIG_FSYNC) += fsync.o -lib-$(CONFIG_HEAD) += head.o -lib-$(CONFIG_HOSTID) += hostid.o -lib-$(CONFIG_ID) += id.o lib-$(CONFIG_INSTALL) += install.o -lib-$(CONFIG_LENGTH) += length.o +#lib-$(CONFIG_LENGTH) += length.o lib-$(CONFIG_LN) += ln.o lib-$(CONFIG_LOGNAME) += logname.o lib-$(CONFIG_LS) += ls.o @@ -64,6 +61,7 @@ lib-$(CONFIG_SEQ) += seq.o lib-$(CONFIG_SHA1SUM) += md5_sha1_sum.o lib-$(CONFIG_SHA256SUM) += md5_sha1_sum.o lib-$(CONFIG_SHA512SUM) += md5_sha1_sum.o +lib-$(CONFIG_SHA3SUM) += md5_sha1_sum.o lib-$(CONFIG_SLEEP) += sleep.o lib-$(CONFIG_SPLIT) += split.o lib-$(CONFIG_SORT) += sort.o @@ -72,9 +70,7 @@ lib-$(CONFIG_STTY) += stty.o lib-$(CONFIG_SUM) += sum.o lib-$(CONFIG_SYNC) += sync.o lib-$(CONFIG_TAC) += tac.o -lib-$(CONFIG_TAIL) += tail.o lib-$(CONFIG_TEE) += tee.o -lib-$(CONFIG_TOUCH) += touch.o lib-$(CONFIG_TRUE) += true.o lib-$(CONFIG_TTY) += tty.o lib-$(CONFIG_UNAME) += uname.o @@ -84,6 +80,5 @@ lib-$(CONFIG_USLEEP) += usleep.o lib-$(CONFIG_UUDECODE) += uudecode.o lib-$(CONFIG_UUENCODE) += uuencode.o lib-$(CONFIG_WC) += wc.o -lib-$(CONFIG_WHO) += who.o lib-$(CONFIG_WHOAMI) += whoami.o lib-$(CONFIG_YES) += yes.o diff --git a/coreutils/basename.c b/coreutils/basename.c index b79d561..1f7a137 100644 --- a/coreutils/basename.c +++ b/coreutils/basename.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -28,6 +28,19 @@ //config: leaving just the filename itself. Enable this option if you wish //config: to enable the 'basename' utility. +//usage:#define basename_trivial_usage +//usage: "FILE [SUFFIX]" +//usage:#define basename_full_usage "\n\n" +//usage: "Strip directory path and .SUFFIX from FILE\n" +//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! */ @@ -38,6 +51,11 @@ int basename_main(int argc, char **argv) size_t m, n; char *s; + if (argv[1] && strcmp(argv[1], "--") == 0) { + argv++; + argc--; + } + if ((unsigned)(argc-2) >= 2) { bb_show_usage(); } diff --git a/coreutils/cal.c b/coreutils/cal.c index c98229c..12c46b1 100644 --- a/coreutils/cal.c +++ b/coreutils/cal.c @@ -4,7 +4,7 @@ * * See original copyright at the end of this file * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant with -j and -y extensions (from util-linux). */ @@ -16,6 +16,14 @@ * * Major size reduction... over 50% (>1.5k) on i386. */ + +//usage:#define cal_trivial_usage +//usage: "[-jy] [[MONTH] YEAR]" +//usage:#define cal_full_usage "\n\n" +//usage: "Display a calendar\n" +//usage: "\n -j Use julian dates" +//usage: "\n -y Display the entire year" + #include "libbb.h" #include "unicode.h" @@ -35,7 +43,7 @@ static const unsigned char days_in_month[] ALIGN1 = { }; static const unsigned char sep1752[] ALIGN1 = { - 1, 2, 14, 15, 16, + 1, 2, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 }; @@ -138,7 +146,7 @@ int cal_main(int argc UNUSED_PARAM, char **argv) if (julian) *hp++ = ' '; { - char *two_wchars = unicode_conv_to_printable_fixedwidth(NULL, buf, 2); + char *two_wchars = unicode_conv_to_printable_fixedwidth(/*NULL,*/ buf, 2); strcpy(hp, two_wchars); free(two_wchars); } @@ -157,10 +165,10 @@ int cal_main(int argc UNUSED_PARAM, char **argv) char lineout[30]; day_array(month, year, dp); - len = sprintf(lineout, "%s %d", month_names[month - 1], year); + len = sprintf(lineout, "%s %u", month_names[month - 1], year); printf("%*s%s\n%s\n", - ((7*julian + WEEK_LEN) - len) / 2, "", - lineout, day_headings); + ((7*julian + WEEK_LEN) - len) / 2, "", + lineout, day_headings); for (row = 0; row < 6; row++) { build_row(lineout, dp)[0] = '\0'; dp += 7; @@ -173,10 +181,11 @@ int cal_main(int argc UNUSED_PARAM, char **argv) sprintf(lineout, "%u", year); center(lineout, - (WEEK_LEN * 3 + HEAD_SEP * 2) - + julian * (J_WEEK_LEN * 2 + HEAD_SEP - - (WEEK_LEN * 3 + HEAD_SEP * 2)), - 0); + (WEEK_LEN * 3 + HEAD_SEP * 2) + + julian * (J_WEEK_LEN * 2 + HEAD_SEP + - (WEEK_LEN * 3 + HEAD_SEP * 2)), + 0 + ); puts("\n"); /* two \n's */ for (i = 0; i < 12; i++) { day_array(i + 1, year, days[i]); diff --git a/coreutils/cat.c b/coreutils/cat.c index ab68258..00c38d4 100644 --- a/coreutils/cat.c +++ b/coreutils/cat.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2, see file License in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -22,6 +22,15 @@ //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. +//usage:#define cat_trivial_usage +//usage: "[FILE]..." +//usage:#define cat_full_usage "\n\n" +//usage: "Concatenate FILEs and print them to stdout" +//usage: +//usage:#define cat_example_usage +//usage: "$ cat /proc/uptime\n" +//usage: "110716.72 17.67" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/coreutils/catv.c b/coreutils/catv.c index ff3139c..e3499c5 100644 --- a/coreutils/catv.c +++ b/coreutils/catv.c @@ -4,12 +4,20 @@ * * Copyright (C) 2006 Rob Landley * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* See "Cat -v considered harmful" at * http://cm.bell-labs.com/cm/cs/doc/84/kp.ps.gz */ +//usage:#define catv_trivial_usage +//usage: "[-etv] [FILE]..." +//usage:#define catv_full_usage "\n\n" +//usage: "Display nonprinting characters as ^x or M-x\n" +//usage: "\n -e End each line with $" +//usage: "\n -t Show tabs as ^I" +//usage: "\n -v Don't use ^x or M-x escapes" + #include "libbb.h" int catv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -17,14 +25,23 @@ int catv_main(int argc UNUSED_PARAM, char **argv) { int retval = EXIT_SUCCESS; int fd; - unsigned flags; - - flags = getopt32(argv, "etv"); + unsigned opts; #define CATV_OPT_e (1<<0) #define CATV_OPT_t (1<<1) #define CATV_OPT_v (1<<2) - flags ^= CATV_OPT_v; + typedef char BUG_const_mismatch[ + CATV_OPT_e == VISIBLE_ENDLINE && CATV_OPT_t == VISIBLE_SHOW_TABS + ? 1 : -1 + ]; + + opts = getopt32(argv, "etv"); argv += optind; +#if 0 /* These consts match, we can just pass "opts" to visible() */ + if (opts & CATV_OPT_e) + flags |= VISIBLE_ENDLINE; + if (opts & CATV_OPT_t) + flags |= VISIBLE_SHOW_TABS; +#endif /* Read from stdin if there's nothing else to do. */ if (!argv[0]) @@ -42,29 +59,17 @@ int catv_main(int argc UNUSED_PARAM, char **argv) res = read(fd, read_buf, COMMON_BUFSIZE); if (res < 0) retval = EXIT_FAILURE; - if (res < 1) + if (res <= 0) break; for (i = 0; i < res; i++) { unsigned char c = read_buf[i]; - - if (c > 126 && (flags & CATV_OPT_v)) { - if (c == 127) { - printf("^?"); - continue; - } - printf("M-"); - c -= 128; - } - if (c < 32) { - if (c == 10) { - if (flags & CATV_OPT_e) - bb_putchar('$'); - } else if (flags & (c==9 ? CATV_OPT_t : CATV_OPT_v)) { - printf("^%c", c+'@'); - continue; - } + if (opts & CATV_OPT_v) { + putchar(c); + } else { + char buf[sizeof("M-^c")]; + visible(c, buf, opts); + fputs(buf, stdout); } - bb_putchar(c); } } if (ENABLE_FEATURE_CLEAN_UP && fd) diff --git a/coreutils/chgrp.c b/coreutils/chgrp.c index 7f39048..7076db6 100644 --- a/coreutils/chgrp.c +++ b/coreutils/chgrp.c @@ -4,13 +4,35 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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: "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..." +//usage:#define chgrp_full_usage "\n\n" +//usage: "Change the group membership of each FILE to GROUP\n" +//usage: "\n -R Recurse" +//usage: "\n -h Affect symlinks instead of symlink targets" +//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: 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! */ diff --git a/coreutils/chmod.c b/coreutils/chmod.c index c04201e..5ee45b9 100644 --- a/coreutils/chmod.c +++ b/coreutils/chmod.c @@ -7,13 +7,35 @@ * Reworked by (C) 2002 Vladimir Oleynik * to correctly parse '-rwxgoa' * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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: "Each MODE is one or more of the letters ugoa, one of the\n" +//usage: "symbols +-= and one or more of the letters rwxst\n" +//usage: "\n -R Recurse" +//usage: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v List all files" +//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! */ diff --git a/coreutils/chown.c b/coreutils/chown.c index 717e4b1..1a91276 100644 --- a/coreutils/chown.c +++ b/coreutils/chown.c @@ -4,12 +4,37 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 defects - none? */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chown.html */ +//usage:#define chown_trivial_usage +//usage: "[-RhLHP"IF_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..." +//usage:#define chown_full_usage "\n\n" +//usage: "Change the owner and/or group of each FILE to OWNER and/or GROUP\n" +//usage: "\n -R Recurse" +//usage: "\n -h Affect symlinks instead of symlink targets" +//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: IF_DESKTOP( +//usage: "\n -c List changed files" +//usage: "\n -v List all files" +//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! */ @@ -101,8 +126,8 @@ int chown_main(int argc UNUSED_PARAM, char **argv) /* 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) + /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */ + IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE) ) { param.chown_func = lchown; } diff --git a/coreutils/chroot.c b/coreutils/chroot.c index 046c2fa..633e66b 100644 --- a/coreutils/chroot.c +++ b/coreutils/chroot.c @@ -4,11 +4,24 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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; @@ -18,16 +31,13 @@ int chroot_main(int argc UNUSED_PARAM, char **argv) if (!*argv) bb_show_usage(); xchroot(*argv); - xchdir("/"); ++argv; if (!*argv) { /* no 2nd param (PROG), use shell */ argv -= 2; - argv[0] = getenv("SHELL"); - if (!argv[0]) { - argv[0] = (char *) DEFAULT_SHELL; - } - argv[1] = (char *) "-i"; + 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/coreutils/cksum.c b/coreutils/cksum.c index 8e65b1c..ac0b0c3 100644 --- a/coreutils/cksum.c +++ b/coreutils/cksum.c @@ -4,10 +4,18 @@ * * Copyright (C) 2006 by Rob Sullivan, with ideas from code by Walter Harms * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define cksum_trivial_usage +//usage: "FILES..." +//usage:#define cksum_full_usage "\n\n" +//usage: "Calculate the CRC32 checksums of FILES" + #include "libbb.h" +/* This is a NOEXEC applet. Be very careful! */ + int cksum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cksum_main(int argc UNUSED_PARAM, char **argv) { @@ -16,7 +24,6 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) off_t length, filesize; int bytes_read; int exit_code = EXIT_SUCCESS; - uint8_t *cp; #if ENABLE_DESKTOP getopt32(argv, ""); /* coreutils 6.9 compat */ @@ -37,11 +44,8 @@ int cksum_main(int argc UNUSED_PARAM, char **argv) #define read_buf bb_common_bufsiz1 while ((bytes_read = safe_read(fd, read_buf, sizeof(read_buf))) > 0) { - cp = (uint8_t *) read_buf; length += bytes_read; - do { - crc = (crc << 8) ^ crc32_table[(crc >> 24) ^ *cp++]; - } while (--bytes_read); + crc = crc32_block_endian1(crc, read_buf, bytes_read, crc32_table); } close(fd); diff --git a/coreutils/comm.c b/coreutils/comm.c index 221cbfb..cd45095 100644 --- a/coreutils/comm.c +++ b/coreutils/comm.c @@ -4,9 +4,17 @@ * * Copyright (C) 2005 by Robert Sullivan * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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) diff --git a/coreutils/cp.c b/coreutils/cp.c index d7c8d91..de2e512 100644 --- a/coreutils/cp.c +++ b/coreutils/cp.c @@ -5,7 +5,7 @@ * Copyright (C) 2000 by Matt Kraai * SELinux support by Yuichi Nakamura * - * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cp.html */ @@ -15,6 +15,23 @@ * Size reduction. */ +//usage:#define cp_trivial_usage +//usage: "[OPTIONS] SOURCE... DEST" +//usage:#define cp_full_usage "\n\n" +//usage: "Copy SOURCE(s) 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 -l,-s Create (sym)links" + #include "libbb.h" #include "libcoreutils/coreutils.h" diff --git a/coreutils/cut.c b/coreutils/cut.c index 53f343a..84449c7 100644 --- a/coreutils/cut.c +++ b/coreutils/cut.c @@ -6,9 +6,26 @@ * Written by Mark Whitley * debloated by Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define cut_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define cut_full_usage "\n\n" +//usage: "Print selected fields from each input FILE to stdout\n" +//usage: "\n -b LIST Output only bytes from LIST" +//usage: "\n -c LIST Output only characters from LIST" +//usage: "\n -d CHAR Use CHAR instead of tab as the field delimiter" +//usage: "\n -s Output only the lines containing delimiter" +//usage: "\n -f N Print only these fields" +//usage: "\n -n Ignored" +//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" /* This is a NOEXEC applet. Be very careful! */ @@ -37,7 +54,6 @@ 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, char delim, const struct cut_list *cut_lists, unsigned nlists) @@ -196,7 +212,7 @@ int cut_main(int argc UNUSED_PARAM, char **argv) if (opt & CUT_OPT_SUPPRESS_FLGS) { bb_error_msg_and_die ("suppressing non-delimited lines makes sense%s", - _op_on_field); + _op_on_field); } if (delim != '\t') { bb_error_msg_and_die @@ -225,7 +241,7 @@ int cut_main(int argc UNUSED_PARAM, char **argv) if (!ntok[0]) { s = BOL; } else { - s = xatoi_u(ntok); + 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) @@ -238,7 +254,7 @@ int cut_main(int argc UNUSED_PARAM, char **argv) } else if (!ltok[0]) { e = EOL; } else { - e = xatoi_u(ltok); + e = xatoi_positive(ltok); /* if the user specified and end position of 0, * that means "til the end of the line" */ if (e == 0) diff --git a/coreutils/date.c b/coreutils/date.c index c737f09..767e0d4 100644 --- a/coreutils/date.c +++ b/coreutils/date.c @@ -7,7 +7,7 @@ * iso-format handling added by Robert Griebl * bugfixes and cleanup by Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* This 'date' command supports only 2 time setting formats, @@ -19,38 +19,7 @@ /* Input parsing code is always bulky - used heavy duty libc stuff as much as possible, missed out a lot of bounds checking */ -/* Default input handling to save surprising some people */ - -/* 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 - */ +//applet:IF_DATE(APPLET(date, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_DATE) += date.o @@ -69,10 +38,12 @@ //config: Enable option (-I) to output an ISO-8601 compliant //config: date/time string. //config: +//config:# defaults to "no": stat's nanosecond field is a bit non-portable //config:config FEATURE_DATE_NANO //config: bool "Support %[num]N nanosecond format specifier" //config: default n -//config: depends on DATE +//config: depends on DATE # syscall(__NR_clock_gettime) +//config: select PLATFORM_LINUX //config: help //config: Support %[num]N format specifier. Adds ~250 bytes of code. //config: @@ -92,6 +63,80 @@ //config: the same format. With it on, 'date DATE' additionally supports //config: MMDDhhmm[[YY]YY][.ss] format. +/* 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] [TIME]" +//usage:#define date_full_usage "\n\n" +//usage: "Display time (using +FMT), or set time\n" +//usage: IF_NOT_LONG_OPTS( +//usage: "\n [-s] TIME Set time to TIME" +//usage: "\n -u Work in UTC (don't convert to local time)" +//usage: "\n -R Output RFC-2822 compliant date string" +//usage: ) IF_LONG_OPTS( +//usage: "\n [-s,--set] TIME Set time to TIME" +//usage: "\n -u,--utc Work in UTC (don't convert to local time)" +//usage: "\n -R,--rfc-2822 Output RFC-2822 compliant date string" +//usage: ) +//usage: IF_FEATURE_DATE_ISOFMT( +//usage: "\n -I[SPEC] Output ISO-8601 compliant date string" +//usage: "\n SPEC='date' (default) for date only," +//usage: "\n 'hours', 'minutes', or 'seconds' for date and" +//usage: "\n time to the indicated precision" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -r FILE Display last modification time of FILE" +//usage: "\n -d TIME Display TIME, not 'now'" +//usage: ) IF_LONG_OPTS( +//usage: "\n -r,--reference FILE Display last modification time of FILE" +//usage: "\n -d,--date TIME Display TIME, not 'now'" +//usage: ) +//usage: IF_FEATURE_DATE_ISOFMT( +//usage: "\n -D FMT Use FMT for -d TIME conversion" +//usage: ) +//usage: "\n" +//usage: "\nRecognized TIME formats:" +//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" #if ENABLE_FEATURE_DATE_NANO # include @@ -208,6 +253,10 @@ int date_main(int argc UNUSED_PARAM, char **argv) 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 @@ -236,7 +285,9 @@ int date_main(int argc UNUSED_PARAM, char **argv) } /* Correct any day of week and day of year etc. fields */ - tm_time.tm_isdst = -1; /* Be sure to recheck dst */ + /* Be sure to recheck dst (but not if date is time_t format) */ + if (date_str[0] != '@') + tm_time.tm_isdst = -1; ts.tv_sec = validate_tm_time(date_str, &tm_time); maybe_set_utc(opt); @@ -300,7 +351,7 @@ int date_main(int argc UNUSED_PARAM, char **argv) scale = 1; pres = 9; if (n) { - pres = xatoi_u(p); + pres = xatoi_positive(p); if (pres == 0) pres = 9; m = 9 - pres; diff --git a/coreutils/dd.c b/coreutils/dd.c index 7c1a0c0..2838f63 100644 --- a/coreutils/dd.c +++ b/coreutils/dd.c @@ -5,9 +5,41 @@ * * Copyright (C) 2000,2001 Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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]\n" +//usage: " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") +//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: ) +//usage: "\n" +//usage: "\nN may be suffixed by c (1), w (2), b (512), kD (1000), k (1024), MD, M, GD, 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" /* This is a NOEXEC applet. Be very careful! */ @@ -24,7 +56,7 @@ static const struct suffix_mult dd_suffixes[] = { { "b", 512 }, { "kD", 1000 }, { "k", 1024 }, - { "K", 1024 }, /* compat with coreutils dd */ + { "K", 1024 }, /* compat with coreutils dd */ { "MD", 1000000 }, { "M", 1048576 }, { "GD", 1000000000 }, @@ -119,13 +151,14 @@ int dd_main(int argc UNUSED_PARAM, char **argv) enum { /* Must be in the same order as OP_conv_XXX! */ /* (see "flags |= (1 << what)" below) */ - FLAG_NOTRUNC = 1 << 0, - FLAG_SYNC = 1 << 1, - FLAG_NOERROR = 1 << 2, - FLAG_FSYNC = 1 << 3, + 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 */ - FLAG_TWOBUFS = 1 << 4, - FLAG_COUNT = 1 << 5, + FLAG_TWOBUFS = (1 << 5) * ENABLE_FEATURE_DD_IBS_OBS, + FLAG_COUNT = 1 << 6, }; static const char keywords[] ALIGN1 = "bs\0""count\0""seek\0""skip\0""if\0""of\0" @@ -135,7 +168,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) ; #if ENABLE_FEATURE_DD_IBS_OBS static const char conv_words[] ALIGN1 = - "notrunc\0""sync\0""noerror\0""fsync\0"; + "notrunc\0""sync\0""noerror\0""fsync\0""swab\0"; #endif enum { OP_bs = 0, @@ -153,11 +186,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv) 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 - //swab swap every pair of input bytes //lcase change upper case to lower case //ucase change lower case to upper case //block pad newline-terminated records with spaces to cbs-size @@ -165,22 +198,33 @@ int dd_main(int argc UNUSED_PARAM, char **argv) //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 #endif }; - int exitcode = EXIT_FAILURE; - size_t ibs = 512, obs = 512; - ssize_t n, w; - char *ibuf, *obuf; - /* And these are all zeroed at once! */ + smallint 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 { int flags; size_t oc; + ssize_t prev_read_size; /* for detecting swab failure */ off_t count; off_t seek, skip; const char *infile, *outfile; } Z; #define flags (Z.flags ) #define oc (Z.oc ) +#define prev_read_size (Z.prev_read_size) #define count (Z.count ) #define seek (Z.seek ) #define skip (Z.skip ) @@ -191,10 +235,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) INIT_G(); //fflush_all(); - is this needed because of NOEXEC? - for (n = 1; argv[n]; n++) { + for (i = 1; argv[i]; i++) { int what; char *val; - char *arg = argv[n]; + char *arg = argv[i]; #if ENABLE_DESKTOP /* "dd --". NB: coreutils 6.9 will complain if they see @@ -223,6 +267,7 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } if (what == OP_conv) { while (1) { + int n; /* 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. @@ -230,20 +275,21 @@ int dd_main(int argc UNUSED_PARAM, char **argv) arg = strchr(val, ','); if (arg) *arg = '\0'; - what = index_in_strings(conv_words, val); - if (what < 0) + n = index_in_strings(conv_words, val); + if (n < 0) bb_error_msg_and_die(bb_msg_invalid_arg, val, "conv"); - flags |= (1 << what); + 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 ',' */ } - continue; /* we trashed 'what', can't fall through */ + /*continue;*/ } #endif if (what == OP_bs) { - ibs = obs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); + ibs = xatoul_range_sfx(val, 1, ((size_t)-1L)/2, dd_suffixes); + obs = ibs; /*continue;*/ } /* These can be large: */ @@ -268,14 +314,17 @@ int dd_main(int argc UNUSED_PARAM, char **argv) outfile = val; /*continue;*/ } - } /* end of "for (argv[n])" */ + } /* end of "for (argv[i])" */ //XXX:FIXME for huge ibs or obs, malloc'ing them isn't the brightest idea ever - ibuf = obuf = xmalloc(ibs); + ibuf = xmalloc(ibs); + obuf = ibuf; +#if ENABLE_FEATURE_DD_IBS_OBS if (ibs != obs) { flags |= FLAG_TWOBUFS; obuf = xmalloc(obs); } +#endif #if ENABLE_FEATURE_DD_SIGNAL_HANDLING signal_SA_RESTART_empty_mask(SIGUSR1, dd_output_status); @@ -284,12 +333,12 @@ int dd_main(int argc UNUSED_PARAM, char **argv) G.begin_time_us = monotonic_us(); #endif - if (infile != NULL) + if (infile) { xmove_fd(xopen(infile, O_RDONLY), ifd); - else { + } else { infile = bb_msg_standard_input; } - if (outfile != NULL) { + if (outfile) { int oflag = O_WRONLY | O_CREAT; if (!seek && !(flags & FLAG_NOTRUNC)) @@ -314,13 +363,13 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } if (skip) { if (lseek(ifd, skip * ibs, SEEK_CUR) < 0) { - while (skip-- > 0) { - n = safe_read(ifd, ibuf, ibs); + do { + ssize_t n = safe_read(ifd, ibuf, ibs); if (n < 0) goto die_infile; if (n == 0) break; - } + } while (--skip != 0); } } if (seek) { @@ -329,6 +378,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } while (!(flags & FLAG_COUNT) || (G.in_full + G.in_part != count)) { + ssize_t n; + n = safe_read(ifd, ibuf, ibs); if (n == 0) break; @@ -343,6 +394,27 @@ int dd_main(int argc UNUSED_PARAM, char **argv) * conv=noerror just ignores input bad blocks */ n = 0; } + if (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++; + } + } if ((size_t)n == ibs) G.in_full++; else { @@ -369,8 +441,10 @@ int dd_main(int argc UNUSED_PARAM, char **argv) oc = 0; } } - } else if (write_and_stats(ibuf, n, obs, outfile)) - goto out_status; + } else { + if (write_and_stats(ibuf, n, obs, outfile)) + goto out_status; + } if (flags & FLAG_FSYNC) { if (fsync(ofd) < 0) @@ -379,9 +453,8 @@ int dd_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_DD_IBS_OBS && oc) { - w = full_write_or_warn(obuf, oc, outfile); - if (w < 0) goto out_status; - if (w > 0) G.out_part++; + if (write_and_stats(obuf, oc, obs, outfile)) + goto out_status; } if (close(ifd) < 0) { die_infile: @@ -397,5 +470,11 @@ int dd_main(int argc UNUSED_PARAM, char **argv) out_status: dd_output_status(0); + if (ENABLE_FEATURE_CLEAN_UP) { + free(obuf); + if (flags & FLAG_TWOBUFS) + free(ibuf); + } + return exitcode; } diff --git a/coreutils/df.c b/coreutils/df.c index 5eeb5b4..5e9a867 100644 --- a/coreutils/df.c +++ b/coreutils/df.c @@ -5,7 +5,7 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 _NOT_ compliant -- option -t missing. */ @@ -22,6 +22,40 @@ * Implement -P and -B; better coreutils compat; cleanup */ +//usage:#define df_trivial_usage +//usage: "[-Pk" +//usage: IF_FEATURE_HUMAN_READABLE("mh") +//usage: IF_FEATURE_DF_FANCY("ai] [-B SIZE") +//usage: "] [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: 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" @@ -76,9 +110,9 @@ int df_main(int argc UNUSED_PARAM, char **argv) df_disp_hr = xatoul_range(chp, 1, ULONG_MAX); /* disallow 0 */ /* From the manpage of df from coreutils-6.10: - Disk space is shown in 1K blocks by default, unless the environment - variable POSIXLY_CORRECT is set, in which case 512-byte blocks are used. - */ + * 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; @@ -160,7 +194,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) } /* GNU coreutils 6.10 skips certain mounts, try to be compatible. */ - if (strcmp(device, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(device, "rootfs") == 0) continue; #ifdef WHY_WE_DO_IT_FOR_DEV_ROOT_ONLY @@ -178,7 +212,7 @@ int df_main(int argc UNUSED_PARAM, char **argv) { uni_stat_t uni_stat; char *uni_dev = unicode_conv_to_printable(&uni_stat, device); - if (uni_stat.unicode_width > 20) { + 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, ""); @@ -186,8 +220,8 @@ int df_main(int argc UNUSED_PARAM, char **argv) free(uni_dev); } #else - if (printf("\n%-20s" + 1, device) > 20) - printf("\n%-20s", ""); + if (printf("\n%-20s" + 1, device) > 20 && !(opt & OPT_POSIX)) + printf("\n%-20s", ""); #endif #if ENABLE_FEATURE_HUMAN_READABLE diff --git a/coreutils/dirname.c b/coreutils/dirname.c index 94c22a7..101067c 100644 --- a/coreutils/dirname.c +++ b/coreutils/dirname.c @@ -4,12 +4,23 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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! */ diff --git a/coreutils/dos2unix.c b/coreutils/dos2unix.c index e06ecc4..07398bd 100644 --- a/coreutils/dos2unix.c +++ b/coreutils/dos2unix.c @@ -9,11 +9,29 @@ * * dos2unix filters reading input from stdin and writing output to stdout. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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 @@ -39,12 +57,10 @@ static void convert(char *fn, int conv_type) fstat(fileno(in), &st); temp_fn = xasprintf("%sXXXXXX", resolved_fn); - i = mkstemp(temp_fn); - if (i == -1 - || fchmod(i, st.st_mode) == -1 - ) { + i = xmkstemp(temp_fn); + if (fchmod(i, st.st_mode) == -1) bb_simple_perror_msg_and_die(temp_fn); - } + out = xfdopen_for_write(i); } diff --git a/coreutils/du.c b/coreutils/du.c index 5894ed4..9c6ff88 100644 --- a/coreutils/du.c +++ b/coreutils/du.c @@ -6,7 +6,7 @@ * Copyright (C) 1999,2000,2001 by John Beppu * Copyright (C) 2002 Edward Betts * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant (unless default blocksize set to 1k) */ @@ -23,6 +23,40 @@ * 4) Fixed busybox bug #1284 involving long overflow with human_readable. */ +//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 each FILE and/or directory\n" +//usage: "\n -a Show file sizes too" +//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" enum { @@ -52,9 +86,14 @@ struct globals { dev_t dir_dev; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) -static void print(unsigned long size, const char *filename) +/* FIXME? coreutils' du rounds sizes up: + * for example, 1025k file is shown as "2" by du -m. + * We round to nearest. + */ +static void print(unsigned long long size, const char *filename) { /* TODO - May not want to defer error checking here. */ #if ENABLE_FEATURE_HUMAN_READABLE @@ -68,15 +107,15 @@ static void print(unsigned long size, const char *filename) size++; size >>= 1; } - printf("%lu\t%s\n", size, filename); + printf("%llu\t%s\n", size, filename); #endif } /* tiny recursive du */ -static unsigned long du(const char *filename) +static unsigned long long du(const char *filename) { struct stat statbuf; - unsigned long sum; + unsigned long long sum; if (lstat(filename, &statbuf) != 0) { bb_simple_perror_msg(filename); @@ -153,10 +192,12 @@ static unsigned long du(const char *filename) int du_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int du_main(int argc UNUSED_PARAM, char **argv) { - unsigned long total; + 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_hr = 1024;) IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;) diff --git a/coreutils/echo.c b/coreutils/echo.c index 6903996..9663894 100644 --- a/coreutils/echo.c +++ b/coreutils/echo.c @@ -5,7 +5,7 @@ * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice is retained at the end of this file. */ @@ -23,128 +23,161 @@ * The previous version did not allow 4-digit octals. */ +//usage:#define echo_trivial_usage +//usage: IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." +//usage:#define echo_full_usage "\n\n" +//usage: "Print the specified ARGs to stdout" +//usage: IF_FEATURE_FANCY_ECHO( "\n" +//usage: "\n -n Suppress trailing newline" +//usage: "\n -e Interpret backslash escapes (i.e., \\t=tab)" +//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; #if !ENABLE_FEATURE_FANCY_ECHO enum { eflag = '\\', nflag = 1, /* 1 -- print '\n' */ }; - /* We must check that stdout is not closed. - * The reason for this is highly non-obvious. - * echo_main is used from shell. Shell must correctly handle "echo foo" - * if stdout is closed. With stdio, output gets shoveled into - * stdout buffer, and even fflush cannot clear it out. It seems that - * even if libc receives EBADF on write attempts, it feels determined - * to output data no matter what. So it will try later, - * and possibly will clobber future output. Not good. */ -// TODO: check fcntl() & O_ACCMODE == O_WRONLY or O_RDWR? - if (fcntl(1, F_GETFL) == -1) - return 1; /* match coreutils 6.10 (sans error msg to stderr) */ - //if (dup2(1, 1) != 1) - old way - // return 1; - - arg = *++argv; - if (!arg) - goto newline_ret; + argv++; #else - const char *p; char nflag = 1; char eflag = 0; - /* We must check that stdout is not closed. */ - if (fcntl(1, F_GETFL) == -1) - return 1; + while ((arg = *++argv) != NULL) { + char n, e; - while (1) { - arg = *++argv; - if (!arg) - goto newline_ret; - if (*arg != '-') - break; + 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. */ - p = arg + 1; - if (!*p) /* A single '-', so echo it. */ - goto just_echo; - + arg++; + n = nflag; + e = eflag; do { - if (!strrchr("neE", *p)) + 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 (*++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); + } + } while (*++arg); + nflag = n; + eflag = e; } just_echo: #endif - while (1) { - /* arg is already == *argv and isn't NULL */ + + 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 */ - fputs(arg, stdout); - } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + 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 + /* "\c" means cancel newline and * ignore all subsequent chars. */ - goto ret; + goto do_write; } -#if !ENABLE_FEATURE_FANCY_ECHO - /* SUSv3 specifies that octal escapes must begin with '0'. */ - if ( ((int)(unsigned char)(*arg) - '0') >= 8) /* '8' or bigger */ -#endif - { - /* Since SUSv3 mandates a first digit of 0, 4-digit octals - * of the form \0### are accepted. */ - if (*arg == '0') { - /* NB: don't turn "...\0" into "...\" */ - if (arg[1] && ((unsigned char)(arg[1]) - '0') < 8) { - arg++; - } + /* 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). */ - c = bb_process_escape_sequence(&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; } } - bb_putchar(c); + *out++ = c; } - arg = *++argv; - if (!arg) + if (!*++argv) break; - bb_putchar(' '); + *out++ = ' '; } - newline_ret: if (nflag) { - bb_putchar('\n'); + *out++ = '\n'; } - ret: - return fflush_all(); + + do_write: + /* Careful to error out on partial writes too (think ENOSPC!) */ + errno = 0; + /*r =*/ full_write(STDOUT_FILENO, buffer, out - buffer); + free(buffer); + if (/*WRONG:r < 0*/ errno) { + bb_perror_msg(bb_msg_write_error); + return 1; + } + return 0; } -/*- +/* * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * @@ -230,7 +263,7 @@ int echo_main(int argc, char **argv) goto just_echo; do { - if (!strrchr("neE", *p)) + if (!strchr("neE", *p)) goto just_echo; } while (*++p); @@ -256,27 +289,23 @@ int echo_main(int argc, char **argv) /* optimization for very common case */ p += strlen(arg); } else while ((c = *arg++)) { - if (c == eflag) { /* Check for escape seq. */ + if (c == eflag) { + /* This is an "\x" sequence */ + if (*arg == 'c') { - /* '\c' means cancel newline and + /* "\c" means cancel newline and * ignore all subsequent chars. */ cur_io->iov_len = p - (char*)cur_io->iov_base; cur_io++; goto ret; } -#if !ENABLE_FEATURE_FANCY_ECHO - /* SUSv3 specifies that octal escapes must begin with '0'. */ - if ( (((unsigned char)*arg) - '1') >= 7) -#endif - { - /* Since SUSv3 mandates a first digit of 0, 4-digit octals - * of the form \0### are accepted. */ - if (*arg == '0' && ((unsigned char)(arg[1]) - '0') < 8) { - arg++; - } - /* bb_process_escape_sequence can handle nul correctly */ - c = bb_process_escape_sequence( (void*) &arg); + /* Since SUSv3 mandates a first digit of 0, 4-digit octals + * of the form \0### are accepted. */ + if (*arg == '0' && (unsigned char)(arg[1] - '0') < 8) { + arg++; } + /* bb_process_escape_sequence can handle nul correctly */ + c = bb_process_escape_sequence( (void*) &arg); } *p++ = c; } diff --git a/coreutils/env.c b/coreutils/env.c index d4eab19..807ef13 100644 --- a/coreutils/env.c +++ b/coreutils/env.c @@ -3,9 +3,9 @@ * env implementation for busybox * * Copyright (c) 1988, 1993, 1994 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice is retained at the end of this file. * @@ -31,6 +31,14 @@ /* This is a NOEXEC applet. Be very careful! */ +//usage:#define env_trivial_usage +//usage: "[-iu] [-] [name=value]... [PROG ARGS]" +//usage:#define env_full_usage "\n\n" +//usage: "Print the current environment or run PROG after setting up\n" +//usage: "the specified environment\n" +//usage: "\n -, -i Start with an empty environment" +//usage: "\n -u Remove variable from the environment" + #include "libbb.h" #if ENABLE_FEATURE_ENV_LONG_OPTIONS @@ -103,8 +111,8 @@ int env_main(int argc UNUSED_PARAM, char **argv) * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * 3. + * 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 diff --git a/coreutils/expand.c b/coreutils/expand.c index b874b6a..8d376ff 100644 --- a/coreutils/expand.c +++ b/coreutils/expand.c @@ -3,7 +3,7 @@ * * Copyright (C) 89, 91, 1995-2006 Free Software Foundation, Inc. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * David MacKenzie * @@ -20,6 +20,35 @@ * * Caveat: this versions of expand and unexpand don't accept tab lists. */ + +//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: IF_FEATURE_EXPAND_LONG_OPTIONS( +//usage: "\n -i,--initial Don't convert tabs after non blanks" +//usage: "\n -t,--tabs=N Tabstops every N chars" +//usage: ) +//usage: IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( +//usage: "\n -i Don't convert tabs after non blanks" +//usage: "\n -t Tabstops every N chars" +//usage: ) + +//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: IF_FEATURE_UNEXPAND_LONG_OPTIONS( +//usage: "\n -a,--all Convert all blanks" +//usage: "\n -f,--first-only Convert only leading blanks" +//usage: "\n -t,--tabs=N Tabstops every N chars" +//usage: ) +//usage: IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( +//usage: "\n -a Convert all blanks" +//usage: "\n -f Convert only leading blanks" +//usage: "\n -t N Tabstops every N chars" +//usage: ) + #include "libbb.h" #include "unicode.h" @@ -49,11 +78,7 @@ static void expand(FILE *file, unsigned tab_size, unsigned opt) unsigned len; *ptr = '\0'; # if ENABLE_UNICODE_SUPPORT - { - uni_stat_t uni_stat; - printable_string(&uni_stat, ptr_strbeg); - len = uni_stat.unicode_width; - } + len = unicode_strwidth(ptr_strbeg); # else len = ptr - ptr_strbeg; # endif @@ -109,12 +134,9 @@ static void unexpand(FILE *file, unsigned tab_size, unsigned opt) printf("%*s%.*s", len, "", n, ptr); # if ENABLE_UNICODE_SUPPORT { - char c; - uni_stat_t uni_stat; - c = ptr[n]; + char c = ptr[n]; ptr[n] = '\0'; - printable_string(&uni_stat, ptr); - len = uni_stat.unicode_width; + len = unicode_strwidth(ptr); ptr[n] = c; } # else diff --git a/coreutils/expr.c b/coreutils/expr.c index f40edad..c986f93 100644 --- a/coreutils/expr.c +++ b/coreutils/expr.c @@ -11,7 +11,7 @@ * - reduced 464 bytes. * - 64 math support * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* This program evaluates expressions. Each token (operator, operand, @@ -25,6 +25,41 @@ /* no getopt needed */ +//usage:#define expr_trivial_usage +//usage: "EXPRESSION" +//usage:#define expr_full_usage "\n\n" +//usage: "Print the value of EXPRESSION to stdout\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 LENGTH Substring of STRING, POS counted 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 "xregex.h" @@ -65,6 +100,7 @@ struct globals { char **args; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) /* forward declarations */ static VALUE *eval(void); @@ -341,7 +377,6 @@ static VALUE *eval6(void) freev(i2); } return v; - } /* Handle : operator (pattern matching). @@ -485,6 +520,8 @@ 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) { diff --git a/coreutils/false.c b/coreutils/false.c index f448ebf..59c2f32 100644 --- a/coreutils/false.c +++ b/coreutils/false.c @@ -4,12 +4,22 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/000095399/utilities/false.html */ +//usage:#define false_trivial_usage +//usage: "" +//usage:#define false_full_usage "\n\n" +//usage: "Return an exit code of FALSE (1)" +//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! */ diff --git a/coreutils/fold.c b/coreutils/fold.c index cbea31f..0e73063 100644 --- a/coreutils/fold.c +++ b/coreutils/fold.c @@ -7,11 +7,22 @@ Modified for busybox based on coreutils v 5.0 Copyright (C) 2003 Glenn McGrath - Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define fold_trivial_usage +//usage: "[-bs] [-w WIDTH] [FILE]..." +//usage:#define fold_full_usage "\n\n" +//usage: "Wrap input lines in each FILE (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 diff --git a/coreutils/fsync.c b/coreutils/fsync.c index 53900f8..652a41c 100644 --- a/coreutils/fsync.c +++ b/coreutils/fsync.c @@ -4,8 +4,15 @@ * * Copyright (C) 2008 Nokia Corporation. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define fsync_trivial_usage +//usage: "[-d] FILE..." +//usage:#define fsync_full_usage "\n\n" +//usage: "Write files' buffered blocks to disk\n" +//usage: "\n -d Avoid syncing metadata" + #include "libbb.h" #ifndef O_NOATIME # define O_NOATIME 0 @@ -27,7 +34,7 @@ int fsync_main(int argc UNUSED_PARAM, char **argv) status = EXIT_SUCCESS; do { - int fd = open3_or_warn(*argv, O_NOATIME | O_NOCTTY | O_RDONLY, 0); + int fd = open_or_warn(*argv, O_NOATIME | O_NOCTTY | O_RDONLY); if (fd == -1) { status = EXIT_FAILURE; diff --git a/coreutils/head.c b/coreutils/head.c index cc28374..9388b02 100644 --- a/coreutils/head.c +++ b/coreutils/head.c @@ -4,15 +4,143 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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 */ +//kbuild:lib-$(CONFIG_HEAD) += head.o + +//usage:#define head_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define head_full_usage "\n\n" +//usage: "Print first 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -n N[kbm] Print first N lines" +//usage: IF_FEATURE_FANCY_HEAD( +//usage: "\n -n -N[kbm] Print all except N last lines" +//usage: "\n -c [-]N[kbm] Print first N bytes" +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: ) +//usage: "\n" +//usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." +//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(circle[head], stdout); + 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 @@ -20,29 +148,25 @@ static const char head_opts[] ALIGN1 = #endif ; -static const struct suffix_mult head_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1024*1024 }, - { "", 0 } -}; - #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; - unsigned long i; #if ENABLE_FEATURE_FANCY_HEAD - int count_bytes = 0; 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 c; int retval = EXIT_SUCCESS; #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD @@ -52,7 +176,7 @@ int head_main(int argc, char **argv) ) { --argc; ++argv; - p = (*argv) + 1; + p = argv[0] + 1; goto GET_COUNT; } #endif @@ -76,7 +200,7 @@ int head_main(int argc, char **argv) #if ENABLE_INCLUDE_SUSv2 || ENABLE_FEATURE_FANCY_HEAD GET_COUNT: #endif - count = xatoul_sfx(p, head_suffixes); + count = eat_num(&negative_N, p); break; default: bb_show_usage(); @@ -89,19 +213,17 @@ int head_main(int argc, char **argv) *--argv = (char*)"-"; fmt = header_fmt_str + 1; -#if ENABLE_FEATURE_FANCY_HEAD if (argc <= header_threshhold) { +#if ENABLE_FEATURE_FANCY_HEAD header_threshhold = 0; - } #else - if (argc <= 1) { fmt += 11; /* "" */ - } - /* Now define some things here to avoid #ifdefs in the code below. - * These should optimize out of the if conditions below. */ -#define header_threshhold 1 -#define count_bytes 0 #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); @@ -112,18 +234,20 @@ int head_main(int argc, char **argv) if (header_threshhold) { printf(fmt, *argv); } - i = count; - while (i && ((c = getc(fp)) != EOF)) { - if (count_bytes || (c == '\n')) { - --i; + if (negative_N) { + if (count_bytes) { + print_except_N_last_bytes(fp, count); + } else { + print_except_N_last_lines(fp, count); } - putchar(c); + } 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; } - die_if_ferror_stdout(); } else { retval = EXIT_FAILURE; } diff --git a/coreutils/hostid.c b/coreutils/hostid.c index a537e3a..e5b1f51 100644 --- a/coreutils/hostid.c +++ b/coreutils/hostid.c @@ -4,11 +4,27 @@ * * Copyright (C) 2000 Edward Betts . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//config:config HOSTID +//config: bool "hostid" +//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 + +//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! */ @@ -20,7 +36,8 @@ int hostid_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) bb_show_usage(); } - printf("%lx\n", gethostid()); + /* POSIX says gethostid returns a "32-bit identifier" */ + printf("%08x\n", (unsigned)(uint32_t)gethostid()); return fflush_all(); } diff --git a/coreutils/id.c b/coreutils/id.c index ec9227d..1f3e1c4 100644 --- a/coreutils/id.c +++ b/coreutils/id.c @@ -5,7 +5,7 @@ * Copyright (C) 2000 by Randolph Chung * Copyright (C) 2008 by Tito Ragusa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant. */ @@ -15,15 +15,59 @@ * Added -G option Tito Ragusa (C) 2008 for SUSv3. */ +//config:config ID +//config: bool "id" +//config: default y +//config: help +//config: id displays the current user and group ID names. + +//config:config GROUPS +//config: bool "groups" +//config: default y +//config: help +//config: Print the group names associated with current user id. + +//kbuild:lib-$(CONFIG_GROUPS) += id.o +//kbuild:lib-$(CONFIG_ID) += id.o + +//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 )) + +//usage:#define id_trivial_usage +//usage: "[OPTIONS] [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 group memberships of USER or for the current process" +//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_MAJOR__) && (__UCLIBC_MAJOR__ == 0) -#if (__UCLIBC_MINOR__ < 9) || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ < 30) +#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 -#endif enum { PRINT_REAL = (1 << 0), @@ -71,7 +115,7 @@ static int print_user(uid_t id, const char *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) + * (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) @@ -85,20 +129,19 @@ static int get_groups(const char *username, gid_t rgid, gid_t *groups, int *n) m = getgrouplist(username, rgid, groups, n); /* I guess *n < 0 might indicate error. Anyway, * malloc'ing -1 bytes won't be good, so: */ - //if (*n < 0) - // return 0; - //return m; - //commented out here, happens below anyway - } else { - /* On error -1 is returned, which ends up in *n */ - int nn = getgroups(*n, groups); - /* 0: nn <= *n, groups[] was big enough; -1 otherwise */ - m = - (nn > *n); - *n = nn; + if (*n < 0) + return 0; + return m; } - if (*n < 0) - return 0; /* error, don't 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; @@ -116,11 +159,22 @@ int id_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_SELINUX security_context_t scontext = NULL; #endif - /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ - /* Don't allow more than one username */ - opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" - IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); - opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); + + 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_complementary = "?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"); + opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); + } username = argv[optind]; if (username) { @@ -157,11 +211,11 @@ int id_main(int argc UNUSED_PARAM, char **argv) /* We are supplying largish buffer, trying * to not run get_groups() twice. That might be slow * ("user database in remote SQL server" case) */ - groups = xmalloc(64 * sizeof(gid_t)); + 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(gid_t)); + groups = xrealloc(groups, n * sizeof(groups[0])); get_groups(username, rgid, groups, &n); } if (n > 0) { @@ -174,10 +228,9 @@ int id_main(int argc UNUSED_PARAM, char **argv) prefix = ","; } } else if (n < 0) { /* error in get_groups() */ - if (!ENABLE_DESKTOP) + if (ENABLE_DESKTOP) bb_error_msg_and_die("can't get groups"); - else - return EXIT_FAILURE; + return EXIT_FAILURE; } if (ENABLE_FEATURE_CLEAN_UP) free(groups); diff --git a/coreutils/install.c b/coreutils/install.c index ab9feff..445497f 100644 --- a/coreutils/install.c +++ b/coreutils/install.c @@ -3,9 +3,26 @@ * Copyright (C) 2003 by Glenn McGrath * SELinux support: by Yuichi Nakamura * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +/* -v, -b, -c are ignored */ +//usage:#define install_trivial_usage +//usage: "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [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: IF_SELINUX( +//usage: "\n -Z Set security context" +//usage: ) + #include "libbb.h" #include "libcoreutils/coreutils.h" diff --git a/coreutils/length.c b/coreutils/length.c.disabled similarity index 57% rename from coreutils/length.c rename to coreutils/length.c.disabled index 015b221..aee898d 100644 --- a/coreutils/length.c +++ b/coreutils/length.c.disabled @@ -1,10 +1,19 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A -- Apparently a busybox (obsolete?) extension. */ +//usage:#define length_trivial_usage +//usage: "STRING" +//usage:#define length_full_usage "\n\n" +//usage: "Print STRING's length" +//usage: +//usage:#define length_example_usage +//usage: "$ length Hello\n" +//usage: "5\n" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/coreutils/libcoreutils/Kbuild.src b/coreutils/libcoreutils/Kbuild.src index 981b606..2042d5f 100644 --- a/coreutils/libcoreutils/Kbuild.src +++ b/coreutils/libcoreutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2004 by Erik Andersen # -# Licensed under the GPL v2 or later, see the file LICENSE in this tarball. +# Licensed under GPLv2 or later, see file LICENSE in this source tree. lib-y:= diff --git a/coreutils/libcoreutils/coreutils.h b/coreutils/libcoreutils/coreutils.h index 99b67b1..307d033 100644 --- a/coreutils/libcoreutils/coreutils.h +++ b/coreutils/libcoreutils/coreutils.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef COREUTILS_H diff --git a/coreutils/ln.c b/coreutils/ln.c index f977aa1..3b822e8 100644 --- a/coreutils/ln.c +++ b/coreutils/ln.c @@ -4,23 +4,42 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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: "[OPTIONS] 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 2nd arg must be a 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 -#define LN_FORCE 2 -#define LN_NODEREFERENCE 4 -#define LN_BACKUP 8 -#define LN_SUFFIX 16 +#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) @@ -35,13 +54,22 @@ int ln_main(int argc, char **argv) int (*link_func)(const char *, const char *); opt_complementary = "-1"; /* min one arg */ - opts = getopt32(argv, "sfnbS:", &suffix); + opts = getopt32(argv, "sfnbS:vT", &suffix); last = argv[argc - 1]; argv += optind; + argc -= optind; + + if ((opts & LN_LINKFILE) && argc > 2) { + bb_error_msg_and_die("-T accepts 2 args max"); + } - if (argc == optind + 1) { + 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)); } @@ -50,9 +78,12 @@ int ln_main(int argc, char **argv) src = last; if (is_directory(src, - (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE, - NULL) + (opts & LN_NODEREFERENCE) ^ LN_NODEREFERENCE + ) ) { + 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); @@ -93,6 +124,10 @@ int ln_main(int argc, char **argv) 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; diff --git a/coreutils/logname.c b/coreutils/logname.c index 8357b9a..10b9615 100644 --- a/coreutils/logname.c +++ b/coreutils/logname.c @@ -4,7 +4,7 @@ * * Copyright (C) 2000 Edward Betts . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -20,6 +20,15 @@ * a diagnostic message and an error return. */ +//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! */ diff --git a/coreutils/ls.c b/coreutils/ls.c index 1197f7d..166473d 100644 --- a/coreutils/ls.c +++ b/coreutils/ls.c @@ -1,9 +1,8 @@ /* vi: set sw=4 ts=4: */ /* - * tiny-ls.c version 0.1.0: A minimalist 'ls' * Copyright (C) 1996 Brian Candler * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* [date unknown. Perhaps before year 2000] @@ -29,6 +28,70 @@ * [2009-03] * ls sorts listing now, and supports almost all options. */ + +//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_LS_TIMESTAMPS("e") +//usage: IF_FEATURE_HUMAN_READABLE("h") +//usage: IF_FEATURE_LS_SORTFILES("rSXv") +//usage: IF_FEATURE_LS_TIMESTAMPS("ctu") +//usage: IF_SELINUX("kKZ") "]" +//usage: IF_FEATURE_AUTOWIDTH(" [-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 entries which start with ." +//usage: "\n -A Like -a, but exclude . and .." +//usage: "\n -C List by columns" +//usage: "\n -x List by lines" +//usage: "\n -d List directory entries instead of 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 dir entries" +//usage: "\n -F Append indicator (one of */=@|) to entries" +//usage: ) +//usage: "\n -l Long listing 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 -e List full date and time" +//usage: ) +//usage: IF_FEATURE_HUMAN_READABLE( +//usage: "\n -h List sizes in human readable format (1K 243M 2G)" +//usage: ) +//usage: IF_FEATURE_LS_SORTFILES( +//usage: "\n -r Sort in reverse order" +//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 -c With -l: sort by ctime" +//usage: "\n -t With -l: sort by mtime" +//usage: "\n -u With -l: sort by atime" +//usage: ) +//usage: IF_SELINUX( +//usage: "\n -k List security context" +//usage: "\n -K List security context in long format" +//usage: "\n -Z List security context and permission" +//usage: ) +//usage: IF_FEATURE_AUTOWIDTH( +//usage: "\n -w N Assume the terminal is N columns wide" +//usage: ) +//usage: IF_FEATURE_LS_COLOR( +//usage: "\n --color[={always,never,auto}] Control coloring" +//usage: ) + #include "libbb.h" #include "unicode.h" @@ -52,15 +115,13 @@ enum { - TERMINAL_WIDTH = 80, /* use 79 if terminal has linefold bug */ -COLUMN_GAP = 2, /* includes the file type char */ -/* what is the overall style of the listing */ -STYLE_COLUMNS = 1 << 21, /* fill columns */ -STYLE_LONG = 2 << 21, /* one record per line, extended info */ -STYLE_SINGLE = 3 << 21, /* one record per line */ -STYLE_MASK = STYLE_SINGLE, +SPLIT_FILE = 0, +SPLIT_DIR = 1, +SPLIT_SUBDIR = 2, + +/* Bits in G.all_fmt: */ /* 51306 lrwxrwxrwx 1 root root 2 May 11 01:43 /bin/view -> vi* */ /* what file information will be listed */ @@ -72,77 +133,75 @@ LIST_ID_NAME = 1 << 4, LIST_ID_NUMERIC = 1 << 5, LIST_CONTEXT = 1 << 6, LIST_SIZE = 1 << 7, -//LIST_DEV = 1 << 8, - unused, synonym to LIST_SIZE -LIST_DATE_TIME = 1 << 9, -LIST_FULLTIME = 1 << 10, -LIST_FILENAME = 1 << 11, -LIST_SYMLINK = 1 << 12, -LIST_FILETYPE = 1 << 13, -LIST_EXEC = 1 << 14, -LIST_MASK = (LIST_EXEC << 1) - 1, +LIST_DATE_TIME = 1 << 8, +LIST_FULLTIME = 1 << 9, +LIST_SYMLINK = 1 << 10, +LIST_FILETYPE = 1 << 11, /* show / suffix for dirs */ +LIST_CLASSIFY = 1 << 12, /* requires LIST_FILETYPE, also show *,|,@,= suffixes */ +LIST_MASK = (LIST_CLASSIFY << 1) - 1, /* what files will be displayed */ -DISP_DIRNAME = 1 << 15, /* 2 or more items? label directories */ -DISP_HIDDEN = 1 << 16, /* show filenames starting with . */ -DISP_DOT = 1 << 17, /* show . and .. */ -DISP_NOLIST = 1 << 18, /* show directory as itself, not contents */ -DISP_RECURSIVE = 1 << 19, /* show directory and everything below it */ -DISP_ROWS = 1 << 20, /* print across rows */ +DISP_DIRNAME = 1 << 13, /* 2 or more items? label directories */ +DISP_HIDDEN = 1 << 14, /* show filenames starting with . */ +DISP_DOT = 1 << 15, /* show . and .. */ +DISP_NOLIST = 1 << 16, /* show directory as itself, not contents */ +DISP_RECURSIVE = 1 << 17, /* show directory and everything below it */ +DISP_ROWS = 1 << 18, /* print across rows */ DISP_MASK = ((DISP_ROWS << 1) - 1) & ~(DISP_DIRNAME - 1), -/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ -SORT_FORWARD = 0, /* sort in reverse order */ -SORT_REVERSE = 1 << 27, /* sort in reverse order */ - -SORT_NAME = 0, /* sort by file name */ -SORT_SIZE = 1 << 28, /* sort by file size */ -SORT_ATIME = 2 << 28, /* sort by last access time */ -SORT_CTIME = 3 << 28, /* sort by last change time */ -SORT_MTIME = 4 << 28, /* sort by last modification time */ -SORT_VERSION = 5 << 28, /* sort by version */ -SORT_EXT = 6 << 28, /* sort by file name extension */ -SORT_DIR = 7 << 28, /* sort by file or directory */ -SORT_MASK = (7 << 28) * ENABLE_FEATURE_LS_SORTFILES, +/* what is the overall style of the listing */ +STYLE_COLUMNAR = 1 << 19, /* many records per line */ +STYLE_LONG = 2 << 19, /* one record per line, extended info */ +STYLE_SINGLE = 3 << 19, /* one record per line */ +STYLE_MASK = STYLE_SINGLE, /* which of the three times will be used */ -TIME_CHANGE = (1 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, -TIME_ACCESS = (1 << 24) * ENABLE_FEATURE_LS_TIMESTAMPS, -TIME_MASK = (3 << 23) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_CHANGE = (1 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_ACCESS = (2 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, +TIME_MASK = (3 << 21) * ENABLE_FEATURE_LS_TIMESTAMPS, -FOLLOW_LINKS = (1 << 25) * ENABLE_FEATURE_LS_FOLLOWLINKS, +/* how will the files be sorted (CONFIG_FEATURE_LS_SORTFILES) */ +SORT_REVERSE = 1 << 23, -LS_DISP_HR = (1 << 26) * ENABLE_FEATURE_HUMAN_READABLE, +SORT_NAME = 0, /* sort by file name */ +SORT_SIZE = 1 << 24, /* sort by file size */ +SORT_ATIME = 2 << 24, /* sort by last access time */ +SORT_CTIME = 3 << 24, /* sort by last change time */ +SORT_MTIME = 4 << 24, /* sort by last modification time */ +SORT_VERSION = 5 << 24, /* sort by version */ +SORT_EXT = 6 << 24, /* sort by file name extension */ +SORT_DIR = 7 << 24, /* sort by file or directory */ +SORT_MASK = (7 << 24) * ENABLE_FEATURE_LS_SORTFILES, -LIST_SHORT = LIST_FILENAME, LIST_LONG = LIST_MODEBITS | LIST_NLINKS | LIST_ID_NAME | LIST_SIZE | \ - LIST_DATE_TIME | LIST_FILENAME | LIST_SYMLINK, - -SPLIT_DIR = 1, -SPLIT_FILE = 0, -SPLIT_SUBDIR = 2, - + LIST_DATE_TIME | LIST_SYMLINK, }; -/* "[-]Cadil1", POSIX mandated options, busybox always supports */ -/* "[-]gnsx", POSIX non-mandated options, busybox always supports */ -/* "[-]Q" GNU option? busybox always supports */ -/* "[-]Ak" GNU options, busybox always supports */ -/* "[-]FLRctur", POSIX mandated options, busybox optionally supports */ -/* "[-]p", POSIX non-mandated options, busybox optionally supports */ -/* "[-]SXvThw", GNU options, busybox optionally supports */ -/* "[-]K", SELinux mandated options, busybox optionally supports */ -/* "[-]e", I think we made this one up */ +/* -Cadil1 Std options, busybox always supports */ +/* -gnsxA Std options, busybox always supports */ +/* -Q GNU option, busybox always supports */ +/* -k SELinux option, busybox always supports (ignores if !SELinux) */ +/* Std has -k which means "show sizes in kbytes" */ +/* -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) */ +/* -KZ SELinux mandated options, busybox optionally supports */ +/* (coreutils 8.4 has no -K, remove it?) */ +/* -e I think we made this one up (looks similar to GNU --full-time) */ +/* We already used up all 32 bits, if we need to add more, candidates for removal: */ +/* -K, -T, -e (add --full-time instead) */ static const char ls_options[] ALIGN1 = - "Cadil1gnsxQAk" /* 13 opts, total 13 */ + "Cadil1gnsxQAk" /* 13 opts, total 13 */ IF_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */ IF_FEATURE_LS_SORTFILES("SXrv") /* 4, 21 */ IF_FEATURE_LS_FILETYPES("Fp") /* 2, 23 */ - IF_FEATURE_LS_FOLLOWLINKS("L") /* 1, 24 */ - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ - ; + IF_FEATURE_LS_RECURSIVE("R") /* 1, 24 */ + IF_SELINUX("KZ") /* 2, 26 */ + IF_FEATURE_LS_FOLLOWLINKS("LH") /* 2, 28 */ + IF_FEATURE_HUMAN_READABLE("h") /* 1, 29 */ + IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 31 */ + /* with --color, we use all 32 bits */; enum { //OPT_C = (1 << 0), //OPT_a = (1 << 1), @@ -157,99 +216,149 @@ enum { OPT_Q = (1 << 10), //OPT_A = (1 << 11), //OPT_k = (1 << 12), - OPTBIT_color = 13 - + 4 * ENABLE_FEATURE_LS_TIMESTAMPS - + 4 * ENABLE_FEATURE_LS_SORTFILES - + 2 * ENABLE_FEATURE_LS_FILETYPES - + 1 * ENABLE_FEATURE_LS_FOLLOWLINKS - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_color = 1 << OPTBIT_color, -}; -enum { - LIST_MASK_TRIGGER = 0, - STYLE_MASK_TRIGGER = STYLE_MASK, - DISP_MASK_TRIGGER = DISP_ROWS, - SORT_MASK_TRIGGER = SORT_MASK, + OPTBIT_c = 13, + OPTBIT_e, + OPTBIT_t, + OPTBIT_u, + OPTBIT_S = OPTBIT_c + 4 * ENABLE_FEATURE_LS_TIMESTAMPS, + OPTBIT_X, /* 18 */ + OPTBIT_r, + OPTBIT_v, + OPTBIT_F = OPTBIT_S + 4 * ENABLE_FEATURE_LS_SORTFILES, + OPTBIT_p, /* 22 */ + OPTBIT_R = OPTBIT_F + 2 * ENABLE_FEATURE_LS_FILETYPES, + OPTBIT_K = OPTBIT_R + 1 * ENABLE_FEATURE_LS_RECURSIVE, + OPTBIT_Z, /* 25 */ + OPTBIT_L = OPTBIT_K + 2 * ENABLE_SELINUX, + OPTBIT_H, /* 27 */ + OPTBIT_h = OPTBIT_L + 2 * ENABLE_FEATURE_LS_FOLLOWLINKS, + OPTBIT_T = OPTBIT_h + 1 * ENABLE_FEATURE_HUMAN_READABLE, + OPTBIT_w, /* 30 */ + OPTBIT_color = OPTBIT_T + 2 * ENABLE_FEATURE_AUTOWIDTH, + + OPT_c = (1 << OPTBIT_c) * ENABLE_FEATURE_LS_TIMESTAMPS, + OPT_e = (1 << OPTBIT_e) * 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_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_K = (1 << OPTBIT_K) * ENABLE_SELINUX, + OPT_Z = (1 << OPTBIT_Z) * ENABLE_SELINUX, + 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_AUTOWIDTH, + OPT_w = (1 << OPTBIT_w) * ENABLE_FEATURE_AUTOWIDTH, + OPT_color = (1 << OPTBIT_color) * ENABLE_FEATURE_LS_COLOR, }; /* TODO: simple toggles may be stored as OPT_xxx bits instead */ -static const unsigned opt_flags[] = { - LIST_SHORT | STYLE_COLUMNS, /* C */ - DISP_HIDDEN | DISP_DOT, /* a */ - DISP_NOLIST, /* d */ - LIST_INO, /* i */ - LIST_LONG | STYLE_LONG, /* l - remember LS_DISP_HR in mask! */ - LIST_SHORT | STYLE_SINGLE, /* 1 */ - 0, /* g (don't show group) - handled via OPT_g */ - LIST_ID_NUMERIC, /* n */ - LIST_BLOCKS, /* s */ - DISP_ROWS, /* x */ - 0, /* Q (quote filename) - handled via OPT_Q */ - DISP_HIDDEN, /* A */ - ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ +static const uint32_t opt_flags[] = { + STYLE_COLUMNAR, /* C */ + DISP_HIDDEN | DISP_DOT, /* a */ + DISP_NOLIST, /* d */ + LIST_INO, /* i */ + LIST_LONG | STYLE_LONG, /* l */ + STYLE_SINGLE, /* 1 */ + LIST_LONG | STYLE_LONG, /* g (don't show owner) - handled via OPT_g. assumes l */ + LIST_ID_NUMERIC | LIST_LONG | STYLE_LONG, /* n (assumes l) */ + LIST_BLOCKS, /* s */ + DISP_ROWS | STYLE_COLUMNAR, /* x */ + 0, /* Q (quote filename) - handled via OPT_Q */ + DISP_HIDDEN, /* A */ + ENABLE_SELINUX * (LIST_CONTEXT|STYLE_SINGLE), /* k (ignored if !SELINUX) */ #if ENABLE_FEATURE_LS_TIMESTAMPS - TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ - LIST_FULLTIME, /* e */ - ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ - TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ + TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ + LIST_FULLTIME, /* e */ + ENABLE_FEATURE_LS_SORTFILES * SORT_MTIME, /* t */ + TIME_ACCESS | (ENABLE_FEATURE_LS_SORTFILES * SORT_ATIME), /* u */ #endif #if ENABLE_FEATURE_LS_SORTFILES - SORT_SIZE, /* S */ - SORT_EXT, /* X */ - SORT_REVERSE, /* r */ - SORT_VERSION, /* v */ + SORT_SIZE, /* S */ + SORT_EXT, /* X */ + SORT_REVERSE, /* r */ + SORT_VERSION, /* v */ #endif #if ENABLE_FEATURE_LS_FILETYPES - LIST_FILETYPE | LIST_EXEC, /* F */ - LIST_FILETYPE, /* p */ -#endif -#if ENABLE_FEATURE_LS_FOLLOWLINKS - FOLLOW_LINKS, /* L */ + LIST_FILETYPE | LIST_CLASSIFY, /* F */ + LIST_FILETYPE, /* p */ #endif #if ENABLE_FEATURE_LS_RECURSIVE - DISP_RECURSIVE, /* R */ -#endif -#if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ -#endif -#if ENABLE_SELINUX - LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ + DISP_RECURSIVE, /* R */ #endif #if ENABLE_SELINUX - LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ + LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME|STYLE_SINGLE, /* K */ + LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT|STYLE_SINGLE, /* Z */ #endif - (1U<<31) - /* options after Z are not processed through opt_flags: - * T, w - ignored - */ + (1U << 31) + /* options after Z are not processed through opt_flags */ }; /* - * a directory entry and its stat info are stored here + * a directory entry and its stat info */ struct dnode { - const char *name; /* the dir entry name */ - const char *fullname; /* the dir entry name */ - struct dnode *next; /* point at the next node */ - smallint fname_allocated; - struct stat dstat; /* the file stat info */ + 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 can 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_atime; + time_t dn_mtime; + time_t dn_ctime; +#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; unsigned all_fmt; #if ENABLE_FEATURE_AUTOWIDTH - unsigned tabstops; // = COLUMN_GAP; - unsigned terminal_width; // = TERMINAL_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" */ @@ -257,77 +366,24 @@ struct globals { #endif } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#if ENABLE_FEATURE_LS_COLOR -# define show_color (G.show_color ) -#else -enum { show_color = 0 }; -#endif -#define exit_code (G.exit_code ) -#define all_fmt (G.all_fmt ) -#if ENABLE_FEATURE_AUTOWIDTH -# define tabstops (G.tabstops ) -# define terminal_width (G.terminal_width) -#else -enum { - tabstops = COLUMN_GAP, - terminal_width = TERMINAL_WIDTH, -}; -#endif -#define current_time_t (G.current_time_t) #define INIT_G() do { \ /* we have to zero it out because of NOEXEC */ \ memset(&G, 0, sizeof(G)); \ - IF_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \ - IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \ - IF_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \ + IF_FEATURE_AUTOWIDTH(G_terminal_width = TERMINAL_WIDTH;) \ + IF_FEATURE_LS_TIMESTAMPS(time(&G.current_time_t);) \ } while (0) -static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) -{ - struct stat dstat; - struct dnode *cur; - IF_SELINUX(security_context_t sid = NULL;) +/*** Output code ***/ - if ((all_fmt & FOLLOW_LINKS) || force_follow) { -#if ENABLE_SELINUX - if (is_selinux_enabled()) { - getfilecon(fullname, &sid); - } -#endif - if (stat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; - return 0; - } - } else { -#if ENABLE_SELINUX - if (is_selinux_enabled()) { - lgetfilecon(fullname, &sid); - } -#endif - if (lstat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; - return 0; - } - } - - cur = xmalloc(sizeof(*cur)); - cur->fullname = fullname; - cur->name = name; - cur->dstat = dstat; - IF_SELINUX(cur->sid = sid;) - return cur; -} /* FYI type values: 1:fifo 2:char 4:dir 6:blk 8:file 10:link 12:socket * (various wacky OSes: 13:Sun door 14:BSD whiteout 5:XENIX named file * 3/7:multiplexed char/block device) * and we use 0 for unknown and 15 for executables (see below) */ #define TYPEINDEX(mode) (((mode) >> 12) & 0x0f) -#define TYPECHAR(mode) ("0pcCd?bB-?l?s???" [TYPEINDEX(mode)]) -#define APPCHAR(mode) ("\0|\0\0/\0\0\0\0\0@\0=\0\0\0" [TYPEINDEX(mode)]) +/* 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 @@ -338,7 +394,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f 045 gray foreground 057 white background */ #define COLOR(mode) ( \ - /*un fi chr dir blk file link sock exe */ \ + /*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) @@ -347,7 +403,7 @@ static struct dnode *my_stat(const char *fullname, const char *name, int force_f * Note: coreutils 6.9 uses inverted red for setuid binaries. */ #define ATTR(mode) ( \ - /*un fi chr dir blk file link sock exe */ \ + /*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)]) @@ -367,14 +423,14 @@ static char bold(mode_t mode) } #endif -#if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR +#if ENABLE_FEATURE_LS_FILETYPES static char append_char(mode_t mode) { - if (!(all_fmt & LIST_FILETYPE)) + if (!(G.all_fmt & LIST_FILETYPE)) return '\0'; if (S_ISDIR(mode)) return '/'; - if (!(all_fmt & LIST_EXEC)) + if (!(G.all_fmt & LIST_CLASSIFY)) return '\0'; if (S_ISREG(mode) && (mode & (S_IXUSR | S_IXGRP | S_IXOTH))) return '*'; @@ -382,149 +438,6 @@ static char append_char(mode_t mode) } #endif -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)->dstat.st_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)->dstat.st_mode)) { - const char *name; - - if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) - continue; - name = (*dn)->name; - if ((which & SPLIT_DIR) - || name[0]!='.' || (name[1] && (name[1]!='.' || name[2])) - ) { - dnp[d++] = *dn; - } - } else if (!(which & (SPLIT_DIR|SPLIT_SUBDIR))) { - 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 sort_opts = all_fmt & SORT_MASK; - off_t dif; - - dif = 0; /* assume SORT_NAME */ - // TODO: use pre-initialized function pointer - // instead of branch forest - if (sort_opts == SORT_SIZE) { - dif = (d2->dstat.st_size - d1->dstat.st_size); - } else if (sort_opts == SORT_ATIME) { - dif = (d2->dstat.st_atime - d1->dstat.st_atime); - } else if (sort_opts == SORT_CTIME) { - dif = (d2->dstat.st_ctime - d1->dstat.st_ctime); - } else if (sort_opts == SORT_MTIME) { - dif = (d2->dstat.st_mtime - d1->dstat.st_mtime); - } else if (sort_opts == SORT_DIR) { - dif = S_ISDIR(d2->dstat.st_mode) - S_ISDIR(d1->dstat.st_mode); - /* } else if (sort_opts == SORT_VERSION) { */ - /* } else if (sort_opts == SORT_EXT) { */ - } - if (dif == 0) { - /* sort by name, or tie_breaker for other sorts */ - if (ENABLE_LOCALE_SUPPORT) - dif = strcoll(d1->name, d2->name); - else - dif = strcmp(d1->name, d2->name); - } - - /* 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 */ - if (dif != 0) { - dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); - } - } - - return (all_fmt & SORT_REVERSE) ? -(int)dif : (int)dif; -} - -static void dnsort(struct dnode **dn, int size) -{ - qsort(dn, size, sizeof(*dn), sortcmp); -} -#else -#define dnsort(dn, size) ((void)0) -#endif - - static unsigned calc_name_len(const char *name) { unsigned len; @@ -547,9 +460,8 @@ static unsigned calc_name_len(const char *name) return len; } - /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value. + * Note that only STYLE_COLUMNAR uses return value. * STYLE_SINGLE and STYLE_LONG don't care. * coreutils 7.2 also supports: * ls -b (--escape) = octal escapes (although it doesn't look like working) @@ -575,99 +487,100 @@ static unsigned print_name(const char *name) putchar('\\'); len++; } - putchar(*name++); + putchar(*name); + name++; } putchar('"'); return len; } /* Return the number of used columns. - * Note that only STYLE_COLUMNS uses return value, + * Note that only STYLE_COLUMNAR uses return value, * STYLE_SINGLE and STYLE_LONG don't care. */ -static NOINLINE unsigned list_single(const struct dnode *dn) +static NOINLINE unsigned display_single(const struct dnode *dn) { unsigned column = 0; - char *lpath = lpath; /* for compiler */ + char *lpath; #if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR - struct stat info; + struct stat statbuf; char append; #endif - /* Never happens: - if (dn->fullname == NULL) - return 0; - */ - #if ENABLE_FEATURE_LS_FILETYPES - append = append_char(dn->dstat.st_mode); + append = append_char(dn->dn_mode); #endif /* Do readlink early, so that if it fails, error message * does not appear *inside* the "ls -l" line */ - if (all_fmt & LIST_SYMLINK) - if (S_ISLNK(dn->dstat.st_mode)) + lpath = NULL; + if (G.all_fmt & LIST_SYMLINK) + if (S_ISLNK(dn->dn_mode)) lpath = xmalloc_readlink_or_warn(dn->fullname); - if (all_fmt & LIST_INO) - column += printf("%7llu ", (long long) dn->dstat.st_ino); - if (all_fmt & LIST_BLOCKS) - column += printf("%4"OFF_FMT"u ", (off_t) (dn->dstat.st_blocks >> 1)); - if (all_fmt & LIST_MODEBITS) - column += printf("%-10s ", (char *) bb_mode_string(dn->dstat.st_mode)); - if (all_fmt & LIST_NLINKS) - column += printf("%4lu ", (long) dn->dstat.st_nlink); + if (G.all_fmt & LIST_INO) + column += printf("%7llu ", (long long) dn->dn_ino); +//TODO: -h should affect -s too: + if (G.all_fmt & LIST_BLOCKS) + column += printf("%6"OFF_FMT"u ", (off_t) (dn->dn_blocks >> 1)); + if (G.all_fmt & LIST_MODEBITS) + column += printf("%-10s ", (char *) bb_mode_string(dn->dn_mode)); + if (G.all_fmt & LIST_NLINKS) + column += printf("%4lu ", (long) dn->dn_nlink); + if (G.all_fmt & LIST_ID_NUMERIC) { + if (option_mask32 & 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 - if (all_fmt & LIST_ID_NAME) { + else if (G.all_fmt & LIST_ID_NAME) { if (option_mask32 & OPT_g) { column += printf("%-8.8s ", - get_cached_username(dn->dstat.st_uid)); + get_cached_groupname(dn->dn_gid)); } else { column += printf("%-8.8s %-8.8s ", - get_cached_username(dn->dstat.st_uid), - get_cached_groupname(dn->dstat.st_gid)); + get_cached_username(dn->dn_uid), + get_cached_groupname(dn->dn_gid)); } } #endif - if (all_fmt & LIST_ID_NUMERIC) { - if (option_mask32 & OPT_g) - column += printf("%-8u ", (int) dn->dstat.st_uid); - else - column += printf("%-8u %-8u ", - (int) dn->dstat.st_uid, - (int) dn->dstat.st_gid); - } - if (all_fmt & (LIST_SIZE /*|LIST_DEV*/ )) { - if (S_ISBLK(dn->dstat.st_mode) || S_ISCHR(dn->dstat.st_mode)) { + if (G.all_fmt & LIST_SIZE) { + if (S_ISBLK(dn->dn_mode) || S_ISCHR(dn->dn_mode)) { column += printf("%4u, %3u ", - (int) major(dn->dstat.st_rdev), - (int) minor(dn->dstat.st_rdev)); + dn->dn_rdev_maj, + dn->dn_rdev_min); } else { - if (all_fmt & LS_DISP_HR) { + if (option_mask32 & OPT_h) { column += printf("%"HUMAN_READABLE_MAX_WIDTH_STR"s ", - /* print st_size, show one fractional, use suffixes */ - make_human_readable_str(dn->dstat.st_size, 1, 0) + /* print size, show one fractional, use suffixes */ + make_human_readable_str(dn->dn_size, 1, 0) ); } else { - column += printf("%9"OFF_FMT"u ", (off_t) dn->dstat.st_size); + column += printf("%9"OFF_FMT"u ", dn->dn_size); } } } #if ENABLE_FEATURE_LS_TIMESTAMPS - if (all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) { + if (G.all_fmt & (LIST_FULLTIME|LIST_DATE_TIME)) { char *filetime; - time_t ttime = dn->dstat.st_mtime; - if (all_fmt & TIME_ACCESS) - ttime = dn->dstat.st_atime; - if (all_fmt & TIME_CHANGE) - ttime = dn->dstat.st_ctime; + time_t ttime = dn->dn_mtime; + if (G.all_fmt & TIME_ACCESS) + ttime = dn->dn_atime; + if (G.all_fmt & TIME_CHANGE) + ttime = dn->dn_ctime; filetime = ctime(&ttime); /* filetime's format: "Wed Jun 30 21:49:08 1993\n" */ - if (all_fmt & LIST_FULLTIME) + if (G.all_fmt & LIST_FULLTIME) { /* -e */ + /* Note: coreutils 8.4 ls --full-time prints: + * 2009-07-13 17:49:27.000000000 +0200 + */ column += printf("%.24s ", filetime); - else { /* LIST_DATE_TIME */ - /* current_time_t ~== time(NULL) */ - time_t age = current_time_t - ttime; + } else { /* LIST_DATE_TIME */ + /* G.current_time_t ~== time(NULL) */ + time_t age = G.current_time_t - ttime; printf("%.6s ", filetime + 4); /* "Jun 30" */ if (age < 3600L * 24 * 365 / 2 && age > -15 * 60) { /* hh:mm if less than 6 months old */ @@ -680,51 +593,52 @@ static NOINLINE unsigned list_single(const struct dnode *dn) } #endif #if ENABLE_SELINUX - if (all_fmt & LIST_CONTEXT) { + if (G.all_fmt & LIST_CONTEXT) { column += printf("%-32s ", dn->sid ? dn->sid : "unknown"); freecon(dn->sid); } #endif - if (all_fmt & LIST_FILENAME) { + #if ENABLE_FEATURE_LS_COLOR - if (show_color) { - info.st_mode = 0; /* for fgcolor() */ - lstat(dn->fullname, &info); - printf("\033[%u;%um", bold(info.st_mode), - fgcolor(info.st_mode)); - } + if (G_show_color) { + mode_t mode = dn->dn_mode_lstat; + if (!mode) + if (lstat(dn->fullname, &statbuf) == 0) + mode = statbuf.st_mode; + printf("\033[%u;%um", bold(mode), fgcolor(mode)); + } #endif - column += print_name(dn->name); - if (show_color) { - printf("\033[0m"); - } + column += print_name(dn->name); + if (G_show_color) { + printf("\033[0m"); } - if (all_fmt & LIST_SYMLINK) { - if (S_ISLNK(dn->dstat.st_mode) && lpath) { - printf(" -> "); + + if (lpath) { + printf(" -> "); #if ENABLE_FEATURE_LS_FILETYPES || ENABLE_FEATURE_LS_COLOR -#if ENABLE_FEATURE_LS_COLOR - info.st_mode = 0; /* for fgcolor() */ -#endif - if (stat(dn->fullname, &info) == 0) { - append = append_char(info.st_mode); - } -#endif -#if ENABLE_FEATURE_LS_COLOR - if (show_color) { - printf("\033[%u;%um", bold(info.st_mode), - fgcolor(info.st_mode)); + if ((G.all_fmt & LIST_FILETYPE) || 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("\033[%u;%um", bold(mode), fgcolor(mode)); } +# endif + } #endif - column += print_name(lpath) + 4; - if (show_color) { - printf("\033[0m"); - } - free(lpath); + column += print_name(lpath) + 4; + free(lpath); + if (G_show_color) { + printf("\033[0m"); } } #if ENABLE_FEATURE_LS_FILETYPES - if (all_fmt & LIST_FILETYPE) { + if (G.all_fmt & LIST_FILETYPE) { if (append) { putchar(append); column++; @@ -735,14 +649,14 @@ static NOINLINE unsigned list_single(const struct dnode *dn) return column; } -static void showfiles(struct dnode **dn, unsigned nfiles) +static void display_files(struct dnode **dn, unsigned nfiles) { unsigned i, ncols, nrows, row, nc; - unsigned column = 0; - unsigned nexttab = 0; - unsigned column_width = 0; /* used only by STYLE_COLUMNS */ + unsigned column; + unsigned nexttab; + unsigned column_width = 0; /* used only by STYLE_COLUMNAR */ - if (all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ + if (G.all_fmt & STYLE_LONG) { /* STYLE_LONG or STYLE_SINGLE */ ncols = 1; } else { /* find the longest file name, use that as the column width */ @@ -751,11 +665,11 @@ static void showfiles(struct dnode **dn, unsigned nfiles) if (column_width < len) column_width = len; } - column_width += tabstops + - IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) - ((all_fmt & LIST_INO) ? 8 : 0) + - ((all_fmt & LIST_BLOCKS) ? 5 : 0); - ncols = (int) (terminal_width / column_width); + column_width += 1 + + IF_SELINUX( ((G.all_fmt & LIST_CONTEXT) ? 33 : 0) + ) + ((G.all_fmt & LIST_INO) ? 8 : 0) + + ((G.all_fmt & LIST_BLOCKS) ? 5 : 0); + ncols = (unsigned)G_terminal_width / column_width; } if (ncols > 1) { @@ -767,21 +681,23 @@ static void showfiles(struct dnode **dn, unsigned 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 (all_fmt & DISP_ROWS) + if (G.all_fmt & DISP_ROWS) 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; + printf("%*s ", nexttab, ""); + column += nexttab + 1; } nexttab = column + column_width; - column += list_single(dn[i]); + column += display_single(dn[i]); } } putchar('\n'); @@ -790,104 +706,241 @@ static void showfiles(struct dnode **dn, unsigned nfiles) } -#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) +/*** Dir scanning code ***/ + +static struct dnode *my_stat(const char *fullname, const char *name, int force_follow) { - uoff_t blocks = 1; - if (dn) { - while (*dn) { - /* st_blocks is in 512 byte blocks */ - blocks += (*dn)->dstat.st_blocks; - dn++; + 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 (is_selinux_enabled()) { + 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 (is_selinux_enabled()) { + 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; } - /* 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; -} + /* 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_atime = statbuf.st_atime ; + cur->dn_mtime = statbuf.st_mtime ; + cur->dn_ctime = 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 struct dnode **list_dir(const char *, unsigned *); - -static void showdirs(struct dnode **dn, int first) +static unsigned count_dirs(struct dnode **dn, int which) { - unsigned nfiles; - unsigned dndirs; - struct dnode **subdnp; - struct dnode **dnd; + unsigned dirs, all; - /* Never happens: - if (dn == NULL || ndirs < 1) { - return; - } - */ + if (!dn) + return 0; + dirs = all = 0; for (; *dn; dn++) { - if (all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { - if (!first) - bb_putchar('\n'); - first = 0; - printf("%s:\n", (*dn)->fullname); + 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++; } - subdnp = list_dir((*dn)->fullname, &nfiles); -#if ENABLE_DESKTOP - if ((all_fmt & STYLE_MASK) == STYLE_LONG) - printf("total %"OFF_FMT"u\n", calculate_blocks(subdnp)); + } + 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 - if (nfiles > 0) { - /* list all files at this level */ - dnsort(subdnp, nfiles); - showfiles(subdnp, nfiles); - if (ENABLE_FEATURE_LS_RECURSIVE - && (all_fmt & DISP_RECURSIVE) + +/* 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])) ) { - /* recursive - list the sub-dirs */ - dnd = splitdnarray(subdnp, SPLIT_SUBDIR); - dndirs = count_dirs(subdnp, SPLIT_SUBDIR); - if (dndirs > 0) { - dnsort(dnd, dndirs); - showdirs(dnd, 0); - /* free the array of dnode pointers to the dirs */ - free(dnd); - } + dnp[d++] = *dn; } - /* free the dnodes and the fullname mem */ - dfree(subdnp); + } 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 sort_opts = G.all_fmt & SORT_MASK; + off_t dif; + + dif = 0; /* assume SORT_NAME */ + // TODO: use pre-initialized function pointer + // instead of branch forest + if (sort_opts == SORT_SIZE) { + dif = (d2->dn_size - d1->dn_size); + } else + if (sort_opts == SORT_ATIME) { + dif = (d2->dn_atime - d1->dn_atime); + } else + if (sort_opts == SORT_CTIME) { + dif = (d2->dn_ctime - d1->dn_ctime); + } else + if (sort_opts == SORT_MTIME) { + dif = (d2->dn_mtime - d1->dn_mtime); + } else + if (sort_opts == SORT_DIR) { + dif = S_ISDIR(d2->dn_mode) - S_ISDIR(d1->dn_mode); + } else +#if defined(HAVE_STRVERSCMP) && HAVE_STRVERSCMP == 1 + if (sort_opts == SORT_VERSION) { + dif = strverscmp(d1->name, d2->name); + } else +#endif + if (sort_opts == SORT_EXT) { + 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); + } + + /* 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 */ + if (dif != 0) { + dif = 1 | (int)((uoff_t)dif >> BITS_TO_SHIFT); } } + + return (G.all_fmt & SORT_REVERSE) ? -(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 **list_dir(const char *path, unsigned *nfiles_p) +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; - /* Never happens: - if (path == NULL) - return NULL; - */ - *nfiles_p = 0; dir = warn_opendir(path); if (dir == NULL) { - exit_code = EXIT_FAILURE; + G.exit_code = EXIT_FAILURE; return NULL; /* could not open the dir */ } dn = NULL; @@ -898,11 +951,11 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) /* are we going to list the file- it may be . or .. or a hidden file */ if (entry->d_name[0] == '.') { if ((!entry->d_name[1] || (entry->d_name[1] == '.' && !entry->d_name[2])) - && !(all_fmt & DISP_DOT) + && !(G.all_fmt & DISP_DOT) ) { continue; } - if (!(all_fmt & DISP_HIDDEN)) + if (!(G.all_fmt & DISP_HIDDEN)) continue; } fullname = concat_path_file(path, entry->d_name); @@ -912,7 +965,7 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) continue; } cur->fname_allocated = 1; - cur->next = dn; + cur->dn_next = dn; dn = cur; nfiles++; } @@ -928,7 +981,7 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) dnp = dnalloc(nfiles); for (i = 0; /* i < nfiles - detected via !dn below */; i++) { dnp[i] = dn; /* save pointer to node in array */ - dn = dn->next; + dn = dn->dn_next; if (!dn) break; } @@ -936,6 +989,77 @@ static struct dnode **list_dir(const char *path, unsigned *nfiles_p) 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.all_fmt & (DISP_DIRNAME | DISP_RECURSIVE)) { + if (!first) + bb_putchar('\n'); + first = 0; + printf("%s:\n", (*dn)->fullname); + } + subdnp = scan_one_dir((*dn)->fullname, &nfiles); +#if ENABLE_DESKTOP + if ((G.all_fmt & STYLE_MASK) == STYLE_LONG) + 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 + && (G.all_fmt & DISP_RECURSIVE) + ) { + 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) { @@ -973,59 +1097,63 @@ int ls_main(int argc UNUSED_PARAM, char **argv) init_unicode(); - all_fmt = LIST_SHORT | - (ENABLE_FEATURE_LS_SORTFILES * (SORT_NAME | SORT_FORWARD)); + if (ENABLE_FEATURE_LS_SORTFILES) + G.all_fmt = SORT_NAME; #if ENABLE_FEATURE_AUTOWIDTH /* obtain the terminal width */ - get_terminal_width_height(STDIN_FILENO, &terminal_width, NULL); + get_terminal_width_height(STDIN_FILENO, &G_terminal_width, NULL); /* go one less... */ - terminal_width--; + G_terminal_width--; #endif /* process options */ IF_FEATURE_LS_COLOR(applet_long_options = ls_longopts;) -#if ENABLE_FEATURE_AUTOWIDTH - opt_complementary = "T+:w+"; /* -T N, -w N */ - opt = getopt32(argv, ls_options, &tabstops, &terminal_width - IF_FEATURE_LS_COLOR(, &color_opt)); -#else - opt = getopt32(argv, ls_options IF_FEATURE_LS_COLOR(, &color_opt)); -#endif - for (i = 0; opt_flags[i] != (1U<<31); i++) { + opt_complementary = + /* -e implies -l */ + IF_FEATURE_LS_TIMESTAMPS("el") + /* 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_AUTOWIDTH(":w+"); + opt = getopt32(argv, ls_options + IF_FEATURE_AUTOWIDTH(, NULL, &G_terminal_width) + IF_FEATURE_LS_COLOR(, &color_opt) + ); + for (i = 0; opt_flags[i] != (1U << 31); i++) { if (opt & (1 << i)) { - unsigned flags = opt_flags[i]; - - if (flags & LIST_MASK_TRIGGER) - all_fmt &= ~LIST_MASK; - if (flags & STYLE_MASK_TRIGGER) - all_fmt &= ~STYLE_MASK; - if (flags & SORT_MASK_TRIGGER) - all_fmt &= ~SORT_MASK; - if (flags & DISP_MASK_TRIGGER) - all_fmt &= ~DISP_MASK; + uint32_t flags = opt_flags[i]; + + if (flags & STYLE_MASK) + G.all_fmt &= ~STYLE_MASK; + if (flags & SORT_MASK) + G.all_fmt &= ~SORT_MASK; if (flags & TIME_MASK) - all_fmt &= ~TIME_MASK; - if (flags & LIST_CONTEXT) - all_fmt |= STYLE_SINGLE; - /* huh?? opt cannot be 'l' */ - //if (LS_DISP_HR && opt == 'l') - // all_fmt &= ~LS_DISP_HR; - all_fmt |= flags; + G.all_fmt &= ~TIME_MASK; + + G.all_fmt |= flags; } } #if ENABLE_FEATURE_LS_COLOR - /* find color bit value - last position for short getopt */ + /* set G_show_color = 1/0 */ if (ENABLE_FEATURE_LS_COLOR_IS_DEFAULT && isatty(STDOUT_FILENO)) { char *p = getenv("LS_COLORS"); /* LS_COLORS is unset, or (not empty && not "none") ? */ if (!p || (p[0] && strcmp(p, "none") != 0)) - show_color = 1; + G_show_color = 1; } if (opt & OPT_color) { if (color_opt[0] == 'n') - show_color = 0; + G_show_color = 0; else switch (index_in_substrings(color_str, color_opt)) { case 3: case 4: @@ -1034,56 +1162,61 @@ int ls_main(int argc UNUSED_PARAM, char **argv) case 0: case 1: case 2: - show_color = 1; + G_show_color = 1; } } } #endif /* sort out which command line options take precedence */ - if (ENABLE_FEATURE_LS_RECURSIVE && (all_fmt & DISP_NOLIST)) - all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ + if (ENABLE_FEATURE_LS_RECURSIVE && (G.all_fmt & DISP_NOLIST)) + G.all_fmt &= ~DISP_RECURSIVE; /* no recurse if listing only dir */ if (ENABLE_FEATURE_LS_TIMESTAMPS && ENABLE_FEATURE_LS_SORTFILES) { - if (all_fmt & TIME_CHANGE) - all_fmt = (all_fmt & ~SORT_MASK) | SORT_CTIME; - if (all_fmt & TIME_ACCESS) - all_fmt = (all_fmt & ~SORT_MASK) | SORT_ATIME; + if (G.all_fmt & TIME_CHANGE) + G.all_fmt = (G.all_fmt & ~SORT_MASK) | SORT_CTIME; + if (G.all_fmt & TIME_ACCESS) + G.all_fmt = (G.all_fmt & ~SORT_MASK) | SORT_ATIME; } - if ((all_fmt & STYLE_MASK) != STYLE_LONG) /* only for long list */ - all_fmt &= ~(LIST_ID_NUMERIC|LIST_FULLTIME|LIST_ID_NAME|LIST_ID_NUMERIC); - if (ENABLE_FEATURE_LS_USERNAME) - if ((all_fmt & STYLE_MASK) == STYLE_LONG && (all_fmt & LIST_ID_NUMERIC)) - all_fmt &= ~LIST_ID_NAME; /* don't list names if numeric uid */ + if ((G.all_fmt & STYLE_MASK) != STYLE_LONG) /* not -l? */ + G.all_fmt &= ~(LIST_ID_NUMERIC|LIST_ID_NAME|LIST_FULLTIME); - /* choose a display format */ - if (!(all_fmt & STYLE_MASK)) - all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNS : STYLE_SINGLE); + /* choose a display format if one was not already specified by an option */ + if (!(G.all_fmt & STYLE_MASK)) + G.all_fmt |= (isatty(STDOUT_FILENO) ? STYLE_COLUMNAR : STYLE_SINGLE); argv += optind; if (!argv[0]) *--argv = (char*)"."; if (argv[1]) - all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */ + G.all_fmt |= DISP_DIRNAME; /* 2 or more items? label directories */ /* stuff the command line file names into a dnode array */ dn = NULL; nfiles = 0; do { - /* NB: follow links on command line unless -l or -s */ - cur = my_stat(*argv, *argv, !(all_fmt & (STYLE_LONG|LIST_BLOCKS))); + cur = my_stat(*argv, *argv, + /* follow links on command line unless -l, -s or -F: */ + !((G.all_fmt & STYLE_MASK) == STYLE_LONG + || (G.all_fmt & LIST_BLOCKS) + || (option_mask32 & 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; - cur->next = dn; + /*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 exit_code; + return G.exit_code; /* now that we know how many files there are * allocate memory for an array to hold dnode pointers @@ -1091,33 +1224,32 @@ int ls_main(int argc UNUSED_PARAM, char **argv) dnp = dnalloc(nfiles); for (i = 0; /* i < nfiles - detected via !dn below */; i++) { dnp[i] = dn; /* save pointer to node in array */ - dn = dn->next; + dn = dn->dn_next; if (!dn) break; } - if (all_fmt & DISP_NOLIST) { - dnsort(dnp, nfiles); - showfiles(dnp, nfiles); + if (G.all_fmt & DISP_NOLIST) { + 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) { - dnsort(dnf, dnfiles); - showfiles(dnf, dnfiles); + sort_and_display_files(dnf, dnfiles); if (ENABLE_FEATURE_CLEAN_UP) free(dnf); } if (dndirs > 0) { dnsort(dnd, dndirs); - showdirs(dnd, dnfiles == 0); + scan_and_display_dirs_recur(dnd, dnfiles == 0); if (ENABLE_FEATURE_CLEAN_UP) free(dnd); } } + if (ENABLE_FEATURE_CLEAN_UP) dfree(dnp); - return exit_code; + return G.exit_code; } diff --git a/coreutils/md5_sha1_sum.c b/coreutils/md5_sha1_sum.c index 3d50bb0..1a5342e 100644 --- a/coreutils/md5_sha1_sum.c +++ b/coreutils/md5_sha1_sum.c @@ -3,22 +3,85 @@ * Copyright (C) 2003 Glenn L. McGrath * Copyright (C) 2003-2004 Erik Andersen * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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]] ")"[FILE]..." +//usage:#define sha3sum_full_usage "\n\n" +//usage: "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA3-512 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: ) + #include "libbb.h" -typedef enum { +/* This is a NOEXEC applet. Be very careful! */ + +enum { /* 4th letter of applet_name is... */ HASH_MD5 = 's', /* "md5>s 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); + } + RELEASE_CONFIG_BUFFER(in_buf); } - RELEASE_CONFIG_BUFFER(in_buf); - if (src_fd != STDIN_FILENO) { close(src_fd); } @@ -97,98 +171,90 @@ int md5_sha1_sum_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int md5_sha1_sum_main(int argc UNUSED_PARAM, char **argv) { int return_value = EXIT_SUCCESS; - uint8_t *hash_value; unsigned flags; - /*hash_algo_t hash_algo = applet_name[3];*/ if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK) { /* -b "binary", -t "text" are ignored (shaNNNsum compat) */ flags = getopt32(argv, "scwbt"); + argv += optind; + //argc -= optind; + } else { + argv += 1; + //argc -= 1; } - else optind = 1; - argv += optind; - //argc -= optind; if (!*argv) *--argv = (char*)"-"; if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && !(flags & FLAG_CHECK)) { if (flags & FLAG_SILENT) { - bb_error_msg_and_die - ("-%c is meaningful only when verifying checksums", 's'); - } else if (flags & FLAG_WARN) { - bb_error_msg_and_die - ("-%c is meaningful only when verifying checksums", 'w'); + bb_error_msg_and_die("-%c is meaningful only with -c", 's'); + } + if (flags & FLAG_WARN) { + bb_error_msg_and_die("-%c is meaningful only with -c", 'w'); } } - if (ENABLE_FEATURE_MD5_SHA1_SUM_CHECK && (flags & FLAG_CHECK)) { - FILE *pre_computed_stream; - int count_total = 0; - int count_failed = 0; - char *line; + 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; - if (argv[1]) { - bb_error_msg_and_die - ("only one argument may be specified when using -c"); - } + pre_computed_stream = xfopen_stdin(*argv); - pre_computed_stream = xfopen_stdin(argv[0]); + while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { + uint8_t *hash_value; + char *filename_ptr; - while ((line = xmalloc_fgetline(pre_computed_stream)) != NULL) { - char *filename_ptr; + count_total++; + filename_ptr = strstr(line, " "); + /* handle format for binary checksums */ + if (filename_ptr == NULL) { + filename_ptr = strstr(line, " *"); + } + if (filename_ptr == NULL) { + if (flags & FLAG_WARN) { + bb_error_msg("invalid format"); + } + count_failed++; + return_value = EXIT_FAILURE; + free(line); + continue; + } + *filename_ptr = '\0'; + filename_ptr += 2; - count_total++; - filename_ptr = strstr(line, " "); - /* handle format for binary checksums */ - if (filename_ptr == NULL) { - filename_ptr = strstr(line, " *"); - } - if (filename_ptr == NULL) { - if (flags & FLAG_WARN) { - bb_error_msg("invalid format"); + hash_value = hash_file(filename_ptr); + + if (hash_value && (strcmp((char*)hash_value, line) == 0)) { + if (!(flags & FLAG_SILENT)) + printf("%s: OK\n", filename_ptr); + } else { + if (!(flags & FLAG_SILENT)) + printf("%s: FAILED\n", filename_ptr); + count_failed++; + return_value = EXIT_FAILURE; } - count_failed++; - return_value = EXIT_FAILURE; + /* possible free(NULL) */ + free(hash_value); free(line); - continue; } - *filename_ptr = '\0'; - filename_ptr += 2; - - hash_value = hash_file(filename_ptr /*, hash_algo*/); - - if (hash_value && (strcmp((char*)hash_value, line) == 0)) { - if (!(flags & FLAG_SILENT)) - printf("%s: OK\n", filename_ptr); - } else { - if (!(flags & FLAG_SILENT)) - printf("%s: FAILED\n", filename_ptr); - count_failed++; - return_value = EXIT_FAILURE; + if (count_failed && !(flags & FLAG_SILENT)) { + bb_error_msg("WARNING: %d of %d computed checksums did NOT match", + count_failed, count_total); } - /* possible free(NULL) */ - free(hash_value); - free(line); - } - if (count_failed && !(flags & FLAG_SILENT)) { - bb_error_msg("WARNING: %d of %d computed checksums did NOT match", - count_failed, count_total); - } - /* - if (fclose_if_not_stdin(pre_computed_stream) == EOF) { - bb_perror_msg_and_die("can't close file %s", file_ptr); - } - */ - } else { - do { - hash_value = hash_file(*argv/*, hash_algo*/); + fclose_if_not_stdin(pre_computed_stream); + } else { + uint8_t *hash_value = hash_file(*argv); if (hash_value == NULL) { return_value = EXIT_FAILURE; } else { printf("%s %s\n", hash_value, *argv); free(hash_value); } - } while (*++argv); - } + } + } while (*++argv); + return return_value; } diff --git a/coreutils/mkdir.c b/coreutils/mkdir.c index c837e97..4a8e43e 100644 --- a/coreutils/mkdir.c +++ b/coreutils/mkdir.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -19,6 +19,24 @@ /* Nov 28, 2006 Yoshinori Sato : Add SELinux Support. */ +//usage:#define mkdir_trivial_usage +//usage: "[OPTIONS] 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! */ @@ -30,13 +48,14 @@ static const char mkdir_longopts[] ALIGN1 = #if ENABLE_SELINUX "context\0" Required_argument "Z" #endif + "verbose\0" No_argument "v" ; #endif int mkdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mkdir_main(int argc UNUSED_PARAM, char **argv) { - mode_t mode = (mode_t)(-1); + long mode = -1; int status = EXIT_SUCCESS; int flags = 0; unsigned opt; @@ -48,12 +67,13 @@ int mkdir_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS applet_long_options = mkdir_longopts; #endif - opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext)); + opt = getopt32(argv, "m:p" IF_SELINUX("Z:") "v", &smode IF_SELINUX(,&scontext)); if (opt & 1) { - mode = 0777; - if (!bb_parse_mode(smode, &mode)) { + mode_t mmode = 0777; + if (!bb_parse_mode(smode, &mmode)) { bb_error_msg_and_die("invalid mode '%s'", smode); } + mode = mmode; } if (opt & 2) flags |= FILEUTILS_RECUR; diff --git a/coreutils/mkfifo.c b/coreutils/mkfifo.c index 6549460..ef58325 100644 --- a/coreutils/mkfifo.c +++ b/coreutils/mkfifo.c @@ -4,15 +4,26 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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) { @@ -28,7 +39,7 @@ int mkfifo_main(int argc UNUSED_PARAM, char **argv) do { if (mkfifo(*argv, mode) < 0) { - bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */ + bb_simple_perror_msg(*argv); /* Avoid multibyte problems. */ retval = EXIT_FAILURE; } } while (*++argv); diff --git a/coreutils/mknod.c b/coreutils/mknod.c index 0c69494..aa04504 100644 --- a/coreutils/mknod.c +++ b/coreutils/mknod.c @@ -4,16 +4,35 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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 and MINOR are ignored)" +//usage: +//usage:#define mknod_example_usage +//usage: "$ mknod /dev/fd0 b 2 0\n" +//usage: "$ mknod -m 644 /tmp/pipe p\n" + #include // For makedev #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 }; @@ -40,7 +59,7 @@ int mknod_main(int argc, char **argv) /* 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))); + xatoul_range(argv[3], 0, minor(UINT_MAX))); } } diff --git a/coreutils/mv.c b/coreutils/mv.c index 1c5a467..f127dfa 100644 --- a/coreutils/mv.c +++ b/coreutils/mv.c @@ -5,7 +5,7 @@ * Copyright (C) 2000 by Matt Kraai * SELinux support by Yuichi Nakamura * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -16,15 +16,30 @@ #include "libbb.h" #include "libcoreutils/coreutils.h" +//usage:#define mv_trivial_usage +//usage: "[-fin] SOURCE DEST\n" +//usage: "or: mv [-fin] SOURCE... DIRECTORY" +//usage:#define mv_full_usage "\n\n" +//usage: "Rename SOURCE to DEST, or move SOURCE(s) 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: +//usage:#define mv_example_usage +//usage: "$ mv /tmp/foo /bin/bar\n" + #if ENABLE_FEATURE_MV_LONG_OPTIONS static const char mv_longopts[] ALIGN1 = "interactive\0" No_argument "i" "force\0" No_argument "f" + "no-clobber\0" No_argument "n" + "verbose\0" No_argument "v" ; #endif -#define OPT_FILEUTILS_FORCE 1 -#define OPT_FILEUTILS_INTERACTIVE 2 +#define OPT_FORCE (1 << 0) +#define OPT_INTERACTIVE (1 << 1) +#define OPT_NOCLOBBER (1 << 2) int mv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mv_main(int argc, char **argv) @@ -40,10 +55,13 @@ int mv_main(int argc, char **argv) #if ENABLE_FEATURE_MV_LONG_OPTIONS applet_long_options = mv_longopts; #endif - // Need at least two arguments - // -f unsets -i, -i unsets -f - opt_complementary = "-2:f-i:i-f"; - flags = getopt32(argv, "fi"); + /* Need at least two arguments. + * If more than one of -f, -i, -n is specified , only the final one + * takes effect (it unsets previous options). + * -v is accepted but ignored. + */ + opt_complementary = "-2:f-in:i-fn:n-fi"; + flags = getopt32(argv, "finv"); argc -= optind; argv += optind; last = argv[argc - 1]; @@ -68,18 +86,22 @@ int mv_main(int argc, char **argv) } DO_MOVE: - if (dest_exists - && !(flags & OPT_FILEUTILS_FORCE) - && ((access(dest, W_OK) < 0 && isatty(0)) - || (flags & OPT_FILEUTILS_INTERACTIVE)) - ) { - if (fprintf(stderr, "mv: overwrite '%s'? ", dest) < 0) { - goto RET_1; /* Ouch! fprintf failed! */ - } - if (!bb_ask_confirmation()) { + 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_confirmation()) { + goto RET_0; + } } } + if (rename(*argv, dest) < 0) { struct stat source_stat; int source_exists; diff --git a/coreutils/nice.c b/coreutils/nice.c index ff3eb11..ce75991 100644 --- a/coreutils/nice.c +++ b/coreutils/nice.c @@ -4,9 +4,15 @@ * * Copyright (C) 2005 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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 #include "libbb.h" @@ -17,12 +23,12 @@ int nice_main(int argc, char **argv) old_priority = getpriority(PRIO_PROCESS, 0); - if (!*++argv) { /* No args, so (GNU) output current nice value. */ + if (!*++argv) { /* No args, so (GNU) output current nice value. */ printf("%d\n", old_priority); fflush_stdout_and_exit(EXIT_SUCCESS); } - adjustment = 10; /* Set default adjustment. */ + adjustment = 10; /* Set default adjustment. */ if (argv[0][0] == '-') { if (argv[0][1] == 'n') { /* -n */ @@ -32,7 +38,7 @@ int nice_main(int argc, char **argv) } else { /* -NNN (NNN may be negative) == -n NNN */ argv[0] += 1; argv--; argc++; } - if (argc < 4) { /* Missing priority and/or utility! */ + if (argc < 4) { /* Missing priority and/or utility! */ bb_show_usage(); } adjustment = xatoi_range(argv[1], INT_MIN/2, INT_MAX/2); diff --git a/coreutils/nohup.c b/coreutils/nohup.c index 3dc5314..63853fd 100644 --- a/coreutils/nohup.c +++ b/coreutils/nohup.c @@ -7,9 +7,17 @@ * Copyright 2006 Rob Landley * Copyright 2006 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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: diff --git a/coreutils/od.c b/coreutils/od.c index 228db19..fb11fcf 100644 --- a/coreutils/od.c +++ b/coreutils/od.c @@ -4,13 +4,19 @@ * Based on code from util-linux v 2.11l * * Copyright (c) 1990 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice is retained at the end of this file. */ +//usage:#if !ENABLE_DESKTOP +//usage:#define od_trivial_usage +//usage: "[-aBbcDdeFfHhIiLlOovXx] [FILE]" +//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 @@ -110,7 +116,7 @@ odoffset(dumper_t *dumper, int argc, char ***argvp) * the offset is changed as well. This isn't pretty, * but it's easy. */ -#define TYPE_OFFSET 7 +#define TYPE_OFFSET 7 { char x_or_d; if (base == 16) { @@ -130,19 +136,19 @@ odoffset(dumper_t *dumper, int argc, char ***argvp) } static const char *const add_strings[] = { - "16/1 \"%3_u \" \"\\n\"", /* a */ - "8/2 \" %06o \" \"\\n\"", /* B, o */ - "16/1 \"%03o \" \"\\n\"", /* b */ - "16/1 \"%3_c \" \"\\n\"", /* c */ - "8/2 \" %05u \" \"\\n\"", /* d */ - "4/4 \" %010u \" \"\\n\"", /* D */ - "2/8 \" %21.14e \" \"\\n\"", /* e (undocumented in od), F */ - "4/4 \" %14.7e \" \"\\n\"", /* f */ - "4/4 \" %08x \" \"\\n\"", /* H, X */ - "8/2 \" %04x \" \"\\n\"", /* h, x */ - "4/4 \" %11d \" \"\\n\"", /* I, L, l */ - "8/2 \" %6d \" \"\\n\"", /* i */ - "4/4 \" %011o \" \"\\n\"", /* O */ + "16/1 \"%3_u \" \"\\n\"", /* a */ + "8/2 \" %06o \" \"\\n\"", /* B, o */ + "16/1 \"%03o \" \"\\n\"", /* b */ + "16/1 \"%3_c \" \"\\n\"", /* c */ + "8/2 \" %05u \" \"\\n\"", /* d */ + "4/4 \" %010u \" \"\\n\"", /* D */ + "2/8 \" %21.14e \" \"\\n\"", /* e (undocumented in od), F */ + "4/4 \" %14.7e \" \"\\n\"", /* f */ + "4/4 \" %08x \" \"\\n\"", /* H, X */ + "8/2 \" %04x \" \"\\n\"", /* h, x */ + "4/4 \" %11d \" \"\\n\"", /* I, L, l */ + "8/2 \" %6d \" \"\\n\"", /* i */ + "4/4 \" %011o \" \"\\n\"", /* O */ }; static const char od_opts[] ALIGN1 = "aBbcDdeFfHhIiLlOoXxv"; @@ -174,7 +180,7 @@ int od_main(int argc, char **argv) bb_dump_add(dumper, "\" \""); } bb_dump_add(dumper, add_strings[(int)od_o2si[(p - od_opts)]]); - } else { /* P, p, s, w, or other unhandled */ + } else { /* P, p, s, w, or other unhandled */ bb_show_usage(); } } diff --git a/coreutils/od_bloaty.c b/coreutils/od_bloaty.c index a9a45c8..2c26dda 100644 --- a/coreutils/od_bloaty.c +++ b/coreutils/od_bloaty.c @@ -13,48 +13,64 @@ You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, - Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - + 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 */ -/* Busyboxed by Denys Vlasenko - -Based on od.c from coreutils-5.2.1 -Top bloat sources: -00000073 t parse_old_offset -0000007b t get_lcm -00000090 r long_options -00000092 t print_named_ascii -000000bf t print_ascii -00000168 t write_block -00000366 t decode_format_string -00000a71 T od_main - -Tested for compat with coreutils 6.3 -using this script. Minor differences fixed. +/* #include "libbb.h" - done in od.c */ +#define assert(a) ((void)0) -#!/bin/sh -echo STD -time /path/to/coreutils/od \ -...params... \ ->std -echo Exit code $? -echo BBOX -time ./busybox od \ -...params... \ ->bbox -echo Exit code $? -diff -u -a std bbox >bbox.diff || { echo Different!; sleep 1; } -*/ +//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 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_f = 1 << 6, + OPT_h = 1 << 7, + OPT_i = 1 << 8, + OPT_j = 1 << 9, + OPT_l = 1 << 10, + OPT_o = 1 << 11, + OPT_t = 1 << 12, + /* 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 << 13, + OPT_x = 1 << 14, + OPT_s = 1 << 15, + OPT_S = 1 << 16, + OPT_w = 1 << 17, + OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, +}; -#include "libbb.h" +#define OD_GETOPT32() getopt32(argv, \ + "A:N:abcdfhij:lot:vxsS:w::", \ + /* -w with optional param */ \ + /* -S was -s and also had optional parameter */ \ + /* but in coreutils 6.3 it was renamed and now has */ \ + /* _mandatory_ parameter */ \ + &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block) -#define assert(a) ((void)0) /* Check for 0x7f is a coreutils 6.3 addition */ -#define ISPRINT(c) (((c)>=' ') && (c) != 0x7f) +#define ISPRINT(c) (((c) >= ' ') && (c) < 0x7f) typedef long double longdouble_t; typedef unsigned long long ulonglong_t; @@ -158,17 +174,9 @@ struct ERR_width_bytes_has_bad_size { char ERR_width_bytes_has_bad_size[ARRAY_SIZE(width_bytes) == N_SIZE_SPECS ? 1 : -1]; }; -static smallint flag_dump_strings; -/* Non-zero if an old-style 'pseudo-address' was specified. */ -static smallint flag_pseudo_start; -static smallint limit_bytes_to_format; -/* When zero and two or more consecutive blocks are equal, format - only the first block and output an asterisk alone on the following - line to indicate that identical blocks have been elided. */ -static smallint verbose; -static smallint ioerror; +static smallint exit_code; -static size_t string_min; +static unsigned string_min; /* An array of specs describing how to format each input block. */ static size_t n_specs; @@ -179,7 +187,11 @@ static struct tspec *spec; static 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 static off_t pseudo_offset; +#else +enum { pseudo_offset = 0 }; +#endif /* When zero, MAX_BYTES_TO_FORMAT and END_OFFSET are ignored, and all input is formatted. */ @@ -214,7 +226,7 @@ static const unsigned char integral_type_size[MAX_INTEGRAL_TYPE_SIZE + 1] ALIGN1 #define MAX_FP_TYPE_SIZE sizeof(longdouble_t) static const unsigned char fp_type_size[MAX_FP_TYPE_SIZE + 1] ALIGN1 = { - /* gcc seems to allow repeated indexes. Last one stays */ + /* gcc seems to allow repeated indexes. Last one wins */ [sizeof(longdouble_t)] = FLOAT_LONG_DOUBLE, [sizeof(double)] = FLOAT_DOUBLE, [sizeof(float)] = FLOAT_SINGLE @@ -376,7 +388,7 @@ print_named_ascii(size_t n_bytes, const char *block, }; // buf[N] pos: 01234 56789 char buf[12] = " x\0 0xx\0"; - // actually " x\0 xxx\0", but I want to share the string with below. + // actually " x\0 xxx\0", but want to share string with print_ascii. // [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. @@ -472,10 +484,10 @@ open_next_file(void) if (in_stream) { break; } - ioerror = 1; + exit_code = 1; } - if (limit_bytes_to_format && !flag_dump_strings) + if ((option_mask32 & (OPT_N|OPT_S)) == OPT_N) setbuf(in_stream, NULL); } @@ -495,15 +507,14 @@ check_and_close(void) ? bb_msg_standard_input : file_list[-1] ); - ioerror = 1; + exit_code = 1; } fclose_if_not_stdin(in_stream); in_stream = NULL; } if (ferror(stdout)) { - bb_error_msg(bb_msg_write_error); - ioerror = 1; + bb_error_msg_and_die(bb_msg_write_error); } } @@ -535,7 +546,6 @@ decode_one_format(const char *s_orig, const char *s, struct tspec *tspec) unsigned field_width = 0; int pos; - switch (*s) { case 'd': case 'o': @@ -781,7 +791,7 @@ skip(off_t n_skip) /* take "check & close / open_next" route */ } else { if (fseeko(in_stream, n_skip, SEEK_CUR) != 0) - ioerror = 1; + exit_code = 1; return; } } else { @@ -882,7 +892,8 @@ write_block(off_t current_offset, size_t n_bytes, static char prev_pair_equal = 0; size_t i; - if (!verbose && !first + if (!(option_mask32 & OPT_v) + && !first && n_bytes == bytes_per_block && memcmp(prev_block, curr_block, bytes_per_block) == 0 ) { @@ -904,9 +915,9 @@ write_block(off_t current_offset, size_t n_bytes, (*spec[i].print_function) (n_bytes, curr_block, spec[i].fmt_string); if (spec[i].hexl_mode_trailer) { /* space-pad out to full line width, then dump the trailer */ - int datum_width = width_bytes[spec[i].size]; - int blank_fields = (bytes_per_block - n_bytes) / datum_width; - int field_width = spec[i].field_width + 1; + unsigned datum_width = width_bytes[spec[i].size]; + unsigned blank_fields = (bytes_per_block - n_bytes) / datum_width; + unsigned field_width = spec[i].field_width + 1; printf("%*s", blank_fields * field_width, ""); dump_hexl_mode_trailer(n_bytes, curr_block); } @@ -954,42 +965,6 @@ get_lcm(void) return l_c_m; } -#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[] = { - { "B", 1024 }, - { "b", 512 }, - { "", 0 } - }; - char *p; - int radix; - - /* Skip over any leading '+'. */ - if (s[0] == '+') ++s; - - /* Determine the radix we'll use to interpret S. If there is a '.', - * it's decimal, otherwise, if the string begins with '0X'or '0x', - * it's hexadecimal, else octal. */ - p = strchr(s, '.'); - radix = 8; - if (p) { - p[0] = '\0'; /* cheating */ - radix = 10; - } else if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) - radix = 16; - - *offset = xstrtooff_sfx(s, radix, Bb); - if (p) p[0] = '.'; - - return (*offset >= 0); -} -#endif - /* Read a chunk of size BYTES_PER_BLOCK from the input files, write the formatted block to standard output, and repeat until the specified maximum number of bytes has been read or until all input has been @@ -1007,27 +982,25 @@ dump(off_t current_offset, off_t end_offset) int idx; size_t n_bytes_read; - block[0] = xmalloc(2*bytes_per_block); + block[0] = xmalloc(2 * bytes_per_block); block[1] = block[0] + bytes_per_block; idx = 0; - if (limit_bytes_to_format) { + 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) bytes_per_block); + n_needed = MIN(end_offset - current_offset, (off_t) bytes_per_block); read_block(n_needed, block[idx], &n_bytes_read); if (n_bytes_read < bytes_per_block) break; assert(n_bytes_read == bytes_per_block); - write_block(current_offset, n_bytes_read, - block[!idx], block[idx]); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); current_offset += n_bytes_read; - idx = !idx; + idx ^= 1; } } else { while (1) { @@ -1035,10 +1008,9 @@ dump(off_t current_offset, off_t end_offset) if (n_bytes_read < bytes_per_block) break; assert(n_bytes_read == bytes_per_block); - write_block(current_offset, n_bytes_read, - block[!idx], block[idx]); + write_block(current_offset, n_bytes_read, block[idx ^ 1], block[idx]); current_offset += n_bytes_read; - idx = !idx; + idx ^= 1; } } @@ -1049,46 +1021,23 @@ dump(off_t current_offset, off_t end_offset) 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. */ + is at least as large as n_bytes_read. */ bytes_to_write = l_c_m * ((n_bytes_read + l_c_m - 1) / l_c_m); memset(block[idx] + n_bytes_read, 0, bytes_to_write - n_bytes_read); write_block(current_offset, bytes_to_write, - block[!idx], block[idx]); + block[idx ^ 1], block[idx]); current_offset += n_bytes_read; } format_address(current_offset, '\n'); - if (limit_bytes_to_format && current_offset >= end_offset) + if ((option_mask32 & OPT_N) && current_offset >= end_offset) check_and_close(); free(block[0]); } -/* Read a single byte into *C from the concatenation of the input files - named in the global array FILE_LIST. On the first call to this - function, the global variable IN_STREAM is expected to be an open - stream associated with the input file INPUT_FILENAME. If IN_STREAM - is at end-of-file, close it and update the global variables IN_STREAM - and INPUT_FILENAME so they correspond to the next file in the list. - Then try to read a byte from the newly opened file. Repeat if - necessary until EOF is reached for the last file in FILE_LIST, then - set *C to EOF and return. Subsequent calls do likewise. */ - -static void -read_char(int *c) -{ - while (in_stream) { /* !EOF */ - *c = fgetc(in_stream); - if (*c != EOF) - return; - check_and_close(); - open_next_file(); - } - *c = EOF; -} - /* Read N bytes into BLOCK from the concatenation of the input files named in the global array FILE_LIST. On the first call to this function, the global variable IN_STREAM is expected to be an open @@ -1112,8 +1061,8 @@ read_char(int *c) static void dump_strings(off_t address, off_t end_offset) { - size_t bufsize = MAX(100, string_min); - char *buf = xmalloc(bufsize); + unsigned bufsize = MAX(100, string_min); + unsigned char *buf = xmalloc(bufsize); while (1) { size_t i; @@ -1121,19 +1070,25 @@ dump_strings(off_t address, off_t end_offset) /* See if the next 'string_min' chars are all printing chars. */ tryline: - if (limit_bytes_to_format && (end_offset - string_min <= address)) + if ((option_mask32 & OPT_N) && (end_offset - string_min <= address)) break; i = 0; - while (!limit_bytes_to_format || address < end_offset) { + while (!(option_mask32 & OPT_N) || address < end_offset) { if (i == bufsize) { bufsize += bufsize/8; buf = xrealloc(buf, bufsize); } - read_char(&c); - if (c < 0) { /* EOF */ - free(buf); - return; + + while (in_stream) { /* !EOF */ + c = fgetc(in_stream); + if (c != EOF) + goto got_char; + check_and_close(); + open_next_file(); } + /* EOF */ + goto ret; + got_char: address++; if (!c) break; @@ -1145,8 +1100,7 @@ dump_strings(off_t address, off_t end_offset) if (i < string_min) /* Too short! */ goto tryline; - /* If we get here, the string is all printable and NUL-terminated, - * so print it. It is all in 'buf' and 'i' is its length. */ + /* If we get here, the string is all printable and NUL-terminated */ buf[i] = 0; format_address(address - i - 1, ' '); @@ -1167,41 +1121,51 @@ dump_strings(off_t address, off_t end_offset) /* We reach this point only if we search through (max_bytes_to_format - string_min) bytes before reaching EOF. */ - free(buf); - check_and_close(); + ret: + free(buf); } -int od_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int od_main(int argc, char **argv) +#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 bkm[] = { + static const struct suffix_mult Bb[] = { + { "B", 1024 }, { "b", 512 }, - { "k", 1024 }, - { "m", 1024*1024 }, { "", 0 } }; - enum { - OPT_A = 1 << 0, - OPT_N = 1 << 1, - OPT_a = 1 << 2, - OPT_b = 1 << 3, - OPT_c = 1 << 4, - OPT_d = 1 << 5, - OPT_f = 1 << 6, - OPT_h = 1 << 7, - OPT_i = 1 << 8, - OPT_j = 1 << 9, - OPT_l = 1 << 10, - OPT_o = 1 << 11, - OPT_t = 1 << 12, - OPT_v = 1 << 13, - OPT_x = 1 << 14, - OPT_s = 1 << 15, - OPT_S = 1 << 16, - OPT_w = 1 << 17, - OPT_traditional = (1 << 18) * ENABLE_LONG_OPTS, - }; + 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" @@ -1209,18 +1173,18 @@ int od_main(int argc, char **argv) "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 - char *str_A, *str_N, *str_j, *str_S; + const char *str_A, *str_N, *str_j, *str_S = "3"; llist_t *lst_t = NULL; unsigned opt; int l_c_m; - /* The old-style 'pseudo starting address' to be printed in parentheses - after any true address. */ - off_t pseudo_start = pseudo_start; // for gcc /* The number of input bytes to skip before formatting and writing. */ off_t n_bytes_to_skip = 0; /* The offset of the first byte after the last byte to be formatted. */ @@ -1232,20 +1196,13 @@ int od_main(int argc, char **argv) format_address = format_address_std; address_base_char = 'o'; address_pad_len_char = '7'; - /* flag_dump_strings = 0; - already is */ /* Parse command line */ opt_complementary = "w+:t::"; /* -w N, -t is a list */ #if ENABLE_LONG_OPTS applet_long_options = od_longopts; #endif - opt = getopt32(argv, "A:N:abcdfhij:lot:vxsS:" - "w::", // -w with optional param - // -S was -s and also had optional parameter - // but in coreutils 6.3 it was renamed and now has - // _mandatory_ parameter - &str_A, &str_N, &str_j, &lst_t, &str_S, &bytes_per_block); - argc -= optind; + opt = OD_GETOPT32(); argv += optind; if (opt & OPT_A) { static const char doxn[] ALIGN1 = "doxn"; @@ -1267,8 +1224,7 @@ int od_main(int argc, char **argv) address_pad_len_char = doxn_address_pad_len_char[pos]; } if (opt & OPT_N) { - limit_bytes_to_format = 1; - max_bytes_to_format = xstrtooff_sfx(str_N, 0, bkm); + 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"); @@ -1277,31 +1233,26 @@ int od_main(int argc, char **argv) if (opt & OPT_f) decode_format_string("fF"); if (opt & OPT_h) decode_format_string("x2"); if (opt & OPT_i) decode_format_string("d2"); - if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm); + if (opt & OPT_j) n_bytes_to_skip = xstrtooff_sfx(str_j, 0, bkm_suffixes); if (opt & OPT_l) decode_format_string("d4"); if (opt & OPT_o) decode_format_string("o2"); - //if (opt & OPT_t)... while (lst_t) { decode_format_string(llist_pop(&lst_t)); } - if (opt & OPT_v) verbose = 1; if (opt & OPT_x) decode_format_string("x2"); if (opt & OPT_s) decode_format_string("d2"); if (opt & OPT_S) { - string_min = 3; - string_min = xstrtou_sfx(str_S, 0, bkm); - flag_dump_strings = 1; + string_min = xstrtou_sfx(str_S, 0, bkm_suffixes); } - //if (opt & OPT_w)... - //if (opt & OPT_traditional)... - if (flag_dump_strings && n_specs > 0) - bb_error_msg_and_die("no type may be specified when dumping strings"); + // Bloat: + //if ((option_mask32 & OPT_S) && 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]]] + * 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 @@ -1309,93 +1260,91 @@ int od_main(int argc, char **argv) #if ENABLE_LONG_OPTS if (opt & OPT_traditional) { - off_t o1, o2; - - if (argc == 1) { - if (parse_old_offset(argv[0], &o1)) { - n_bytes_to_skip = o1; - --argc; - ++argv; - } - } else if (argc == 2) { - if (parse_old_offset(argv[0], &o1) - && parse_old_offset(argv[1], &o2) - ) { - n_bytes_to_skip = o1; - flag_pseudo_start = 1; - pseudo_start = o2; - argv += 2; - argc -= 2; - } else if (parse_old_offset(argv[1], &o2)) { - n_bytes_to_skip = o2; - --argc; - argv[1] = argv[0]; - ++argv; - } else { - bb_error_msg_and_die("invalid second operand " - "in compatibility mode '%s'", argv[1]); - } - } else if (argc == 3) { - if (parse_old_offset(argv[1], &o1) - && parse_old_offset(argv[2], &o2) - ) { - n_bytes_to_skip = o1; - flag_pseudo_start = 1; - pseudo_start = o2; - argv[2] = argv[0]; - argv += 2; - argc -= 2; - } else { - bb_error_msg_and_die("in compatibility mode " - "the last two arguments must be offsets"); + 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_error_msg_and_die("the last two arguments must be offsets"); + } + } else { /* >3 args */ + bb_error_msg_and_die("too many arguments"); } - } else if (argc > 3) { - bb_error_msg_and_die("compatibility mode supports " - "at most three arguments"); - } - if (flag_pseudo_start) { - if (format_address == format_address_none) { - address_base_char = 'o'; - address_pad_len_char = '7'; - format_address = format_address_paren; - } else - format_address = format_address_label; + if (pseudo_start >= 0) { + if (format_address == format_address_none) { + address_base_char = 'o'; + address_pad_len_char = '7'; + format_address = format_address_paren; + } else { + format_address = format_address_label; + } + pseudo_offset = pseudo_start - n_bytes_to_skip; + } } + /* else: od --traditional (without args) */ } #endif - if (limit_bytes_to_format) { + if (option_mask32 & OPT_N) { end_offset = n_bytes_to_skip + max_bytes_to_format; if (end_offset < n_bytes_to_skip) - bb_error_msg_and_die("skip-bytes + read-bytes is too large"); + bb_error_msg_and_die("SKIP + SIZE is too large"); } if (n_specs == 0) { decode_format_string("o2"); - n_specs = 1; + /*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: "-". */ file_list = bb_argv_dash; - if (argc > 0) { + if (argv[0]) { /* Set the global pointer FILE_LIST so that it references the first file-argument on the command-line. */ file_list = (char const *const *) argv; } - /* open the first input file */ + /* Open the first input file */ open_next_file(); - /* skip over any unwanted header bytes */ + /* Skip over any unwanted header bytes */ skip(n_bytes_to_skip); if (!in_stream) return EXIT_FAILURE; - pseudo_offset = (flag_pseudo_start ? pseudo_start - n_bytes_to_skip : 0); - - /* Compute output block length. */ + /* Compute output block length */ l_c_m = get_lcm(); if (opt & OPT_w) { /* -w: width */ @@ -1417,13 +1366,13 @@ int od_main(int argc, char **argv) } #endif - if (flag_dump_strings) + if (option_mask32 & OPT_S) dump_strings(n_bytes_to_skip, end_offset); else dump(n_bytes_to_skip, end_offset); - if (fclose(stdin) == EOF) + if (fclose(stdin)) bb_perror_msg_and_die(bb_msg_standard_input); - return ioerror; + return exit_code; } diff --git a/coreutils/printenv.c b/coreutils/printenv.c index 2430f3a..bd5db70 100644 --- a/coreutils/printenv.c +++ b/coreutils/printenv.c @@ -5,11 +5,19 @@ * Copyright (C) 2005 by Erik Andersen * Copyright (C) 2005 by Mike Frysinger * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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) { @@ -17,9 +25,14 @@ int printenv_main(int argc UNUSED_PARAM, char **argv) /* no variables specified, show whole env */ if (!argv[1]) { - int e = 0; - while (environ[e]) - puts(environ[e++]); + 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; diff --git a/coreutils/printf.c b/coreutils/printf.c index eb53fa4..3dd43a9 100644 --- a/coreutils/printf.c +++ b/coreutils/printf.c @@ -4,7 +4,7 @@ Copyright 1999 Dave Cinege Portions copyright (C) 1990-1996 Free Software Foundation, Inc. - Licensed under GPL v2 or later, see file LICENSE in this tarball for details. + Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Usage: printf format [argument...] @@ -36,7 +36,16 @@ David MacKenzie */ -// 19990508 Busy Boxed! Dave Cinege +/* 19990508 Busy Boxed! Dave Cinege */ + +//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" @@ -66,7 +75,7 @@ static int multiconvert(const char *arg, void *result, converter convert) errno = 0; convert(arg, result); if (errno) { - bb_error_msg("%s: invalid number", arg); + bb_error_msg("invalid number '%s'", arg); return 1; } return 0; @@ -122,16 +131,29 @@ static double my_xstrtod(const char *arg) return result; } -static void print_esc_string(char *str) +/* Handles %b */ +static void print_esc_string(const char *str) { - while (*str) { - if (*str == '\\') { - str++; - bb_putchar(bb_process_escape_sequence((const char **)&str)); - } else { - bb_putchar(*str); - 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++; + } + } + { + /* 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); } } @@ -230,7 +252,7 @@ static int get_width_prec(const char *str) { int v = bb_strtoi(str, NULL, 10); if (errno) { - bb_error_msg("%s: invalid number", str); + bb_error_msg("invalid number '%s'", str); v = 0; } return v; @@ -344,7 +366,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err) f--; break; default: - bb_putchar(*f); + putchar(*f); } } diff --git a/coreutils/pwd.c b/coreutils/pwd.c index 11278a2..bb3ad04 100644 --- a/coreutils/pwd.c +++ b/coreutils/pwd.c @@ -4,20 +4,79 @@ * * Copyright (C) 1995, 1996 by Bruce Perens . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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" /* This is a NOFORK applet. Be very careful! */ +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 != NULL) { + + if (buf) { puts(buf); free(buf); return fflush_all(); diff --git a/coreutils/readlink.c b/coreutils/readlink.c index 20df38b..d73ef4d 100644 --- a/coreutils/readlink.c +++ b/coreutils/readlink.c @@ -4,8 +4,19 @@ * * Copyright (C) 2000,2001 Matt Kraai * - * Licensed under GPL v2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define readlink_trivial_usage +//usage: IF_FEATURE_READLINK_FOLLOW("[-fnv] ") "FILE" +//usage:#define readlink_full_usage "\n\n" +//usage: "Display the value of a symlink" +//usage: IF_FEATURE_READLINK_FOLLOW( "\n" +//usage: "\n -f Canonicalize by following all symlinks" +//usage: "\n -n Don't add newline" +//usage: "\n -v Verbose" +//usage: ) + #include "libbb.h" /* @@ -28,7 +39,10 @@ * -q, --quiet, -s, --silent suppress most error messages * -v, --verbose report error messages * - * bbox supports: -f -n -v (fully), -q -s (accepts but ignores) + * 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; @@ -36,7 +50,6 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) { char *buf; char *fname; - char pathbuf[PATH_MAX]; IF_FEATURE_READLINK_FOLLOW( unsigned opt; @@ -56,7 +69,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) logmode = LOGMODE_NONE; if (opt & 1) { /* -f */ - buf = realpath(fname, pathbuf); + buf = xmalloc_realpath(fname); } else { buf = xmalloc_readlink_or_warn(fname); } @@ -65,7 +78,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) return EXIT_FAILURE; printf((opt & 2) ? "%s" : "%s\n", buf); - if (ENABLE_FEATURE_CLEAN_UP && !opt) + if (ENABLE_FEATURE_CLEAN_UP) free(buf); fflush_stdout_and_exit(EXIT_SUCCESS); diff --git a/coreutils/realpath.c b/coreutils/realpath.c index 3bc40ee..c513b55 100644 --- a/coreutils/realpath.c +++ b/coreutils/realpath.c @@ -7,9 +7,14 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define realpath_trivial_usage +//usage: "FILE..." +//usage:#define realpath_full_usage "\n\n" +//usage: "Return the absolute pathnames of given FILE" + #include "libbb.h" int realpath_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/coreutils/rm.c b/coreutils/rm.c index 3090cc3..042fba1 100644 --- a/coreutils/rm.c +++ b/coreutils/rm.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -15,6 +15,17 @@ * Size reduction. */ +//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 NOFORK applet. Be very careful! */ diff --git a/coreutils/rmdir.c b/coreutils/rmdir.c index 2450a43..cc2dea0 100644 --- a/coreutils/rmdir.c +++ b/coreutils/rmdir.c @@ -4,19 +4,35 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/rmdir.html */ +//usage:#define rmdir_trivial_usage +//usage: "[OPTIONS] DIRECTORY..." +//usage:#define rmdir_full_usage "\n\n" +//usage: "Remove DIRECTORY if it is empty\n" +//usage: IF_FEATURE_RMDIR_LONG_OPTIONS( +//usage: "\n -p|--parents Include parents" +//usage: "\n --ignore-fail-on-non-empty" +//usage: ) +//usage: IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( +//usage: "\n -p Include parents" +//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 0x01 -#define IGNORE_NON_EMPTY 0x02 +#define PARENTS (1 << 0) +//efine VERBOSE (1 << 1) //accepted but ignored +#define IGNORE_NON_EMPTY (1 << 2) int rmdir_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int rmdir_main(int argc UNUSED_PARAM, char **argv) @@ -28,13 +44,14 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_RMDIR_LONG_OPTIONS static const char rmdir_longopts[] ALIGN1 = "parents\0" No_argument "p" + "verbose\0" No_argument "v" /* Debian etch: many packages fail to be purged or installed * because they desperately want this option: */ "ignore-fail-on-non-empty\0" No_argument "\xff" ; applet_long_options = rmdir_longopts; #endif - flags = getopt32(argv, "p"); + flags = getopt32(argv, "pv"); argv += optind; if (!*argv) { @@ -50,7 +67,7 @@ int rmdir_main(int argc UNUSED_PARAM, char **argv) if ((flags & IGNORE_NON_EMPTY) && errno == ENOTEMPTY) break; #endif - bb_perror_msg("'%s'", path); /* Match gnu rmdir msg. */ + bb_perror_msg("'%s'", path); /* Match gnu rmdir msg. */ status = EXIT_FAILURE; } else if (flags & PARENTS) { /* Note: path was not "" since rmdir succeeded. */ diff --git a/coreutils/seq.c b/coreutils/seq.c index 84d11fd..8986192 100644 --- a/coreutils/seq.c +++ b/coreutils/seq.c @@ -4,8 +4,17 @@ * * Copyright (C) 2004, Glenn McGrath * - * Licensed under the GPL v2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//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 to last with leading zeros" +//usage: "\n -s SEP String separator" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ @@ -86,7 +95,8 @@ int seq_main(int argc, char **argv) v = first; n = 0; while (increment >= 0 ? v <= last : v >= last) { - printf("%s%0*.*f", sep, width, frac_part, v); + 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++; diff --git a/coreutils/sleep.c b/coreutils/sleep.c index 399a38d..0ffbd16 100644 --- a/coreutils/sleep.c +++ b/coreutils/sleep.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -18,9 +18,24 @@ * time suffixes for seconds, minutes, hours, and days. */ +//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" -/* This is a NOFORK applet. Be very careful! */ +/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells */ #if ENABLE_FEATURE_FANCY_SLEEP || ENABLE_FEATURE_FLOAT_SLEEP @@ -49,6 +64,10 @@ int sleep_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_FLOAT_SLEEP +# if ENABLE_LOCALE_SUPPORT + /* undo busybox.c setlocale */ + setlocale(LC_NUMERIC, "C"); +# endif duration = 0; do { char *arg = *argv; @@ -62,14 +81,15 @@ int sleep_main(int argc UNUSED_PARAM, char **argv) d = strtod(arg, &pp); if (errno || *pp) bb_show_usage(); - arg[len] = sv; - len--; - sv = arg[len]; - arg[len] = '1'; - duration += d * xatoul_sfx(&arg[len], sfx); - arg[len] = sv; - } else + arg += len; + *arg-- = sv; + sv = *arg; + *arg = '1'; + duration += d * xatoul_sfx(arg, sfx); + *arg = sv; + } else { duration += xatoul_sfx(arg, sfx); + } } while (*++argv); ts.tv_sec = MAXINT(typeof(ts.tv_sec)); diff --git a/coreutils/sort.c b/coreutils/sort.c index 5c3fa1a..a1625fc 100644 --- a/coreutils/sort.c +++ b/coreutils/sort.c @@ -6,12 +6,59 @@ * * MAINTAINER: Rob Landley * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * 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 */ +//usage:#define sort_trivial_usage +//usage: "[-nru" +//usage: IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][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 -b Ignore leading blanks" +//usage: "\n -c Check whether input is sorted" +//usage: "\n -d Dictionary order (blank or alphanumeric only)" +//usage: "\n -f Ignore case" +//usage: "\n -g General numerical sort" +//usage: "\n -i Ignore unprintable characters" +//usage: "\n -k Sort key" +//usage: "\n -M Sort month" +//usage: ) +//usage: "\n -n Sort numbers" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -o Output to file" +//usage: "\n -k Sort by key" +//usage: "\n -t CHAR Key separator" +//usage: ) +//usage: "\n -r Reverse sort order" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -s Stable (don't sort ties alphabetically)" +//usage: ) +//usage: "\n -u Suppress duplicate lines" +//usage: IF_FEATURE_SORT_BIG( +//usage: "\n -z Lines are terminated by NUL, not newline" +//usage: "\n -mST 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" /* This is a NOEXEC applet. Be very careful! */ @@ -52,8 +99,8 @@ enum { 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 */ + struct sort_key *next_key; /* linked list */ + unsigned range[4]; /* start word, start char, end word, end char */ unsigned flags; } *key_list; @@ -172,7 +219,7 @@ static int compare_keys(const void *xarg, const void *yarg) 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 */ + * level of the for () loop we're not using */ { x = *(char **)xarg; y = *(char **)yarg; @@ -412,7 +459,7 @@ int sort_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_SORT_BIG /* Open output file _after_ we read all input ones */ if (option_mask32 & FLAG_o) - xmove_fd(xopen3(str_o, O_WRONLY, 0666), STDOUT_FILENO); + xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), STDOUT_FILENO); #endif flag = (option_mask32 & FLAG_z) ? '\0' : '\n'; for (i = 0; i < linecount; i++) diff --git a/coreutils/split.c b/coreutils/split.c index c2f3885..1e1673e 100644 --- a/coreutils/split.c +++ b/coreutils/split.c @@ -3,25 +3,35 @@ * split - split a file into pieces * Copyright (c) 2007 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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" -static const struct suffix_mult split_suffices[] = { #if ENABLE_FEATURE_SPLIT_FANCY +static const struct suffix_mult split_suffixes[] = { { "b", 512 }, -#endif { "k", 1024 }, { "m", 1024*1024 }, -#if ENABLE_FEATURE_SPLIT_FANCY { "g", 1024*1024*1024 }, -#endif { "", 0 } }; +#endif /* Increment the suffix part of the filename. * Returns NULL if we are out of filenames. @@ -32,7 +42,7 @@ static char *next_file(char *old, unsigned suffix_len) unsigned i = 1; char *curr; - do { + while (1) { curr = old + end - i; if (*curr < 'z') { *curr += 1; @@ -43,7 +53,7 @@ static char *next_file(char *old, unsigned suffix_len) return NULL; } *curr = 'a'; - } while (1); + } return old; } @@ -74,7 +84,10 @@ int split_main(int argc UNUSED_PARAM, char **argv) if (opt & SPLIT_OPT_l) cnt = XATOOFF(count_p); if (opt & SPLIT_OPT_b) // FIXME: also needs XATOOFF - cnt = xatoull_sfx(count_p, split_suffices); + cnt = xatoull_sfx(count_p, + IF_FEATURE_SPLIT_FANCY(split_suffixes) + IF_NOT_FEATURE_SPLIT_FANCY(km_suffixes) + ); sfx = "x"; argv += optind; @@ -82,9 +95,7 @@ int split_main(int argc UNUSED_PARAM, char **argv) int fd; if (argv[1]) sfx = argv[1]; - fd = open_or_warn_stdin(argv[0]); - if (fd == -1) - return EXIT_FAILURE; + fd = xopen_stdin(argv[0]); xmove_fd(fd, STDIN_FILENO); } else { argv[0] = (char *) bb_msg_standard_input; diff --git a/coreutils/stat.c b/coreutils/stat.c index e7c24e6..dc9d81c 100644 --- a/coreutils/stat.c +++ b/coreutils/stat.c @@ -10,8 +10,68 @@ * Written by Michael Meskes * Taken from coreutils and turned into a busybox applet by Mike Frysinger * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define stat_trivial_usage +//usage: "[OPTIONS] FILE..." +//usage:#define stat_full_usage "\n\n" +//usage: "Display file (default) or filesystem status\n" +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n -c fmt Use the specified format" +//usage: ) +//usage: "\n -f Display filesystem status" +//usage: "\n -L Follow links" +//usage: "\n -t Display info in terse form" +//usage: IF_SELINUX( +//usage: "\n -Z Print security context" +//usage: ) +//usage: IF_FEATURE_STAT_FORMAT( +//usage: "\n\nValid format sequences 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 The 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 of owner\n" +//usage: " %G Group name of owner\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 of owner\n" +//usage: " %U User name of owner\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: "\nValid format sequences for file systems:\n" +//usage: " %a Free blocks available to non-superuser\n" +//usage: " %b Total data blocks in file system\n" +//usage: " %c Total file nodes in file system\n" +//usage: " %d Free file nodes in file system\n" +//usage: " %f Free blocks in file system\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: ) + #include "libbb.h" #define OPT_FILESYS (1 << 0) @@ -39,9 +99,15 @@ static const char *file_type(const struct stat *st) 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 @@ -61,7 +127,7 @@ static const char *human_time(time_t t) /*static char buf[sizeof("YYYY-MM-DD HH:MM:SS.000000000")] ALIGN1;*/ #define buf bb_common_bufsiz1 - strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S.000000000", localtime(&t)); + strcpy(strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &t), ".000000000"); return buf; #undef buf } @@ -247,14 +313,12 @@ static void FAST_FUNC print_stat(char *pformat, const char m, strcat(pformat, "lu"); printf(pformat, (unsigned long) statbuf->st_uid); } else if (m == 'U') { - setpwent(); pw_ent = getpwuid(statbuf->st_uid); printfs(pformat, (pw_ent != NULL) ? pw_ent->pw_name : "UNKNOWN"); } else if (m == 'g') { strcat(pformat, "lu"); printf(pformat, (unsigned long) statbuf->st_gid); } else if (m == 'G') { - setgrent(); gw_ent = getgrgid(statbuf->st_gid); printfs(pformat, (gw_ent != NULL) ? gw_ent->gr_name : "UNKNOWN"); } else if (m == 't') { @@ -378,7 +442,7 @@ static bool do_statfs(const char *filename, const char *format) : getfilecon(filename, &scontext) ) < 0 ) { - bb_perror_msg(filename); + bb_simple_perror_msg(filename); return 0; } } @@ -471,7 +535,7 @@ static bool do_statfs(const char *filename, const char *format) if (scontext) freecon(scontext); # endif -#endif /* FEATURE_STAT_FORMAT */ +#endif /* FEATURE_STAT_FORMAT */ return 1; } @@ -491,7 +555,7 @@ static bool do_stat(const char *filename, const char *format) : getfilecon(filename, &scontext) ) < 0 ) { - bb_perror_msg(filename); + bb_simple_perror_msg(filename); return 0; } } @@ -527,37 +591,43 @@ static bool do_stat(const char *filename, const char *format) # 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"); + "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o %C\n" + : + "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o\n" + ); } else { if (S_ISBLK(statbuf.st_mode) || S_ISCHR(statbuf.st_mode)) { format = (option_mask32 & OPT_SELINUX ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %-5h" - " Device type: %t,%T\n" - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - " S_Context: %C\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n": - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %-5h" - " Device type: %t,%T\n" - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n"); + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + " S_Context: %C\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n" + : + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %-5h" + " Device type: %t,%T\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n" + ); } else { format = (option_mask32 & OPT_SELINUX ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %h\n" - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - "S_Context: %C\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n": - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %h\n" - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n"); + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "S_Context: %C\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n" + : + " File: %N\n" + " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" + "Device: %Dh/%dd\tInode: %-10i Links: %h\n" + "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" + "Access: %x\n" "Modify: %y\n" "Change: %z\n" + ); } } # endif @@ -591,20 +661,20 @@ static bool do_stat(const char *filename, const char *format) # endif } else { char *linkname = NULL; - struct passwd *pw_ent; struct group *gw_ent; - setgrent(); + gw_ent = getgrgid(statbuf.st_gid); - setpwent(); pw_ent = getpwuid(statbuf.st_uid); if (S_ISLNK(statbuf.st_mode)) linkname = xmalloc_readlink_or_warn(filename); - if (linkname) + if (linkname) { printf(" File: '%s' -> '%s'\n", filename, linkname); - else + 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", @@ -632,12 +702,11 @@ static bool do_stat(const char *filename, const char *format) # if ENABLE_SELINUX printf(" S_Context: %lc\n", *scontext); # endif - printf("Access: %s\n" "Modify: %s\n" "Change: %s\n", - human_time(statbuf.st_atime), - human_time(statbuf.st_mtime), - human_time(statbuf.st_ctime)); + printf("Access: %s\n", human_time(statbuf.st_atime)); + printf("Modify: %s\n", human_time(statbuf.st_mtime)); + printf("Change: %s\n", human_time(statbuf.st_ctime)); } -#endif /* FEATURE_STAT_FORMAT */ +#endif /* FEATURE_STAT_FORMAT */ return 1; } diff --git a/coreutils/stty.c b/coreutils/stty.c index c40d718..378a848 100644 --- a/coreutils/stty.c +++ b/coreutils/stty.c @@ -2,7 +2,7 @@ /* stty -- change and print terminal line settings Copyright (C) 1990-1999 Free Software Foundation, Inc. - Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Usage: stty [-ag] [-F device] [setting...] @@ -21,6 +21,16 @@ */ +//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" + #include "libbb.h" #ifndef _POSIX_VDISABLE @@ -59,6 +69,10 @@ #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 @@ -115,6 +129,116 @@ # 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 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 @@ -122,10 +246,21 @@ enum speed_setting { /* Which member(s) of 'struct termios' a mode uses */ enum { - /* Do NOT change the order or values, as mode_type_flag() - * depends on them */ 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 */ @@ -167,13 +302,13 @@ enum { IDX_cbreak, IDX_crt, IDX_dec, -#ifdef IXANY +#if IXANY IDX_decctlq, #endif -#if defined(TABDLY) || defined(OXTABS) +#if TABDLY || OXTABS IDX_tabs, #endif -#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) +#if XCASE && IUCLC && OLCUC IDX_lcase, IDX_LCASE, #endif @@ -196,13 +331,13 @@ static const char mode_name[] = MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) MI_ENTRY("crt", combination, OMIT, 0, 0 ) MI_ENTRY("dec", combination, OMIT, 0, 0 ) -#ifdef IXANY +#if IXANY MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) #endif -#if defined(TABDLY) || defined(OXTABS) +#if TABDLY || OXTABS MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) #endif -#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) +#if XCASE && IUCLC && OLCUC MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) #endif @@ -217,7 +352,7 @@ static const char mode_name[] = MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) -#ifdef CRTSCTS +#if CRTSCTS MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) #endif MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) @@ -231,100 +366,107 @@ static const char mode_name[] = MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) -#ifdef IUCLC + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) +#if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif -#ifdef IXANY +#if IXANY MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) #endif -#ifdef IMAXBEL +#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 ) -#ifdef OLCUC +#if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) #endif -#ifdef OCRNL +#if OCRNL MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) #endif -#ifdef ONLCR +#if ONLCR MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) #endif -#ifdef ONOCR +#if ONOCR MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) #endif -#ifdef ONLRET +#if ONLRET MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) #endif -#ifdef OFILL +#if OFILL MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) #endif -#ifdef OFDEL +#if OFDEL MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) #endif -#ifdef NLDLY +#if NLDLY MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) #endif -#ifdef CRDLY +#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 -#ifdef TABDLY +#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 -# ifdef OXTABS +# if OXTABS MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) # endif #endif -#ifdef BSDLY +#if BSDLY MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) #endif -#ifdef VTDLY +#if VTDLY MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) #endif -#ifdef FFDLY +#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 ) -#ifdef IEXTEN +#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, REV | OMIT, 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 ) -#ifdef XCASE +#if XCASE MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) #endif -#ifdef TOSTOP +#if TOSTOP MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) #endif -#ifdef ECHOPRT +#if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif -#ifdef ECHOCTL +#if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif -#ifdef ECHOKE +#if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif ; @@ -346,13 +488,13 @@ static const struct mode_info mode_info[] = { MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) MI_ENTRY("crt", combination, OMIT, 0, 0 ) MI_ENTRY("dec", combination, OMIT, 0, 0 ) -#ifdef IXANY +#if IXANY MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) #endif -#if defined(TABDLY) || defined(OXTABS) +#if TABDLY || OXTABS MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) #endif -#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) +#if XCASE && IUCLC && OLCUC MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) #endif @@ -367,7 +509,7 @@ static const struct mode_info mode_info[] = { MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) -#ifdef CRTSCTS +#if CRTSCTS MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) #endif MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) @@ -381,100 +523,107 @@ static const struct mode_info mode_info[] = { MI_ENTRY("icrnl", input, SANE_SET | REV, ICRNL, 0 ) MI_ENTRY("ixon", input, REV, IXON, 0 ) MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) -#ifdef IUCLC + MI_ENTRY("tandem", input, OMIT | REV, IXOFF, 0 ) +#if IUCLC MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) #endif -#ifdef IXANY +#if IXANY MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) #endif -#ifdef IMAXBEL +#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 ) -#ifdef OLCUC +#if OLCUC MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) #endif -#ifdef OCRNL +#if OCRNL MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) #endif -#ifdef ONLCR +#if ONLCR MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) #endif -#ifdef ONOCR +#if ONOCR MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) #endif -#ifdef ONLRET +#if ONLRET MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) #endif -#ifdef OFILL +#if OFILL MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) #endif -#ifdef OFDEL +#if OFDEL MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) #endif -#ifdef NLDLY +#if NLDLY MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) #endif -#ifdef CRDLY +#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 -#ifdef TABDLY +#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 -# ifdef OXTABS +# if OXTABS MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) # endif #endif -#ifdef BSDLY +#if BSDLY MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) #endif -#ifdef VTDLY +#if VTDLY MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) #endif -#ifdef FFDLY +#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 ) -#ifdef IEXTEN +#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, REV | OMIT, 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 ) -#ifdef XCASE +#if XCASE MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) #endif -#ifdef TOSTOP +#if TOSTOP MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) #endif -#ifdef ECHOPRT +#if ECHOPRT MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) + MI_ENTRY("prterase", local, OMIT | REV, ECHOPRT, 0 ) #endif -#ifdef ECHOCTL +#if ECHOCTL MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) + MI_ENTRY("ctlecho", local, OMIT | REV, ECHOCTL, 0 ) #endif -#ifdef ECHOKE +#if ECHOKE MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) + MI_ENTRY("crtkill", local, OMIT | REV, ECHOKE, 0 ) #endif }; @@ -497,31 +646,31 @@ enum { CIDX_kill, CIDX_eof, CIDX_eol, -#ifdef VEOL2 +#if VEOL2 CIDX_eol2, #endif -#ifdef VSWTCH +#if VSWTCH CIDX_swtch, #endif CIDX_start, CIDX_stop, CIDX_susp, -#ifdef VDSUSP +#if VDSUSP CIDX_dsusp, #endif -#ifdef VREPRINT +#if VREPRINT CIDX_rprnt, #endif -#ifdef VWERASE +#if VWERASE CIDX_werase, #endif -#ifdef VLNEXT +#if VLNEXT CIDX_lnext, #endif -#ifdef VFLUSHO +#if VFLUSHO CIDX_flush, #endif -#ifdef VSTATUS +#if VSTATUS CIDX_status, #endif CIDX_min, @@ -538,31 +687,31 @@ static const char control_name[] = CI_ENTRY("kill", CKILL, VKILL ) CI_ENTRY("eof", CEOF, VEOF ) CI_ENTRY("eol", CEOL, VEOL ) -#ifdef VEOL2 +#if VEOL2 CI_ENTRY("eol2", CEOL2, VEOL2 ) #endif -#ifdef VSWTCH +#if VSWTCH CI_ENTRY("swtch", CSWTCH, VSWTCH ) #endif CI_ENTRY("start", CSTART, VSTART ) CI_ENTRY("stop", CSTOP, VSTOP ) CI_ENTRY("susp", CSUSP, VSUSP ) -#ifdef VDSUSP +#if VDSUSP CI_ENTRY("dsusp", CDSUSP, VDSUSP ) #endif -#ifdef VREPRINT +#if VREPRINT CI_ENTRY("rprnt", CRPRNT, VREPRINT) #endif -#ifdef VWERASE +#if VWERASE CI_ENTRY("werase", CWERASE, VWERASE ) #endif -#ifdef VLNEXT +#if VLNEXT CI_ENTRY("lnext", CLNEXT, VLNEXT ) #endif -#ifdef VFLUSHO +#if VFLUSHO CI_ENTRY("flush", CFLUSHO, VFLUSHO ) #endif -#ifdef VSTATUS +#if VSTATUS CI_ENTRY("status", CSTATUS, VSTATUS ) #endif /* These must be last because of the display routines */ @@ -581,31 +730,31 @@ static const struct control_info control_info[] = { CI_ENTRY("kill", CKILL, VKILL ) CI_ENTRY("eof", CEOF, VEOF ) CI_ENTRY("eol", CEOL, VEOL ) -#ifdef VEOL2 +#if VEOL2 CI_ENTRY("eol2", CEOL2, VEOL2 ) #endif -#ifdef VSWTCH +#if VSWTCH CI_ENTRY("swtch", CSWTCH, VSWTCH ) #endif CI_ENTRY("start", CSTART, VSTART ) CI_ENTRY("stop", CSTOP, VSTOP ) CI_ENTRY("susp", CSUSP, VSUSP ) -#ifdef VDSUSP +#if VDSUSP CI_ENTRY("dsusp", CDSUSP, VDSUSP ) #endif -#ifdef VREPRINT +#if VREPRINT CI_ENTRY("rprnt", CRPRNT, VREPRINT) #endif -#ifdef VWERASE +#if VWERASE CI_ENTRY("werase", CWERASE, VWERASE ) #endif -#ifdef VLNEXT +#if VLNEXT CI_ENTRY("lnext", CLNEXT, VLNEXT ) #endif -#ifdef VFLUSHO +#if VFLUSHO CI_ENTRY("flush", CFLUSHO, VFLUSHO ) #endif -#ifdef VSTATUS +#if VSTATUS CI_ENTRY("status", CSTATUS, VSTATUS ) #endif /* These must be last because of the display routines */ @@ -632,51 +781,6 @@ struct globals { G.max_col = 80; \ } while (0) - -/* Return a string that is the printable representation of character CH */ -/* Adapted from 'cat' by Torbjorn Granlund */ -static const char *visible(unsigned ch) -{ - char *bpout = G.buf; - - if (ch == _POSIX_VDISABLE) - return ""; - - if (ch >= 128) { - ch -= 128; - *bpout++ = 'M'; - *bpout++ = '-'; - } - - if (ch < 32) { - *bpout++ = '^'; - *bpout++ = ch + 64; - } else if (ch < 127) { - *bpout++ = ch; - } else { - *bpout++ = '^'; - *bpout++ = '?'; - } - - *bpout = '\0'; - return G.buf; -} - -static tcflag_t *mode_type_flag(unsigned type, const struct termios *mode) -{ - static const uint8_t tcflag_offsets[] ALIGN1 = { - offsetof(struct termios, c_cflag), /* control */ - offsetof(struct termios, c_iflag), /* input */ - offsetof(struct termios, c_oflag), /* output */ - offsetof(struct termios, c_lflag) /* local */ - }; - - if (type <= local) { - return (tcflag_t*) (((char*)mode) + tcflag_offsets[type]); - } - return NULL; -} - static void set_speed_or_die(enum speed_setting type, const char *arg, struct termios *mode) { @@ -740,6 +844,7 @@ static void newline(void) wrapf("\n"); } +#ifdef TIOCGWINSZ static void set_window_size(int rows, int cols) { struct winsize win = { 0, 0, 0, 0 }; @@ -760,6 +865,7 @@ static void set_window_size(int rows, int cols) bail: perror_on_device("%s"); } +#endif static void display_window_size(int fancy) { @@ -874,8 +980,9 @@ static void display_speed(const struct termios *mode, int fancy) const char *fmt_str = "%lu %lu\n\0ispeed %lu baud; ospeed %lu baud;"; unsigned long ispeed, ospeed; - ospeed = ispeed = cfgetispeed(mode); - if (ispeed == 0 || ispeed == (ospeed = cfgetospeed(mode))) { + 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;"; @@ -894,13 +1001,14 @@ static void do_display(const struct termios *mode, int all) display_speed(mode, 1); if (all) display_window_size(1); -#ifdef HAVE_C_LINE +#ifdef __linux__ wrapf("line = %u;\n", mode->c_line); #else newline(); #endif for (i = 0; i != CIDX_min; ++i) { + char ch; /* If swtch is the same as susp, don't print both */ #if VSWTCH == VSUSP if (i == CIDX_swtch) @@ -914,8 +1022,12 @@ static void do_display(const struct termios *mode, int all) continue; } #endif - wrapf("%s = %s;", nth_string(control_name, i), - visible(mode->c_cc[control_info[i].offset])); + ch = mode->c_cc[control_info[i].offset]; + if (ch == _POSIX_VDISABLE) + strcpy(G.buf, ""); + else + visible(ch, G.buf, 0); + wrapf("%s = %s;", nth_string(control_name, i), G.buf); } #if VEOF == VMIN if ((mode->c_lflag & ICANON) == 0) @@ -931,7 +1043,7 @@ static void do_display(const struct termios *mode, int all) prev_type = mode_info[i].type; } - bitsp = mode_type_flag(mode_info[i].type, mode); + 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)) @@ -950,7 +1062,6 @@ static void do_display(const struct termios *mode, int all) static void sane_mode(struct termios *mode) { int i; - tcflag_t *bitsp; for (i = 0; i < NUM_control_info; ++i) { #if VMIN == VEOF @@ -961,83 +1072,52 @@ static void sane_mode(struct termios *mode) } 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 = mode_type_flag(mode_info[i].type, mode); - *bitsp = (*bitsp & ~((unsigned long)mode_info[i].mask)) - | mode_info[i].bits; - } else if (mode_info[i].flags & SANE_UNSET) { - bitsp = mode_type_flag(mode_info[i].type, mode); - *bitsp = *bitsp & ~((unsigned long)mode_info[i].mask) - & ~mode_info[i].bits; + *bitsp = val | mode_info[i].bits; + } else + if (mode_info[i].flags & SANE_UNSET) { + *bitsp = val & ~mode_info[i].bits; } } } -/* Save set_mode from #ifdef forest plague */ -#ifndef ONLCR -#define ONLCR 0 -#endif -#ifndef OCRNL -#define OCRNL 0 -#endif -#ifndef ONLRET -#define ONLRET 0 -#endif -#ifndef XCASE -#define XCASE 0 -#endif -#ifndef IXANY -#define IXANY 0 -#endif -#ifndef TABDLY -#define TABDLY 0 -#endif -#ifndef OXTABS -#define OXTABS 0 -#endif -#ifndef IUCLC -#define IUCLC 0 -#endif -#ifndef OLCUC -#define OLCUC 0 -#endif -#ifndef ECHOCTL -#define ECHOCTL 0 -#endif -#ifndef ECHOKE -#define ECHOKE 0 -#endif - static void set_mode(const struct mode_info *info, int reversed, struct termios *mode) { tcflag_t *bitsp; - bitsp = mode_type_flag(info->type, mode); + bitsp = get_ptr_to_tcflag(info->type, mode); if (bitsp) { + tcflag_t val = *bitsp & ~info->mask; if (reversed) - *bitsp = *bitsp & ~info->mask & ~info->bits; + *bitsp = val & ~info->bits; else - *bitsp = (*bitsp & ~info->mask) | info->bits; + *bitsp = val | info->bits; return; } - /* Combination mode */ + /* !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; + 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; + 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; + 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; @@ -1093,27 +1173,32 @@ static void set_mode(const struct mode_info *info, int reversed, mode->c_cc[VTIME] = 0; } } - else if (IXANY && info == &mode_info[IDX_decctlq]) { +#if IXANY + else if (info == &mode_info[IDX_decctlq]) { if (reversed) mode->c_iflag |= IXANY; else mode->c_iflag &= ~IXANY; } - else if (TABDLY && info == &mode_info[IDX_tabs]) { +#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; } - else if (OXTABS && info == &mode_info[IDX_tabs]) { +#endif +#if OXTABS + else if (info == &mode_info[IDX_tabs]) { if (reversed) mode->c_oflag |= OXTABS; else mode->c_oflag &= ~OXTABS; - } else - if (XCASE && IUCLC && OLCUC - && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE]) - ) { + } +#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; @@ -1123,7 +1208,9 @@ static void set_mode(const struct mode_info *info, int reversed, mode->c_iflag |= IUCLC; mode->c_oflag |= OLCUC; } - } else if (info == &mode_info[IDX_crt]) { + } +#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 */ @@ -1255,7 +1342,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) } switch (param) { -#ifdef HAVE_C_LINE +#ifdef __linux__ case param_line: # ifndef TIOCGWINSZ xatoul_range_sfx(argnext, 1, INT_MAX, stty_suffixes); @@ -1291,13 +1378,15 @@ int stty_main(int argc UNUSED_PARAM, char **argv) /* Specifying both -a and -g is an error */ if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) == - (STTY_verbose_output | STTY_recoverable_output)) - bb_error_msg_and_die("verbose and stty-readable output styles are mutually exclusive"); + (STTY_verbose_output | STTY_recoverable_output) + ) { + bb_error_msg_and_die("-a and -g are mutually exclusive"); + } /* Specifying -a or -g with non-options is an error */ - if (!(stty_state & STTY_noargs) - && (stty_state & (STTY_verbose_output | STTY_recoverable_output)) + if ((stty_state & (STTY_verbose_output | STTY_recoverable_output)) + && !(stty_state & STTY_noargs) ) { - bb_error_msg_and_die("modes may not be set when specifying an output style"); + bb_error_msg_and_die("modes may not be set when -a or -g is used"); } /* Now it is safe to start doing things */ @@ -1359,7 +1448,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) } switch (param) { -#ifdef HAVE_C_LINE +#ifdef __linux__ case param_line: mode.c_line = xatoul_sfx(argnext, stty_suffixes); stty_state |= STTY_require_set_attr; @@ -1419,7 +1508,12 @@ int stty_main(int argc UNUSED_PARAM, char **argv) perror_on_device_and_die("%s"); if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { -#ifdef CIBAUD +/* + * 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 diff --git a/coreutils/sum.c b/coreutils/sum.c index 35e89a6..deb068e 100644 --- a/coreutils/sum.c +++ b/coreutils/sum.c @@ -10,9 +10,16 @@ * Written by Kayvan Aghaiepour and David MacKenzie * Taken from coreutils and turned into a busybox applet by Mike Frysinger * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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" enum { SUM_BSD, PRINT_NAME, SUM_SYSV }; @@ -63,9 +70,9 @@ static unsigned sum_file(const char *file, unsigned type) if (type >= SUM_SYSV) { r = (s & 0xffff) + ((s & 0xffffffff) >> 16); s = (r & 0xffff) + (r >> 16); - printf("%d %llu %s\n", s, (total_bytes + 511) / 512, file); + printf("%u %llu %s\n", s, (total_bytes + 511) / 512, file); } else - printf("%05d %5llu %s\n", s, (total_bytes + 1023) / 1024, file); + printf("%05u %5llu %s\n", s, (total_bytes + 1023) / 1024, file); return 1; #undef buf } @@ -87,8 +94,8 @@ int sum_main(int argc UNUSED_PARAM, char **argv) n = sum_file("-", type); } else { /* Need to print the name if either - - more than one file given - - doing sysv */ + * - more than one file given + * - doing sysv */ type += (argv[1] || type == SUM_SYSV); n = 1; do { diff --git a/coreutils/sync.c b/coreutils/sync.c index 59305c6..7d98a1e 100644 --- a/coreutils/sync.c +++ b/coreutils/sync.c @@ -4,11 +4,16 @@ * * Copyright (C) 1995, 1996 by Bruce Perens . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ +//usage:#define sync_trivial_usage +//usage: "" +//usage:#define sync_full_usage "\n\n" +//usage: "Write all buffered blocks to disk" + #include "libbb.h" /* This is a NOFORK applet. Be very careful! */ diff --git a/coreutils/tac.c b/coreutils/tac.c index d70e23a..94d669d 100644 --- a/coreutils/tac.c +++ b/coreutils/tac.c @@ -6,7 +6,7 @@ * Copyright (C) 2007 Natanael Copa * Copyright (C) 2007 Tito Ragusa * - * Licensed under GPLv2, see file License in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * */ @@ -16,6 +16,11 @@ * http://www.uclibc.org/lists/busybox/2003-July/008813.html */ +//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! */ diff --git a/coreutils/tail.c b/coreutils/tail.c index 6397702..eab502b 100644 --- a/coreutils/tail.c +++ b/coreutils/tail.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 by Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant (need fancy for -c) */ @@ -24,19 +24,39 @@ * 7) lseek attempted when count==0 even if arg was +0 (from top) */ -#include "libbb.h" +//kbuild:lib-$(CONFIG_TAIL) += tail.o + +//usage:#define tail_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define tail_full_usage "\n\n" +//usage: "Print last 10 lines of each FILE (or stdin) to stdout.\n" +//usage: "With more than one FILE, precede each with a filename header.\n" +//usage: "\n -f Print data as file grows" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -s SECONDS Wait SECONDS between reads with -f" +//usage: ) +//usage: "\n -n N[kbm] Print last N lines" +//usage: "\n -n +N[kbm] Start on Nth line and print the rest" +//usage: IF_FEATURE_FANCY_TAIL( +//usage: "\n -c [+]N[kbm] Print last N bytes" +//usage: "\n -q Never print headers" +//usage: "\n -v Always print headers" +//usage: "\n" +//usage: "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." +//usage: ) +//usage: +//usage:#define tail_example_usage +//usage: "$ tail -n 1 /etc/resolv.conf\n" +//usage: "nameserver 10.0.0.1\n" -static const struct suffix_mult tail_suffixes[] = { - { "b", 512 }, - { "k", 1024 }, - { "m", 1024*1024 }, - { "", 0 } -}; +#include "libbb.h" struct globals { - bool status; + bool from_top; + bool exitcode; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) static void tail_xprint_header(const char *fmt, const char *filename) { @@ -47,20 +67,11 @@ static void tail_xprint_header(const char *fmt, const char *filename) static ssize_t tail_read(int fd, char *buf, size_t count) { ssize_t r; - off_t current; - struct stat sbuf; - - /* /proc files report zero st_size, don't lseek them. */ - if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) { - current = lseek(fd, 0, SEEK_CUR); - if (sbuf.st_size < current) - xlseek(fd, 0, SEEK_SET); - } r = full_read(fd, buf, count); if (r < 0) { bb_perror_msg(bb_msg_read_error); - G.status = EXIT_FAILURE; + G.exitcode = EXIT_FAILURE; } return r; @@ -74,9 +85,9 @@ static unsigned eat_num(const char *p) p++; else if (*p == '+') { p++; - G.status = 1; /* mark that we saw "+" */ + G.from_top = 1; } - return xatou_sfx(p, tail_suffixes); + return xatou_sfx(p, bkm_suffixes); } int tail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -84,7 +95,6 @@ int tail_main(int argc, char **argv) { unsigned count = 10; unsigned sleep_period = 1; - bool from_top; const char *str_c, *str_n; char *tailbuf; @@ -95,6 +105,9 @@ int tail_main(int argc, char **argv) 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. */ @@ -127,8 +140,6 @@ int tail_main(int argc, char **argv) #endif argc -= optind; argv += optind; - from_top = G.status; /* 1 if there was "-c +N" or "-n +N" */ - G.status = EXIT_SUCCESS; /* open all the files */ fds = xmalloc(sizeof(fds[0]) * (argc + 1)); @@ -146,7 +157,7 @@ int tail_main(int argc, char **argv) do { int fd = open_or_warn_stdin(argv[i]); if (fd < 0 && !FOLLOW_RETRY) { - G.status = EXIT_FAILURE; + G.exitcode = EXIT_FAILURE; continue; } fds[nfiles] = fd; @@ -158,15 +169,19 @@ int tail_main(int argc, char **argv) /* prepare the buffer */ tailbufsize = BUFSIZ; - if (!from_top && COUNT_BYTES) { + if (!G.from_top && COUNT_BYTES) { if (tailbufsize < count + BUFSIZ) { tailbufsize = count + BUFSIZ; } } - tailbuf = xmalloc(tailbufsize); + /* 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 header leading newline on first output */ + + fmt = header_fmt_str + 1; /* skip leading newline in the header on the first output */ i = 0; do { char *buf; @@ -177,14 +192,14 @@ int tail_main(int argc, char **argv) int fd = fds[i]; if (ENABLE_FEATURE_FANCY_TAIL && fd < 0) - continue; /* may happen with -E */ + continue; /* may happen with -F */ if (nfiles > header_threshhold) { tail_xprint_header(fmt, argv[i]); fmt = header_fmt_str; } - if (!from_top) { + if (!G.from_top) { off_t current = lseek(fd, 0, SEEK_END); if (current > 0) { unsigned off; @@ -217,20 +232,23 @@ int tail_main(int argc, char **argv) } } + 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 (from_top) { + 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 = count; + seen += nread; } else { char *s = buf; do { @@ -288,10 +306,11 @@ int tail_main(int argc, char **argv) buf = tailbuf + taillen; } } /* while (tail_read() > 0) */ - if (!from_top) { + if (!G.from_top) { xwrite(STDOUT_FILENO, tailbuf, taillen); } } while (++i < nfiles); + prev_fd = fds[i-1]; tailbuf = xrealloc(tailbuf, BUFSIZ); @@ -335,17 +354,32 @@ int tail_main(int argc, char **argv) if (nfiles > header_threshhold) { fmt = header_fmt_str; } - while ((nread = tail_read(fd, tailbuf, BUFSIZ)) > 0) { - if (fmt) { + for (;;) { + /* tail -f keeps following files even if they are truncated */ + struct stat sbuf; + /* /proc files report zero st_size, don't lseek them */ + if (fstat(fd, &sbuf) == 0 && sbuf.st_size > 0) { + off_t current = lseek(fd, 0, SEEK_CUR); + if (sbuf.st_size < current) + xlseek(fd, 0, SEEK_SET); + } + + nread = tail_read(fd, tailbuf, BUFSIZ); + if (nread <= 0) + break; + 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.status; + return G.exitcode; } diff --git a/coreutils/tee.c b/coreutils/tee.c index 0f24246..48cc050 100644 --- a/coreutils/tee.c +++ b/coreutils/tee.c @@ -4,12 +4,24 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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" + #include "libbb.h" int tee_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -42,7 +54,7 @@ int tee_main(int argc, char **argv) * that doesn't consume all its input. Good idea... */ signal(SIGPIPE, SIG_IGN); - /* Allocate an array of FILE *'s, with one extra for a sentinal. */ + /* Allocate an array of FILE *'s, with one extra for a sentinel. */ fp = files = xzalloc(sizeof(FILE *) * (argc + 2)); np = names = argv - 1; @@ -70,8 +82,8 @@ int tee_main(int argc, char **argv) while ((c = safe_read(STDIN_FILENO, buf, sizeof(buf))) > 0) { fp = files; do - fwrite(buf, 1, c, *fp++); - while (*fp); + fwrite(buf, 1, c, *fp); + while (*++fp); } if (c < 0) { /* Make sure read errors are signaled. */ retval = EXIT_FAILURE; @@ -81,8 +93,8 @@ int tee_main(int argc, char **argv) while ((c = getchar()) != EOF) { fp = files; do - putc(c, *fp++); - while (*fp); + putc(c, *fp); + while (*++fp); } #endif diff --git a/coreutils/test.c b/coreutils/test.c index 70eac5f..4df505a 100644 --- a/coreutils/test.c +++ b/coreutils/test.c @@ -14,7 +14,7 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice states: * "This program is in the Public Domain." @@ -39,19 +39,42 @@ //config: help //config: Enable 64-bit support in test. +/* "test --help" does not print help (POSIX compat), only "[ --help" does. + * We display " EXPRESSION ]" here (not " EXPRESSION") + * Unfortunately, it screws up generated BusyBox.html. TODO. */ +//usage:#define test_trivial_usage +//usage: "EXPRESSION ]" +//usage:#define test_full_usage "\n\n" +//usage: "Check file types, compare values etc. Return a 0/1 exit code\n" +//usage: "depending on logical value of EXPRESSION" +//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 /* This is a NOFORK applet. Be very careful! */ /* test_main() is called from shells, and we need to be extra careful here. - * This is true regardless of PREFER_APPLETS and STANDALONE_SHELL + * 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 + oexpr ::= aexpr | aexpr "-o" oexpr ; + aexpr ::= nexpr | nexpr "-a" aexpr ; + nexpr ::= primary | "!" primary primary ::= unary-operator operand | operand binary-operator operand | operand @@ -587,7 +610,7 @@ static int test_eaccess(char *path, int mode) return 0; /* Root can execute any file that has any one of the execute - bits set. */ + * bits set. */ if (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) return 0; } @@ -687,7 +710,8 @@ static number_t nexpr(enum token n) if (n == EOI) { /* special case: [ ! ], [ a -a ! ] are valid */ /* IOW, "! ARG" may miss ARG */ - unnest_msg("aexpr(%s)\n", TOKSTR[n]); res = nexpr(n); - dbg_msg("aexpr: nexpr:%lld, next args:%s\n", res, args[1]); + 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\n", args[1]); + 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\n", res, args[1]); + 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\n", args[1]); + dbg_msg("oexpr: next arg is OR, next args:%s(%p)\n", args[1], &args[1]); res = oexpr(check_operator(*++args)) || res; unnest_msg(" * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ struct test_statics; diff --git a/coreutils/touch.c b/coreutils/touch.c index dceb7c1..293a968 100644 --- a/coreutils/touch.c +++ b/coreutils/touch.c @@ -4,10 +4,10 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m, -r, -t not supported. */ +/* BB_AUDIT SUSv3 _NOT_ compliant -- options -a, -m not supported. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/touch.html */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -19,6 +19,53 @@ #include "libbb.h" +//config:config TOUCH +//config: bool "touch" +//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_NODEREF +//config: bool "Add support for -h" +//config: default y +//config: depends on TOUCH +//config: help +//config: Enable touch to have the -h option. +//config: This requires libc support for lutimes() function. +//config: +//config:config FEATURE_TOUCH_SUSV3 +//config: bool "Add support for SUSV3 features (-d -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: "[-c]" IF_FEATURE_TOUCH_SUSV3(" [-d DATE] [-t DATE] [-r FILE]") " FILE..." +//usage:#define touch_full_usage "\n\n" +//usage: "Update the last-modified date on the given FILE[s]\n" +//usage: "\n -c Don't create files" +//usage: IF_FEATURE_TOUCH_NODEREF( +//usage: "\n -h Don't follow links" +//usage: ) +//usage: IF_FEATURE_TOUCH_SUSV3( +//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" + /* This is a NOFORK applet. Be very careful! */ /* coreutils implements: @@ -29,6 +76,7 @@ * 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 @@ -43,13 +91,21 @@ int touch_main(int argc UNUSED_PARAM, char **argv) int fd; int status = EXIT_SUCCESS; int opts; -#if ENABLE_DESKTOP + enum { + OPT_c = (1 << 0), + OPT_r = (1 << 1) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_d = (1 << 2) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_t = (1 << 3) * ENABLE_FEATURE_TOUCH_SUSV3, + OPT_h = (1 << 4) * ENABLE_FEATURE_TOUCH_NODEREF, + }; +#if ENABLE_FEATURE_TOUCH_SUSV3 # if ENABLE_LONG_OPTS static const char touch_longopts[] ALIGN1 = /* name, has_arg, val */ "no-create\0" No_argument "c" "reference\0" Required_argument "r" "date\0" Required_argument "d" + IF_FEATURE_TOUCH_NODEREF("no-dereference\0" No_argument "h") ; # endif char *reference_file = NULL; @@ -62,20 +118,20 @@ int touch_main(int argc UNUSED_PARAM, char **argv) # define timebuf ((struct timeval*)NULL) #endif -#if ENABLE_DESKTOP && ENABLE_LONG_OPTS +#if ENABLE_FEATURE_TOUCH_SUSV3 && ENABLE_LONG_OPTS applet_long_options = touch_longopts; #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 = getopt32(argv, "c" IF_DESKTOP("r:d:t:") + opts = getopt32(argv, "c" IF_FEATURE_TOUCH_SUSV3("r:d:t:") + IF_FEATURE_TOUCH_NODEREF("h") /*ignored:*/ "fma" - IF_DESKTOP(, &reference_file) - IF_DESKTOP(, &date_str) - IF_DESKTOP(, &date_str) + IF_FEATURE_TOUCH_SUSV3(, &reference_file) + IF_FEATURE_TOUCH_SUSV3(, &date_str) + IF_FEATURE_TOUCH_SUSV3(, &date_str) ); - opts &= 1; /* only -c bit is left */ argv += optind; if (!*argv) { bb_show_usage(); @@ -85,28 +141,40 @@ int touch_main(int argc UNUSED_PARAM, char **argv) struct stat stbuf; xstat(reference_file, &stbuf); timebuf[1].tv_sec = timebuf[0].tv_sec = stbuf.st_mtime; + /* Can use .st_mtim.tv_nsec + * (or is it .st_mtimensec?? see date.c) + * to set microseconds too. + */ } if (date_str) { struct tm tm_time; time_t t; - //time(&t); - //localtime_r(&t, &tm_time); - memset(&tm_time, 0, sizeof(tm_time)); + //memset(&tm_time, 0, sizeof(tm_time)); + /* Better than memset: makes "HH:MM" dates meaningful */ + time(&t); + localtime_r(&t, &tm_time); parse_datestr(date_str, &tm_time); /* Correct any day of week and day of year etc. fields */ - tm_time.tm_isdst = -1; /* Be sure to recheck dst */ + tm_time.tm_isdst = -1; /* Be sure to recheck dst */ t = validate_tm_time(date_str, &tm_time); timebuf[1].tv_sec = timebuf[0].tv_sec = t; } do { - if (utimes(*argv, (reference_file || date_str) ? timebuf : NULL) != 0) { - if (errno == ENOENT) { /* no such file */ - if (opts) { /* creation is disabled, so ignore */ + int result; + result = ( +#if ENABLE_FEATURE_TOUCH_NODEREF + (opts & OPT_h) ? lutimes : +#endif + utimes)(*argv, (reference_file || date_str) ? timebuf : NULL); + if (result != 0) { + if (errno == ENOENT) { /* no such file? */ + if (opts & OPT_c) { + /* Creation is disabled, so ignore */ continue; } /* Try to create the file */ diff --git a/coreutils/tr.c b/coreutils/tr.c index f3db379..e67948a 100644 --- a/coreutils/tr.c +++ b/coreutils/tr.c @@ -13,7 +13,7 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* http://www.opengroup.org/onlinepubs/009695399/utilities/tr.html * TODO: graph, print @@ -47,6 +47,18 @@ //config: useful for cases when no other way of expressing a character //config: is possible. +//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 { @@ -203,7 +215,7 @@ static unsigned expand(const char *arg, char **buffer_p) buffer[pos++] = *arg; /* copy CHAR */ if (!arg[0] || arg[1] != '=' || arg[2] != ']') bb_show_usage(); - arg += 3; /* skip CHAR=] */ + arg += 3; /* skip CHAR=] */ continue; } /* The rest of "[xyz..." cases is treated as normal @@ -258,9 +270,9 @@ int tr_main(int argc UNUSED_PARAM, char **argv) 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) +#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; @@ -324,5 +336,11 @@ int tr_main(int argc UNUSED_PARAM, char **argv) str2[out_index++] = last = coded; } + if (ENABLE_FEATURE_CLEAN_UP) { + free(vector); + free(str2); + free(str1); + } + return EXIT_SUCCESS; } diff --git a/coreutils/true.c b/coreutils/true.c index 8a7e6ae..382e476 100644 --- a/coreutils/true.c +++ b/coreutils/true.c @@ -4,12 +4,22 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/true.html */ +//usage:#define true_trivial_usage +//usage: "" +//usage:#define true_full_usage "\n\n" +//usage: "Return an exit code of TRUE (0)" +//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! */ diff --git a/coreutils/tty.c b/coreutils/tty.c index 69352ec..4517505 100644 --- a/coreutils/tty.c +++ b/coreutils/tty.c @@ -4,22 +4,34 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv4 compliant */ /* http://www.opengroup.org/onlinepubs/9699919799/utilities/tty.html */ +//usage:#define tty_trivial_usage +//usage: "" +//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. */ + IF_INCLUDE_SUSv2(int silent;) /* Note: No longer relevant in SUSv3. */ int retval; - xfunc_error_retval = 2; /* SUSv3 requires > 1 for error. */ + xfunc_error_retval = 2; /* SUSv3 requires > 1 for error. */ IF_INCLUDE_SUSv2(silent = getopt32(argv, "s");) IF_INCLUDE_SUSv2(argv += optind;) diff --git a/coreutils/uname.c b/coreutils/uname.c index 9822e49..b96d76b 100644 --- a/coreutils/uname.c +++ b/coreutils/uname.c @@ -2,7 +2,7 @@ /* uname -- print system information * Copyright (C) 1989-1999 Free Software Foundation, Inc. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ @@ -48,6 +48,22 @@ * Fix handling of -a to not print "unknown", add -o and -i support. */ +//usage:#define uname_trivial_usage +//usage: "[-amnrspv]" +//usage:#define uname_full_usage "\n\n" +//usage: "Print system information\n" +//usage: "\n -a Print all" +//usage: "\n -m The machine (hardware) type" +//usage: "\n -n Hostname" +//usage: "\n -r OS release" +//usage: "\n -s OS name (default)" +//usage: "\n -p Processor type" +//usage: "\n -v OS version" +//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" + #include "libbb.h" /* After libbb.h, since it needs sys/types.h on some systems */ #include diff --git a/coreutils/uniq.c b/coreutils/uniq.c index e566dc1..9208d34 100644 --- a/coreutils/uniq.c +++ b/coreutils/uniq.c @@ -4,12 +4,29 @@ * * Copyright (C) 2005 Manuel Novoa III * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 compliant */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/uniq.html */ +//usage:#define uniq_trivial_usage +//usage: "[-cdu][-f,s,w N] [INPUT [OUTPUT]]" +//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 -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; @@ -52,8 +69,8 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) if (output[0] != '-' || output[1]) { // Won't work with "uniq - FILE" and closed stdin: //close(STDOUT_FILENO); - //xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666); - xmove_fd(xopen3(output, O_WRONLY | O_CREAT | O_TRUNC, 0666), STDOUT_FILENO); + //xopen(output, O_WRONLY | O_CREAT | O_TRUNC); + xmove_fd(xopen(output, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); } } } @@ -86,7 +103,7 @@ int uniq_main(int argc UNUSED_PARAM, char **argv) } free(cur_line); - ++dups; /* testing for overflow seems excessive */ + ++dups; /* testing for overflow seems excessive */ } if (old_line) { diff --git a/coreutils/usleep.c b/coreutils/usleep.c index e7acd5f..2e4eb57 100644 --- a/coreutils/usleep.c +++ b/coreutils/usleep.c @@ -4,11 +4,20 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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! */ @@ -20,9 +29,7 @@ int usleep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); } - if (usleep(xatou(argv[1]))) { - bb_perror_nomsg_and_die(); - } + usleep(xatou(argv[1])); return EXIT_SUCCESS; } diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c index 0298a4b..b298fcb 100644 --- a/coreutils/uudecode.c +++ b/coreutils/uudecode.c @@ -1,20 +1,31 @@ /* vi: set sw=4 ts=4: */ /* - * Copyright 2003, Glenn McGrath + * Copyright 2003, Glenn McGrath * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * 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 + * 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 + * Bugs: the spec doesn't mention anything about "`\n`\n" prior to the + * "end" line */ +//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" -static void read_stduu(FILE *src_stream, FILE *dst_stream) +#if ENABLE_UUDECODE +static void FAST_FUNC read_stduu(FILE *src_stream, FILE *dst_stream, int flags UNUSED_PARAM) { char *line; @@ -74,67 +85,9 @@ static void read_stduu(FILE *src_stream, FILE *dst_stream) } bb_error_msg_and_die("short file"); } +#endif -static void read_base64(FILE *src_stream, FILE *dst_stream) -{ - int term_count = 1; - - while (1) { - char translated[4]; - int count = 0; - - while (count < 4) { - char *table_ptr; - int ch; - - /* Get next _valid_ character. - * global vector bb_uuenc_tbl_base64[] contains this string: - * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" - */ - do { - ch = fgetc(src_stream); - if (ch == EOF) { - bb_error_msg_and_die("short file"); - } - table_ptr = strchr(bb_uuenc_tbl_base64, ch); - } while (table_ptr == NULL); - - /* Convert encoded character to decimal */ - ch = table_ptr - bb_uuenc_tbl_base64; - - if (*table_ptr == '=') { - if (term_count == 0) { - translated[count] = '\0'; - break; - } - term_count++; - } else if (*table_ptr == '\n') { - /* Check for terminating line */ - if (term_count == 5) { - return; - } - term_count = 1; - continue; - } else { - translated[count] = ch; - count++; - term_count = 0; - } - } - - /* Merge 6 bit chars to 8 bit */ - if (count > 1) { - fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); - } - if (count > 2) { - fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); - } - if (count > 3) { - fputc(translated[2] << 6 | translated[3], dst_stream); - } - } -} - +#if ENABLE_UUDECODE int uudecode_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uudecode_main(int argc UNUSED_PARAM, char **argv) { @@ -146,13 +99,13 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) getopt32(argv, "o:", &outname); argv += optind; - if (!*argv) + if (!argv[0]) *--argv = (char*)"-"; - src_stream = xfopen_stdin(*argv); + src_stream = xfopen_stdin(argv[0]); /* Search for the start of the encoding */ while ((line = xmalloc_fgetline(src_stream)) != NULL) { - void (*decode_fn_ptr)(FILE *src, FILE *dst); + void FAST_FUNC (*decode_fn_ptr)(FILE *src, FILE *dst, int flags); char *line_ptr; FILE *dst_stream; int mode; @@ -172,10 +125,11 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) mode = bb_strtou(line_ptr, NULL, 8); if (outname == NULL) { outname = strchr(line_ptr, ' '); - if ((outname == NULL) || (*outname == '\0')) { + if (!outname) break; - } outname++; + if (!outname[0]) + break; } dst_stream = stdout; if (NOT_LONE_DASH(outname)) { @@ -183,12 +137,73 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv) fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } free(line); - decode_fn_ptr(src_stream, dst_stream); + 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_error_msg_and_die("no 'begin' line"); } +#endif + +//applet:IF_BASE64(APPLET(base64, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_BASE64) += uudecode.o + +//config:config BASE64 +//config: bool "base64" +//config: default y +//config: help +//config: Base64 encode and decode + +//usage:#define base64_trivial_usage +//usage: "[-d] [FILE]" +//usage:#define base64_full_usage "\n\n" +//usage: "Base64 encode or decode FILE to standard output" +//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" + +#if ENABLE_BASE64 +int base64_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int base64_main(int argc UNUSED_PARAM, char **argv) +{ + FILE *src_stream; + unsigned opts; + + opt_complementary = "?1"; /* 1 argument max */ + opts = getopt32(argv, "d"); + argv += optind; + + if (!argv[0]) + *--argv = (char*)"-"; + src_stream = xfopen_stdin(argv[0]); + if (opts) { + read_base64(src_stream, stdout, /*flags:*/ (char)EOF); + } else { + enum { + SRC_BUF_SIZE = 76/4*3, /* This *MUST* be a multiple of 3 */ + DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), + }; + char src_buf[SRC_BUF_SIZE]; + char dst_buf[DST_BUF_SIZE + 1]; + int src_fd = fileno(src_stream); + while (1) { + size_t size = full_read(src_fd, src_buf, SRC_BUF_SIZE); + if (!size) + break; + if ((ssize_t)size < 0) + bb_perror_msg_and_die(bb_msg_read_error); + /* Encode the buffer we just read in */ + bb_uuencode(dst_buf, src_buf, size, bb_uuenc_tbl_base64); + xwrite(STDOUT_FILENO, dst_buf, 4 * ((size + 2) / 3)); + bb_putchar('\n'); + fflush(stdout); + } + } + + fflush_stdout_and_exit(EXIT_SUCCESS); +} +#endif /* Test script. Put this into an empty dir with busybox binary, an run. diff --git a/coreutils/uuencode.c b/coreutils/uuencode.c index bf66185..673ef36 100644 --- a/coreutils/uuencode.c +++ b/coreutils/uuencode.c @@ -5,13 +5,26 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//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 = 45, /* This *MUST* be a multiple of 3 */ + SRC_BUF_SIZE = 15*3, /* This *MUST* be a multiple of 3 */ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), }; @@ -33,7 +46,7 @@ int uuencode_main(int argc UNUSED_PARAM, char **argv) } argv += optind; if (argv[1]) { - src_fd = xopen(*argv, O_RDONLY); + src_fd = xopen(argv[0], O_RDONLY); fstat(src_fd, &stat_buf); mode = stat_buf.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO); argv++; diff --git a/coreutils/wc.c b/coreutils/wc.c index 7116842..a410e40 100644 --- a/coreutils/wc.c +++ b/coreutils/wc.c @@ -4,10 +4,10 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* BB_AUDIT SUSv3 _NOT_ compliant -- option -m is not currently supported. */ +/* BB_AUDIT SUSv3 compliant. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/wc.html */ /* Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) @@ -19,10 +19,6 @@ * 3) no checking of ferror on EOF returns * 4) isprint() wasn't considered when word counting. * - * TODO: - * - * When locale support is enabled, count multibyte chars in the '-m' case. - * * NOTES: * * The previous busybox wc attempted an optimization using stat for the @@ -40,8 +36,8 @@ * * for which 'wc -c' should output '0'. */ - #include "libbb.h" +#include "unicode.h" #if !ENABLE_LOCALE_SUPPORT # undef isprint @@ -58,11 +54,38 @@ # 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 each FILE (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, - WC_WORDS = 1, - WC_CHARS = 2, - WC_LENGTH = 3 + 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; @@ -72,16 +95,18 @@ int wc_main(int argc UNUSED_PARAM, char **argv) const char *start_fmt = " %9"COUNT_FMT + 1; const char *fname_fmt = " %s\n"; COUNT_T *pcounts; - COUNT_T counts[4]; - COUNT_T totals[4]; + COUNT_T counts[NUM_WCS]; + COUNT_T totals[NUM_WCS]; int num_files; smallint status = EXIT_SUCCESS; unsigned print_type; - print_type = getopt32(argv, "lwcL"); + init_unicode(); + + print_type = getopt32(argv, "lwmcL"); if (print_type == 0) { - print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_CHARS); + print_type = (1 << WC_LINES) | (1 << WC_WORDS) | (1 << WC_BYTES); } argv += optind; @@ -99,7 +124,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) pcounts = counts; num_files = 0; - while ((arg = *argv++) != 0) { + while ((arg = *argv++) != NULL) { FILE *fp; const char *s; unsigned u; @@ -117,21 +142,28 @@ int wc_main(int argc UNUSED_PARAM, char **argv) linepos = 0; in_word = 0; - do { + while (1) { int c; /* Our -w doesn't match GNU wc exactly... oh well */ - ++counts[WC_CHARS]; c = getc(fp); if (c == EOF) { if (ferror(fp)) { bb_simple_perror_msg(arg); status = EXIT_FAILURE; } - --counts[WC_CHARS]; - goto DO_EOF; /* Treat an EOF as '\r'. */ + goto DO_EOF; /* Treat an EOF as '\r'. */ } - if (isprint_asciionly(c)) { + + /* 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; @@ -146,7 +178,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) */ if (c == '\t') { linepos = (linepos | 7) + 1; - } else { /* '\n', '\r', '\f', or '\v' */ + } else { /* '\n', '\r', '\f', or '\v' */ DO_EOF: if (linepos > counts[WC_LENGTH]) { counts[WC_LENGTH] = linepos; @@ -167,18 +199,18 @@ int wc_main(int argc UNUSED_PARAM, char **argv) if (c == EOF) { break; } - } while (1); + } + + fclose_if_not_stdin(fp); if (totals[WC_LENGTH] < counts[WC_LENGTH]) { totals[WC_LENGTH] = counts[WC_LENGTH]; } totals[WC_LENGTH] -= counts[WC_LENGTH]; - fclose_if_not_stdin(fp); - OUTPUT: /* coreutils wc tries hard to print pretty columns - * (saves results for all files, find max col len etc...) + * (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; @@ -188,7 +220,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) s = " %9"COUNT_FMT; /* Ok... restore the leading space. */ } totals[u] += pcounts[u]; - } while (++u < 4); + } while (++u < NUM_WCS); printf(fname_fmt, arg); } @@ -197,7 +229,7 @@ int wc_main(int argc UNUSED_PARAM, char **argv) * 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. */ + num_files = 0; /* Make sure we don't get here again. */ arg = "total"; pcounts = totals; --argv; diff --git a/coreutils/who.c b/coreutils/who.c index 2b43310..f955ce6 100644 --- a/coreutils/who.c +++ b/coreutils/who.c @@ -12,14 +12,45 @@ * * Copyright (c) 2002 AYR Networks, Inc. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * *---------------------------------------------------------------------- */ /* BB_AUDIT SUSv3 _NOT_ compliant -- missing options -b, -d, -l, -m, -p, -q, -r, -s, -t, -T, -u; Missing argument 'file'. */ +//config:config WHO +//config: bool "who" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: who is used to show who is logged on. + +//config:config USERS +//config: bool "users" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Print users currently logged on. + +//applet:IF_USERS(APPLET_ODDNAME(users, who, BB_DIR_USR_BIN, BB_SUID_DROP, users)) +//applet:IF_WHO( APPLET( who, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_USERS) += who.o +//kbuild:lib-$(CONFIG_WHO) += who.o + +//usage:#define users_trivial_usage +//usage: "" +//usage:#define users_full_usage "\n\n" +//usage: "Print the users currently logged on" + +//usage:#define who_trivial_usage +//usage: "[-a]" +//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" -#include static void idle_string(char *str6, time_t t) { @@ -44,9 +75,11 @@ int who_main(int argc UNUSED_PARAM, char **argv) { struct utmp *ut; unsigned opt; + int do_users = (ENABLE_USERS && (!ENABLE_WHO || applet_name[0] == 'u')); + const char *fmt = "%s"; opt_complementary = "=0"; - opt = getopt32(argv, "aH"); + opt = getopt32(argv, do_users ? "" : "aH"); if (opt & 2) // -H printf("USER\t\tTTY\t\tIDLE\tTIME\t\t HOST\n"); @@ -55,36 +88,43 @@ int who_main(int argc UNUSED_PARAM, char **argv) if (ut->ut_user[0] && ((opt & 1) || ut->ut_type == USER_PROCESS) ) { - char str6[6]; - char name[sizeof("/dev/") + sizeof(ut->ut_line) + 1]; - struct stat st; - time_t seconds; + 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, - ctime(&seconds) + 4, - (int)sizeof(ut->ut_host), ut->ut_host - ); + 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, + 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) endutent(); return EXIT_SUCCESS; diff --git a/coreutils/whoami.c b/coreutils/whoami.c index 22d722e..30b17ca 100644 --- a/coreutils/whoami.c +++ b/coreutils/whoami.c @@ -4,11 +4,16 @@ * * Copyright (C) 2000 Edward Betts . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* 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" /* This is a NOFORK applet. Be very careful! */ diff --git a/coreutils/yes.c b/coreutils/yes.c index ead674b..5d799f0 100644 --- a/coreutils/yes.c +++ b/coreutils/yes.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A -- Matches GNU behavior. */ diff --git a/debian/bin/genorig.py b/debian/bin/genorig.py deleted file mode 100755 index f0857fa..0000000 --- a/debian/bin/genorig.py +++ /dev/null @@ -1,168 +0,0 @@ -#!/usr/bin/env python - -import os, os.path, re, shutil, sys - -class Changelog(list): - _rules = r""" -^ -(?P - \w[-+0-9a-z.]+ -) -\ -\( -(?P - [^\(\)\ \t]+ -) -\) -\s+ -(?P - [-+0-9a-zA-Z.]+ -) -\; -""" - _re = re.compile(_rules, re.X) - - class Entry(object): - __slot__ = 'distribution', 'source', 'version' - - def __init__(self, distribution, source, version): - self.distribution, self.source, self.version = distribution, source, version - - def __init__(self, dir = '', version = None): - if version is None: - version = Version - f = file(os.path.join(dir, "debian/changelog")) - while True: - line = f.readline() - if not line: - break - match = self._re.match(line) - if not match: - continue - try: - v = version(match.group('version')) - except Exception: - if not len(self): - raise - v = Version(match.group('version')) - self.append(self.Entry(match.group('distribution'), match.group('source'), v)) - -class Version(object): - _version_rules = ur""" -^ -(?: - (?P - \d+ - ) - : -)? -(?P - .+? -) -(?: - - - (?P[^-]+) -)? -$ -""" - _version_re = re.compile(_version_rules, re.X) - - def __init__(self, version): - match = self._version_re.match(version) - if match is None: - raise RuntimeError, "Invalid debian version" - self.epoch = None - if match.group("epoch") is not None: - self.epoch = int(match.group("epoch")) - self.upstream = match.group("upstream") - self.revision = match.group("revision") - - def __str__(self): - return self.complete - - @property - def complete(self): - if self.epoch is not None: - return "%d:%s" % (self.epoch, self.complete_noepoch) - return self.complete_noepoch - - @property - def complete_noepoch(self): - if self.revision is not None: - return "%s-%s" % (self.upstream, self.revision) - return self.upstream - -class Main(object): - def __init__(self, input_tar, override_version): - self.log = sys.stdout.write - - self.input_tar = input_tar - - changelog = Changelog()[0] - source = changelog.source - version = changelog.version - - if override_version: - version = Version('%s-undef' % override_version) - - self.log('Using source name %s, version %s\n' % (source, version.upstream)) - - self.orig = '%s-%s' % (source, version.upstream) - self.orig_tar = '%s_%s.orig.tar.gz' % (source, version.upstream) - - def __call__(self): - import tempfile - self.dir = tempfile.mkdtemp(prefix = 'genorig', dir = 'debian') - try: - self.upstream() - self.remove() - self.tar() - finally: - shutil.rmtree(self.dir) - - def upstream(self): - self.log("Extracting tarball %s\n" % self.input_tar) - match = re.match(r'(^|.*/).*\.(?P(tar\.(bz2|gz)|tbz2|tgz))?$', self.input_tar) - if not match: - raise RuntimeError("Can't identify name of tarball") - cmdline = ['tar -xf', self.input_tar, '-C', self.dir] - if match.group('extension') in ('tar.bz2', 'tbz2'): - cmdline.append('-j') - elif match.group('extension') in ('tar.gz', 'tgz'): - cmdline.append('-z') - if os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)]): - raise RuntimeError("Can't extract tarball") - - def remove(self): - self.log("Remove files\n") - root = os.path.join(self.dir, self.orig) - os.unlink(os.path.join(root, "networking/ftp_ipv6_rfc2428.txt")) - - def tar(self): - out = os.path.join("../orig", self.orig_tar) - try: - os.mkdir("../orig") - except OSError: pass - try: - os.stat(out) - raise RuntimeError("Destination already exists") - except OSError: pass - self.log("Generate tarball %s\n" % out) - cmdline = ['tar -czf', out, '-C', self.dir, self.orig] - try: - if os.spawnv(os.P_WAIT, '/bin/sh', ['sh', '-c', ' '.join(cmdline)]): - raise RuntimeError("Can't patch source") - os.chmod(out, 0644) - except: - try: - os.unlink(out) - except OSError: - pass - raise - -if __name__ == '__main__': - from optparse import OptionParser - parser = OptionParser(usage = "%prog [OPTION]... TAR [PATCH]") - parser.add_option("-v", "--version", dest = "version", help = "Override version", metavar = "VERSION") - options, args = parser.parse_args() - Main(args[0], options.version)() diff --git a/debian/busybox-klogd.service b/debian/busybox-klogd.service deleted file mode 100644 index 8b5d726..0000000 --- a/debian/busybox-klogd.service +++ /dev/null @@ -1,10 +0,0 @@ -[Unit] -Description=Busybox Logging Service: klogd -After=busybox-syslogd.service syslog.target - -[Service] -Type=simple -ExecStart=/sbin/klogd -n -c4 - -[Install] -WantedBy=multi-user.target diff --git a/debian/busybox-static.install b/debian/busybox-static.install deleted file mode 100644 index 1434949..0000000 --- a/debian/busybox-static.install +++ /dev/null @@ -1,2 +0,0 @@ -busybox bin -docs/busybox.1 usr/share/man/man1 diff --git a/debian/busybox-symlinks-adduser.links b/debian/busybox-symlinks-adduser.links deleted file mode 100644 index af4207a..0000000 --- a/debian/busybox-symlinks-adduser.links +++ /dev/null @@ -1,4 +0,0 @@ -bin/busybox usr/sbin/addgroup -bin/busybox usr/sbin/adduser -bin/busybox usr/sbin/delgroup -bin/busybox usr/sbin/deluser diff --git a/debian/busybox-symlinks-adjtimex.links b/debian/busybox-symlinks-adjtimex.links deleted file mode 100644 index cdb3eeb..0000000 --- a/debian/busybox-symlinks-adjtimex.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/adjtimex diff --git a/debian/busybox-symlinks-binutils.links b/debian/busybox-symlinks-binutils.links deleted file mode 100644 index c687a4c..0000000 --- a/debian/busybox-symlinks-binutils.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/ar -bin/busybox usr/bin/strings diff --git a/debian/busybox-symlinks-bridge-utils.links b/debian/busybox-symlinks-bridge-utils.links deleted file mode 100644 index 63dd55c..0000000 --- a/debian/busybox-symlinks-bridge-utils.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/brctl diff --git a/debian/busybox-symlinks-bsdmainutils.links b/debian/busybox-symlinks-bsdmainutils.links deleted file mode 100644 index be467d6..0000000 --- a/debian/busybox-symlinks-bsdmainutils.links +++ /dev/null @@ -1,3 +0,0 @@ -bin/busybox usr/bin/cal -bin/busybox usr/bin/hd -bin/busybox usr/bin/hexdump diff --git a/debian/busybox-symlinks-busybox.links b/debian/busybox-symlinks-busybox.links deleted file mode 100644 index 3debeb1..0000000 --- a/debian/busybox-symlinks-busybox.links +++ /dev/null @@ -1,35 +0,0 @@ -bin/busybox usr/bin/[[ -bin/busybox usr/bin/catv -bin/busybox usr/sbin/crond -bin/busybox usr/sbin/dhcprelay -bin/busybox usr/sbin/dnsd -bin/busybox bin/dumpkmap -bin/busybox usr/bin/ether-wake -bin/busybox usr/sbin/fakeidentd -bin/busybox sbin/fbsplash -bin/busybox bin/fsync -bin/busybox usr/bin/ftpget -bin/busybox usr/bin/ftpput -bin/busybox usr/sbin/httpd -bin/busybox sbin/ifenslave -bin/busybox sbin/inotifyd -bin/busybox bin/ipaddr -bin/busybox bin/iplink -bin/busybox bin/iproute -bin/busybox bin/iprule -bin/busybox usr/bin/length -bin/busybox usr/bin/loadfont -bin/busybox sbin/loadkmap -bin/busybox sbin/logread -bin/busybox sbin/makedevs -bin/busybox sbin/mdev -bin/busybox usr/bin/microcom -bin/busybox usr/bin/nmeter -bin/busybox usr/bin/pscan -bin/busybox sbin/raidautorun -bin/busybox usr/bin/readahead -bin/busybox sbin/setconsole -bin/busybox usr/sbin/tftpd -bin/busybox usr/bin/ttysize -bin/busybox bin/usleep -bin/busybox usr/bin/volname diff --git a/debian/busybox-symlinks-bzip2.links b/debian/busybox-symlinks-bzip2.links deleted file mode 100644 index 590ea6c..0000000 --- a/debian/busybox-symlinks-bzip2.links +++ /dev/null @@ -1,3 +0,0 @@ -bin/busybox bin/bunzip2 -bin/busybox bin/bzcat -bin/busybox bin/bzip2 diff --git a/debian/busybox-symlinks-console-tools.links b/debian/busybox-symlinks-console-tools.links deleted file mode 100644 index 9c39eed..0000000 --- a/debian/busybox-symlinks-console-tools.links +++ /dev/null @@ -1,8 +0,0 @@ -bin/busybox usr/bin/chvt -bin/busybox usr/bin/deallocvt -bin/busybox bin/fgconsole -bin/busybox usr/bin/kbd_mode -bin/busybox usr/bin/openvt -bin/busybox usr/bin/setkeycodes -bin/busybox usr/bin/setlogcons -bin/busybox usr/bin/showkey diff --git a/debian/busybox-symlinks-cpio.links b/debian/busybox-symlinks-cpio.links deleted file mode 100644 index b31d727..0000000 --- a/debian/busybox-symlinks-cpio.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox bin/cpio diff --git a/debian/busybox-symlinks-cpio.postinst b/debian/busybox-symlinks-cpio.postinst deleted file mode 100644 index 3c12d3d..0000000 --- a/debian/busybox-symlinks-cpio.postinst +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -update-alternatives --install /bin/mt mt /bin/busybox 1 diff --git a/debian/busybox-symlinks-cpio.prerm b/debian/busybox-symlinks-cpio.prerm deleted file mode 100644 index c6a3f50..0000000 --- a/debian/busybox-symlinks-cpio.prerm +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh -set -e -update-alternatives --remove mt /bin/busybox diff --git a/debian/busybox-symlinks-cron.links b/debian/busybox-symlinks-cron.links deleted file mode 100644 index 9b1fe35..0000000 --- a/debian/busybox-symlinks-cron.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/crontab diff --git a/debian/busybox-symlinks-daemontools.links b/debian/busybox-symlinks-daemontools.links deleted file mode 100644 index 3330648..0000000 --- a/debian/busybox-symlinks-daemontools.links +++ /dev/null @@ -1,4 +0,0 @@ -bin/busybox usr/bin/envdir -bin/busybox usr/bin/envuidgid -bin/busybox usr/bin/setuidgid -bin/busybox usr/bin/softlimit diff --git a/debian/busybox-symlinks-dc.links b/debian/busybox-symlinks-dc.links deleted file mode 100644 index 86f8c30..0000000 --- a/debian/busybox-symlinks-dc.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/dc diff --git a/debian/busybox-symlinks-dnsutils.links b/debian/busybox-symlinks-dnsutils.links deleted file mode 100644 index eb44fc7..0000000 --- a/debian/busybox-symlinks-dnsutils.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/nslookup diff --git a/debian/busybox-symlinks-dosfstools.links b/debian/busybox-symlinks-dosfstools.links deleted file mode 100644 index ff83723..0000000 --- a/debian/busybox-symlinks-dosfstools.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox sbin/mkdosfs -bin/busybox sbin/mkfs.vfat diff --git a/debian/busybox-symlinks-ed.links b/debian/busybox-symlinks-ed.links deleted file mode 100644 index 90fbc07..0000000 --- a/debian/busybox-symlinks-ed.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox bin/ed diff --git a/debian/busybox-symlinks-eject.links b/debian/busybox-symlinks-eject.links deleted file mode 100644 index 70e7ff1..0000000 --- a/debian/busybox-symlinks-eject.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/eject diff --git a/debian/busybox-symlinks-fbset.links b/debian/busybox-symlinks-fbset.links deleted file mode 100644 index d2526a1..0000000 --- a/debian/busybox-symlinks-fbset.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox bin/fbset diff --git a/debian/busybox-symlinks-fdflush.links b/debian/busybox-symlinks-fdflush.links deleted file mode 100644 index 66c3d68..0000000 --- a/debian/busybox-symlinks-fdflush.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox bin/fdflush diff --git a/debian/busybox-symlinks-hdparm.links b/debian/busybox-symlinks-hdparm.links deleted file mode 100644 index b7ddf97..0000000 --- a/debian/busybox-symlinks-hdparm.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox sbin/hdparm diff --git a/debian/busybox-symlinks-ifupdown.dirs b/debian/busybox-symlinks-ifupdown.dirs deleted file mode 100644 index d7fd273..0000000 --- a/debian/busybox-symlinks-ifupdown.dirs +++ /dev/null @@ -1,4 +0,0 @@ -etc/network/if-post-down.d -etc/network/if-pre-up.d -etc/network/if-up.d -etc/network/if-down.d diff --git a/debian/busybox-symlinks-ifupdown.links b/debian/busybox-symlinks-ifupdown.links deleted file mode 100644 index 26e4525..0000000 --- a/debian/busybox-symlinks-ifupdown.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox sbin/ifdown -bin/busybox sbin/ifup diff --git a/debian/busybox-symlinks-initscripts.links b/debian/busybox-symlinks-initscripts.links deleted file mode 100644 index 8fca0bb..0000000 --- a/debian/busybox-symlinks-initscripts.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox bin/mountpoint diff --git a/debian/busybox-symlinks-ipcalc.links b/debian/busybox-symlinks-ipcalc.links deleted file mode 100644 index 9cbb249..0000000 --- a/debian/busybox-symlinks-ipcalc.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/ipcalc diff --git a/debian/busybox-symlinks-iproute.links b/debian/busybox-symlinks-iproute.links deleted file mode 100644 index 5875622..0000000 --- a/debian/busybox-symlinks-iproute.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox bin/ip -bin/busybox sbin/ip diff --git a/debian/busybox-symlinks-ipsvd.links b/debian/busybox-symlinks-ipsvd.links deleted file mode 100644 index 1376e43..0000000 --- a/debian/busybox-symlinks-ipsvd.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/tcpsvd -bin/busybox usr/bin/udpsvd diff --git a/debian/busybox-symlinks-iputils-arping.links b/debian/busybox-symlinks-iputils-arping.links deleted file mode 100644 index da66deb..0000000 --- a/debian/busybox-symlinks-iputils-arping.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/arping diff --git a/debian/busybox-symlinks-iputils-ping.links b/debian/busybox-symlinks-iputils-ping.links deleted file mode 100644 index 80d5ce2..0000000 --- a/debian/busybox-symlinks-iputils-ping.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox bin/ping -bin/busybox bin/ping6 diff --git a/debian/busybox-symlinks-klogd.links b/debian/busybox-symlinks-klogd.links deleted file mode 100644 index f7749be..0000000 --- a/debian/busybox-symlinks-klogd.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox sbin/klogd diff --git a/debian/busybox-symlinks-loadlin.links b/debian/busybox-symlinks-loadlin.links deleted file mode 100644 index 4890004..0000000 --- a/debian/busybox-symlinks-loadlin.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/freeramdisk diff --git a/debian/busybox-symlinks-lrzsz.links b/debian/busybox-symlinks-lrzsz.links deleted file mode 100644 index 1a33f12..0000000 --- a/debian/busybox-symlinks-lrzsz.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/rx diff --git a/debian/busybox-symlinks-lzma.links b/debian/busybox-symlinks-lzma.links deleted file mode 100644 index 42f8232..0000000 --- a/debian/busybox-symlinks-lzma.links +++ /dev/null @@ -1,3 +0,0 @@ -bin/busybox usr/bin/lzcat -bin/busybox usr/bin/lzma -bin/busybox usr/bin/unlzma diff --git a/debian/busybox-symlinks-lzop.links b/debian/busybox-symlinks-lzop.links deleted file mode 100644 index 9987db9..0000000 --- a/debian/busybox-symlinks-lzop.links +++ /dev/null @@ -1,3 +0,0 @@ -bin/busybox usr/bin/lzop -bin/busybox usr/bin/lzopcat -bin/busybox usr/bin/unlzop diff --git a/debian/busybox-symlinks-module-init-tools.links b/debian/busybox-symlinks-module-init-tools.links deleted file mode 100644 index 5b1da4a..0000000 --- a/debian/busybox-symlinks-module-init-tools.links +++ /dev/null @@ -1,6 +0,0 @@ -bin/busybox sbin/depmod -bin/busybox sbin/insmod -bin/busybox sbin/lsmod -bin/busybox sbin/modinfo -bin/busybox sbin/modprobe -bin/busybox sbin/rmmod diff --git a/debian/busybox-symlinks-mtd-utils.links b/debian/busybox-symlinks-mtd-utils.links deleted file mode 100644 index e981bc4..0000000 --- a/debian/busybox-symlinks-mtd-utils.links +++ /dev/null @@ -1,6 +0,0 @@ -bin/busybox usr/sbin/flash_eraseall -bin/busybox usr/sbin/flash_lock -bin/busybox usr/sbin/flash_unlock -bin/busybox usr/sbin/flashcp -bin/busybox usr/sbin/ubiattach -bin/busybox usr/sbin/ubidetach diff --git a/debian/busybox-symlinks-net-tools.links b/debian/busybox-symlinks-net-tools.links deleted file mode 100644 index 18df066..0000000 --- a/debian/busybox-symlinks-net-tools.links +++ /dev/null @@ -1,7 +0,0 @@ -bin/busybox usr/sbin/arp -bin/busybox sbin/ifconfig -bin/busybox sbin/iptunnel -bin/busybox sbin/nameif -bin/busybox bin/netstat -bin/busybox sbin/route -bin/busybox sbin/slattach diff --git a/debian/busybox-symlinks-openbsd-inetd.links b/debian/busybox-symlinks-openbsd-inetd.links deleted file mode 100644 index d9b1e3f..0000000 --- a/debian/busybox-symlinks-openbsd-inetd.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/inetd diff --git a/debian/busybox-symlinks-passwd.links b/debian/busybox-symlinks-passwd.links deleted file mode 100644 index 168db94..0000000 --- a/debian/busybox-symlinks-passwd.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/sbin/chpasswd -bin/busybox usr/bin/passwd diff --git a/debian/busybox-symlinks-patch.links b/debian/busybox-symlinks-patch.links deleted file mode 100644 index 74ed545..0000000 --- a/debian/busybox-symlinks-patch.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/patch diff --git a/debian/busybox-symlinks-ppp.links b/debian/busybox-symlinks-ppp.links deleted file mode 100644 index 5193ff0..0000000 --- a/debian/busybox-symlinks-ppp.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/chat diff --git a/debian/busybox-symlinks-procps.links b/debian/busybox-symlinks-procps.links deleted file mode 100644 index 62dd8f8..0000000 --- a/debian/busybox-symlinks-procps.links +++ /dev/null @@ -1,9 +0,0 @@ -bin/busybox usr/bin/free -bin/busybox bin/kill -bin/busybox usr/bin/pgrep -bin/busybox usr/bin/pkill -bin/busybox bin/ps -bin/busybox sbin/sysctl -bin/busybox usr/bin/top -bin/busybox usr/bin/uptime -bin/busybox usr/bin/watch diff --git a/debian/busybox-symlinks-psmisc.links b/debian/busybox-symlinks-psmisc.links deleted file mode 100644 index e9f1a83..0000000 --- a/debian/busybox-symlinks-psmisc.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox bin/fuser -bin/busybox usr/bin/killall diff --git a/debian/busybox-symlinks-rdate.links b/debian/busybox-symlinks-rdate.links deleted file mode 100644 index 87edc7f..0000000 --- a/debian/busybox-symlinks-rdate.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/rdate diff --git a/debian/busybox-symlinks-realpath.links b/debian/busybox-symlinks-realpath.links deleted file mode 100644 index 17f3c90..0000000 --- a/debian/busybox-symlinks-realpath.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/realpath diff --git a/debian/busybox-symlinks-rpm.links b/debian/busybox-symlinks-rpm.links deleted file mode 100644 index b943439..0000000 --- a/debian/busybox-symlinks-rpm.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/rpm -bin/busybox usr/bin/rpm2cpio diff --git a/debian/busybox-symlinks-runit.links b/debian/busybox-symlinks-runit.links deleted file mode 100644 index 14ba9b5..0000000 --- a/debian/busybox-symlinks-runit.links +++ /dev/null @@ -1,5 +0,0 @@ -bin/busybox usr/bin/chpst -bin/busybox usr/bin/runsv -bin/busybox usr/bin/runsvdir -bin/busybox usr/bin/sv -bin/busybox usr/bin/svlogd diff --git a/debian/busybox-symlinks-sharutils.links b/debian/busybox-symlinks-sharutils.links deleted file mode 100644 index adf295a..0000000 --- a/debian/busybox-symlinks-sharutils.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/uudecode -bin/busybox usr/bin/uuencode diff --git a/debian/busybox-symlinks-ssmtp.links b/debian/busybox-symlinks-ssmtp.links deleted file mode 100644 index 4221fd1..0000000 --- a/debian/busybox-symlinks-ssmtp.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/sendmail diff --git a/debian/busybox-symlinks-sysklogd.links b/debian/busybox-symlinks-sysklogd.links deleted file mode 100644 index 20fb96b..0000000 --- a/debian/busybox-symlinks-sysklogd.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox sbin/syslogd diff --git a/debian/busybox-symlinks-telnetd.links b/debian/busybox-symlinks-telnetd.links deleted file mode 100644 index fc22170..0000000 --- a/debian/busybox-symlinks-telnetd.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/telnetd diff --git a/debian/busybox-symlinks-tftp.links b/debian/busybox-symlinks-tftp.links deleted file mode 100644 index f9d5794..0000000 --- a/debian/busybox-symlinks-tftp.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/tftp diff --git a/debian/busybox-symlinks-time.links b/debian/busybox-symlinks-time.links deleted file mode 100644 index 9cfd606..0000000 --- a/debian/busybox-symlinks-time.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/time diff --git a/debian/busybox-symlinks-tofrodos.links b/debian/busybox-symlinks-tofrodos.links deleted file mode 100644 index 40760e8..0000000 --- a/debian/busybox-symlinks-tofrodos.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/dos2unix -bin/busybox usr/bin/unix2dos diff --git a/debian/busybox-symlinks-udhcpc.links b/debian/busybox-symlinks-udhcpc.links deleted file mode 100644 index 45827b4..0000000 --- a/debian/busybox-symlinks-udhcpc.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/udhcpc diff --git a/debian/busybox-symlinks-udhcpd.links b/debian/busybox-symlinks-udhcpd.links deleted file mode 100644 index 62f4d1e..0000000 --- a/debian/busybox-symlinks-udhcpd.links +++ /dev/null @@ -1,2 +0,0 @@ -bin/busybox usr/bin/dumpleases -bin/busybox usr/sbin/udhcpd diff --git a/debian/busybox-symlinks-unzip.links b/debian/busybox-symlinks-unzip.links deleted file mode 100644 index 9e7bba2..0000000 --- a/debian/busybox-symlinks-unzip.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/unzip diff --git a/debian/busybox-symlinks-vlan.links b/debian/busybox-symlinks-vlan.links deleted file mode 100644 index bc2fce5..0000000 --- a/debian/busybox-symlinks-vlan.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox sbin/vconfig diff --git a/debian/busybox-symlinks-vlock.links b/debian/busybox-symlinks-vlock.links deleted file mode 100644 index a42391a..0000000 --- a/debian/busybox-symlinks-vlock.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/vlock diff --git a/debian/busybox-symlinks-watchdog.links b/debian/busybox-symlinks-watchdog.links deleted file mode 100644 index c7cfe6e..0000000 --- a/debian/busybox-symlinks-watchdog.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/sbin/watchdog diff --git a/debian/busybox-symlinks-wget.links b/debian/busybox-symlinks-wget.links deleted file mode 100644 index 3d55978..0000000 --- a/debian/busybox-symlinks-wget.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/wget diff --git a/debian/busybox-symlinks-xterm.links b/debian/busybox-symlinks-xterm.links deleted file mode 100644 index aa45607..0000000 --- a/debian/busybox-symlinks-xterm.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/resize diff --git a/debian/busybox-symlinks-zcip.links b/debian/busybox-symlinks-zcip.links deleted file mode 100644 index 5e8f40d..0000000 --- a/debian/busybox-symlinks-zcip.links +++ /dev/null @@ -1 +0,0 @@ -bin/busybox usr/bin/zcip diff --git a/debian/busybox-syslogd.busybox-klogd.init b/debian/busybox-syslogd.busybox-klogd.init deleted file mode 100644 index 9acda52..0000000 --- a/debian/busybox-syslogd.busybox-klogd.init +++ /dev/null @@ -1,158 +0,0 @@ -#!/bin/sh -# -# init.d script with LSB support. -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# Copyright (c) 2008 Axel Beckert -# -# This is free software; you may redistribute 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 is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: busybox-klogd klogd -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Should-Start: syslogd -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Starts klogd -# Description: Starts the busybox klogd -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -NAME=klogd # Introduce the short server's name here -DAEMON=/sbin/$NAME # Introduce the server's location here -DESC="busybox' $NAME implementation" # Introduce a short description here -NEEDED_OPTS='' -DAEMON_USER='root' - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -# Default options, these can be overriden by the information -# at /etc/default/$NAME -KLOG_OPTS="" # Additional options given to the server - -DIETIME=10 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -STARTTIME=2 # Time to wait for the server to start, in seconds - # If this value is set each time the server is - # started (on start or restart) the script will - # stall to try to determine if it is running - # If it is not set and the server takes time - # to setup a pid file the log message might - # be a false positive (says it did not start - # when it actually did) - -# Include defaults if available -if [ -f /etc/default/busybox-syslogd ] ; then - . /etc/default/busybox-syslogd -fi - -set -e - -start_server() { - start-stop-daemon --start --verbose --name $NAME \ - --exec $DAEMON -- $NEEDED_OPTS $KLOG_OPTS -} - -stop_server() { - start-stop-daemon --stop --verbose --name $NAME -} - -running() { - cut -d ' ' -f 1-2 /proc/[0-9]*/stat 2> /dev/null | grep -F "($NAME)" -} - -case "$1" in - start) - log_daemon_msg "Starting $DESC " "$NAME" - # Check if it's running first - if running ; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if start_server ; then - # NOTE: Some servers might die some time after they start, - # this code will detect this issue if STARTTIME is set - # to a reasonable value - [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time - if running ; then - # It's ok, the server started and is running - log_end_msg 0 - else - # It is not running after we did start - log_end_msg 1 - fi - else - # Either we could not start it - log_end_msg 1 - fi - ;; - - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if running ; then - # Only stop the server if we see it running - errcode=0 - stop_server || errcode=$? - log_end_msg $errcode - else - # If it's not running don't do anything - log_progress_msg "apparently not running" - log_end_msg 0 - exit 0 - fi - ;; - - restart|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - errcode=0 - stop_server || errcode=$? - # Wait some sensible amount, some server need this - [ -n "$DIETIME" ] && sleep $DIETIME - start_server || errcode=$? - [ -n "$STARTTIME" ] && sleep $STARTTIME - running || errcode=$? - log_end_msg $errcode - ;; - - status) - log_daemon_msg "Checking status of $DESC" "$NAME" - if running ; then - log_progress_msg "running" - log_end_msg 0 - else - log_progress_msg "apparently not running" - log_end_msg 1 - exit 1 - fi - ;; - - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/debian/busybox-syslogd.default b/debian/busybox-syslogd.default deleted file mode 100644 index bc9a28f..0000000 --- a/debian/busybox-syslogd.default +++ /dev/null @@ -1,7 +0,0 @@ -# Defaults for busybox-syslogd initscript -# This is a POSIX shell fragment sourced by /etc/init.d/busybox-syslogd - -# Additional options that are passed to the daemons. Default is to log -# to ring buffer (to be read with logread(1)) and drop duplicates. -SYSLOG_OPTS="-C128" -KLOG_OPTS="" diff --git a/debian/busybox-syslogd.init b/debian/busybox-syslogd.init deleted file mode 100644 index f489dd2..0000000 --- a/debian/busybox-syslogd.init +++ /dev/null @@ -1,161 +0,0 @@ -#!/bin/sh -# -# init.d script with LSB support. -# -# Copyright (c) 2007 Javier Fernandez-Sanguino -# Copyright (c) 2008 Axel Beckert -# -# This is free software; you may redistribute 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 is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License with -# the Debian operating system, in /usr/share/common-licenses/GPL; if -# not, write to the Free Software Foundation, Inc., 59 Temple Place, -# Suite 330, Boston, MA 02111-1307 USA -# -### BEGIN INIT INFO -# Provides: busybox-syslogd syslogd -# Required-Start: $remote_fs -# Required-Stop: $remote_fs -# Should-Start: -# Should-Stop: -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Starts syslogd -# Description: Starts the busybox syslogd -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin - -NAME=syslogd # Introduce the short server's name here -DAEMON=/sbin/$NAME # Introduce the server's location here -DESC="busybox' $NAME implementation" # Introduce a short description here -NEEDED_OPTS='' -DAEMON_USER='root' - -test -x $DAEMON || exit 0 - -. /lib/lsb/init-functions - -# Default options, these can be overriden by the information -# at /etc/default/$NAME -SYSLOG_OPTS="" # Additional options given to the server - -DIETIME=10 # Time to wait for the server to die, in seconds - # If this value is set too low you might not - # let some servers to die gracefully and - # 'restart' will not work - -#STARTTIME=2 # Time to wait for the server to start, in seconds - # If this value is set each time the server is - # started (on start or restart) the script will - # stall to try to determine if it is running - # If it is not set and the server takes time - # to setup a pid file the log message might - # be a false positive (says it did not start - # when it actually did) - -# Include defaults if available -if [ -f /etc/default/busybox-syslogd ] ; then - . /etc/default/busybox-syslogd -fi - -set -e - -start_server() { - start-stop-daemon --start --verbose --name $NAME \ - --exec $DAEMON -- $NEEDED_OPTS $SYSLOG_OPTS -} - -stop_server() { - start-stop-daemon --stop --quiet --name $NAME -} - -running() { - cut -d ' ' -f 1-2 /proc/[0-9]*/stat 2> /dev/null | grep -F "($NAME)" -} - -case "$1" in - start) - log_daemon_msg "Starting $DESC " "$NAME" - # Check if it's running first - if running ; then - log_progress_msg "apparently already running" - log_end_msg 0 - exit 0 - fi - if start_server ; then - # NOTE: Some servers might die some time after they start, - # this code will detect this issue if STARTTIME is set - # to a reasonable value - [ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time - if running ; then - # It's ok, the server started and is running - log_end_msg 0 - else - # It is not running after we did start - log_end_msg 1 - fi - else - # Either we could not start it - log_end_msg 1 - fi - ;; - stop) - log_daemon_msg "Stopping $DESC" "$NAME" - if running ; then - # Only stop the server if we see it running - errcode=0 - stop_server || errcode=$? - log_end_msg $errcode - else - # If it's not running don't do anything - log_progress_msg "apparently not running" - log_end_msg 0 - exit 0 - fi - ;; - restart|force-reload) - log_daemon_msg "Restarting $DESC" "$NAME" - errcode=0 - stop_server || errcode=$? - # Wait some sensible amount, some server need this - [ -n "$DIETIME" ] && sleep $DIETIME - start_server || errcode=$? - [ -n "$STARTTIME" ] && sleep $STARTTIME - running || errcode=$? - log_end_msg $errcode - ;; - status) - - log_daemon_msg "Checking status of $DESC" "$NAME" - if running ; then - log_progress_msg "running" - log_end_msg 0 - else - log_progress_msg "apparently not running" - log_end_msg 1 - exit 1 - fi - ;; - # daemon cannot reload - reload) - log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon" - log_warning_msg "cannot re-read the config file (use restart)." - ;; - - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload|status}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/debian/busybox-syslogd.service b/debian/busybox-syslogd.service deleted file mode 100644 index 36227a2..0000000 --- a/debian/busybox-syslogd.service +++ /dev/null @@ -1,11 +0,0 @@ -[Unit] -Description=Busybox Logging Service: syslogd - -[Service] -Type=simple -ExecStartPre=/bin/systemctl stop systemd-kmsg-syslogd.service -ExecStart=/sbin/syslogd -n -Sockets=syslog.socket - -[Install] -WantedBy=multi-user.target diff --git a/debian/busybox-systemd-klogd.install b/debian/busybox-systemd-klogd.install deleted file mode 100644 index cbab4d7..0000000 --- a/debian/busybox-systemd-klogd.install +++ /dev/null @@ -1 +0,0 @@ -debian/busybox-klogd.service lib/systemd/system/ diff --git a/debian/busybox-systemd-klogd.links b/debian/busybox-systemd-klogd.links deleted file mode 100644 index 0fae3ea..0000000 --- a/debian/busybox-systemd-klogd.links +++ /dev/null @@ -1 +0,0 @@ -lib/systemd/system/busybox-klogd.service lib/systemd/system/multi-user.target.wants/busybox-klogd.service diff --git a/debian/busybox-systemd-sysklogd.install b/debian/busybox-systemd-sysklogd.install deleted file mode 100644 index 0379dc9..0000000 --- a/debian/busybox-systemd-sysklogd.install +++ /dev/null @@ -1 +0,0 @@ -debian/busybox-syslogd.service lib/systemd/system/ diff --git a/debian/busybox-systemd-sysklogd.links b/debian/busybox-systemd-sysklogd.links deleted file mode 100644 index 1a1f1aa..0000000 --- a/debian/busybox-systemd-sysklogd.links +++ /dev/null @@ -1 +0,0 @@ -lib/systemd/system/busybox-syslogd.service lib/systemd/system/multi-user.target.wants/busybox-syslogd.service diff --git a/debian/busybox-udeb.install b/debian/busybox-udeb.install deleted file mode 100644 index d094590..0000000 --- a/debian/busybox-udeb.install +++ /dev/null @@ -1,2 +0,0 @@ -../../tree/busybox-udeb/* / -_install/* / diff --git a/debian/busybox.dirs b/debian/busybox.dirs deleted file mode 100644 index d653148..0000000 --- a/debian/busybox.dirs +++ /dev/null @@ -1,3 +0,0 @@ -bin -sbin -usr/share/man/man1 diff --git a/debian/busybox.install b/debian/busybox.install deleted file mode 100644 index b2b3f72..0000000 --- a/debian/busybox.install +++ /dev/null @@ -1 +0,0 @@ -busybox bin diff --git a/debian/busybox.links b/debian/busybox.links deleted file mode 100644 index 97a2764..0000000 --- a/debian/busybox.links +++ /dev/null @@ -1,127 +0,0 @@ -bin/busybox bin/ash -bin/busybox bin/cat -bin/busybox bin/chgrp -bin/busybox bin/chmod -bin/busybox bin/chown -bin/busybox bin/cp -bin/busybox bin/date -bin/busybox bin/dd -bin/busybox bin/df -bin/busybox bin/dmesg -bin/busybox bin/dnsdomainname -bin/busybox bin/echo -bin/busybox bin/egrep -bin/busybox bin/false -bin/busybox bin/fgrep -bin/busybox bin/grep -bin/busybox bin/gunzip -bin/busybox bin/gzip -bin/busybox bin/hostname -bin/busybox bin/ln -bin/busybox bin/ls -bin/busybox bin/mkdir -bin/busybox bin/mknod -bin/busybox bin/mktemp -bin/busybox bin/more -bin/busybox bin/mount -bin/busybox bin/mv -bin/busybox bin/pwd -bin/busybox bin/readlink -bin/busybox bin/rm -bin/busybox bin/rmdir -bin/busybox bin/sed -bin/busybox bin/sh -bin/busybox bin/sleep -bin/busybox bin/stty -bin/busybox bin/sync -bin/busybox bin/tar -bin/busybox bin/touch -bin/busybox bin/true -bin/busybox bin/umount -bin/busybox bin/uname -bin/busybox bin/uncompress -bin/busybox bin/zcat -bin/busybox sbin/blkid -bin/busybox sbin/blockdev -bin/busybox sbin/fdisk -bin/busybox sbin/fsck.minix -bin/busybox sbin/getty -bin/busybox sbin/hwclock -bin/busybox sbin/losetup -bin/busybox sbin/mkfs.minix -bin/busybox sbin/mkswap -bin/busybox sbin/pivot_root -bin/busybox sbin/swapoff -bin/busybox sbin/swapon -bin/busybox sbin/switch_root -bin/busybox usr/bin/[ -bin/busybox usr/bin/basename -bin/busybox usr/bin/chrt -bin/busybox usr/bin/cksum -bin/busybox usr/bin/cmp -bin/busybox usr/bin/comm -bin/busybox usr/bin/cut -bin/busybox usr/bin/diff -bin/busybox usr/bin/dirname -bin/busybox usr/bin/du -bin/busybox usr/bin/env -bin/busybox usr/bin/expand -bin/busybox usr/bin/expr -bin/busybox usr/bin/fdformat -bin/busybox usr/bin/find -bin/busybox usr/bin/flock -bin/busybox usr/bin/fold -bin/busybox usr/bin/getopt -bin/busybox usr/bin/head -bin/busybox usr/bin/hostid -bin/busybox usr/bin/id -bin/busybox usr/bin/install -bin/busybox usr/bin/ionice -bin/busybox usr/bin/ipcrm -bin/busybox usr/bin/ipcs -bin/busybox usr/bin/less -bin/busybox usr/bin/linux32 -bin/busybox usr/bin/linux64 -bin/busybox usr/bin/logger -bin/busybox usr/bin/logname -bin/busybox usr/bin/md5sum -bin/busybox usr/bin/mkfifo -bin/busybox usr/bin/nice -bin/busybox usr/bin/nohup -bin/busybox usr/bin/od -bin/busybox usr/bin/printenv -bin/busybox usr/bin/printf -bin/busybox usr/bin/renice -bin/busybox usr/bin/rev -bin/busybox usr/bin/rtcwake -bin/busybox usr/bin/script -bin/busybox usr/bin/scriptreplay -bin/busybox usr/bin/seq -bin/busybox usr/bin/setarch -bin/busybox usr/bin/setsid -bin/busybox usr/bin/sha1sum -bin/busybox usr/bin/sha256sum -bin/busybox usr/bin/sha512sum -bin/busybox usr/bin/sort -bin/busybox usr/bin/split -bin/busybox usr/bin/stat -bin/busybox usr/bin/sum -bin/busybox usr/bin/tac -bin/busybox usr/bin/tail -bin/busybox usr/bin/taskset -bin/busybox usr/bin/tee -bin/busybox usr/bin/test -bin/busybox usr/bin/timeout -bin/busybox usr/bin/tr -bin/busybox usr/bin/tty -bin/busybox usr/bin/unexpand -bin/busybox usr/bin/uniq -bin/busybox usr/bin/wall -bin/busybox usr/bin/wc -bin/busybox usr/bin/who -bin/busybox usr/bin/whoami -bin/busybox usr/bin/xargs -bin/busybox usr/bin/yes -bin/busybox usr/sbin/chroot -bin/busybox usr/sbin/rdev -bin/busybox usr/sbin/readprofile diff --git a/debian/busybox.postinst b/debian/busybox.postinst deleted file mode 100644 index d48f82a..0000000 --- a/debian/busybox.postinst +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -set -e -update-alternatives --install /usr/bin/pager pager /bin/more 10 -update-alternatives --install /usr/bin/man man /bin/busybox 1 -update-alternatives --install /usr/bin/traceroute traceroute /bin/busybox 1 -update-alternatives --install /usr/bin/pager pager /usr/bin/less 20 -update-alternatives --install /usr/bin/telnet telnet /bin/busybox 1 -update-alternatives --install /usr/bin/awk awk /bin/busybox 1 -update-alternatives --install /usr/bin/vi vi /bin/busybox 1 -dpkg-divert --package busybox --add /bin/sh diff --git a/debian/busybox.prerm b/debian/busybox.prerm deleted file mode 100644 index ec46dd0..0000000 --- a/debian/busybox.prerm +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -set -e -update-alternatives --remove pager /bin/more -update-alternatives --remove man /bin/busybox -update-alternatives --remove traceroute /bin/busybox -update-alternatives --remove pager /usr/bin/less -update-alternatives --remove telnet /bin/busybox -update-alternatives --remove awk /bin/busybox -update-alternatives --remove vi /bin/busybox -dpkg-divert --package busybox --remove /bin/sh diff --git a/debian/changelog b/debian/changelog deleted file mode 100644 index ac9f800..0000000 --- a/debian/changelog +++ /dev/null @@ -1,1350 +0,0 @@ -busybox (3:1.17.1-10slp2+s8) unstable; urgency=low - - * Fix displaying of unicode characters. - * Git: slp/pkgs/b/busybox - * Tag: busybox_3%1.17.1-10slp2+s8 - - -- Rafal Krypa Mon, 16 Apr 2012 13:10:58 +0200 - -busybox (3:1.17.1-10slp2+s7) unstable; urgency=low - - * slp: Disable chat(1) - * Git: slp/pkgs/b/busybox - * Tag: busybox_3%1.17.1-10slp2+s7 - - -- Karol Lewandowski Tue, 17 Jan 2012 11:41:58 +0100 - -busybox (3:1.17.1-10slp2+s6-1) unstable; urgency=low - - * Add tag required by build server - * Git: slp/pkgs/b/busybox - * Tag: busybox_3%1.17.1-10slp2+s6-1 - - -- Karol Lewandowski Thu, 12 Jan 2012 12:45:55 +0100 - -busybox (3:1.17.1-10slp2+s6) unstable; urgency=low - - * slp: Import SMACK patch - * slp: Don't allow SELINUX and SMACK to be enabled at the same time - * slp: Fix obvious mistake in smack patch - - -- Karol Lewandowski Wed, 11 Jan 2012 12:31:43 +0100 - -busybox (3:1.17.1-10slp2+s5) unstable; urgency=low - - * klogd: Handle facility too when reading from /proc/kmsg - * Make sure klogd starts after busybox's syslogd - * Ugly hack: Increase console log level to make camera app work - - -- Karol Lewandowski Mon, 07 Nov 2011 15:40:21 +0100 - -busybox (3:1.17.1-10slp2+s4) unstable; urgency=low - - * mount: Handle list of comma-separated fs types ("-t" option) - - -- Karol Lewandowski Mon, 10 Oct 2011 11:31:10 +0200 - -busybox (3:1.17.1-10slp2+s3) unstable; urgency=low - - * Support receiving server socket from systemd in syslogd - * Add packages with systemd units for syslogd and klogd - - -- Karol Lewandowski Thu, 01 Sep 2011 19:14:44 +0200 - -busybox (3:1.17.1-10slp2+s2) unstable; urgency=low - - [ Rafal Krypa ] - * Enable mktemp applet. - * Make debian/scripts/*.py files executable. - * debian/scripts/README: adapt to SLP - - [ Mike McCormack ] - * Disable netcat. - - [ Yeongil Jang ] - * Add CONFIG_LZOP_COMPR_HIGH option for building 2.6.36 kernel - - -- Rafal Krypa Mon, 01 Aug 2011 11:31:35 +0200 - -busybox (3:1.17.1-10slp2+s1) unstable; urgency=low - - * Bump epoch back to 3 to let things upgrade correctly. - - -- Mike McCormack Tue, 19 Apr 2011 10:51:42 +0900 - -busybox (1:1.17.1-10slp2+s1) unstable; urgency=low - - [ Minho Ban ] - * getty: Disable SW flow control (XON/XOFF). - - [ Rafal Krypa ] - * Merge with Debian. - * Enable blockdev applet, backported by Debian. - - -- Rafal Krypa Fri, 15 Apr 2011 13:19:25 +0200 - -busybox (1:1.17.1-10) unstable; urgency=low - - [ Michael Tokarev ] - * tiny build system changes: from main source to build directories: - don't copy .dotfiles, use ln instead of cp - - [ Joey Hess ] - * Enable sha256sum in udeb, needed by debootstrap to handle Release - files w/o md5sums. - * Did not disable md5sum in udeb because eg anna still uses them to verify - md5sum fields from d-i Packages files. (Those fields are still present.. - for now.) - - -- Joey Hess Mon, 21 Feb 2011 20:32:15 -0400 - -busybox (1:1.17.1-9) unstable; urgency=low - - * Team upload - - [ Matt Palmer ] - * Build busybox udeb with IPv6 support, since otherwise wget has a - severe sadness. - - [ Christian Perrier ] - * Add arping to udeb to allow link detection in netcfg - Closes: #612249 - - -- Christian Perrier Sun, 13 Feb 2011 08:23:54 +0100 - -busybox (1:1.17.1-8) unstable; urgency=low - - * Set udhcpc and udhcpd Section to net, to match overrides. - * Disable blockdev on non-Linux architectures. - - -- Colin Watson Mon, 15 Nov 2010 14:36:31 +0000 - -busybox (1:1.17.1-7) unstable; urgency=low - - * Backport blockdev applet from upstream, so that we can use it in - os-prober (closes: #418163). - - -- Colin Watson Tue, 09 Nov 2010 12:33:35 +0000 - -busybox (3:1.17.1-6slp2+s4) unstable; urgency=low - - * Increase size of log file - - -- Mike McCormack Wed, 16 Mar 2011 17:16:34 +0900 - -busybox (3:1.17.1-6slp2+s3) unstable; urgency=low - - * Add SLP patch: udhcpc-fast-request.patch. - * Enable the new feature. - - -- Rafal Krypa Fri, 10 Dec 2010 12:53:38 +0100 - -busybox (3:1.17.1-6slp2+s2) unstable; urgency=low - - * SLP: adjust the config to be more compatible with BB provided by the - kernel team. - * Remove dependency on busybox-symlinks-busybox from the busybox - package to resolve dependency loop. - - -- Rafal Krypa Sun, 28 Nov 2010 12:39:33 +0900 - -busybox (3:1.17.1-6slp2+s1) unstable; urgency=low - - * debian/patches/03tar.dpatch: remove - applied in upstream. - * debian/patches/top-display-rss.patch: adapt to new upstream version. - * debian/config/slp: move to new location debian/config/pkg/slp. - * Adapt config to new upstream version, enable: wall, flock, rev. - - -- Rafal Krypa Fri, 05 Nov 2010 20:35:13 +0900 - -busybox (1:1.17.1-6) unstable; urgency=low - - * Apply patch from Samuel Thibault to enable - hardware flow control for serial console (closes: #528560). - - -- Otavio Salvador Thu, 21 Oct 2010 16:17:03 -0200 - -busybox (1:1.17.1-5) unstable; urgency=low - - [ Colin Watson ] - * Never execute busybox applets when chrooting (closes: #599101). - - [ Otavio Salvador ] - * Fix initscript error messages in syslogd and klogd (closes: - #591436). - * Fix restart and force-reload for udhcpd initscript (closes: - #597510). - - -- Otavio Salvador Thu, 21 Oct 2010 11:53:52 -0200 - -busybox (1:1.17.1-4) unstable; urgency=low - - * Update u-mount-FreeBSD-support.patch: - - Add a few more mount options. - - Fix mounting of nullfs filesystems. - - -- Aurelien Jarno Mon, 23 Aug 2010 10:19:20 +0200 - -busybox (1:1.17.1-3) unstable; urgency=low - - [ Jérémie Koenig ] - * Enable CONFIG_FEATURE_INITRD on Hurd (Closes: #593865). - - [ Aurelien Jarno ] - * [udeb] Disable volume id support. - - -- Aurelien Jarno Sun, 22 Aug 2010 19:46:52 +0200 - -busybox (1:1.17.1-2) unstable; urgency=low - - * Upload to unstable. - * [udeb] Enable volume id support. - * [deb] Enable all file system in volume id support. - - -- Aurelien Jarno Fri, 06 Aug 2010 22:54:40 +0200 - -busybox (1:1.17.1-1) experimental; urgency=low - - [ Aurelien Jarno ] - * New upstream release. - - Add --list option (Closes: #405108). - - Fix nc segfaults (Closes: #503672). - - Enable new options: - [all] Add support for unicode (Closes: #395227, #570789) - [all] Enable btrfs volume identification - * Update configuration: - [udeb/deb] Enable dd conv=notrunc (Closes: #552495) - * Fix busybox-udeb description: s/busybox-cvs-udeb/busybox-udeb/ - * Fix busybox description wrt --install option (Closes: #326243). - * Fix /etc/init.d/udhcpd restart (Closes: #581342) - * Fix /etc/init.d/busybox-{klogd,syslogd} to correctly depend on - $remote_fs. - * Fix bashism in udhcpc default.script (Closes: #572008, #572013, - #572622). - - [ Jérémie Koenig ] - * Refresh patches: - - debian/patches/applets-fallback.patch - - debian/patches/doc-man-name.patch - - debian/patches/shell-ash-export-HOME.patch - * Add per-OS configuration overrides. - * Add FreeBSD and Hurd compatibility patches from the latest git upstream - branch, and a few more to be merged soon (Closes: #323670). - * scripts/gen_build_files.sh: skip .pc files from quilt. - - -- Aurelien Jarno Tue, 03 Aug 2010 06:42:39 +0200 - -busybox (3:1.15.3-1slp2+s5) unstable; urgency=low - - * debian/scripts/debian-mappings.txt: fix mappings for mktemp, - sha256sum, sha512sum, dnsdomainname. - * debian/scripts/create-control.py: modify dependencies for busybox, - don't start output with blank line. - * debian/config/slp: disable lzop, enable applets for 'adduser' - package. - * Recreate control and *.links files. - - -- Rafal Krypa Thu, 14 Oct 2010 12:18:08 +0200 - -busybox (3:1.15.3-1+s4) unstable; urgency=low - - * Apply all quilt patches missed during import (this is 3.0 (quilt) - source format). - * Apply our quilt patches as well. - * Fix busybox-zero-ifr.ifr_hwaddr.sa_data.patch to apply without fuzz - (solves problem with dpkg-source). - - -- Rafal Krypa Wed, 16 Jun 2010 15:15:14 +0200 - -busybox (3:1.15.3-1+s3) unstable; urgency=low - - * Drop /bin/login and /bin/su for slp - it uses standard "shadow" - tools now - * Update maintaners and uploaders lists - * Add Essential tag to busybox package - * Don't use lsb_release in slp variant - * Kill bogus binary-arch_slp rule - - -- Karol Lewandowski Wed, 19 May 2010 19:03:35 +0200 - -busybox (3:1.15.3-1+s2) unstable; urgency=low - - * Workaround for Scratchbox 1 apt problems - drop the Essential tag on - busybox package. - * Scratchbox 1 workaround - reduce debhelper compat level to 5. - - -- Rafal Krypa Tue, 30 Mar 2010 12:42:43 +0200 - -busybox (3:1.15.3-1+s1) unstable; urgency=low - - * Merge Debian version 1.15.3-1 - * Drop patches with features that are now in upstream: - - fsync.patch - - pidof-fix.patch - - ls-s-dont-follow-links.patch - - upstart-support.patch - * Adapt patches to new upstream version: - - 03tar.dpatch - - top-display-rss.patch - * debian/rules: fix install source path for busybox binary - * debian/config/slp: using some new features - * Don't apply shell-hist.patch - it is incompatible with new upstream version - and we don't need it anyway. - - -- Rafal Krypa Wed, 24 Mar 2010 18:23:28 +0100 - -busybox (3:1.10.2.legal-1osso26+0m5+s1) unstable; urgency=low - - * Update configuration of Debian essential packages according to - current Sid version. - * Configure for SLP 2.0. - * Drop build-dependency on lsb-release. - * debian/control: added Uploaders field. - - -- Rafal Krypa Thu, 04 Feb 2010 10:41:03 +0900 - -busybox (3:1.10.2.legal-1osso26+0m5) unstable; urgency=low - - * This entry has been added by BIFH queue processor - Suffix +0m5 added to package revision - - -- Attiq Malik Wed, 01 Jul 2009 13:11:49 +0300 - -busybox (3:1.10.2.legal-1osso26) unstable; urgency=low - - * Enable more fance tar features. Fixes: NB#124832. - - -- Alexander Shishkin Mon, 29 Jun 2009 15:32:56 +0300 - -busybox (3:1.10.2.legal-1osso25) unstable; urgency=low - - * Call telinit to facilitate proper shutdown/reboot. Fixes: NB#120283. - - -- Alexander Shishkin Wed, 24 Jun 2009 14:41:13 +0300 - -busybox (3:1.10.2.legal-1osso24) unstable; urgency=low - - * Don't follow symlinks for -l or -s in ls. Fixes: NB#120999. - - -- Alexander Shishkin Mon, 15 Jun 2009 12:55:17 +0300 - -busybox (3:1.10.2.legal-1osso23) unstable; urgency=low - - * Enable more options for pidof. Fixes: NB#112823. - - -- Alexander Shishkin Thu, 23 Apr 2009 16:10:24 +0300 - -busybox (3:1.10.2.legal-1osso22) unstable; urgency=low - - * Remove 3 second sleep()s from sfdisk. - - -- Alexander Shishkin Thu, 23 Apr 2009 11:32:08 +0300 - -busybox (3:1.10.2.legal-1osso21) unstable; urgency=low - - * Drop dependencies to symlink packages. Fixes: NB#86011. - - -- Alexander Shishkin Wed, 01 Apr 2009 14:14:32 +0300 - -busybox (3:1.10.2.legal-1osso20) unstable; urgency=low - - * Merge sysvinit-maemo into busybox. - * Remove last from provided symlinks. Fixes: NB#108560. - * Patch to display RSS instead of VSZ in top. Fixes: NB#103591. - * Patch to only update history upon shell exit. Fixes: NB#107770. - - -- Alexander Shishkin Tue, 31 Mar 2009 14:28:47 +0300 - -busybox (3:1.10.2.legal-1osso19) unstable; urgency=low - - * Create alternatives directory if missing. Fixes: NB#107784. - * Enable CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY. Fixes: NB#107771. - * Disable wtmp for applets. Fixes: NB#101256. - - -- Alexander Shishkin Wed, 25 Mar 2009 10:28:05 +0200 - -busybox (3:1.10.2.legal-1osso18) unstable; urgency=low - - * Transition: make busybox depend on all packages with symlinks - to facilitate NB#86011. - * Symlinks moved to separate packages to match debian's counterparts. - * Enable xargs support for quotes. Fixes: NB#96575. - - -- Alexander Shishkin Wed, 18 Mar 2009 12:39:35 +0200 - -busybox (3:1.10.2.legal-1osso17) unstable; urgency=low - - * Add IPv6 support. Fixes: NB#98038. - * Add fix for pidof/killall5. Fixes: NB#101755. - - -- Alexander Shishkin Tue, 10 Mar 2009 15:14:05 +0200 - -busybox (3:1.10.2.legal-1osso16) unstable; urgency=low - - * Added CONFIG_CLEAR and CONFIG_RESET to config.maemo - * Added ncurses-bin to Provides/Replaces/Conflicts. Fixes: NB#92440 - - -- Turo Janka Thu, 12 Feb 2009 12:50:42 +0200 - -busybox (3:1.10.2.legal-1osso15) unstable; urgency=low - - * Removed CONFIG_FEATURE_GUNZIP_UNCOMPRESS from config.maemo - * Added CONFIG_UNCOMPRESS to config.maemo. Fixes: NB#98035 - - -- Turo Janka Wed, 11 Feb 2009 16:08:12 +0200 - -busybox (3:1.10.2.legal-1osso14) unstable; urgency=low - - * Fixes time command segfault. Fixes: NB#98230 - - -- Turo Janka Tue, 21 Jan 2009 15:48:12 +0200 - -busybox (3:1.10.2.legal-1osso13) unstable; urgency=low - - * Enable more tools. Fixes: NB#98035 - - -- Turo Janka Tue, 20 Jan 2009 15:18:12 +0200 - -busybox (3:1.10.2.legal-1osso12) unstable; urgency=low - - * Enable MD5SUM and FEATURE_MD5_SHA1_SUM_CHECK. Fixes: NB#95950 - - -- Turo Janka Tue, 20 Jan 2009 11:16:20 +0200 - -busybox (3:1.10.2.legal-1osso11) unstable; urgency=low - - * Enable CONFIG_LFS. Fixes: NB#95830 - - -- Turo Janka Tue, 13 Jan 2009 15:26:23 +0200 - -busybox (3:1.10.2.legal-1osso10) unstable; urgency=low - - * Enable CONFIG_FEATURE_SORT_BIG. Fixes: NB#90925 - - -- Yauheni Kaliuta Mon, 27 Oct 2008 12:20:50 +0200 - -busybox (3:1.10.2.legal-1osso9) unstable; urgency=low - - * Disable runlevel, using a script from mini-rc - - -- Yauheni Kaliuta Mon, 27 Oct 2008 11:54:48 +0200 - -busybox (3:1.10.2.legal-1osso8) unstable; urgency=low - - * Added busybox-zero-ifr.ifr_hwaddr.sa_data.patch - Fixes: NB#89189 - - -- Yauheni Kaliuta Fri, 17 Oct 2008 15:38:53 +0300 - -busybox (3:1.10.2.legal-1osso7) unstable; urgency=low - - * Reverting the utilities, it breaks R&D images - * Revert "enabled xargs -0 (265 bytes)" - * Revert "enabled addgroup (872 bytes), delgroup (652 bytes)" - * Revert "enabled less (6773 bytes)" - * Revert "enabled setsid (111 bytes)" - * Revert "enabled script (1443 bytes), strings (489 bytes)" - * Revert "enabled ip (23780 bytes)" - - -- Yauheni Kaliuta Thu, 09 Oct 2008 15:26:35 +0300 - -busybox (3:1.10.2.legal-1osso6) unstable; urgency=low - - [ Pekka Pessi ] - * fsync.patch: fixed usage - * enabled xargs -0 (265 bytes) - * enabled addgroup (872 bytes), delgroup (652 bytes) - * enabled less (6773 bytes) - * enabled setsid (111 bytes) - * enabled script (1443 bytes), strings (489 bytes) - * enabled ip (23780 bytes) - - -- Yauheni Kaliuta Wed, 08 Oct 2008 13:16:50 +0300 - -busybox (3:1.10.2.legal-1osso5) unstable; urgency=low - - * config.maemo: enable fsync - * Added fsync.patch - - -- Yauheni Kaliuta Tue, 07 Oct 2008 11:15:54 +0300 - -busybox (3:1.10.2.legal-1osso4) unstable; urgency=low - - * Disable modutils, submitting real module-init-tools now - - -- Yauheni Kaliuta Thu, 02 Oct 2008 16:37:48 +0300 - -busybox (3:1.10.2.legal-1osso3) unstable; urgency=low - - * Enable hwclock applet - - -- Yauheni Kaliuta Wed, 24 Sep 2008 16:38:48 +0300 - -busybox (3:1.10.2.legal-1osso2) unstable; urgency=low - - * Install local/tempfile, forgot in upgrade. - Fixes: NB#88128 - - -- Yauheni Kaliuta Thu, 18 Sep 2008 14:23:08 +0300 - -busybox (3:1.10.2.legal-1osso1) unstable; urgency=low - - * Use .legal name (forgot) - * Updated config.maemo for 1.10.2 - - -- Yauheni Kaliuta Thu, 24 Jul 2008 12:35:10 +0300 - -busybox (3:1.10.2-1osso1) unstable; urgency=low - - * osso adoptation - * Added debug package - * tar -m dummy switch added - * build only deb package, no udeb or static - * CONFIG: fixing segfault - * Add tools needed by sysvinit/upstart - * Do not conflict with module-init-tools, divert should work - - -- Yauheni Kaliuta Thu, 24 Jul 2008 12:22:11 +0300 - -busybox (1:1.10.2-1) unstable; urgency=low - - * New upstream release. - - -- Bastian Blank Fri, 06 Jun 2008 19:20:43 +0200 - -busybox (1:1.9.2-3) unstable; urgency=low - - * Readd package version into greeting. - * Ignore init action if device is not available. (closes: #473659) - - -- Bastian Blank Sat, 12 Apr 2008 17:23:30 +0200 - -busybox (1:1.9.2-2) unstable; urgency=low - - * Set correct source section. - * Move busybox-static to extra. - * Update Standards-Version to 3.7.3, no changes. - * Add generic applet fallback. (closes: #472653) - - -- Bastian Blank Wed, 26 Mar 2008 11:33:59 +0100 - -busybox (1:1.9.2-1) unstable; urgency=low - - * New upstream release. - * [deb] Reenable prefer applets. - * [deb, static] Make the shell use applets first. (closes: #472389) - - -- Bastian Blank Mon, 24 Mar 2008 09:40:13 +0100 - -busybox (1:1.9.1-3) unstable; urgency=low - - * debian/config.udeb: - - Reenable fancy prompt. - * Readd copyright file. - - -- Bastian Blank Sat, 22 Mar 2008 23:01:57 +0100 - -busybox (1:1.9.1-2) experimental; urgency=low - - * Readd sections gc to dynamic built binaries. - * debian/config.udeb: - - Fix remaining problems. - - Disable ifconfig. - * util-linux/mount.c: - - Support relatime. (closes: #460824) - - -- Bastian Blank Thu, 13 Mar 2008 14:25:53 +0100 - -busybox (1:1.9.1-1) experimental; urgency=low - - * New upstream release. - * Drop unused busybox-floppy-udeb. - - -- Bastian Blank Fri, 15 Feb 2008 16:25:31 +0000 - -busybox (1:1.1.3-5) unstable; urgency=low - - * debian/config*: - - Drop devfs support. (closes: #431569) - - -- Bastian Blank Tue, 3 Jul 2007 15:45:43 +0000 - -busybox (1:1.1.3-4) unstable; urgency=low - - * coreutils/sort.c: - - Try again to fix sorting issues. Patch by Goswin Brederlow. - (closes: #373704) - - -- Bastian Blank Sun, 21 Jan 2007 15:29:02 +0000 - -busybox (1:1.1.3-3) unstable; urgency=low - - * debian/control: - - Add build dependency to new dpkg-dev. (closes: #383710) - * debian/copyright: - - Mention copyright holders. (closes: #378654) - - -- Bastian Blank Fri, 18 Aug 2006 22:32:04 +0000 - -busybox (1:1.1.3-2) unstable; urgency=low - - * coreutils/sort.c: - - Fix sorting of input which begins with the seperator. (closes: #373704) - - -- Bastian Blank Thu, 29 Jun 2006 19:36:19 +0000 - -busybox (1:1.1.3-1) unstable; urgency=low - - * New upstream version. - * debian/config-udeb: - - Enable fancy head and tail. Readds support for head -1. - * coreutils/tr.c: - - Don't segfault on incorrect input. - - -- Bastian Blank Thu, 01 Jun 2006 18:02:00 +0000 - -busybox (1:1.1.2-2) unstable; urgency=low - - * applets/install.sh: - - Fix installation if libbusybox is disabled. (closes: #368013) - * debian/config*: - - Support umount -a. (closes: #367714) - - -- Bastian Blank Mon, 22 May 2006 17:58:17 +0000 - -busybox (1:1.1.2-1) unstable; urgency=low - - * New upstream version. - * debian/config*: - - Rework. - - Remove modutils support. - * modutils: - - Remove modutils patch. - * shell: - - Export PATH. (closes: #329406) - - -- Bastian Blank Sun, 7 May 2006 19:31:17 +0000 - -busybox (1:1.01-4) unstable; urgency=low - - * debian/config*: (closes: #321304) - - Enable readlink -f support. - - Enable egrep alias. - - Enable ash command builtin. - * debianutils: Add readlink -f support. - * util-linux/umount.c: Fix loop for rootfs. (closes: #317062) - - -- Bastian Blank Sat, 17 Dec 2005 14:35:56 +0100 - -busybox (1:1.01-3) unstable; urgency=low - - * debian/config-deb: - - Recheck options. - - -- Bastian Blank Wed, 12 Oct 2005 14:40:08 +0200 - -busybox (1:1.01-2) unstable; urgency=low - - * debian/rules: - - Use CONFIG_DEBUG=y. - * modutils/obj: - - Fix bad casts that cause insmod (and probably depmod) to fail on - 64-bit architectures. (closes: #321503) - - -- Bastian Blank Thu, 08 Sep 2005 17:07:21 +0200 - -busybox (1:1.01-1) unstable; urgency=low - - * New upstream version. - * Fix more compilation errors. (closes: #325244) - - -- Bastian Blank Wed, 24 Aug 2005 19:28:13 +0200 - -busybox (1:1.00-5) unstable; urgency=low - - * Fix build. - * Enable ip applet in deb. - * Fix remove syslog. - - -- Bastian Blank Tue, 16 Aug 2005 19:20:13 +0200 - -busybox (1:1.00-4) unstable; urgency=low - - * Fix several problems with more strict gcc. (closes: #294474) - - -- Bastian Blank Sun, 31 Jul 2005 13:10:29 +0200 - -busybox (1:1.00-3) unstable; urgency=low - - * shell/ash.c: - - Fix eval. (closes: #315444) - - -- Bastian Blank Tue, 28 Jun 2005 14:45:54 +0200 - -busybox (1:1.00-2) unstable; urgency=low - - * debian/rules: - - Specify -s for debhelper tools. (closes: #314512) - - -- Bastian Blank Mon, 27 Jun 2005 18:09:52 +0200 - -busybox (1:1.00-1) unstable; urgency=low - - * New upstream release. (closes: #276771) - * New maintainer. (closes: #298363) - - -- Bastian Blank Fri, 10 Jun 2005 10:32:29 +0200 - -busybox-cvs (20040623-2) UNRELEASED; urgency=low - - * modutils: - - Fix error. (closes: #258546) - - Don't return failure if the module is already loaded. (closes: #257201) - * util-linux/umount.c: - - Don't ignore proc on umount -a. (closes: #257625) - - -- Bastian Blank Wed, 28 Jul 2004 11:20:58 +0200 - -busybox-cvs (20040623-1) unstable; urgency=low - - * New CVS version. - - Support 64 bit arithmetic. (closes: #251302) - - -- Bastian Blank Wed, 23 Jun 2004 21:53:52 +0200 - -busybox-cvs (20040612-2) unstable; urgency=low - - * modutils: - - Merge changes from modutils 2.4.26 (closes: #254214). - - -- Bastian Blank Sun, 13 Jun 2004 21:11:08 +0200 - -busybox-cvs (20040612-1) unstable; urgency=low - - * New CVS version. - * modutils: - - Fix missdetection of module file extension. - - -- Bastian Blank Fri, 21 May 2004 15:43:11 +0200 - -busybox-cvs (20040507-3) unstable; urgency=low - - * debian/config-udeb*: - - Disable udhcpc. (closes: #220652) - - Enable sleep. - - -- Bastian Blank Fri, 14 May 2004 18:13:52 +0200 - -busybox-cvs (20040507-2) unstable; urgency=low - - * editors/sed.c: - - Never assign the return value of getopt to char. (closes: #248106) - - -- Bastian Blank Sun, 09 May 2004 16:34:41 +0200 - -busybox-cvs (20040507-1) unstable; urgency=low - - * New CVS version - - Fix detection of hardlinks. (closes: #244589) - - Fix CAN-2003-0856. - * debian/config-udeb*: - - Enable netcat. (closes: #243508) - - Enable support for md5sum -c. - * modutils: - - Fix parameter passing for 2.4 modules. (closes: #245560) - - Add biarch support to 2.4 depmod and lsmod. (closes: #231606, #231618) - - Add 2.6 support to lsmod. (closes: #245580) - - -- Bastian Blank Sat, 08 May 2004 14:58:04 +0200 - -busybox-cvs (20040415-3) unstable; urgency=low - - * modutils: - - Fix detection of 2.4 kernel. (closes: #244806) - - -- Bastian Blank Tue, 20 Apr 2004 11:55:12 +0200 - -busybox-cvs (20040415-2) unstable; urgency=low - - * modutils: - - Make depmod quiet. - - Fix name of dependency files. - - -- Bastian Blank Sun, 18 Apr 2004 20:00:51 +0200 - -busybox-cvs (20040415-1) unstable; urgency=low - - * New CVS version - * modutils: - - Merge 2.6 support into insmod and depmod. - * debian/config-*udeb-linux: - - Update. - - -- Bastian Blank Sun, 18 Apr 2004 18:53:44 +0200 - -busybox-cvs (20040408-1) unstable; urgency=low - - * New CVS version - - Fix wget ftp handling. (closes: #242779) - * debian/config-*udeb: - - Disable standalone shell. - - -- Bastian Blank Thu, 15 Apr 2004 22:40:35 +0200 - -busybox-cvs (20040402-1) unstable; urgency=low - - * New CVS version - - Fix llseek mess. (closes: #240918) - * debian/config-*: - - Update. - - -- Bastian Blank Fri, 02 Apr 2004 23:49:25 +0200 - -busybox-cvs (20040306-1) unstable; urgency=low - - * New CVS version - - Fix directory header in ls. (closes: #231994) - - wget checks for empty *_proxy. (closes: #234130) - * debian/config-*: - - Update. - - -- Bastian Blank Mon, 23 Feb 2004 13:22:38 +0100 - -busybox-cvs (20040101-7) unstable; urgency=low - - * archival/libunarchive/get_header_tar.c: - - Fix usage of tar typeflag field (upstream). (closes: #233627) - * debian/config-*: - - Disable oldgnu support in tar. - - -- Bastian Blank Sat, 21 Feb 2004 12:34:40 +0100 - -busybox-cvs (20040101-6) unstable; urgency=low - - * debian/config-udeb*: - - Enable dd. (closes: #228248) - * debian/control: - - Set Standards-Version to 3.6.1, no changes. - - Remove Glenn McGrath from Uploaders. - * shell/cmdedit.c: - - Fix lockup (upstream). (closes: #228915) - * networking/wget.c: - - Fix proxy (upstream). - - -- Bastian Blank Thu, 22 Jan 2004 14:25:24 +0100 - -busybox-cvs (20040101-4) unstable; urgency=low - - * Fix cp truncation bug (Closes: #227081) - - -- Glenn McGrath Mon, 12 Jan 2004 20:51:01 +1100 - -busybox-cvs (20040101-3) unstable; urgency=low - - * debian/control: - - Change descriptions a little bit. - - Build-Depend against di-packages-build (>= 0.5). - * debian/rules: - - Install correct manpages. - - Mark build-* rules as notparallel. - - -- Bastian Blank Fri, 09 Jan 2004 22:09:02 +0100 - -busybox-cvs (20040101-2) unstable; urgency=low - - * coreutils/ln.c: - - Fix check in symlink mode (upstream). (closes: #226722) - - -- Bastian Blank Thu, 08 Jan 2004 12:50:27 +0100 - -busybox-cvs (20040101-1) unstable; urgency=low - - * New CVS version. - - Fix ln. (closes: #216435) - - Make insmod quiet. (closes: #215612) - * debiann/control: - - Build-Depend against di-packages-build (>= 0.4). - * debian/rules: - - Use di-packages-build. - - -- Bastian Blank Mon, 05 Jan 2004 06:21:03 +0100 - -busybox-cvs (20031212-3) unstable; urgency=low - - * debian/config-udeb-linux: - - Enable freeramdisk. (closes: #225360) - - -- Bastian Blank Tue, 30 Dec 2003 22:36:50 +0100 - -busybox-cvs (20031212-2) unstable; urgency=low - - * debian/config-udeb: - - Enable freeramdisk - * archival/libunarchive/data_extract_to_stdout.c: - - Don't extract to much (upstream). - * archival/libunarchive/data_extract_all.c: - - Don't set permissions on symlinks (upstream). - * editors/sed.c: - - Fix (upstream). (closes: #224676) - - -- Bastian Blank Tue, 23 Dec 2003 16:59:13 +0100 - -busybox-cvs (20031212-1) unstable; urgency=low - - * new cvs version - - fixes IOR in fdisk. (closes: #223773) - * debian/config* - - update - - remove mtab support from mount in busybox-static. (closes: #222386) - - enable progress bar for wget. (closes: #223770) - * modutils/obj/obj_s390{,x}.c - - fix abi change, R_390_GOTOFF -> R_390_GOTOFF32. (closes: #216528) - * acknowledge nmu. (closes: #216950, #216756, #215169, #215613) - - -- Bastian Blank Fri, 12 Dec 2003 21:19:41 +0100 - -busybox-cvs (20030926-2.1) unstable; urgency=low - - * NMU - * Remove /sbin/init from the udebs, while still leaving init support - compiled in. rootskel takes over providing init, but then calls bb init. - Remove linuxrc support from the udebs entirely. Closes: #216756 - * config-floppy-udeb-linux: add minimal find, grep. Closes: #215169 - * net-udeb-linux-i386: add loopback mount support. Closes: #215613 - - -- Joey Hess Tue, 21 Oct 2003 12:47:52 -0400 - -busybox-cvs (20030926-2) unstable; urgency=low - - * debian/config-floppy-udeb-linux - - update for new floppy images (closes: #212986, #214102) - - -- Bastian Blank Thu, 09 Oct 2003 12:25:49 +0200 - -busybox-cvs (20030926-1) unstable; urgency=low - - * new cvs version - * Makefile - - fix libpwdgrp link (upstream) (closes: #211675) - * Rules.mak.in - - fix optimization (closes: #212485) - * debian/config* - - update - * debian/config*udeb* - - move linux-i386 to linux (enable modutils on any linux arch) - - rename net to floppy - - enable wget status bar (closes: #211457) - * init/init.c - - workaround race conditions (closes: #212764) - - -- Bastian Blank Fri, 26 Sep 2003 15:10:14 +0200 - -busybox-cvs (0.60.99.cvs20030819-3) unstable; urgency=low - - * shell/ash.c - - fix signal handling (upstream) - - -- Bastian Blank Mon, 15 Sep 2003 18:12:09 +0200 - -busybox-cvs (0.60.99.cvs20030819-2) unstable; urgency=low - - * Fix configure permisions - * Set source Section to embedded - - -- Glenn McGrath Mon, 25 Aug 2003 06:33:19 +0000 - -busybox-cvs (0.60.99.cvs20030819-1) unstable; urgency=low - - * new cvs version - - -- Bastian Blank Tue, 19 Aug 2003 13:18:54 +0200 - -busybox-cvs (0.60.99.cvs20030426-10) unstable; urgency=low - - * archival/libunarchive/* - - add hardlink support (pending) - * debian/config-*udeb* - - add support for oldgnu tar format - - -- Bastian Blank Tue, 10 Jun 2003 12:06:41 +0200 - -busybox-cvs (0.60.99.cvs20030426-9) unstable; urgency=low - - * modutils/depmod.c - - fix base_dir for modules.dep - - -- Bastian Blank Sat, 07 Jun 2003 14:52:54 +0200 - -busybox-cvs (0.60.99.cvs20030426-8) unstable; urgency=low - - * util-linux/fdisk.c - - fix syscalls. (pending) - * libpwd/* - - don't build setgroups.o - - -- Bastian Blank Tue, 03 Jun 2003 11:26:28 +0200 - -busybox-cvs (0.60.99.cvs20030426-7) unstable; urgency=low - - * libbb/*syscallc.c - - fix syscalls. (upstream) (closes: #194631) - * modutils/* - - update complete objects code from upstream. (pending) - * debian/config-*udeb* - - update to busybox-applets.txt:1.14 - - -- Bastian Blank Thu, 29 May 2003 16:17:14 +0200 - -busybox-cvs (0.60.99.cvs20030426-6) unstable; urgency=low - - * modutils/Makefile.in - - don't build anything if deactivated - - -- Bastian Blank Sat, 24 May 2003 18:57:14 +0200 - -busybox-cvs (0.60.99.cvs20030426-5) unstable; urgency=low - - * debian/config-*udeb* - - revert changes (closes: #192717, #192753) - - readd initrd support (workaround) - - make init quiet - * archival/tar.c - - fix usage of tar -O (upstream) (closes: #193788) - - -- Bastian Blank Sat, 24 May 2003 13:25:36 +0200 - -busybox-cvs (0.60.99.cvs20030426-4) unstable; urgency=low - - * debian/config-*udeb* - - update to busybox-applets.txt:1.12 - * debian/rules - - use system instead of arch to determine which config file to use - - -- Bastian Blank Fri, 09 May 2003 11:21:13 +0200 - -busybox-cvs (0.60.99.cvs20030426-3) unstable; urgency=low - - * debian/config-udeb* - - update to busybox-applets.txt:1.11 - - -- Bastian Blank Wed, 07 May 2003 10:37:40 +0200 - -busybox-cvs (0.60.99.cvs20030426-2) unstable; urgency=low - - * modutils/* - - modprobe failes gracefully if the module is already loaded. (pending) - - implement depmod. (pending) - * debian/config* - - update - - -- Bastian Blank Wed, 30 Apr 2003 14:12:36 +0200 - -busybox-cvs (0.60.99.cvs20030426-1) unstable; urgency=low - - * new cvs version - - -- Bastian Blank Sat, 26 Apr 2003 18:33:17 +0200 - -busybox-cvs (0.60.99.cvs20030420-4) unstable; urgency=low - - * network/libiproute/iproute.c - - fix usage of ip route flush (upstream) - - -- Bastian Blank Fri, 25 Apr 2003 16:48:43 +0200 - -busybox-cvs (0.60.99.cvs20030420-3) unstable; urgency=low - - * debian/config-*udeb* - - update to busybox-applets.txt:1.10 - - -- Bastian Blank Fri, 25 Apr 2003 14:03:23 +0200 - -busybox-cvs (0.60.99.cvs20030420-2) unstable; urgency=low - - * archival/tar.c, archival/libunarchive/data_extract_all.c - - unlink files first (upstream patch) - - -- Bastian Blank Mon, 21 Apr 2003 12:42:06 +0200 - -busybox-cvs (0.60.99.cvs20030420-1) unstable; urgency=low - - * new cvs version - * debian/config*-udeb* - - add ifconfig/route for easier transition - * debian/config-net-udeb-i386 - - add logger - * debian/config-udeb* - - add uniq - - -- Bastian Blank Sun, 20 Apr 2003 21:02:58 +0200 - -busybox-cvs (0.60.99.cvs20030405-1) unstable; urgency=low - - * new cvs version - * debian/control - - add busybox-cvs-net-udeb - * debian/rules - - arch depend debs - - new net-udeb - * debian/config* - - cleanup applet list - - -- Bastian Blank Sat, 05 Apr 2003 11:44:50 +0200 - -busybox-cvs (0.60.99.cvs20030221-1) unstable; urgency=low - - * new cvs version - * enable new applets in udeb - - -- Bastian Blank Fri, 21 Feb 2003 23:15:16 +0100 - -busybox-cvs (0.60.99.cvs20030114-1) unstable; urgency=low - - * new cvs version - - -- Bastian Blank Tue, 14 Jan 2003 17:06:43 +0000 - -busybox-cvs (0.60.99.cvs20030105-1) unstable; urgency=low - - * Fix ip command build failure on ia64 (Closes: #172580 - * Dont build with BSD partition table support in fdisk, fails on m68k - - -- Glenn McGrath Sun, 5 Jan 2003 12:48:05 +1100 - -busybox-cvs (0.60.99.cvs20030104-2) unstable; urgency=low - - * floppy-retriever needs the cut command in the udeb - - -- Glenn McGrath Sat, 4 Jan 2003 17:13:05 +1100 - -busybox-cvs (0.60.99.cvs20030104-1) unstable; urgency=low - - * new cvs version - * Include new applets in the static package - * Include ash in the udeb - - -- Glenn McGrath Sat, 4 Jan 2003 13:39:04 +1100 - -busybox-cvs (0.60.99.cvs20021214-1) unstable; urgency=low - - * new cvs version - - udhcp merge. - * fix location of ip link. - - -- Bastian Blank Sat, 14 Dec 2002 13:52:15 +0100 - -busybox-cvs (0.60.99.cvs20021210-1) unstable; urgency=low - - * new cvs version - - various upstream fixes found in the last version. - * busybox-cvs-udeb - - include readlink and realpath. - - -- Bastian Blank Tue, 10 Dec 2002 21:23:40 +0100 - -busybox-cvs (0.60.99.cvs20021209-2) unstable; urgency=low - - * cleanup scripts/config/ within make clean (closes: #172413) - * busybox-cvs-udeb - - include readlink - * include manpages within busybox-cvs and busybox-cvs-static - - -- Bastian Blank Mon, 09 Dec 2002 22:09:52 +0100 - -busybox-cvs (0.60.99.cvs20021209-1) unstable; urgency=low - - * New cvs version. - - fix udhcpc for use with ip. - - klogd supports -c. - * busybox-cvs-udeb - - set priority to extra. (closes: #172302) - - don't longer provide busybox-udeb. - - -- Bastian Blank Mon, 09 Dec 2002 16:22:03 +0100 - -busybox-cvs (0.60.99.cvs20021203-1) unstable; urgency=low - - * New packages based on busybox cvs. - * changes for the udeb - - enable ip applet with address, link and route part. - - enable udhcpc. - - disable ifconfig and route applet. - - disable ls color. - - -- Bastian Blank Tue, 03 Dec 2002 18:51:00 +0100 - -busybox (1:0.60.0-1) unstable; urgency=low - - * New version released. See changelog for details. - - -- Erik Andersen Thu, 2 Aug 2001 12:12:37 -0600 - -busybox (1:0.52-1.1) unstable; urgency=high - - * Non-maintainer upload - * Fixed wget -P handling (closes: #106223). - - -- Matt Kraai Wed, 25 Jul 2001 11:01:38 -0600 - -busybox (1:0.52-1) unstable; urgency=high - - * New version released. See changelog for details. - - -- Erik Andersen Sat, 7 Jul 2001 01:23:45 -0600 - -busybox (1:0.51-10) unstable; urgency=high - - * Fix a compile problem with gcc 3.0 on hppa (closes: #102045) - - -- Erik Andersen Sat, 23 Jun 2001 23:55:57 -0600 - -busybox (1:0.51-9) unstable; urgency=high - - * tar was creating leading directories with 0777 permissions as - as reult of faulty umask handling. This fixes it, repairing - a grave security problem in the woody the boot floppies. - (closes: #101169) - - -- Erik Andersen Wed, 20 Jun 2001 16:17:38 -0600 - -busybox (1:0.51-8) unstable; urgency=high - - * Fix cp from /proc, where size=0 (closes: #100369) - * Add some padding to struct sysinfo for m68k. - * Apparently some bugs failed to be closed when master choked - (closes: #99627, #99637, #98571) - * Disable the busybox shell for the .deb, since it is not needed - for the boot floppies. - - -- Erik Andersen Mon, 11 Jun 2001 13:26:07 -0600 - -busybox (1:0.51-7) unstable; urgency=high - - * Fix tar permission setting for existing directories (closes: #99627) - * Do not remove the .cvsignore files on 'make release' (closes: #99637) - - -- Erik Andersen Mon, 4 Jun 2001 10:55:19 -0600 - -busybox (1:0.51-6) testing unstable; urgency=high - - * Update the version in testing so DHCP in the woody boot-floppies will work. - * Enable expr for the boot-floppies (closes: #98433) - * It builds on arm just fine now (closes: #97510) - - -- Erik Andersen Wed, 23 May 2001 14:50:13 -0600 - -busybox (1:0.51-5) unstable; urgency=low - - * Backport a sed fix from 0.52pre - * Backport chroot fix from 0.52pre - - -- Erik Andersen Wed, 16 May 2001 23:50:33 -0600 - -busybox (1:0.51-4) unstable; urgency=low - - * Backport from 0.52pre an endianness bugfix for md5sum - * Backport some updates to grep and sed - * Fix 'wget -O -' so it sets the quiet flag - - -- Erik Andersen Mon, 14 May 2001 14:17:36 -0600 - -busybox (1:0.51-3) unstable; urgency=low - - * This is the "I am an idiot" release. - * Make cp and mv work again (closes: #97290) - * Fix the version number. - - -- Erik Andersen Sat, 12 May 2001 17:35:58 -0600 - -busybox (0.51-2) unstable; urgency=low - - * Backport several release critical fixes into the 0.51 codebase - so the boot-floppies will work again. - * Fix a link ordering problem. (closes: #93362) - * Fixed gunzip (closes: #94331) - * Fixed cp permission setting (closes: #94580) - - -- Erik Andersen Sat, 12 May 2001 11:22:35 -0600 - -busybox (0.51-1) unstable; urgency=low - - * Fixes several critical bugs (see the busybox changelog - for complete details) - * Force USE_SYSTEM_PWD_GRP=false, so busybox bypasses - the glibc NSS libraries. (closes: #93362) - * Fixed a bug in sed's address range handling (closes: #91758) - * Removed irrelevant cruft from the bottem of debian/changelog - - -- Erik Andersen Tue, 10 Apr 2001 14:07:29 -0600 - -busybox (0.50-2) unstable; urgency=low - - * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) - * Disabled lash (the busybox shell) in the udeb (closes: #91337) - * fixed a bug in syslog, a problem with rebooting when booted as - an initrd, and a few other minor problems. - - -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 - - -busybox (0.50-2) unstable; urgency=low - - * Enabled freeramdisk and pivot_root in the udeb (closes: #91336) - * Disabled lash (the busybox shell) in the udeb (closes: #91337) - * fixed a bug in syslog, a problem with rebooting when booted as - an initrd, and a few other minor problems. - - -- Erik Andersen Sun, 25 Mar 2001 20:59:44 -0700 - -busybox (0.50-1) unstable; urgency=low - - * Tons on improvements all around -- See changelog for details. - * Fix malformed Build-Depends (closes: #86930) - * grep has worked for some time now (closes: #81084) - * init compiles with DEBUG_INIT enabled (closes: #85794) - * md5sum no longer displays filename when reading stdin (closes: #81283) - * lsmod, rmmod, and insmod are no longer enabled (closes: #85642) - * busybox and buxybox-static now conflict/replace each other (closes: #80421) - - -- Erik Andersen Thu, 15 Mar 2001 14:45:00 -0700 - -busybox (0.49-1) unstable; urgency=low - - * Lots more source updates and bug fixes. See changelog for details. - - -- Erik Andersen Sat, 27 Jan 2001 01:45:53 -0700 - -busybox (0.48-1) unstable; urgency=low - - * Lots more source updates and bug fixes. See changelog for details. - * Now includes .udeb support for the debian-installer. The .udeb - probably needs some more work, but this should be a good start. - - -- Erik Andersen Wed, 13 Dec 2000 08:36:07 -0700 - -busybox (0.47-1) unstable; urgency=low - - * New version released. See changelog for details. - - -- Erik Andersen Mon, 25 Sep 2000 23:00:56 -0600 - -busybox (0.46-1) unstable; urgency=low - - * New version released. See changelog for details. - - -- Erik Andersen Tue, 11 Jul 2000 12:15:44 -0600 - -busybox (0.45-1) unstable; urgency=low - - * First attempt at packaging BusyBox as a .deb. This has been in - in the Debian boot-floppies CVS tree forever. Hopefully, having it as a - standalone app will make life easier for me, the debian-installer team, and - everyone else as well... - * I have created a busybox-static that can be used as a rescue shell when you - hose your system. Just invoke "busybox sh" to fir up the shell. This has - every app provided by busybox staically linked in. There have been several - times in the past that I would have loved to have this sitting on my system - (i.e. when libc gets screwed up.) - - -- Erik Andersen Tue, 27 Jun 2000 12:26:41 -0600 - diff --git a/debian/compat b/debian/compat deleted file mode 100644 index 7ed6ff8..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -5 diff --git a/debian/config/config.maemo b/debian/config/config.maemo deleted file mode 100644 index 0535cbd..0000000 --- a/debian/config/config.maemo +++ /dev/null @@ -1,825 +0,0 @@ -# -# Automatically generated make config: don't edit -# Busybox version: 1.10.2 -# Thu Jul 24 12:28:58 2008 -# -CONFIG_HAVE_DOT_CONFIG=y - -# -# Busybox Settings -# - -# -# General Configuration -# -# CONFIG_NITPICK is not set -# CONFIG_DESKTOP is not set -# CONFIG_FEATURE_BUFFERS_USE_MALLOC is not set -# 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 is not set -CONFIG_FEATURE_COMPRESS_USAGE=y -# CONFIG_FEATURE_INSTALLER is not set -# CONFIG_LOCALE_SUPPORT is not set -CONFIG_GETOPT_LONG=y -CONFIG_FEATURE_DEVPTS=y -# CONFIG_FEATURE_CLEAN_UP is not set -# CONFIG_FEATURE_PIDFILE is not set -CONFIG_FEATURE_SUID=y -# CONFIG_FEATURE_SUID_CONFIG is not set -# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set -# CONFIG_SELINUX is not set -# CONFIG_FEATURE_APPLETS_FALLBACK is not set -CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" -CONFIG_FEATURE_SYSLOG=y -CONFIG_FEATURE_HAVE_RPC=y - -# -# Build Options -# -# CONFIG_STATIC 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 - -# -# Debugging Options -# -CONFIG_DEBUG=y -# CONFIG_WERROR is not set -CONFIG_NO_DEBUG_LIB=y -# CONFIG_DMALLOC is not set -# CONFIG_EFENCE is not set -CONFIG_INCLUDE_SUSv2=y - -# -# 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_SIZE_VS_SPEED=0 -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=y -CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y -CONFIG_FEATURE_COPYBUF_KB=4 -CONFIG_MONOTONIC_SYSCALL=y -CONFIG_IOCTL_HEX2STR_ERROR=y - -# -# Applets -# - -# -# Archival Utilities -# -# CONFIG_AR is not set -# CONFIG_FEATURE_AR_LONG_FILENAMES is not set -# CONFIG_BUNZIP2 is not set -# CONFIG_BZIP2 is not set -# CONFIG_CPIO is not set -# CONFIG_DPKG is not set -# CONFIG_DPKG_DEB is not set -# CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set -CONFIG_GUNZIP=y -# CONFIG_FEATURE_GUNZIP_UNCOMPRESS is not set -CONFIG_GZIP=y -# CONFIG_RPM2CPIO is not set -# CONFIG_RPM is not set -# CONFIG_FEATURE_RPM_BZ2 is not set -CONFIG_TAR=y -CONFIG_FEATURE_TAR_CREATE=y -CONFIG_FEATURE_TAR_GZIP=y -# CONFIG_FEATURE_TAR_BZIP2 is not set -# CONFIG_FEATURE_TAR_LZMA is not set -# CONFIG_FEATURE_TAR_COMPRESS is not set -# CONFIG_FEATURE_TAR_AUTODETECT is not set -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 is not set -CONFIG_FEATURE_TAR_TOUCH=y -CONFIG_UNCOMPRESS=y -# CONFIG_UNLZMA is not set -# CONFIG_FEATURE_LZMA_FAST is not set -# CONFIG_UNZIP is not set - -# -# Common options for cpio and tar -# -# CONFIG_FEATURE_UNARCHIVE_TAPE is not set -# CONFIG_FEATURE_DEB_TAR_GZ is not set -# CONFIG_FEATURE_DEB_TAR_BZ2 is not set -# CONFIG_FEATURE_DEB_TAR_LZMA is not set - -# -# Coreutils -# -CONFIG_BASENAME=y -# CONFIG_CAL is not set -CONFIG_CAT=y -# CONFIG_CATV is not set -CONFIG_CHGRP=y -CONFIG_CHMOD=y -CONFIG_CHOWN=y -CONFIG_CHROOT=y -CONFIG_CKSUM=y -CONFIG_COMM=y -CONFIG_CP=y -CONFIG_CUT=y -CONFIG_DATE=y -CONFIG_FEATURE_DATE_ISOFMT=y -CONFIG_DD=y -CONFIG_FEATURE_DD_SIGNAL_HANDLING=y -# CONFIG_FEATURE_DD_IBS_OBS is not set -CONFIG_DF=y -# CONFIG_FEATURE_DF_INODE is not set -CONFIG_DIRNAME=y -# CONFIG_DOS2UNIX is not set -# CONFIG_UNIX2DOS is not set -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 is not set -CONFIG_FALSE=y -CONFIG_FOLD=y -CONFIG_FSYNC=y -CONFIG_HEAD=y -# CONFIG_FEATURE_FANCY_HEAD is not set -CONFIG_HOSTID=y -CONFIG_ID=y -CONFIG_INSTALL=y -# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -# CONFIG_LENGTH is not set -CONFIG_LN=y -CONFIG_LOGNAME=y -CONFIG_LS=y -# CONFIG_FEATURE_LS_FILETYPES is not set -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=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 is not set -CONFIG_SEQ=y -CONFIG_SHA1SUM=y -CONFIG_SLEEP=y -# CONFIG_FEATURE_FANCY_SLEEP is not set -CONFIG_SORT=y -CONFIG_FEATURE_SORT_BIG=y -CONFIG_SPLIT=y -# CONFIG_FEATURE_SPLIT_FANCY is not set -CONFIG_STAT=y -# 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 is not set -CONFIG_TEST=y -CONFIG_FEATURE_TEST_64=y -CONFIG_TOUCH=y -CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set -CONFIG_TRUE=y -CONFIG_TTY=y -CONFIG_UNAME=y -CONFIG_UNEXPAND=y -# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set -CONFIG_UNIQ=y -# CONFIG_USLEEP is not set -# CONFIG_UUDECODE is not set -# CONFIG_UUENCODE is not set -CONFIG_WC=y -# CONFIG_FEATURE_WC_LARGE is not set -CONFIG_WHO=y -CONFIG_WHOAMI=y -CONFIG_YES=y - -# -# Common options for cp and mv -# -# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set - -# -# Common options for ls, more and telnet -# -CONFIG_FEATURE_AUTOWIDTH=y - -# -# Common options for df, du, ls -# -CONFIG_FEATURE_HUMAN_READABLE=y -CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y - -# -# Console Utilities -# -CONFIG_CHVT=y -CONFIG_CLEAR=y -CONFIG_DEALLOCVT=y -# CONFIG_DUMPKMAP is not set -CONFIG_KBD_MODE=y -# CONFIG_LOADFONT is not set -# CONFIG_LOADKMAP is not set -CONFIG_OPENVT=y -CONFIG_RESET=y -# 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_SETKEYCODES=y -CONFIG_SETLOGCONS=y - -# -# Debian Utilities -# -CONFIG_MKTEMP=y -# CONFIG_PIPE_PROGRESS is not set -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_AWK=y -# CONFIG_FEATURE_AWK_MATH is not set -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_BINARY is not set -# CONFIG_FEATURE_DIFF_DIR is not set -# CONFIG_FEATURE_DIFF_MINIMAL is not set -# CONFIG_ED is not set -# CONFIG_PATCH is not set -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 is not set -# CONFIG_FEATURE_VI_SETOPTS is not set -# CONFIG_FEATURE_VI_SET is not set -CONFIG_FEATURE_VI_WIN_RESIZE=y -CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=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 is not set -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 is not set -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 is not set -CONFIG_FEATURE_FIND_PATH=y -CONFIG_FEATURE_FIND_REGEX=y -# CONFIG_FEATURE_FIND_CONTEXT is not set -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 is not set -CONFIG_FEATURE_XARGS_SUPPORT_QUOTES=y -# 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_CALL_TELINIT=y -CONFIG_TELINIT_PATH="/sbin/telinit" -# CONFIG_DEBUG_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_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_HALT=y -CONFIG_MESG=y - -# -# Login/Password Management Utilities -# -# CONFIG_FEATURE_SHADOWPASSWDS is not set -# CONFIG_USE_BB_SHADOW is not set -# CONFIG_USE_BB_PWD_GRP is not set -# CONFIG_ADDGROUP 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_DELUSER is not set -CONFIG_GETTY=y -CONFIG_FEATURE_UTMP=y -# CONFIG_FEATURE_WTMP is not set -CONFIG_LOGIN=y -# CONFIG_PAM is not set -# CONFIG_LOGIN_SCRIPTS is not set -CONFIG_FEATURE_NOLOGIN=y -CONFIG_FEATURE_SECURETTY=y -# 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=y -CONFIG_FEATURE_SU_SYSLOG=y -# 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 - -# -# Linux Module Utilities -# -# CONFIG_INSMOD 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_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_MULTIPLE_OPTIONS is not set -# CONFIG_FEATURE_MODPROBE_FANCY_ALIAS is not set -# CONFIG_FEATURE_CHECK_TAINTED_MODULE is not set -# CONFIG_FEATURE_2_4_MODULES is not set -# CONFIG_FEATURE_2_6_MODULES is not set -# CONFIG_FEATURE_QUERY_MODULE_INTERFACE is not set - -# -# Linux System Utilities -# -CONFIG_DMESG=y -CONFIG_FEATURE_DMESG_PRETTY=y -# 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 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_FDISK_ADVANCED is not set -# CONFIG_FINDFS is not set -# CONFIG_FREERAMDISK is not set -# CONFIG_FSCK_MINIX is not set -# CONFIG_MKFS_MINIX is not set -# CONFIG_FEATURE_MINIX2 is not set -CONFIG_GETOPT=y -# CONFIG_HEXDUMP is not set -# CONFIG_FEATURE_HEXDUMP_REVERSE is not set -# CONFIG_HD is not set -CONFIG_HWCLOCK=y -# CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS is not set -# CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS is not set -CONFIG_IPCRM=y -CONFIG_IPCS=y -CONFIG_LOSETUP=y -# CONFIG_MDEV is not set -# CONFIG_FEATURE_MDEV_CONF is not set -# CONFIG_FEATURE_MDEV_RENAME is not set -# CONFIG_FEATURE_MDEV_EXEC is not set -# CONFIG_FEATURE_MDEV_LOAD_FIRMWARE is not set -CONFIG_MKSWAP=y -# CONFIG_FEATURE_MKSWAP_V0 is not set -CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=y -# CONFIG_VOLUMEID is not set -# CONFIG_FEATURE_VOLUMEID_EXT 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=y -CONFIG_FEATURE_MOUNT_FAKE=y -# CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -# CONFIG_FEATURE_MOUNT_LABEL is not set -CONFIG_FEATURE_MOUNT_NFS=y -# CONFIG_FEATURE_MOUNT_CIFS is not set -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y -# CONFIG_RDATE is not set -# CONFIG_READPROFILE is not set -# CONFIG_RTCWAKE is not set -# CONFIG_SETARCH is not set -CONFIG_SWAPONOFF=y -# CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y -# CONFIG_FEATURE_UMOUNT_ALL is not set - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y -CONFIG_FEATURE_MTAB_SUPPORT=y - -# -# Miscellaneous Utilities -# -# CONFIG_ADJTIMEX is not set -# CONFIG_BBCONFIG is not set -# 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_DEBUG_CROND_OPTION is not set -# CONFIG_FEATURE_CROND_CALL_SENDMAIL is not set -# CONFIG_CRONTAB is not set -# CONFIG_DC 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_EJECT is not set -# CONFIG_FEATURE_EJECT_SCSI is not set -# CONFIG_LAST is not set -# CONFIG_LESS is not set -CONFIG_FEATURE_LESS_MAXLINES= -# CONFIG_FEATURE_LESS_BRACKETS is not set -# CONFIG_FEATURE_LESS_FLAGS is not set -# CONFIG_FEATURE_LESS_FLAGCS is not set -# CONFIG_FEATURE_LESS_MARKS is not set -# CONFIG_FEATURE_LESS_REGEXP 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_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_RUNLEVEL is not set -# CONFIG_RX is not set -# CONFIG_SCRIPT is not set -# CONFIG_STRINGS is not set -CONFIG_SETSID=y -# CONFIG_TASKSET is not set -# CONFIG_FEATURE_TASKSET_FANCY is not set -CONFIG_TIME=y -# CONFIG_TTYSIZE is not set -# CONFIG_WATCHDOG is not set - -# -# Networking Utilities -# -CONFIG_FEATURE_IPV6=y -# 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_DNSD is not set -# CONFIG_ETHER_WAKE is not set -# CONFIG_FAKEIDENTD is not set -# CONFIG_FTPGET is not set -# CONFIG_FTPPUT is not set -# CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS is not set -CONFIG_HOSTNAME=y -# CONFIG_HTTPD is not set -# CONFIG_FEATURE_HTTPD_RANGES is not set -# CONFIG_FEATURE_HTTPD_USE_SENDFILE is not set -# CONFIG_FEATURE_HTTPD_RELOAD_CONFIG_SIGHUP 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_CONFIG_WITH_MIME_TYPES 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=y -CONFIG_FEATURE_IFCONFIG_STATUS=y -# CONFIG_FEATURE_IFCONFIG_SLIP is not set -# CONFIG_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ is not set -CONFIG_FEATURE_IFCONFIG_HW=y -# CONFIG_FEATURE_IFCONFIG_BROADCAST_PLUS is not set -# CONFIG_IFENSLAVE is not set -CONFIG_IFUPDOWN=y -CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" -# CONFIG_FEATURE_IFUPDOWN_IP is not set -# CONFIG_FEATURE_IFUPDOWN_IP_BUILTIN is not set -CONFIG_FEATURE_IFUPDOWN_IFCONFIG_BUILTIN=y -CONFIG_FEATURE_IFUPDOWN_IPV4=y -# 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=y -# 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=y -# CONFIG_FEATURE_NETSTAT_WIDE is not set -CONFIG_NSLOOKUP=y -CONFIG_PING=y -CONFIG_PING6=y -CONFIG_FEATURE_FANCY_PING=y -# CONFIG_PSCAN is not set -CONFIG_ROUTE=y -# CONFIG_SENDMAIL is not set -# CONFIG_FETCHMAIL is not set -CONFIG_SLATTACH=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_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_DEBUG_TFTP is not set -# CONFIG_TRACEROUTE is not set -# CONFIG_FEATURE_TRACEROUTE_VERBOSE is not set -# CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE is not set -# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set -# CONFIG_APP_UDHCPD is not set -# CONFIG_APP_DHCPRELAY is not set -# CONFIG_APP_DUMPLEASES is not set -# CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set -CONFIG_DHCPD_LEASES_FILE="" -# CONFIG_APP_UDHCPC is not set -# CONFIG_FEATURE_UDHCPC_ARPING is not set -# CONFIG_FEATURE_UDHCP_PORT is not set -# CONFIG_FEATURE_UDHCP_DEBUG is not set -# CONFIG_FEATURE_RFC3397 is not set -CONFIG_DHCPC_DEFAULT_SCRIPT="" -CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS= -# 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 -# CONFIG_TCPSVD is not set -# CONFIG_UDPSVD is not set - -# -# Process Utilities -# -CONFIG_FREE=y -CONFIG_FUSER=y -CONFIG_KILL=y -CONFIG_KILLALL=y -CONFIG_KILLALL5=y -# CONFIG_NMETER is not set -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_TIME 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_DECIMALS=y -CONFIG_FEATURE_TOPMEM=y -CONFIG_UPTIME=y -CONFIG_WATCH=y - -# -# Shells -# -CONFIG_FEATURE_SH_IS_ASH=y -# CONFIG_FEATURE_SH_IS_HUSH is not set -# CONFIG_FEATURE_SH_IS_MSH is not set -# CONFIG_FEATURE_SH_IS_NONE is not set -CONFIG_ASH=y - -# -# Ash Shell Options -# -CONFIG_ASH_JOB_CONTROL=y -# CONFIG_ASH_READ_NCHARS is not set -CONFIG_ASH_READ_TIMEOUT=y -CONFIG_ASH_ALIAS=y -CONFIG_ASH_MATH_SUPPORT=y -# CONFIG_ASH_MATH_SUPPORT_64 is not set -# CONFIG_ASH_GETOPTS is not set -CONFIG_ASH_BUILTIN_ECHO=y -CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y -# CONFIG_ASH_MAIL is not set -CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -# CONFIG_ASH_RANDOM_SUPPORT is not set -# CONFIG_ASH_EXPAND_PRMT is not set -# CONFIG_HUSH 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_LASH is not set -# CONFIG_MSH is not set - -# -# Bourne Shell Options -# -# CONFIG_FEATURE_SH_EXTRA_QUIET is not set -# CONFIG_FEATURE_SH_STANDALONE 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_IPC_SYSLOG is not set -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE= -# CONFIG_LOGREAD is not set -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -# CONFIG_KLOGD is not set -CONFIG_LOGGER=y - -# -# Runit Utilities -# -# CONFIG_RUNSV is not set -# CONFIG_RUNSVDIR is not set -# CONFIG_SV is not set -# 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 - -# -# Print Utilities -# -# CONFIG_LPD is not set -# CONFIG_LPR is not set -# CONFIG_LPQ is not set diff --git a/debian/config/os/hurd b/debian/config/os/hurd deleted file mode 100644 index 827a002..0000000 --- a/debian/config/os/hurd +++ /dev/null @@ -1,7 +0,0 @@ -CONFIG_PLATFORM_LINUX=n -CONFIG_INIT_TERMINAL_TYPE="mach" -CONFIG_FEATURE_INITRD=y -CONFIG_BLOCKDEV=n -CONFIG_MOUNT=n -CONFIG_UMOUNT=n -CONFIG_SWAPONOFF=n diff --git a/debian/config/os/kfreebsd b/debian/config/os/kfreebsd deleted file mode 100644 index 9e40944..0000000 --- a/debian/config/os/kfreebsd +++ /dev/null @@ -1,3 +0,0 @@ -CONFIG_PLATFORM_LINUX=n -CONFIG_INIT_TERMINAL_TYPE="cons25" -CONFIG_BLOCKDEV=n diff --git a/debian/config/os/linux b/debian/config/os/linux deleted file mode 100644 index 6af524c..0000000 --- a/debian/config/os/linux +++ /dev/null @@ -1,2 +0,0 @@ -CONFIG_PLATFORM_LINUX=y - diff --git a/debian/control b/debian/control deleted file mode 100644 index 9890abf..0000000 --- a/debian/control +++ /dev/null @@ -1,597 +0,0 @@ -Source: busybox -Priority: optional -Section: utils -Maintainer: Rafal Krypa -Uploaders: Karol Lewandowski -X-Maemo-Maintainer: Yauheni Kaliuta -X-Original-Maintainer: Debian Install System Team -X-Original-Uploaders: Bastian Blank -Build-Depends: debhelper (>> 5), python, quilt, libsystemd-daemon-dev -Standards-Version: 3.7.3 - -Package: busybox -Priority: required -Essential: yes -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: ash, awk, bsdutils, coreutils, diffutils, editor, findutils, grep, gzip, hostname, less, man-browser, mount, sed, tar, telnet-client, traceroute, util-linux -Replaces: ash, bsdutils, coreutils, diffutils, findutils, grep, gzip, hostname, mount, sed, tar, util-linux -Conflicts: ash, bsdutils, coreutils, diffutils, findutils, grep, gzip, hostname, mount, sed, tar, util-linux -Description: Tiny utilities for small and embedded systems - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for the most common - utilities you would usually find on your desktop system (i.e., ls, cp, mv, - mount, tar, etc.). The utilities in BusyBox generally have fewer options than - their full-featured GNU cousins; however, the options that are included - provide the expected functionality and behave very much like their GNU - counterparts. - . - This package installs: - - the BusyBox binary - - symlinks for tools included into it that correspond to binaries - in essential Debian packages - - alternatives from packages that don't have anything else - . - Symlinks to other tools included into BusyBox which correspond to binaries - in non-essential Debian packages are provided in separate symlink packages. - Those package are split and named according to the corresponding Debian - packages. - -Package: busybox-dbg -Architecture: any -Depends: busybox (= ${binary:Version}) -Section: devel -Description: Debug symbols for BusyBox - Debug symbol file for BusyBox. BusyBox provides tiny utilities for small - and embedded systems. - -Package: busybox-symlinks-busybox -Architecture: all -Depends: busybox (= ${binary:Version}) -Description: BusyBox specific symlinks - BusyBox symlinks for utilities without counterparts in Debian. - These are in separate package because they aren't essentials - (e.g. needed for system package upgrades). - -Package: busybox-symlinks-adduser -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: adduser -Replaces: adduser -Conflicts: adduser -Description: BusyBox symlinks to provide 'adduser' - BusyBox symlinks for utilities corresponding to 'adduser' package. - -Package: busybox-symlinks-adjtimex -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: adjtimex -Replaces: adjtimex -Conflicts: adjtimex -Description: BusyBox symlinks to provide 'adjtimex' - BusyBox symlinks for utilities corresponding to 'adjtimex' package. - -Package: busybox-symlinks-binutils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: binutils -Replaces: binutils -Conflicts: binutils -Description: BusyBox symlinks to provide 'binutils' - BusyBox symlinks for utilities corresponding to 'binutils' package. - -Package: busybox-symlinks-bridge-utils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: bridge-utils -Replaces: bridge-utils -Conflicts: bridge-utils -Description: BusyBox symlinks to provide 'bridge-utils' - BusyBox symlinks for utilities corresponding to 'bridge-utils' package. - -Package: busybox-symlinks-bsdmainutils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: bsdmainutils -Replaces: bsdmainutils -Conflicts: bsdmainutils -Description: BusyBox symlinks to provide 'bsdmainutils' - BusyBox symlinks for utilities corresponding to 'bsdmainutils' package. - -Package: busybox-symlinks-bzip2 -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: bzip2 -Replaces: bzip2 -Conflicts: bzip2 -Description: BusyBox symlinks to provide 'bzip2' - BusyBox symlinks for utilities corresponding to 'bzip2' package. - -Package: busybox-symlinks-console-tools -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: console-tools -Replaces: console-tools -Conflicts: console-tools -Description: BusyBox symlinks to provide 'console-tools' - BusyBox symlinks for utilities corresponding to 'console-tools' package. - -Package: busybox-symlinks-cpio -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: cpio -Replaces: cpio -Conflicts: cpio -Description: BusyBox symlinks to provide 'cpio' - BusyBox symlinks for utilities corresponding to 'cpio' package. - -Package: busybox-symlinks-cron -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: cron -Replaces: cron -Conflicts: cron -Description: BusyBox symlinks to provide 'cron' - BusyBox symlinks for utilities corresponding to 'cron' package. - -Package: busybox-symlinks-daemontools -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: daemontools -Replaces: daemontools -Conflicts: daemontools -Description: BusyBox symlinks to provide 'daemontools' - BusyBox symlinks for utilities corresponding to 'daemontools' package. - -Package: busybox-symlinks-dc -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: dc -Replaces: dc -Conflicts: dc -Description: BusyBox symlinks to provide 'dc' - BusyBox symlinks for utilities corresponding to 'dc' package. - -Package: busybox-symlinks-dnsutils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: dnsutils -Replaces: dnsutils -Conflicts: dnsutils -Description: BusyBox symlinks to provide 'dnsutils' - BusyBox symlinks for utilities corresponding to 'dnsutils' package. - -Package: busybox-symlinks-dosfstools -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: dosfstools -Replaces: dosfstools -Conflicts: dosfstools -Description: BusyBox symlinks to provide 'dosfstools' - BusyBox symlinks for utilities corresponding to 'dosfstools' package. - -Package: busybox-symlinks-ed -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ed -Replaces: ed -Conflicts: ed -Description: BusyBox symlinks to provide 'ed' - BusyBox symlinks for utilities corresponding to 'ed' package. - -Package: busybox-symlinks-eject -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: eject -Replaces: eject -Conflicts: eject -Description: BusyBox symlinks to provide 'eject' - BusyBox symlinks for utilities corresponding to 'eject' package. - -Package: busybox-symlinks-fbset -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: fbset -Replaces: fbset -Conflicts: fbset -Description: BusyBox symlinks to provide 'fbset' - BusyBox symlinks for utilities corresponding to 'fbset' package. - -Package: busybox-symlinks-fdflush -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: fdflush -Replaces: fdflush -Conflicts: fdflush -Description: BusyBox symlinks to provide 'fdflush' - BusyBox symlinks for utilities corresponding to 'fdflush' package. - -Package: busybox-symlinks-hdparm -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: hdparm -Replaces: hdparm -Conflicts: hdparm -Description: BusyBox symlinks to provide 'hdparm' - BusyBox symlinks for utilities corresponding to 'hdparm' package. - -Package: busybox-symlinks-ifupdown -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ifupdown -Replaces: ifupdown -Conflicts: ifupdown -Description: BusyBox symlinks to provide 'ifupdown' - BusyBox symlinks for utilities corresponding to 'ifupdown' package. - -Package: busybox-symlinks-initscripts -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: initscripts -Replaces: initscripts -Conflicts: initscripts -Description: BusyBox symlinks to provide 'initscripts' - BusyBox symlinks for utilities corresponding to 'initscripts' package. - -Package: busybox-symlinks-ipcalc -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ipcalc -Replaces: ipcalc -Conflicts: ipcalc -Description: BusyBox symlinks to provide 'ipcalc' - BusyBox symlinks for utilities corresponding to 'ipcalc' package. - -Package: busybox-symlinks-iproute -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: iproute -Replaces: iproute -Conflicts: iproute -Description: BusyBox symlinks to provide 'iproute' - BusyBox symlinks for utilities corresponding to 'iproute' package. - -Package: busybox-symlinks-ipsvd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ipsvd -Replaces: ipsvd -Conflicts: ipsvd -Description: BusyBox symlinks to provide 'ipsvd' - BusyBox symlinks for utilities corresponding to 'ipsvd' package. - -Package: busybox-symlinks-iputils-arping -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: iputils-arping -Replaces: iputils-arping -Conflicts: iputils-arping -Description: BusyBox symlinks to provide 'iputils-arping' - BusyBox symlinks for utilities corresponding to 'iputils-arping' package. - -Package: busybox-symlinks-iputils-ping -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: iputils-ping -Replaces: iputils-ping -Conflicts: iputils-ping -Description: BusyBox symlinks to provide 'iputils-ping' - BusyBox symlinks for utilities corresponding to 'iputils-ping' package. - -Package: busybox-symlinks-klogd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: klogd -Replaces: klogd -Conflicts: klogd -Description: BusyBox symlinks to provide 'klogd' - BusyBox symlinks for utilities corresponding to 'klogd' package. - -Package: busybox-symlinks-loadlin -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: loadlin -Replaces: loadlin -Conflicts: loadlin -Description: BusyBox symlinks to provide 'loadlin' - BusyBox symlinks for utilities corresponding to 'loadlin' package. - -Package: busybox-symlinks-lrzsz -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: lrzsz -Replaces: lrzsz -Conflicts: lrzsz -Description: BusyBox symlinks to provide 'lrzsz' - BusyBox symlinks for utilities corresponding to 'lrzsz' package. - -Package: busybox-symlinks-lzma -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: lzma -Replaces: lzma -Conflicts: lzma -Description: BusyBox symlinks to provide 'lzma' - BusyBox symlinks for utilities corresponding to 'lzma' package. - -Package: busybox-symlinks-lzop -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: lzop -Replaces: lzop -Conflicts: lzop -Description: BusyBox symlinks to provide 'lzop' - BusyBox symlinks for utilities corresponding to 'lzop' package. - -Package: busybox-symlinks-module-init-tools -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: module-init-tools -Replaces: module-init-tools -Conflicts: module-init-tools -Description: BusyBox symlinks to provide 'module-init-tools' - BusyBox symlinks for utilities corresponding to 'module-init-tools' package. - -Package: busybox-symlinks-mtd-utils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: mtd-utils -Replaces: mtd-utils -Conflicts: mtd-utils -Description: BusyBox symlinks to provide 'mtd-utils' - BusyBox symlinks for utilities corresponding to 'mtd-utils' package. - -Package: busybox-symlinks-net-tools -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: net-tools -Replaces: net-tools -Conflicts: net-tools -Description: BusyBox symlinks to provide 'net-tools' - BusyBox symlinks for utilities corresponding to 'net-tools' package. - -Package: busybox-symlinks-openbsd-inetd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: openbsd-inetd -Replaces: openbsd-inetd -Conflicts: openbsd-inetd -Description: BusyBox symlinks to provide 'openbsd-inetd' - BusyBox symlinks for utilities corresponding to 'openbsd-inetd' package. - -Package: busybox-symlinks-passwd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: passwd -Replaces: passwd -Conflicts: passwd -Description: BusyBox symlinks to provide 'passwd' - BusyBox symlinks for utilities corresponding to 'passwd' package. - -Package: busybox-symlinks-patch -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: patch -Replaces: patch -Conflicts: patch -Description: BusyBox symlinks to provide 'patch' - BusyBox symlinks for utilities corresponding to 'patch' package. - -Package: busybox-symlinks-ppp -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ppp -Replaces: ppp -Conflicts: ppp -Description: BusyBox symlinks to provide 'ppp' - BusyBox symlinks for utilities corresponding to 'ppp' package. - -Package: busybox-symlinks-procps -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: procps -Replaces: procps -Conflicts: procps -Description: BusyBox symlinks to provide 'procps' - BusyBox symlinks for utilities corresponding to 'procps' package. - -Package: busybox-symlinks-psmisc -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: psmisc -Replaces: psmisc -Conflicts: psmisc -Description: BusyBox symlinks to provide 'psmisc' - BusyBox symlinks for utilities corresponding to 'psmisc' package. - -Package: busybox-symlinks-rdate -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: rdate -Replaces: rdate -Conflicts: rdate -Description: BusyBox symlinks to provide 'rdate' - BusyBox symlinks for utilities corresponding to 'rdate' package. - -Package: busybox-symlinks-realpath -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: realpath -Replaces: realpath -Conflicts: realpath -Description: BusyBox symlinks to provide 'realpath' - BusyBox symlinks for utilities corresponding to 'realpath' package. - -Package: busybox-symlinks-rpm -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: rpm -Replaces: rpm -Conflicts: rpm -Description: BusyBox symlinks to provide 'rpm' - BusyBox symlinks for utilities corresponding to 'rpm' package. - -Package: busybox-symlinks-runit -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: runit -Replaces: runit -Conflicts: runit -Description: BusyBox symlinks to provide 'runit' - BusyBox symlinks for utilities corresponding to 'runit' package. - -Package: busybox-symlinks-sharutils -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: sharutils -Replaces: sharutils -Conflicts: sharutils -Description: BusyBox symlinks to provide 'sharutils' - BusyBox symlinks for utilities corresponding to 'sharutils' package. - -Package: busybox-symlinks-ssmtp -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: ssmtp -Replaces: ssmtp -Conflicts: ssmtp -Description: BusyBox symlinks to provide 'ssmtp' - BusyBox symlinks for utilities corresponding to 'ssmtp' package. - -Package: busybox-symlinks-sysklogd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: sysklogd -Replaces: sysklogd -Conflicts: sysklogd -Description: BusyBox symlinks to provide 'sysklogd' - BusyBox symlinks for utilities corresponding to 'sysklogd' package. - -Package: busybox-symlinks-telnetd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: telnetd -Replaces: telnetd -Conflicts: telnetd -Description: BusyBox symlinks to provide 'telnetd' - BusyBox symlinks for utilities corresponding to 'telnetd' package. - -Package: busybox-symlinks-tftp -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: tftp -Replaces: tftp -Conflicts: tftp -Description: BusyBox symlinks to provide 'tftp' - BusyBox symlinks for utilities corresponding to 'tftp' package. - -Package: busybox-symlinks-time -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: time -Replaces: time -Conflicts: time -Description: BusyBox symlinks to provide 'time' - BusyBox symlinks for utilities corresponding to 'time' package. - -Package: busybox-symlinks-tofrodos -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: tofrodos -Replaces: tofrodos -Conflicts: tofrodos -Description: BusyBox symlinks to provide 'tofrodos' - BusyBox symlinks for utilities corresponding to 'tofrodos' package. - -Package: busybox-symlinks-udhcpc -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: udhcpc -Replaces: udhcpc -Conflicts: udhcpc -Description: BusyBox symlinks to provide 'udhcpc' - BusyBox symlinks for utilities corresponding to 'udhcpc' package. - -Package: busybox-symlinks-udhcpd -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: udhcpd -Replaces: udhcpd -Conflicts: udhcpd -Description: BusyBox symlinks to provide 'udhcpd' - BusyBox symlinks for utilities corresponding to 'udhcpd' package. - -Package: busybox-symlinks-unzip -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: unzip -Replaces: unzip -Conflicts: unzip -Description: BusyBox symlinks to provide 'unzip' - BusyBox symlinks for utilities corresponding to 'unzip' package. - -Package: busybox-symlinks-vlan -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: vlan -Replaces: vlan -Conflicts: vlan -Description: BusyBox symlinks to provide 'vlan' - BusyBox symlinks for utilities corresponding to 'vlan' package. - -Package: busybox-symlinks-vlock -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: vlock -Replaces: vlock -Conflicts: vlock -Description: BusyBox symlinks to provide 'vlock' - BusyBox symlinks for utilities corresponding to 'vlock' package. - -Package: busybox-symlinks-watchdog -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: watchdog -Replaces: watchdog -Conflicts: watchdog -Description: BusyBox symlinks to provide 'watchdog' - BusyBox symlinks for utilities corresponding to 'watchdog' package. - -Package: busybox-symlinks-wget -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: wget -Replaces: wget -Conflicts: wget -Description: BusyBox symlinks to provide 'wget' - BusyBox symlinks for utilities corresponding to 'wget' package. - -Package: busybox-symlinks-xterm -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: xterm -Replaces: xterm -Conflicts: xterm -Description: BusyBox symlinks to provide 'xterm' - BusyBox symlinks for utilities corresponding to 'xterm' package. - -Package: busybox-symlinks-zcip -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: zcip -Replaces: zcip -Conflicts: zcip -Description: BusyBox symlinks to provide 'zcip' - BusyBox symlinks for utilities corresponding to 'zcip' package. - -Package: busybox-systemd-klogd -Architecture: all -Depends: busybox-symlinks-klogd (= ${binary:Version}) -Description: systemd unit file for BusyBox's klogd - This package provides systemd unit file for BusyBox's klogd - -Package: busybox-systemd-sysklogd -Architecture: all -Depends: busybox-symlinks-sysklogd (= ${binary:Version}) -Description: systemd unit file for BusyBox's syslogd - This package provides systemd unit file for BusyBox's syslogd diff --git a/debian/copyright b/debian/copyright deleted file mode 100644 index 7d98fb8..0000000 --- a/debian/copyright +++ /dev/null @@ -1,28 +0,0 @@ -This package was debianized by Erik Andersen on -Sun, 18 Jun 2000 23:31:02 -0600 - -It was downloaded from ftp://ftp.busybox.net/busybox - -BusyBox is an aggregate of multiple packages. These packages are copyrighted -by their respective authors. - -Copyright: 1999-2005 Erik Andersen - -License: - - This package is free software; 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 dated June, 1991. - - This package is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this package; if not, write to the Free Software - Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, - MA 02110-1301, USA. - -On Debian GNU/Linux systems, the complete text of the GNU General -Public License can be found in `/usr/share/common-licenses/GPL-2'. diff --git a/debian/local/bash b/debian/local/bash deleted file mode 100644 index 1006ab8..0000000 --- a/debian/local/bash +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/ash -/bin/ash "$@" diff --git a/debian/local/faketrue b/debian/local/faketrue deleted file mode 100644 index 1a24852..0000000 --- a/debian/local/faketrue +++ /dev/null @@ -1 +0,0 @@ -#!/bin/sh diff --git a/debian/local/tempfile b/debian/local/tempfile deleted file mode 100644 index d94f654..0000000 --- a/debian/local/tempfile +++ /dev/null @@ -1,69 +0,0 @@ -#!/bin/sh - -#set -x - -mode=0600 -ver=0.0.1 - -usage() { - cat < -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: No description. - -@DPATCH@ -diff --git a/Makefile.flags b/Makefile.flags -index 988d6e7..e55e3a2 100644 ---- a/Makefile.flags -+++ b/Makefile.flags -@@ -41,7 +41,7 @@ CFLAGS += $(call cc-option,-Os -fno-builtin-strlen -finline-limit=0 -fomit-frame - # of branch probabilities (hopefully makes bloatcheck more stable): - CFLAGS += $(call cc-option,-fno-guess-branch-probability,) - CFLAGS += $(call cc-option,-funsigned-char -static-libgcc,) --CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1,) -+CFLAGS += $(call cc-option,-falign-functions=1 -falign-jumps=1 -falign-labels=1 -falign-loops=1 $(THUMB),) - - # FIXME: These warnings are at least partially to be concerned about and should - # be fixed.. diff --git a/debian/patches/06ls.dpatch b/debian/patches/06ls.dpatch deleted file mode 100644 index b953d77..0000000 --- a/debian/patches/06ls.dpatch +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/sh /usr/share/dpatch/dpatch-run -## 99-unnamed.dpatch by Yauheni Kaliuta -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: No description. - -@DPATCH@ -diff --git a/coreutils/ls.c b/coreutils/ls.c -index 067e463..39aa63e 100644 ---- a/coreutils/ls.c -+++ b/coreutils/ls.c -@@ -431,6 +431,7 @@ static void showfiles(struct dnode **dn, int nfiles) - } - } - putchar('\n'); -+ fflush(NULL); - column = 0; - } - } diff --git a/debian/patches/applets-fallback.patch b/debian/patches/applets-fallback.patch deleted file mode 100644 index 880cbe5..0000000 --- a/debian/patches/applets-fallback.patch +++ /dev/null @@ -1,197 +0,0 @@ ---- a/shell/ash.c -+++ b/shell/ash.c -@@ -7241,25 +7241,10 @@ - - - static void --tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) -+tryexec(IF_FEATURE_SH_STANDALONE(int applet_no UNUSED_PARAM,) char *cmd, char **argv, char **envp) - { - int repeated = 0; - --#if ENABLE_FEATURE_SH_STANDALONE -- if (applet_no >= 0) { -- if (APPLET_IS_NOEXEC(applet_no)) { -- clearenv(); -- while (*envp) -- putenv(*envp++); -- run_applet_no_and_exit(applet_no, argv); -- } -- /* re-exec ourselves with the new arguments */ -- execve(bb_busybox_exec_path, argv, envp); -- /* If they called chroot or otherwise made the binary no longer -- * executable, fall through */ -- } --#endif -- - repeat: - #ifdef SYSV - do { -@@ -7309,14 +7294,14 @@ - - clearredir(/*drop:*/ 1); - envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); -- if (strchr(argv[0], '/') != NULL --#if ENABLE_FEATURE_SH_STANDALONE -- || (applet_no = find_applet_by_name(argv[0])) >= 0 --#endif -- ) { -+ if (strchr(argv[0], '/') != NULL) { - tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); - e = errno; - } else { -+#if ENABLE_FEATURE_SH_STANDALONE -+ bb_execv_applet(argv[0], argv, envp); -+#endif -+ - e = ENOENT; - while ((cmdname = path_advance(&path, argv[0])) != NULL) { - if (--idx < 0 && pathopt == NULL) { ---- a/libbb/execable.c -+++ b/libbb/execable.c -@@ -9,6 +9,9 @@ - - #include "libbb.h" - -+#include -+#include -+ - /* check if path points to an executable file; - * return 1 if found; - * return 0 otherwise; -@@ -68,12 +71,60 @@ - } - - #if ENABLE_FEATURE_PREFER_APPLETS -+int FAST_FUNC bb_execv_applet(const char *name, char *const argv[], char *const envp[]) -+{ -+ const char **path = bb_busybox_exec_paths; -+ -+ errno = ENOENT; -+ -+ if (find_applet_by_name(name) < 0) -+ return -1; -+ -+ for (; *path; ++path) -+ execve(*path, argv, envp); -+ -+ return -1; -+} -+ - /* just like the real execvp, but try to launch an applet named 'file' first - */ - int FAST_FUNC bb_execvp(const char *file, char *const argv[]) - { -- return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, -- argv); -+ int ret = bb_execv_applet(file, argv, environ); -+ if (errno != ENOENT) -+ return ret; -+ -+ return execvp(file, argv); -+} -+ -+int FAST_FUNC bb_execlp(const char *file, const char *arg, ...) -+{ -+#define INITIAL_ARGV_MAX 16 -+ size_t argv_max = INITIAL_ARGV_MAX; -+ const char **argv = malloc(argv_max * sizeof (const char *)); -+ va_list args; -+ unsigned int i = 0; -+ int ret; -+ -+ va_start (args, arg); -+ while (argv[i++] != NULL) { -+ if (i == argv_max) { -+ const char **nptr; -+ argv_max *= 2; -+ nptr = realloc (argv, argv_max * sizeof (const char *)); -+ if (nptr == NULL) -+ return -1; -+ argv = nptr; -+ } -+ -+ argv[i] = va_arg (args, const char *); -+ } -+ va_end (args); -+ -+ ret = bb_execvp(file, (char *const *)argv); -+ free(argv); -+ -+ return ret; - } - #endif - ---- a/libbb/messages.c -+++ b/libbb/messages.c -@@ -45,6 +45,15 @@ - const char bb_path_motd_file[] ALIGN1 = "/etc/motd"; - const char bb_dev_null[] ALIGN1 = "/dev/null"; - const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; -+const char *bb_busybox_exec_paths[] ALIGN1 = { -+#ifdef __linux__ -+ "/proc/self/exe", -+#endif -+#ifdef CONFIG_BUSYBOX_EXEC_PATH -+ CONFIG_BUSYBOX_EXEC_PATH, -+#endif -+ NULL -+}; - const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, - * but I want to save a few bytes here. Check libbb.h before changing! */ ---- a/include/libbb.h -+++ b/include/libbb.h -@@ -830,11 +830,11 @@ - * but it may exec busybox and call applet instead of searching PATH. - */ - #if ENABLE_FEATURE_PREFER_APPLETS -+int bb_execv_applet(const char *name, char *const argv[], char *const envp[]) FAST_FUNC; - int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; --#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) --#define BB_EXECLP(prog,cmd,...) \ -- execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \ -- cmd, __VA_ARGS__) -+int bb_execlp(const char *file, const char *arg, ...) FAST_FUNC; -+#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) -+#define BB_EXECLP(prog,cmd,...) bb_execlp(prog,cmd, __VA_ARGS__) - #else - #define BB_EXECVP(prog,cmd) execvp(prog,cmd) - #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) -@@ -1575,6 +1575,7 @@ - extern const char bb_path_wtmp_file[]; - extern const char bb_dev_null[]; - extern const char bb_busybox_exec_path[]; -+extern const char *bb_busybox_exec_paths[]; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, - * but I want to save a few bytes here */ - extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ ---- a/Config.in -+++ b/Config.in -@@ -386,13 +386,10 @@ - - config BUSYBOX_EXEC_PATH - string "Path to BusyBox executable" -- default "/proc/self/exe" -+ default "/bin/busybox" - help - When Busybox applets need to run other busybox applets, BusyBox -- sometimes needs to exec() itself. When the /proc filesystem is -- mounted, /proc/self/exe always points to the currently running -- executable. If you haven't got /proc, set this to wherever you -- want to run BusyBox from. -+ sometimes needs to exec() itself. - - # These are auto-selected by other options - ---- a/coreutils/chroot.c -+++ b/coreutils/chroot.c -@@ -30,5 +30,7 @@ - argv[1] = (char *) "-i"; - } - -- BB_EXECVP_or_die(argv); -+ execvp(argv[0], argv); -+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; -+ bb_perror_msg_and_die("can't execute '%s'", argv[0]); - } diff --git a/debian/patches/blockdev.patch b/debian/patches/blockdev.patch deleted file mode 100644 index 46f57b7..0000000 --- a/debian/patches/blockdev.patch +++ /dev/null @@ -1,210 +0,0 @@ -Description: Backport blockdev applet from upstream - This allows os-prober to avoid replaying journals when mounting block - devices read-only. -Origin: http://git.busybox.net/busybox/tree/util-linux/blockdev.c -Bug-Debian: http://bugs.debian.org/418163 -Author: Sergey Naumov -Author: Denys Vlasenko -Forwarded: not-needed -Last-Update: 2010-11-09 - -Index: b/util-linux/blockdev.c -=================================================================== ---- /dev/null -+++ b/util-linux/blockdev.c -@@ -0,0 +1,195 @@ -+/* -+ * blockdev implementation for busybox -+ * -+ * Copyright (C) 2010 Sergey Naumov -+ * -+ * Licensed under GPLv2, see file LICENSE in this source tree. -+ */ -+ -+//applet:IF_BLOCKDEV(APPLET(blockdev, _BB_DIR_SBIN, _BB_SUID_DROP)) -+ -+//kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o -+ -+//config:config BLOCKDEV -+//config: bool "blockdev" -+//config: default y -+//config: help -+//config: Performs some ioctls with block devices. -+ -+//usage:#define blockdev_trivial_usage -+//usage: "OPTION BLOCKDEV" -+//usage:#define blockdev_full_usage "\n\n" -+//usage: "Options:" -+//usage: "\n --setro Set ro" -+//usage: "\n --setrw Set rw" -+//usage: "\n --getro Get ro" -+//usage: "\n --getss Get sector size" -+//usage: "\n --getbsz Get block size" -+//usage: "\n --setbsz BYTES Set block size" -+//usage: "\n --getsize Get device size in 512-byte sectors" -+//usage: "\n --getsize64 Get device size in bytes" -+//usage: "\n --flushbufs Flush buffers" -+//usage: "\n --rereadpt Reread partition table" -+ -+ -+#include "libbb.h" -+#include -+ -+enum { -+ ARG_NONE = 0, -+ ARG_INT = 1, -+ ARG_ULONG = 2, -+ /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */ -+ ARG_U64 = 3, -+ ARG_MASK = 3, -+ -+ FL_USRARG = 4, /* argument is provided by user */ -+ FL_NORESULT = 8, -+}; -+ -+struct bdc { -+ uint32_t ioc; /* ioctl code */ -+ const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */ -+ uint8_t flags; -+ int8_t argval; /* default argument value */ -+}; -+ -+static const struct bdc bdcommands[] = { -+ { -+ .ioc = BLKROSET, -+ .name = "setro", -+ .flags = ARG_INT + FL_NORESULT, -+ .argval = 1, -+ },{ -+ .ioc = BLKROSET, -+ .name = "setrw", -+ .flags = ARG_INT + FL_NORESULT, -+ .argval = 0, -+ },{ -+ .ioc = BLKROGET, -+ .name = "getro", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKSSZGET, -+ .name = "getss", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKBSZGET, -+ .name = "getbsz", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKBSZSET, -+ .name = "setbsz", -+ .flags = ARG_INT + FL_NORESULT + FL_USRARG, -+ .argval = 0, -+ },{ -+ .ioc = BLKGETSIZE, -+ .name = "getsize", -+ .flags = ARG_ULONG, -+ .argval = -1, -+ },{ -+ .ioc = BLKGETSIZE64, -+ .name = "getsize64", -+ .flags = ARG_U64, -+ .argval = -1, -+ },{ -+ .ioc = BLKFLSBUF, -+ .name = "flushbufs", -+ .flags = ARG_NONE + FL_NORESULT, -+ .argval = 0, -+ },{ -+ .ioc = BLKRRPART, -+ .name = "rereadpt", -+ .flags = ARG_NONE + FL_NORESULT, -+ .argval = 0, -+ } -+}; -+ -+static const struct bdc *find_cmd(const char *s) -+{ -+ const struct bdc *bdcmd = bdcommands; -+ if (s[0] == '-' && s[1] == '-') { -+ s += 2; -+ do { -+ if (strcmp(s, bdcmd->name) == 0) -+ return bdcmd; -+ bdcmd++; -+ } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands)); -+ } -+ bb_show_usage(); -+} -+ -+int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -+int blockdev_main(int argc, char **argv) -+{ -+ const struct bdc *bdcmd; -+ int fd; -+ uint64_t u64; -+ union { -+ int i; -+ unsigned long lu; -+ uint64_t u64; -+ } ioctl_val_on_stack; -+ -+ if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */ -+ bb_show_usage(); -+ -+ bdcmd = find_cmd(*++argv); -+ -+ u64 = (int)bdcmd->argval; -+ if (bdcmd->flags & FL_USRARG) -+ u64 = xatoi_u(*++argv); -+ -+ if (!*++argv || argv[1]) -+ bb_show_usage(); -+ fd = xopen(*argv, O_RDONLY); -+ -+ ioctl_val_on_stack.u64 = u64; -+#if BB_BIG_ENDIAN -+ /* Store data properly wrt data size. -+ * (1) It's no-op for little-endian. -+ * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1, -+ * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT. -+ * Thus, we don't need to handle ARG_ULONG. -+ */ -+ switch (bdcmd->flags & ARG_MASK) { -+ case ARG_INT: -+ ioctl_val_on_stack.i = (int)u64; -+ break; -+# if 0 /* unused */ -+ case ARG_ULONG: -+ ioctl_val_on_stack.lu = (unsigned long)u64; -+ break; -+# endif -+ } -+#endif -+ -+ if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1) -+ bb_simple_perror_msg_and_die(*argv); -+ -+ /* Fetch it into register(s) */ -+ u64 = ioctl_val_on_stack.u64; -+ -+ /* Zero- or one-extend the value if needed, then print */ -+ switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) { -+ case ARG_INT: -+ /* Smaller code when we use long long -+ * (gcc tail-merges printf call) -+ */ -+ printf("%lld\n", (long long)(int)u64); -+ break; -+ case ARG_ULONG: -+ u64 = (unsigned long)u64; -+ /* FALLTHROUGH */ -+ case ARG_U64: -+ printf("%llu\n", (unsigned long long)u64); -+ break; -+ } -+ -+ if (ENABLE_FEATURE_CLEAN_UP) -+ close(fd); -+ return EXIT_SUCCESS; -+} diff --git a/debian/patches/bootchartd-mounting-tmpfs-is-Linux-specific.patch b/debian/patches/bootchartd-mounting-tmpfs-is-Linux-specific.patch deleted file mode 100644 index aafbed2..0000000 --- a/debian/patches/bootchartd-mounting-tmpfs-is-Linux-specific.patch +++ /dev/null @@ -1,66 +0,0 @@ -From e7a0632b7b38f635853a08c276dad2fbd395ba92 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:53 +0200 -Subject: [PATCH 11/12] bootchartd: mounting tmpfs is Linux-specific - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/bootchartd.c | 20 +++++++++++++------- - 1 files changed, 13 insertions(+), 7 deletions(-) - -diff --git a/init/bootchartd.c b/init/bootchartd.c -index a1c0164..465a349 100644 ---- a/init/bootchartd.c -+++ b/init/bootchartd.c -@@ -6,7 +6,6 @@ - //config:config BOOTCHARTD - //config: bool "bootchartd" - //config: default y --//config: depends on PLATFORM_LINUX - //config: help - //config: bootchartd is commonly used to profile the boot process - //config: for the purpose of speeding it up. In this case, it is started -@@ -46,12 +45,15 @@ - #include "libbb.h" - /* After libbb.h, since it needs sys/types.h on some systems */ - #include --#include --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --#ifndef MNT_DETACH --# define MNT_DETACH 0x00000002 -+ -+#ifdef __linux__ -+# include -+# ifndef MS_SILENT -+# define MS_SILENT (1 << 15) -+# endif -+# ifndef MNT_DETACH -+# define MNT_DETACH 0x00000002 -+# endif - #endif - - #define BC_VERSION_STR "0.8" -@@ -175,6 +177,7 @@ static char *make_tempdir(void) - char template[] = "/tmp/bootchart.XXXXXX"; - char *tempdir = xstrdup(mkdtemp(template)); - if (!tempdir) { -+#ifdef __linux__ - /* /tmp is not writable (happens when we are used as init). - * Try to mount a tmpfs, them cd and lazily unmount it. - * Since we unmount it at once, we can mount it anywhere. -@@ -192,6 +195,9 @@ static char *make_tempdir(void) - if (umount2(try_dir, MNT_DETACH) != 0) { - bb_perror_msg_and_die("can't %smount tmpfs", "un"); - } -+#else -+ bb_perror_msg_and_die("can't create temporary directory"); -+#endif - } else { - xchdir(tempdir); - } --- -1.7.1 - diff --git a/debian/patches/busybox-zero-ifr.ifr_hwaddr.sa_data.patch b/debian/patches/busybox-zero-ifr.ifr_hwaddr.sa_data.patch deleted file mode 100644 index 9fc6f7d..0000000 --- a/debian/patches/busybox-zero-ifr.ifr_hwaddr.sa_data.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/networking/interface.c b/networking/interface.c -index ef187be..6cb1afa 100644 ---- a/networking/interface.c -+++ b/networking/interface.c -@@ -623,6 +623,7 @@ static int if_fetch(struct interface *ife) - - strncpy_IFNAMSIZ(ifr.ifr_name, ifname); - memset(ife->hwaddr, 0, 32); -+ memset(ifr.ifr_hwaddr.sa_data, 0, 8); - if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) - memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); - diff --git a/debian/patches/cttyhack-serial-console-detection-is-Linux-specific.patch b/debian/patches/cttyhack-serial-console-detection-is-Linux-specific.patch deleted file mode 100644 index 7228615..0000000 --- a/debian/patches/cttyhack-serial-console-detection-is-Linux-specific.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 430ba79c39eeed4725c36e9c2ad61c438c8a5d3e Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Fri, 30 Jul 2010 06:21:21 +0200 -Subject: [PATCH 13/19] cttyhack: serial console detection is Linux-specific - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - shell/cttyhack.c | 15 ++++++++++++--- - 1 files changed, 12 insertions(+), 3 deletions(-) - -Index: busybox-1.17.1/shell/cttyhack.c -=================================================================== ---- busybox-1.17.1.orig/shell/cttyhack.c 2010-08-01 05:38:31.000000000 +0200 -+++ busybox-1.17.1/shell/cttyhack.c 2010-08-01 05:39:26.000000000 +0200 -@@ -6,6 +6,10 @@ - */ - #include "libbb.h" - -+#if !defined(__linux__) && !defined(TIOCGSERIAL) -+# warning cttyhack will not be able to detect a controlling tty on this system -+#endif -+ - /* From */ - struct vt_stat { - unsigned short v_active; /* active vt */ -@@ -59,13 +63,19 @@ - close(fd); - } else { - /* We don't have ctty (or don't have "/dev/tty" node...) */ -- if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { -+ if (0) {} -+#ifdef TIOCGSERIAL -+ else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { - /* this is a serial console */ - sprintf(console + 8, "S%d", u.sr.line); -- } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { -+ } -+#endif -+#ifdef __linux__ -+ else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { - /* this is linux virtual tty */ - sprintf(console + 8, "S%d" + 1, u.vt.v_active); - } -+#endif - if (console[8]) { - fd = xopen(console, O_RDWR); - //bb_error_msg("switching to '%s'", console); -Index: busybox-1.17.1/shell/Config.src -=================================================================== ---- busybox-1.17.1.orig/shell/Config.src 2010-08-01 05:39:44.000000000 +0200 -+++ busybox-1.17.1/shell/Config.src 2010-08-01 05:39:49.000000000 +0200 -@@ -370,7 +370,6 @@ - config CTTYHACK - bool "cttyhack" - default y -- depends on PLATFORM_LINUX - help - One common problem reported on the mailing list is "can't access tty; - job control turned off" error message which typically appears when diff --git a/debian/patches/debian-changes-1:1.17.1-10 b/debian/patches/debian-changes-1:1.17.1-10 deleted file mode 100644 index 6bb43e4..0000000 --- a/debian/patches/debian-changes-1:1.17.1-10 +++ /dev/null @@ -1,70 +0,0 @@ -Description: Upstream changes introduced in version 1:1.17.1-10 - This patch has been created by dpkg-source during the package build. - Here's the last changelog entry, hopefully it gives details on why - those changes were made: - . - busybox (1:1.17.1-10) unstable; urgency=low - . - [ Michael Tokarev ] - * tiny build system changes: from main source to build directories: - don't copy .dotfiles, use ln instead of cp - . - [ Joey Hess ] - * Enable sha256sum in udeb, needed by debootstrap to handle Release - files w/o md5sums. - * Did not disable md5sum in udeb because eg anna still uses them to verify - md5sum fields from d-i Packages files. (Those fields are still present.. - for now.) - . - The person named in the Author field signed this changelog entry. -Author: Joey Hess - ---- -The information above should follow the Patch Tagging Guidelines, please -checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here -are templates for supplementary fields that you might want to add: - -Origin: , -Bug: -Bug-Debian: http://bugs.debian.org/ -Bug-Ubuntu: https://launchpad.net/bugs/ -Forwarded: -Reviewed-By: -Last-Update: - ---- /dev/null -+++ busybox-1.17.1/busybox-1.17.1/.indent.pro -@@ -0,0 +1,33 @@ -+--blank-lines-after-declarations -+--blank-lines-after-procedures -+--break-before-boolean-operator -+--no-blank-lines-after-commas -+--braces-on-if-line -+--braces-on-struct-decl-line -+--comment-indentation25 -+--declaration-comment-column25 -+--no-comment-delimiters-on-blank-lines -+--cuddle-else -+--continuation-indentation4 -+--case-indentation0 -+--else-endif-column33 -+--space-after-cast -+--line-comments-indentation0 -+--declaration-indentation1 -+--dont-format-first-column-comments -+--dont-format-comments -+--honour-newlines -+--indent-level4 -+/* changed from 0 to 4 */ -+--parameter-indentation4 -+--line-length78 /* changed from 75 */ -+--continue-at-parentheses -+--no-space-after-function-call-names -+--dont-break-procedure-type -+--dont-star-comments -+--leave-optional-blank-lines -+--dont-space-special-semicolon -+--tab-size4 -+/* additions by Mark */ -+--case-brace-indentation0 -+--leave-preprocessor-space diff --git a/debian/patches/doc-man-name.patch b/debian/patches/doc-man-name.patch deleted file mode 100644 index d793c35..0000000 --- a/debian/patches/doc-man-name.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/Makefile.custom -+++ b/Makefile.custom -@@ -107,7 +107,7 @@ - - # Documentation Targets - .PHONY: doc --doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html -+doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html - - # FIXME: Doesn't belong here - cmd_doc = -@@ -134,10 +134,10 @@ - $(Q)-mkdir -p docs - $(Q)-pod2text $< > $@ - --docs/BusyBox.1: docs/busybox.pod -+docs/busybox.1: docs/busybox.pod - $(disp_doc) - $(Q)-mkdir -p docs -- $(Q)-pod2man --center=BusyBox --release="version $(KERNELVERSION)" $< > $@ -+ $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ - - docs/BusyBox.html: docs/busybox.net/BusyBox.html - $(disp_doc) diff --git a/debian/patches/init-console-CRTSCTS.patch b/debian/patches/init-console-CRTSCTS.patch deleted file mode 100644 index ddc06fb..0000000 --- a/debian/patches/init-console-CRTSCTS.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/init/init.c.original 2010-10-17 20:12:02.000000000 +0200 -+++ b/init/init.c 2010-10-17 20:12:17.000000000 +0200 -@@ -232,7 +232,11 @@ - #endif - - /* Make it be sane */ -- tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; -+ tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD -+#ifdef CRTSCTS -+ | CRTSCTS -+#endif -+ ; - tty.c_cflag |= CREAD | HUPCL | CLOCAL; - - /* input modes */ diff --git a/debian/patches/init-console.patch b/debian/patches/init-console.patch deleted file mode 100644 index 6845950..0000000 --- a/debian/patches/init-console.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/init/init.c -+++ b/init/init.c -@@ -441,6 +441,8 @@ - for (a = init_action_list; a; a = a->next) { - if (!(a->action_type & action_type)) - continue; -+ if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) -+ continue; - - if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) { - pid_t pid = run(a); diff --git a/debian/patches/init-halt-portability-improvements.patch b/debian/patches/init-halt-portability-improvements.patch deleted file mode 100644 index 94618c3..0000000 --- a/debian/patches/init-halt-portability-improvements.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 714674e4da3d92c5dd14e00ab30794a895b91eb4 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:38:44 +0200 -Subject: [PATCH 4/9] init,halt: portability improvements - -* make init and halt use the same RB_* constants for reboot() -* conditionalize the Linux-specific code - -Inspired by init.init.diff from the Debian kFreeBSD patches at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/Config.src | 2 -- - init/halt.c | 14 +------------- - init/init.c | 16 ++++++++-------- - init/reboot.h | 31 +++++++++++++++++++++++++++++++ - 4 files changed, 40 insertions(+), 23 deletions(-) - create mode 100644 init/reboot.h - -Index: busybox-1.17.1/init/Config.src -=================================================================== ---- busybox-1.17.1.orig/init/Config.src 2010-08-01 05:32:43.000000000 +0200 -+++ busybox-1.17.1/init/Config.src 2010-08-01 05:36:47.000000000 +0200 -@@ -10,7 +10,6 @@ - config INIT - bool "init" - default y -- depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - init is the first program run when the system boots. -@@ -93,7 +92,6 @@ - config HALT - bool "poweroff, halt, and reboot" - default y -- depends on PLATFORM_LINUX - help - Stop all processes and either halt, reboot, or power off the system. - -Index: busybox-1.17.1/init/halt.c -=================================================================== ---- busybox-1.17.1.orig/init/halt.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/init/halt.c 2010-08-01 05:36:47.000000000 +0200 -@@ -8,7 +8,7 @@ - */ - - #include "libbb.h" --#include -+#include "reboot.h" - - #if ENABLE_FEATURE_WTMP - #include -@@ -36,18 +36,6 @@ - #define write_wtmp() ((void)0) - #endif - --#ifndef RB_HALT_SYSTEM --#define RB_HALT_SYSTEM RB_HALT --#endif -- --#ifndef RB_POWERDOWN --/* Stop system and switch power off if possible. */ --# define RB_POWERDOWN 0x4321fedc --#endif --#ifndef RB_POWER_OFF --# define RB_POWER_OFF RB_POWERDOWN --#endif -- - - int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int halt_main(int argc UNUSED_PARAM, char **argv) -Index: busybox-1.17.1/init/init.c -=================================================================== ---- busybox-1.17.1.orig/init/init.c 2010-08-01 05:36:45.000000000 +0200 -+++ busybox-1.17.1/init/init.c 2010-08-01 05:36:47.000000000 +0200 -@@ -12,7 +12,6 @@ - #include "libbb.h" - #include - #include --#include - #include - #ifdef __linux__ - #include -@@ -20,6 +19,7 @@ - #if ENABLE_FEATURE_UTMP - # include /* DEAD_PROCESS */ - #endif -+#include "reboot.h" /* reboot() constants */ - - /* Used only for sanitizing purposes in set_sane_term() below. On systems where - * the baud rate is stored in a separate field, we can safely disable them. */ -@@ -97,13 +97,6 @@ - enum { - L_LOG = 0x1, - L_CONSOLE = 0x2, --#ifndef RB_HALT_SYSTEM -- RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */ -- RB_ENABLE_CAD = 0x89abcdef, -- RB_DISABLE_CAD = 0, -- RB_POWER_OFF = 0x4321fedc, -- RB_AUTOBOOT = 0x01234567, --#endif - }; - - /* Print a message to the specified device. -@@ -726,10 +719,12 @@ - - run_shutdown_and_kill_processes(); - -+#ifdef RB_ENABLE_CAD - /* Allow Ctrl-Alt-Del to reboot the system. - * This is how kernel sets it up for init, we follow suit. - */ - reboot(RB_ENABLE_CAD); /* misnomer */ -+#endif - - if (open_stdio_to_tty(a->terminal)) { - dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); -@@ -872,9 +867,11 @@ - ) { - bb_show_usage(); - } -+#ifdef RB_DISABLE_CAD - /* Turn off rebooting via CTL-ALT-DEL - we get a - * SIGINT on CAD so we can shut things down gracefully... */ - reboot(RB_DISABLE_CAD); /* misnomer */ -+#endif - } - - /* Figure out where the default console should be */ -@@ -897,6 +894,8 @@ - message(L_CONSOLE | L_LOG, "init started: %s", bb_banner); - #endif - -+/* struct sysinfo is linux-specific */ -+#ifdef __linux__ - /* Make sure there is enough memory to do something useful. */ - if (ENABLE_SWAPONOFF) { - struct sysinfo info; -@@ -912,6 +911,7 @@ - run_actions(SYSINIT); /* wait and removing */ - } - } -+#endif - - /* Check if we are supposed to be in single user mode */ - if (argv[1] -Index: busybox-1.17.1/init/reboot.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ busybox-1.17.1/init/reboot.h 2010-08-01 05:36:47.000000000 +0200 -@@ -0,0 +1,31 @@ -+/* -+ * Definitions related to the reboot() system call, -+ * shared between init.c and halt.c. -+ */ -+ -+#include -+ -+#ifndef RB_HALT_SYSTEM -+# if defined(__linux__) -+# define RB_HALT_SYSTEM 0xcdef0123 -+# define RB_ENABLE_CAD 0x89abcdef -+# define RB_DISABLE_CAD 0 -+# define RB_POWER_OFF 0x4321fedc -+# define RB_AUTOBOOT 0x01234567 -+# elif defined(RB_HALT) -+# define RB_HALT_SYSTEM RB_HALT -+# endif -+#endif -+ -+/* Stop system and switch power off if possible. */ -+#ifndef RB_POWER_OFF -+# if defined(RB_POWERDOWN) -+# define RB_POWER_OFF RB_POWERDOWN -+# elif defined(__linux__) -+# define RB_POWER_OFF 0x4321fedc -+# else -+# warning "poweroff unsupported, using halt as fallback" -+# define RB_POWER_OFF RB_HALT_SYSTEM -+# endif -+#endif -+ diff --git a/debian/patches/init-loginutils-termios-portability-fixes.patch b/debian/patches/init-loginutils-termios-portability-fixes.patch deleted file mode 100644 index c612263..0000000 --- a/debian/patches/init-loginutils-termios-portability-fixes.patch +++ /dev/null @@ -1,199 +0,0 @@ -From f812eace1863feeac64dc8af27f4ab0f98119618 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:37:32 +0200 -Subject: [PATCH 3/9] init,loginutils: termios portability fixes - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/init.c | 17 ++++++++++++++++- - loginutils/Config.src | 2 -- - loginutils/getty.c | 27 ++++++++++++++------------- - loginutils/login.c | 2 +- - 4 files changed, 31 insertions(+), 17 deletions(-) - -diff --git a/init/init.c b/init/init.c -index 2eb8f1a..1388c75 100644 ---- a/init/init.c -+++ b/init/init.c -@@ -14,11 +14,19 @@ - #include - #include - #include -+#ifdef __linux__ - #include -+#endif - #if ENABLE_FEATURE_UTMP - # include /* DEAD_PROCESS */ - #endif - -+/* Used only for sanitizing purposes in set_sane_term() below. On systems where -+ * the baud rate is stored in a separate field, we can safely disable them. */ -+#ifndef CBAUD -+# define CBAUD 0 -+# define CBAUDEX 0 -+#endif - - /* Was a CONFIG_xxx option. A lot of people were building - * not fully functional init by switching it on! */ -@@ -166,7 +174,9 @@ static void message(int where, const char *fmt, ...) - - static void console_init(void) - { -+#ifdef VT_OPENQRY - int vtno; -+#endif - char *s; - - s = getenv("CONSOLE"); -@@ -190,6 +200,7 @@ static void console_init(void) - } - - s = getenv("TERM"); -+#ifdef VT_OPENQRY - if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) { - /* Not a linux terminal, probably serial console. - * Force the TERM setting to vt102 -@@ -198,7 +209,9 @@ static void console_init(void) - putenv((char*)"TERM=vt102"); - if (!ENABLE_FEATURE_INIT_SYSLOG) - log_console = NULL; -- } else if (!s) -+ } else -+#endif -+ if (!s) - putenv((char*)"TERM=linux"); - } - -@@ -220,8 +233,10 @@ static void set_sane_term(void) - tty.c_cc[VSTOP] = 19; /* C-s */ - tty.c_cc[VSUSP] = 26; /* C-z */ - -+#ifdef __linux__ - /* use line discipline 0 */ - tty.c_line = 0; -+#endif - - /* Make it be sane */ - tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; -diff --git a/loginutils/Config.src b/loginutils/Config.src -index 425d041..6ec2893 100644 ---- a/loginutils/Config.src -+++ b/loginutils/Config.src -@@ -179,7 +179,6 @@ config DELUSER - config GETTY - bool "getty" - default y -- depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - getty lets you log in on a tty, it is normally invoked by init. -@@ -187,7 +186,6 @@ config GETTY - config LOGIN - bool "login" - default y -- depends on PLATFORM_LINUX - select FEATURE_SUID - select FEATURE_SYSLOG - help -diff --git a/loginutils/getty.c b/loginutils/getty.c -index a5e8e90..7f04d33 100644 ---- a/loginutils/getty.c -+++ b/loginutils/getty.c -@@ -282,10 +282,8 @@ static void termios_init(struct termios *tp, int speed, struct options *op) - * reads will be done in raw mode anyway. Errors will be dealt with - * later on. - */ --#ifdef __linux__ - /* flush input and output queues, important for modems! */ -- ioctl(0, TCFLSH, TCIOFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ --#endif -+ tcflush(0, TCIOFLUSH); - ispeed = ospeed = speed; - if (speed == B0) { - /* Speed was specified as "0" on command line. -@@ -299,10 +297,13 @@ static void termios_init(struct termios *tp, int speed, struct options *op) - cfsetispeed(tp, ispeed); - cfsetospeed(tp, ospeed); - -- tp->c_iflag = tp->c_lflag = tp->c_line = 0; -+ tp->c_iflag = tp->c_lflag = 0; - tp->c_oflag = OPOST | ONLCR; - tp->c_cc[VMIN] = 1; - tp->c_cc[VTIME] = 0; -+#ifdef __linux__ -+ tp->c_line = 0; -+#endif - - /* Optionally enable hardware flow control */ - #ifdef CRTSCTS -@@ -360,10 +361,8 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) - for (bp = buf; bp < buf + nread; bp++) { - if (isdigit(*bp)) { - speed = bcode(bp); -- if (speed > 0) { -- tp->c_cflag &= ~CBAUD; -- tp->c_cflag |= speed; -- } -+ if (speed > 0) -+ cfsetspeed(tp, speed); - break; - } - } -@@ -417,7 +416,7 @@ static char *get_logname(char *logname, unsigned size_logname, - - /* Flush pending input (esp. after parsing or switching the baud rate). */ - sleep(1); -- ioctl(0, TCFLSH, TCIFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ -+ tcflush(0, TCIOFLUSH); - - /* Prompt for and read a login name. */ - logname[0] = '\0'; -@@ -526,7 +525,9 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat - tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ - tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ - tp->c_cc[VEOL] = DEF_EOL; -+#ifdef VSWTC - tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ -+#endif - - /* Account for special characters seen in input. */ - if (cp->eol == CR) { -@@ -572,8 +573,8 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat - #endif - - /* Finally, make the new settings effective */ -- /* It's tcsetattr_stdin_TCSANOW() + error check */ -- ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); -+ if (tcsetattr_stdin_TCSANOW(tp) < 0) -+ bb_perror_msg_and_die("%s: tcsetattr", op->tty); - } - - int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -@@ -650,8 +651,8 @@ int getty_main(int argc UNUSED_PARAM, char **argv) - * by patching the SunOS kernel variable "zsadtrlow" to a larger value; - * 5 seconds seems to be a good value. - */ -- /* tcgetattr() + error check */ -- ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty); -+ if (tcgetattr(0, &termios) < 0) -+ bb_perror_msg_and_die("%s: tcgetattr", options.tty); - - pid = getpid(); - #ifdef __linux__ -diff --git a/loginutils/login.c b/loginutils/login.c -index 88ed0af..1001248 100644 ---- a/loginutils/login.c -+++ b/loginutils/login.c -@@ -264,7 +264,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) - - while (1) { - /* flush away any type-ahead (as getty does) */ -- ioctl(0, TCFLSH, TCIFLUSH); -+ tcflush(0, TCIFLUSH); - - if (!username[0]) - get_username_or_die(username, sizeof(username)); --- -1.7.1 - diff --git a/debian/patches/init-make-the-initial-TERM-value-configurable.patch b/debian/patches/init-make-the-initial-TERM-value-configurable.patch deleted file mode 100644 index fb04a1e..0000000 --- a/debian/patches/init-make-the-initial-TERM-value-configurable.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 1c05303fdc302725093294eb0305adc003d52bcb Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:07 +0200 -Subject: [PATCH 5/9] init: make the initial $TERM value configurable - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/Config.src | 12 ++++++++++++ - init/init.c | 2 +- - 2 files changed, 13 insertions(+), 1 deletions(-) - -diff --git a/init/Config.src b/init/Config.src -index 590e298..2cac357 100644 ---- a/init/Config.src -+++ b/init/Config.src -@@ -89,6 +89,18 @@ config FEATURE_INITRD - This does not apply to initramfs, which runs /init as PID 1 and - requires no special support. - -+config INIT_TERMINAL_TYPE -+ string "Initial terminal type" -+ default "linux" -+ depends on INIT -+ help -+ This is the initial value set by init for the TERM environment -+ variable. This variable is used by programs which make use of -+ extended terminal capabilities. -+ -+ Note that on Linux, init attempts to detect serial terminal and -+ sets TERM to "vt102" if one is found. -+ - config HALT - bool "poweroff, halt, and reboot" - default y -diff --git a/init/init.c b/init/init.c -index d8bf158..fa1af6d 100644 ---- a/init/init.c -+++ b/init/init.c -@@ -205,7 +205,7 @@ static void console_init(void) - } else - #endif - if (!s) -- putenv((char*)"TERM=linux"); -+ putenv((char*)"TERM=" CONFIG_INIT_TERMINAL_TYPE); - } - - /* Set terminal settings to reasonable defaults. --- -1.7.1 - diff --git a/debian/patches/klogd-make-it-work-on-non-linux-systems.patch b/debian/patches/klogd-make-it-work-on-non-linux-systems.patch deleted file mode 100644 index 033617f..0000000 --- a/debian/patches/klogd-make-it-work-on-non-linux-systems.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Sun, 1 Aug 2010 03:01:44 +0200 -Subject: [PATCH 1/2] klogd: make it work on non-linux systems - -The klogctl() interface allows changing the console loglevel, but is -Linux-specific. The more portable method of reading from _PATH_KLOG is -added as an alternative. - -Adapted from the Debian kFreeBSD patch at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian/klogd.diff - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - sysklogd/Config.src | 17 ++++++- - sysklogd/klogd.c | 128 +++++++++++++++++++++++++++++++++++++++++++------- - 2 files changed, 126 insertions(+), 19 deletions(-) - -diff --git a/sysklogd/Config.src b/sysklogd/Config.src -index 41c0d28..1e59872 100644 ---- a/sysklogd/Config.src -+++ b/sysklogd/Config.src -@@ -109,7 +109,6 @@ config FEATURE_LOGREAD_REDUCED_LOCKING - config KLOGD - bool "klogd" - default y -- depends on PLATFORM_LINUX - help - klogd is a utility which intercepts and logs all - messages from the Linux kernel and sends the messages -@@ -117,6 +116,22 @@ config KLOGD - you wish to record the messages produced by the kernel, - you should enable this option. - -+config FEATURE_KLOGD_KLOGCTL -+ bool "Use the klogctl() interface" -+ default y -+ depends on KLOGD && PLATFORM_LINUX -+ help -+ The klogd applet supports two interfaces for reading -+ kernel messages. Linux provides the klogctl() interface -+ which allows reading messages from the kernel ring buffer -+ independently from the file system. -+ -+ If you answer 'N' here, klogd will use the more portable -+ approach of reading them from /proc or a device node. -+ However, this method requires the file to be available. -+ -+ If in doubt, say 'Y'. -+ - config LOGGER - bool "logger" - default y -diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c -index c54e80a..3468656 100644 ---- a/sysklogd/klogd.c -+++ b/sysklogd/klogd.c -@@ -4,7 +4,7 @@ - * - * Copyright (C) 2001 by Gennady Feldman . - * Changes: Made this a standalone busybox module which uses standalone -- * syslog() client interface. -+ * syslog() client interface. - * - * Copyright (C) 1999-2004 by Erik Andersen - * -@@ -19,18 +19,93 @@ - - #include "libbb.h" - #include --#include - --static void klogd_signal(int sig) -+ -+/* The Linux-specific klogctl(3) interface does not rely on the filesystem and -+ * allows us to change the console loglevel. Alternatively, we read the -+ * messages from _PATH_KLOG. */ -+ -+#if ENABLE_FEATURE_KLOGD_KLOGCTL -+ -+# include -+ -+static void klogd_open(void) -+{ -+ /* "Open the log. Currently a NOP" */ -+ klogctl(1, NULL, 0); -+} -+ -+static void klogd_setloglevel(int lvl) -+{ -+ /* "printk() prints a message on the console only if it has a loglevel -+ * less than console_loglevel". Here we set console_loglevel = lvl. */ -+ klogctl(8, NULL, lvl); -+} -+ -+static int klogd_read(char *bufp, int len) -+{ -+ return klogctl(2, bufp, len); -+} -+# define READ_ERROR "klogctl(2) error" -+ -+static void klogd_close(void) - { - /* FYI: cmd 7 is equivalent to setting console_loglevel to 7 - * via klogctl(8, NULL, 7). */ - klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */ - klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */ -- syslog(LOG_NOTICE, "klogd: exiting"); -- kill_myself_with_sig(sig); - } - -+#else -+ -+# include -+# ifndef _PATH_KLOG -+# ifdef __GNU__ -+# define _PATH_KLOG "/dev/klog" -+# else -+# error "your system's _PATH_KLOG is unknown" -+# endif -+# endif -+# define PATH_PRINTK "/proc/sys/kernel/printk" -+ -+enum { klogfd = 3 }; -+ -+static void klogd_open(void) -+{ -+ int fd = xopen(_PATH_KLOG, O_RDONLY); -+ xmove_fd(fd, klogfd); -+} -+ -+static void klogd_setloglevel(int lvl) -+{ -+ FILE *fp = fopen_or_warn(PATH_PRINTK, "w"); -+ if (fp) { -+ /* This changes only first value: -+ * "messages with a higher priority than this -+ * [that is, with numerically lower value] -+ * will be printed to the console". -+ * The other three values in this pseudo-file aren't changed. -+ */ -+ fprintf(fp, "%u\n", lvl); -+ fclose(fp); -+ } -+} -+ -+static int klogd_read(char *bufp, int len) -+{ -+ return read(klogfd, bufp, len); -+} -+# define READ_ERROR "read error" -+ -+static void klogd_close(void) -+{ -+ klogd_setloglevel(7); -+ if (ENABLE_FEATURE_CLEAN_UP) -+ close(klogfd); -+} -+ -+#endif -+ - #define log_buffer bb_common_bufsiz1 - enum { - KLOGD_LOGBUF_SIZE = sizeof(log_buffer), -@@ -38,6 +113,19 @@ enum { - OPT_FOREGROUND = (1 << 1), - }; - -+/* TODO: glibc openlog(LOG_KERN) reverts to LOG_USER instead, -+ * because that's how they interpret word "default" -+ * in the openlog() manpage: -+ * LOG_USER (default) -+ * generic user-level messages -+ * and the fact that LOG_KERN is a constant 0. -+ * glibc interprets it as "0 in openlog() call means 'use default'". -+ * I think it means "if openlog wasn't called before syslog() is called, -+ * use default". -+ * Convincing glibc maintainers otherwise is, as usual, nearly impossible. -+ * Should we open-code syslog() here to use correct facility? -+ */ -+ - int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int klogd_main(int argc UNUSED_PARAM, char **argv) - { -@@ -55,34 +143,34 @@ int klogd_main(int argc UNUSED_PARAM, char **argv) - bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); - } - -- openlog("kernel", 0, LOG_KERN); -- -- bb_signals(BB_FATAL_SIGS, klogd_signal); -- signal(SIGHUP, SIG_IGN); -+ logmode = LOGMODE_SYSLOG; - -- /* "Open the log. Currently a NOP" */ -- klogctl(1, NULL, 0); -+ /* klogd_open() before openlog(), since it might use fixed fd 3, -+ * and openlog() also may use the same fd 3 if we swap them: -+ */ -+ klogd_open(); -+ openlog("kernel", 0, LOG_KERN); - -- /* "printk() prints a message on the console only if it has a loglevel -- * less than console_loglevel". Here we set console_loglevel = i. */ - if (i) -- klogctl(8, NULL, i); -+ klogd_setloglevel(i); -+ -+ bb_signals(BB_FATAL_SIGS, record_signo); -+ signal(SIGHUP, SIG_IGN); - - syslog(LOG_NOTICE, "klogd started: %s", bb_banner); - -- while (1) { -+ while (!bb_got_signal) { - int n; - int priority; - char *start; - - /* "2 -- Read from the log." */ - start = log_buffer + used; -- n = klogctl(2, start, KLOGD_LOGBUF_SIZE-1 - used); -+ n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used); - if (n < 0) { - if (errno == EINTR) - continue; -- syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m", -- errno); -+ bb_perror_msg(READ_ERROR); - break; - } - start[n] = '\0'; -@@ -131,5 +219,9 @@ int klogd_main(int argc UNUSED_PARAM, char **argv) - } - } - -+ klogd_close(); -+ syslog(LOG_NOTICE, "klogd: exiting"); -+ if (bb_got_signal) -+ kill_myself_with_sig(bb_got_signal); - return EXIT_FAILURE; - } --- -1.7.1 - diff --git a/debian/patches/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch b/debian/patches/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch deleted file mode 100644 index 5bec32f..0000000 --- a/debian/patches/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 5a71fb82025d8bbb87a2d0a0851cb4c9cc31e888 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:47 +0200 -Subject: [PATCH 10/12] less: remove misguided dependency on PLATFORM_LINUX - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - miscutils/Config.src | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) - -Index: busybox-1.17.1/miscutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/miscutils/Config.src 2010-08-01 07:33:11.000000000 +0200 -+++ busybox-1.17.1/miscutils/Config.src 2010-08-02 00:45:01.000000000 +0200 -@@ -351,11 +351,6 @@ - config LESS - bool "less" - default y -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX - help - 'less' is a pager, meaning that it displays text files. It possesses - a wide array of features, and is an improvement over 'more'. diff --git a/debian/patches/libbb-conditionalize-AF_-usage-in-error-reporting.patch b/debian/patches/libbb-conditionalize-AF_-usage-in-error-reporting.patch deleted file mode 100644 index 73c9c32..0000000 --- a/debian/patches/libbb-conditionalize-AF_-usage-in-error-reporting.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 29885114a5e3d22ee7aa3ab0e373e00e7cff443c Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:39:24 +0200 -Subject: [PATCH 8/9] libbb: conditionalize AF_* usage in error reporting - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - libbb/xfuncs_printf.c | 4 ++++ - networking/Config.src | 1 - - 2 files changed, 4 insertions(+), 1 deletions(-) - -diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c -index 7069a7c..91f7ba2 100644 ---- a/libbb/xfuncs_printf.c -+++ b/libbb/xfuncs_printf.c -@@ -387,8 +387,12 @@ int FAST_FUNC xsocket(int domain, int type, int protocol) - /* Hijack vaguely related config option */ - #if ENABLE_VERBOSE_RESOLUTION_ERRORS - const char *s = "INET"; -+# ifdef AF_PACKET - if (domain == AF_PACKET) s = "PACKET"; -+# endif -+# ifdef AF_NETLINK - if (domain == AF_NETLINK) s = "NETLINK"; -+# endif - IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";) - bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol); - #else -diff --git a/networking/Config.src b/networking/Config.src -index 26c59e7..fc613e8 100644 ---- a/networking/Config.src -+++ b/networking/Config.src -@@ -43,7 +43,6 @@ config FEATURE_PREFER_IPV4_ADDRESS - config VERBOSE_RESOLUTION_ERRORS - bool "Verbose resolution errors" - default n -- depends on PLATFORM_LINUX #because of xsocket() in libbb/xfuncs_prinf.c - help - Enable if you are not satisfied with simplistic - "can't resolve 'hostname.com'" and want to know more. --- -1.7.1 - diff --git a/debian/patches/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch b/debian/patches/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch deleted file mode 100644 index 91ac9bf..0000000 --- a/debian/patches/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 816ed971e4ce60564f7ecbdc016d268d8e936230 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:29 +0200 -Subject: [PATCH 6/9] libbb.h: add device names for Hurd and FreeBSD - -Adapted from include.libbb.diff from the Debian kFreeBSD people: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - include/libbb.h | 26 +++++++++++++++++++++----- - 1 files changed, 21 insertions(+), 5 deletions(-) - -Index: busybox-1.17.1/include/libbb.h -=================================================================== ---- busybox-1.17.1.orig/include/libbb.h 2010-08-01 05:24:36.000000000 +0200 -+++ busybox-1.17.1/include/libbb.h 2010-08-01 05:36:59.000000000 +0200 -@@ -1614,7 +1614,27 @@ - /* "sh" */ - #define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) - --#if ENABLE_FEATURE_DEVFS -+/* The following devices are the same on all systems. */ -+#define CURRENT_TTY "/dev/tty" -+#define DEV_CONSOLE "/dev/console" -+ -+#if defined(__FreeBSD_kernel__) -+# define CURRENT_VC CURRENT_TTY -+# define VC_1 "/dev/ttyv0" -+# define VC_2 "/dev/ttyv1" -+# define VC_3 "/dev/ttyv2" -+# define VC_4 "/dev/ttyv3" -+# define VC_5 "/dev/ttyv4" -+# define VC_FORMAT "/dev/ttyv%d" -+#elif defined(__GNU__) -+# define CURRENT_VC CURRENT_TTY -+# define VC_1 "/dev/tty1" -+# define VC_2 "/dev/tty2" -+# define VC_3 "/dev/tty3" -+# define VC_4 "/dev/tty4" -+# define VC_5 "/dev/tty5" -+# define VC_FORMAT "/dev/tty%d" -+#elif ENABLE_FEATURE_DEVFS /* from now on, assume Linux naming */ - # define CURRENT_VC "/dev/vc/0" - # define VC_1 "/dev/vc/1" - # define VC_2 "/dev/vc/2" -@@ -1661,10 +1681,6 @@ - # define FB_0 "/dev/fb0" - #endif - --/* The following devices are the same on devfs and non-devfs systems. */ --#define CURRENT_TTY "/dev/tty" --#define DEV_CONSOLE "/dev/console" -- - - #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) - diff --git a/debian/patches/make_gen_build_files_skip_quilt.patch b/debian/patches/make_gen_build_files_skip_quilt.patch deleted file mode 100644 index d654468..0000000 --- a/debian/patches/make_gen_build_files_skip_quilt.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: busybox-1.17.1/scripts/gen_build_files.sh -=================================================================== ---- busybox-1.17.1.orig/scripts/gen_build_files.sh 2010-08-01 07:28:13.000000000 +0200 -+++ busybox-1.17.1/scripts/gen_build_files.sh 2010-08-01 07:31:03.000000000 +0200 -@@ -48,7 +48,7 @@ - fi - - # (Re)generate */Kbuild and */Config.in --{ cd -- "$srctree" && find -type d; } | while read -r d; do -+{ cd -- "$srctree" && find -name .\?\* -prune -or -type d -print; } | while read -r d; do - d="${d#./}" - - src="$srctree/$d/Kbuild.src" diff --git a/debian/patches/make_unicode_printable.patch b/debian/patches/make_unicode_printable.patch deleted file mode 100644 index b62ed6f..0000000 --- a/debian/patches/make_unicode_printable.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/libbb/printable_string.c b/libbb/printable_string.c -index 83a4821..8a62725 100644 ---- a/libbb/printable_string.c -+++ b/libbb/printable_string.c -@@ -31,8 +31,8 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) - } - if (c < ' ') - break; -- if (c >= 0x7f) -- break; -+ /* if (c >= 0x7f) */ -+ /* break; */ - s++; - } - -@@ -45,7 +45,8 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) - unsigned char c = *d; - if (c == '\0') - break; -- if (c < ' ' || c >= 0x7f) -+ /* if (c < ' ' || c >= 0x7f) */ -+ if (c < ' ') - *d = '?'; - d++; - } diff --git a/debian/patches/mark-Linux-specific-configuration-options.patch b/debian/patches/mark-Linux-specific-configuration-options.patch deleted file mode 100644 index 8f89c3e..0000000 --- a/debian/patches/mark-Linux-specific-configuration-options.patch +++ /dev/null @@ -1,915 +0,0 @@ -From 1d7266d3b59be361763dab61f680103bbb70f3e9 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Mon, 19 Jul 2010 00:44:56 +0200 -Subject: [PATCH 2/9] mark Linux-specific configuration options - -PLATFORM_LINUX is used as a dependency for applets or features -which require Linux-specific interfaces. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - Config.in | 12 ++++++++++++ - console-tools/Config.src | 13 +++++++++++++ - coreutils/Config.src | 2 ++ - coreutils/date.c | 2 +- - e2fsprogs/Config.src | 1 + - init/Config.src | 2 ++ - init/bootchartd.c | 1 + - libbb/Config.src | 1 + - loginutils/Config.src | 3 +++ - miscutils/Config.src | 19 ++++++++++++++++++- - miscutils/conspy.c | 1 + - miscutils/ubi_attach_detach.c | 2 ++ - modutils/Config.src | 1 + - networking/Config.src | 23 ++++++++++++++++++++++- - networking/udhcp/Config.src | 2 ++ - procps/Config.src | 4 +++- - shell/cttyhack.c | 1 + - sysklogd/Config.src | 1 + - util-linux/Config.src | 27 +++++++++++++++++++++++++++ - 19 files changed, 114 insertions(+), 4 deletions(-) - -Index: busybox-1.17.1/Config.in -=================================================================== ---- busybox-1.17.1.orig/Config.in 2010-08-01 05:24:36.000000000 +0200 -+++ busybox-1.17.1/Config.in 2010-08-01 05:32:43.000000000 +0200 -@@ -47,6 +47,17 @@ - compiler other than gcc. - If you do use gcc, this option may needlessly increase code size. - -+config PLATFORM_LINUX -+ bool "Enable Linux-specific applets and features" -+ default y -+ help -+ For the most part, busybox requires only POSIX compatibility -+ from the target system, but some applets and features use -+ Linux-specific interfaces. -+ -+ Answering 'N' here will disable such applets and hide the -+ corresponding configuration options. -+ - choice - prompt "Buffer allocation policy" - default FEATURE_BUFFERS_USE_MALLOC -@@ -353,6 +364,7 @@ - config SELINUX - bool "Support NSA Security Enhanced Linux" - default n -+ depends on PLATFORM_LINUX - help - Enable support for SELinux in applets ls, ps, and id. Also provide - the option of compiling in SELinux applets. -Index: busybox-1.17.1/console-tools/Config.src -=================================================================== ---- busybox-1.17.1.orig/console-tools/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/console-tools/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config CHVT - bool "chvt" - default y -+ depends on PLATFORM_LINUX - help - This program is used to change to another terminal. - Example: chvt 4 (change to terminal /dev/tty4) -@@ -17,6 +18,7 @@ - config FGCONSOLE - bool "fgconsole" - default y -+ depends on PLATFORM_LINUX - help - This program prints active (foreground) console number. - -@@ -29,12 +31,14 @@ - config DEALLOCVT - bool "deallocvt" - default y -+ depends on PLATFORM_LINUX - help - This program deallocates unused virtual consoles. - - config DUMPKMAP - bool "dumpkmap" - default y -+ depends on PLATFORM_LINUX - help - This program dumps the kernel's keyboard translation table to - stdout, in binary format. You can then use loadkmap to load it. -@@ -42,18 +46,21 @@ - config KBD_MODE - bool "kbd_mode" - default y -+ depends on PLATFORM_LINUX - help - This program reports and sets keyboard mode. - - config LOADFONT - bool "loadfont" - default y -+ depends on PLATFORM_LINUX - help - This program loads a console font from standard input. - - config LOADKMAP - bool "loadkmap" - default y -+ depends on PLATFORM_LINUX - help - This program loads a keyboard translation table from - standard input. -@@ -61,6 +68,7 @@ - config OPENVT - bool "openvt" - default y -+ depends on PLATFORM_LINUX - help - This program is used to start a command on an unused - virtual terminal. -@@ -92,6 +100,7 @@ - config SETCONSOLE - bool "setconsole" - default y -+ depends on PLATFORM_LINUX - help - This program redirects the system console to another device, - like the current tty while logged in via telnet. -@@ -106,6 +115,7 @@ - config SETFONT - bool "setfont" - default y -+ depends on PLATFORM_LINUX - help - Allows to load console screen map. Useful for i18n. - -@@ -127,6 +137,7 @@ - config SETKEYCODES - bool "setkeycodes" - default y -+ depends on PLATFORM_LINUX - help - This program loads entries into the kernel's scancode-to-keycode - map, allowing unusual keyboards to generate usable keycodes. -@@ -134,12 +145,14 @@ - config SETLOGCONS - bool "setlogcons" - default y -+ depends on PLATFORM_LINUX - help - This program redirects the output console of kernel messages. - - config SHOWKEY - bool "showkey" - default y -+ depends on PLATFORM_LINUX - help - Shows keys pressed. - -Index: busybox-1.17.1/coreutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/coreutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/coreutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -591,6 +591,7 @@ - config STAT - bool "stat" - default y -+ depends on PLATFORM_LINUX # statfs() - help - display file or filesystem status. - -@@ -606,6 +607,7 @@ - config STTY - bool "stty" - default y -+ depends on PLATFORM_LINUX - help - stty is used to change and print terminal line settings. - -Index: busybox-1.17.1/coreutils/date.c -=================================================================== ---- busybox-1.17.1.orig/coreutils/date.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/coreutils/date.c 2010-08-01 05:32:43.000000000 +0200 -@@ -72,7 +72,7 @@ - //config:config FEATURE_DATE_NANO - //config: bool "Support %[num]N nanosecond format specifier" - //config: default n --//config: depends on DATE -+//config: depends on DATE && PLATFORM_LINUX # syscall(__NR_clock_gettime) - //config: help - //config: Support %[num]N format specifier. Adds ~250 bytes of code. - //config: -Index: busybox-1.17.1/e2fsprogs/Config.src -=================================================================== ---- busybox-1.17.1.orig/e2fsprogs/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/e2fsprogs/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -33,6 +33,7 @@ - config LSATTR - bool "lsattr" - default y -+ depends on PLATFORM_LINUX - help - lsattr lists the file attributes on a second extended file system. - -Index: busybox-1.17.1/init/Config.src -=================================================================== ---- busybox-1.17.1.orig/init/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/init/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config INIT - bool "init" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - init is the first program run when the system boots. -@@ -92,6 +93,7 @@ - config HALT - bool "poweroff, halt, and reboot" - default y -+ depends on PLATFORM_LINUX - help - Stop all processes and either halt, reboot, or power off the system. - -Index: busybox-1.17.1/init/bootchartd.c -=================================================================== ---- busybox-1.17.1.orig/init/bootchartd.c 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/init/bootchartd.c 2010-08-01 05:32:43.000000000 +0200 -@@ -6,6 +6,7 @@ - //config:config BOOTCHARTD - //config: bool "bootchartd" - //config: default y -+//config: depends on PLATFORM_LINUX - //config: help - //config: bootchartd is commonly used to profile the boot process - //config: for the purpose of speeding it up. In this case, it is started -Index: busybox-1.17.1/libbb/Config.src -=================================================================== ---- busybox-1.17.1.orig/libbb/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/libbb/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -153,6 +153,7 @@ - config MONOTONIC_SYSCALL - bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" - default n -+ depends on PLATFORM_LINUX - help - Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring - time intervals (time, ping, traceroute etc need this). -Index: busybox-1.17.1/loginutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/loginutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/loginutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -179,6 +179,7 @@ - config GETTY - bool "getty" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - getty lets you log in on a tty, it is normally invoked by init. -@@ -186,6 +187,7 @@ - config LOGIN - bool "login" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - select FEATURE_SYSLOG - help -@@ -295,6 +297,7 @@ - config VLOCK - bool "vlock" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - help - Build the "vlock" applet which allows you to lock (virtual) terminals. -Index: busybox-1.17.1/miscutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/miscutils/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/miscutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config ADJTIMEX - bool "adjtimex" - default y -+ depends on PLATFORM_LINUX - help - Adjtimex reads and optionally sets adjustment parameters for - the Linux clock adjustment algorithm. -@@ -24,6 +25,7 @@ - config BEEP - bool "beep" - default y -+ depends on PLATFORM_LINUX - help - The beep applets beeps in a given freq/Hz. - -@@ -180,6 +182,7 @@ - config DEVFSD - bool "devfsd (obsolete)" - default n -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - This is deprecated and should NOT be used anymore. -@@ -223,6 +226,7 @@ - config FEATURE_DEVFS - bool "Use devfs names for all devices (obsolete)" - default n -+ depends on PLATFORM_LINUX - help - This is obsolete and should NOT be used anymore. - Use linux >= 2.6 (optionally with hotplug) and mdev instead! -@@ -242,6 +246,7 @@ - config EJECT - bool "eject" - default y -+ depends on PLATFORM_LINUX - help - Used to eject cdroms. (defaults to /dev/cdrom) - -@@ -256,6 +261,7 @@ - config FBSPLASH - bool "fbsplash" - default y -+ depends on PLATFORM_LINUX - help - Shows splash image and progress bar on framebuffer device. - Can be used during boot phase of an embedded device. ~2kb. -@@ -305,6 +311,7 @@ - config IONICE - bool "ionice" - default y -+ depends on PLATFORM_LINUX - help - Set/set program io scheduling class and priority - Requires kernel >= 2.6.13 -@@ -344,6 +351,11 @@ - config LESS - bool "less" - default y -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX - help - 'less' is a pager, meaning that it displays text files. It possesses - a wide array of features, and is an improvement over 'more'. -@@ -410,6 +422,7 @@ - config HDPARM - bool "hdparm" - default y -+ depends on PLATFORM_LINUX - help - Get/Set hard drive parameters. Primarily intended for ATA - drives. Adds about 13k (or around 30k if you enable the -@@ -526,6 +539,7 @@ - config RAIDAUTORUN - bool "raidautorun" - default y -+ depends on PLATFORM_LINUX - help - raidautorun tells the kernel md driver to - search and start RAID arrays. -@@ -533,7 +547,7 @@ - config READAHEAD - bool "readahead" - default y -- depends on LFS -+ depends on LFS && PLATFORM_LINUX - help - Preload the files listed on the command line into RAM cache so that - subsequent reads on these files will not block on disk I/O. -@@ -550,6 +564,7 @@ - config RFKILL - bool "rfkill" - default n # doesn't build on Ubuntu 9.04 -+ depends on PLATFORM_LINUX - help - Enable/disable wireless devices. - -@@ -570,6 +585,7 @@ - config RX - bool "rx" - default y -+ depends on PLATFORM_LINUX - help - Receive files using the Xmodem protocol. - -@@ -641,6 +657,7 @@ - config WATCHDOG - bool "watchdog" - default y -+ depends on PLATFORM_LINUX - help - The watchdog utility is used with hardware or software watchdog - device drivers. It opens the specified watchdog device special file -Index: busybox-1.17.1/miscutils/conspy.c -=================================================================== ---- busybox-1.17.1.orig/miscutils/conspy.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/miscutils/conspy.c 2010-08-01 05:32:43.000000000 +0200 -@@ -17,6 +17,7 @@ - //config:config CONSPY - //config: bool "conspy" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: A text-mode VNC like program for Linux virtual terminals. - //config: example: conspy NUM shared access to console num -Index: busybox-1.17.1/miscutils/ubi_attach_detach.c -=================================================================== ---- busybox-1.17.1.orig/miscutils/ubi_attach_detach.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/miscutils/ubi_attach_detach.c 2010-08-01 05:32:43.000000000 +0200 -@@ -12,12 +12,14 @@ - //config:config UBIATTACH - //config: bool "ubiattach" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: Attach MTD device to an UBI device. - //config: - //config:config UBIDETACH - //config: bool "ubidetach" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: Detach MTD device from an UBI device. - -Index: busybox-1.17.1/modutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/modutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/modutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -4,6 +4,7 @@ - # - - menu "Linux Module Utilities" -+depends on PLATFORM_LINUX - - INSERT - -Index: busybox-1.17.1/networking/Config.src -=================================================================== ---- busybox-1.17.1.orig/networking/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/networking/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -43,6 +43,7 @@ - config VERBOSE_RESOLUTION_ERRORS - bool "Verbose resolution errors" - default n -+ depends on PLATFORM_LINUX #because of xsocket() in libbb/xfuncs_prinf.c - help - Enable if you are not satisfied with simplistic - "can't resolve 'hostname.com'" and want to know more. -@@ -51,18 +52,21 @@ - config ARP - bool "arp" - default y -+ depends on PLATFORM_LINUX - help - Manipulate the system ARP cache. - - config ARPING - bool "arping" - default y -+ depends on PLATFORM_LINUX - help - Ping hosts by ARP packets. - - config BRCTL - bool "brctl" - default y -+ depends on PLATFORM_LINUX - help - Manage ethernet bridges. - Supports addbr/delbr and addif/delif. -@@ -95,6 +99,7 @@ - config ETHER_WAKE - bool "ether-wake" - default y -+ depends on PLATFORM_LINUX - help - Send a magic packet to wake up sleeping machines. - -@@ -269,6 +274,7 @@ - config IFCONFIG - bool "ifconfig" - default y -+ depends on PLATFORM_LINUX - help - Ifconfig is used to configure the kernel-resident network interfaces. - -@@ -316,6 +322,7 @@ - config IFENSLAVE - bool "ifenslave" - default y -+ depends on PLATFORM_LINUX - help - Userspace application to bind several interfaces - to a logical interface (use with kernel bonding driver). -@@ -323,6 +330,7 @@ - config IFPLUGD - bool "ifplugd" - default y -+ depends on PLATFORM_LINUX - help - Network interface plug detection daemon. - -@@ -364,7 +372,7 @@ - config FEATURE_IFUPDOWN_IP_BUILTIN - bool "Use busybox ip applet" - default y -- depends on FEATURE_IFUPDOWN_IP -+ depends on FEATURE_IFUPDOWN_IP && PLATFORM_LINUX - select IP - select FEATURE_IP_ADDRESS - select FEATURE_IP_LINK -@@ -483,6 +491,7 @@ - config IP - bool "ip" - default y -+ depends on PLATFORM_LINUX - help - The "ip" applet is a TCP/IP interface configuration and routing - utility. You generally don't need "ip" to use busybox with -@@ -598,6 +607,7 @@ - config NAMEIF - bool "nameif" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - nameif is used to rename network interface by its MAC address. -@@ -626,6 +636,7 @@ - config NETSTAT - bool "netstat" - default y -+ depends on PLATFORM_LINUX - help - netstat prints information about the Linux networking subsystem. - -@@ -654,6 +665,7 @@ - config NTPD - bool "ntpd" - default y -+ depends on PLATFORM_LINUX - help - The NTP client/server daemon. - -@@ -668,6 +680,7 @@ - config PING - bool "ping" - default y -+ depends on PLATFORM_LINUX - help - ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to - elicit an ICMP ECHO_RESPONSE from a host or gateway. -@@ -696,12 +709,14 @@ - config ROUTE - bool "route" - default y -+ depends on PLATFORM_LINUX - help - Route displays or manipulates the kernel's IP routing tables. - - config SLATTACH - bool "slattach" - default y -+ depends on PLATFORM_LINUX - help - slattach is a small utility to attach network interfaces to serial - lines. -@@ -719,6 +734,7 @@ - config TCPSVD - bool "tcpsvd" - default y -+ depends on PLATFORM_LINUX - help - tcpsvd listens on a TCP port and runs a program for each new - connection. -@@ -888,6 +904,7 @@ - config TRACEROUTE - bool "traceroute" - default y -+ depends on PLATFORM_LINUX - help - Utility to trace the route of IP packets. - -@@ -924,6 +941,7 @@ - config TUNCTL - bool "tunctl" - default y -+ depends on PLATFORM_LINUX - help - tunctl creates or deletes tun devices. - -@@ -949,6 +967,7 @@ - config UDPSVD - bool "udpsvd" - default y -+ depends on PLATFORM_LINUX - help - udpsvd listens on an UDP port and runs a program for each new - connection. -@@ -956,6 +975,7 @@ - config VCONFIG - bool "vconfig" - default y -+ depends on PLATFORM_LINUX - help - Creates, removes, and configures VLAN interfaces - -@@ -990,6 +1010,7 @@ - config ZCIP - bool "zcip" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. -Index: busybox-1.17.1/networking/udhcp/Config.src -=================================================================== ---- busybox-1.17.1.orig/networking/udhcp/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/networking/udhcp/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -8,6 +8,7 @@ - config UDHCPD - bool "udhcp server (udhcpd)" - default y -+ depends on PLATFORM_LINUX - help - udhcpd is a DHCP server geared primarily toward embedded systems, - while striving to be fully functional and RFC compliant. -@@ -51,6 +52,7 @@ - config UDHCPC - bool "udhcp client (udhcpc)" - default y -+ depends on PLATFORM_LINUX - help - udhcpc is a DHCP client geared primarily toward embedded systems, - while striving to be fully functional and RFC compliant. -Index: busybox-1.17.1/procps/Config.src -=================================================================== ---- busybox-1.17.1.orig/procps/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/procps/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config FREE - bool "free" - default y -+ depends on PLATFORM_LINUX #sysinfo() - help - free displays the total amount of free and used physical and swap - memory in the system, as well as the buffers used by the kernel. -@@ -104,7 +105,7 @@ - config FEATURE_PS_TIME - bool "Enable time and elapsed time output" - default y -- depends on PS && DESKTOP -+ depends on PS && DESKTOP && PLATFORM_LINUX #sysinfo() - help - Support -o time and -o etime output specifiers. - -@@ -200,6 +201,7 @@ - config UPTIME - bool "uptime" - default y -+ depends on PLATFORM_LINUX #sysinfo() - help - uptime gives a one line display of the current time, how long - the system has been running, how many users are currently logged -Index: busybox-1.17.1/sysklogd/Config.src -=================================================================== ---- busybox-1.17.1.orig/sysklogd/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/sysklogd/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -109,6 +109,7 @@ - config KLOGD - bool "klogd" - default y -+ depends on PLATFORM_LINUX - help - klogd is a utility which intercepts and logs all - messages from the Linux kernel and sends the messages -Index: busybox-1.17.1/util-linux/Config.src -=================================================================== ---- busybox-1.17.1.orig/util-linux/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/util-linux/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config ACPID - bool "acpid" - default y -+ depends on PLATFORM_LINUX - help - acpid listens to ACPI events coming either in textual form from - /proc/acpi/event (though it is marked deprecated it is still widely -@@ -32,6 +33,7 @@ - config BLKID - bool "blkid" - default y -+ depends on PLATFORM_LINUX - select VOLUMEID - help - Lists labels and UUIDs of all filesystems. -@@ -41,6 +43,7 @@ - config DMESG - bool "dmesg" - default y -+ depends on PLATFORM_LINUX - help - dmesg is used to examine or control the kernel ring buffer. When the - Linux kernel prints messages to the system log, they are stored in -@@ -74,6 +77,7 @@ - config FBSET - bool "fbset" - default y -+ depends on PLATFORM_LINUX - help - fbset is used to show or change the settings of a Linux frame buffer - device. The frame buffer device provides a simple and unique -@@ -102,6 +106,7 @@ - config FDFLUSH - bool "fdflush" - default y -+ depends on PLATFORM_LINUX - help - fdflush is only needed when changing media on slightly-broken - removable media drives. It is used to make Linux believe that a -@@ -114,12 +119,14 @@ - config FDFORMAT - bool "fdformat" - default y -+ depends on PLATFORM_LINUX - help - fdformat is used to low-level format a floppy disk. - - config FDISK - bool "fdisk" - default y -+ depends on PLATFORM_LINUX - help - The fdisk utility is used to divide hard disks into one or more - logical disks, which are generally called partitions. This utility -@@ -187,6 +194,7 @@ - config FINDFS - bool "findfs" - default y -+ depends on PLATFORM_LINUX - select VOLUMEID - help - Prints the name of a filesystem with given label or UUID. -@@ -202,6 +210,7 @@ - config FREERAMDISK - bool "freeramdisk" - default y -+ depends on PLATFORM_LINUX - help - Linux allows you to create ramdisks. This utility allows you to - delete them and completely free all memory that was used for the -@@ -224,12 +233,14 @@ - config MKFS_EXT2 - bool "mkfs_ext2" - default y -+ depends on PLATFORM_LINUX - help - Utility to create EXT2 filesystems. - - config MKFS_MINIX - bool "mkfs_minix" - default y -+ depends on PLATFORM_LINUX - help - The minix filesystem is a nice, small, compact, read-write filesystem - with little overhead. If you wish to be able to create minix -@@ -247,6 +258,7 @@ - config MKFS_REISER - bool "mkfs_reiser" - default n -+ depends on PLATFORM_LINUX - help - Utility to create ReiserFS filesystems. - Note: this applet needs a lot of testing and polishing. -@@ -254,6 +266,7 @@ - config MKFS_VFAT - bool "mkfs_vfat" - default y -+ depends on PLATFORM_LINUX - help - Utility to create FAT32 filesystems. - -@@ -302,6 +315,7 @@ - config HWCLOCK - bool "hwclock" - default y -+ depends on PLATFORM_LINUX - help - The hwclock utility is used to read and set the hardware clock - on a system. This is primarily used to set the current time on -@@ -341,6 +355,7 @@ - config IPCS - bool "ipcs" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - help - The ipcs utility is used to provide information on the currently -@@ -349,6 +364,7 @@ - config LOSETUP - bool "losetup" - default y -+ depends on PLATFORM_LINUX - help - losetup is used to associate or detach a loop device with a regular - file or block device, and to query the status of a loop device. This -@@ -357,6 +373,7 @@ - config LSPCI - bool "lspci" - default y -+ #depends on PLATFORM_LINUX - help - lspci is a utility for displaying information about PCI buses in the - system and devices connected to them. -@@ -366,6 +383,7 @@ - config LSUSB - bool "lsusb" - default y -+ #depends on PLATFORM_LINUX - help - lsusb is a utility for displaying information about USB buses in the - system and devices connected to them. -@@ -375,6 +393,7 @@ - config MDEV - bool "mdev" - default y -+ depends on PLATFORM_LINUX - help - mdev is a mini-udev implementation for dynamically creating device - nodes in the /dev directory. -@@ -473,6 +492,7 @@ - config MOUNT - bool "mount" - default y -+ depends on PLATFORM_LINUX - help - All files and filesystems in Unix are arranged into one big directory - tree. The 'mount' utility is used to graft a filesystem onto a -@@ -555,6 +575,7 @@ - config PIVOT_ROOT - bool "pivot_root" - default y -+ depends on PLATFORM_LINUX - help - The pivot_root utility swaps the mount points for the root filesystem - with some other mounted filesystem. This allows you to do all sorts -@@ -582,12 +603,14 @@ - config READPROFILE - bool "readprofile" - default y -+ #depends on PLATFORM_LINUX - help - This allows you to parse /proc/profile for basic profiling. - - config RTCWAKE - bool "rtcwake" - default y -+ depends on PLATFORM_LINUX - help - Enter a system sleep state until specified wakeup time. - -@@ -607,6 +630,7 @@ - config SETARCH - bool "setarch" - default y -+ depends on PLATFORM_LINUX - help - The linux32 utility is used to create a 32bit environment for the - specified program (usually a shell). It only makes sense to have -@@ -616,6 +640,7 @@ - config SWAPONOFF - bool "swaponoff" - default y -+ depends on PLATFORM_LINUX - help - This option enables both the 'swapon' and the 'swapoff' utilities. - Once you have created some swap space using 'mkswap', you also need -@@ -634,6 +659,7 @@ - config SWITCH_ROOT - bool "switch_root" - default y -+ depends on PLATFORM_LINUX - help - The switch_root utility is used from initramfs to select a new - root device. Under initramfs, you have to use this instead of -@@ -653,6 +679,7 @@ - config UMOUNT - bool "umount" - default y -+ depends on PLATFORM_LINUX - help - When you want to remove a mounted filesystem from its current mount - point, for example when you are shutting down the system, the -Index: busybox-1.17.1/shell/Config.src -=================================================================== ---- busybox-1.17.1.orig/shell/Config.src 2010-08-01 05:33:24.000000000 +0200 -+++ busybox-1.17.1/shell/Config.src 2010-08-01 05:33:34.000000000 +0200 -@@ -370,6 +370,7 @@ - config CTTYHACK - bool "cttyhack" - default y -+ depends on PLATFORM_LINUX - help - One common problem reported on the mailing list is "can't access tty; - job control turned off" error message which typically appears when diff --git a/debian/patches/mkdir-fix-p-on-FreeBSD.patch b/debian/patches/mkdir-fix-p-on-FreeBSD.patch deleted file mode 100644 index fc5bf7f..0000000 --- a/debian/patches/mkdir-fix-p-on-FreeBSD.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 84b01d5afc8230c79a1b8469c222d940c0d4e792 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:33 +0200 -Subject: [PATCH 7/9] mkdir: fix -p on FreeBSD - -This patch is libbb.make_directory.diff from Debian kFreeBSD at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - libbb/make_directory.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/libbb/make_directory.c b/libbb/make_directory.c -index 4486eb1..6dd04cf 100644 ---- a/libbb/make_directory.c -+++ b/libbb/make_directory.c -@@ -86,7 +86,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) - if (mkdir(path, 0777) < 0) { - /* If we failed for any other reason than the directory - * already exists, output a diagnostic and return -1 */ -- if (errno != EEXIST -+ if ((errno != EEXIST && errno != EISDIR) - || !(flags & FILEUTILS_RECUR) - || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) - ) { --- -1.7.1 - diff --git a/debian/patches/readlink-use-xmalloc_realpath.patch b/debian/patches/readlink-use-xmalloc_realpath.patch deleted file mode 100644 index e1103ec..0000000 --- a/debian/patches/readlink-use-xmalloc_realpath.patch +++ /dev/null @@ -1,50 +0,0 @@ -From b175462422f02a159a14dc5561d8bef6f84b2b66 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:32:19 +0200 -Subject: [PATCH 1/9] readlink: use xmalloc_realpath() - -Using realpath() directly with a non-NULL output buffer is unsafe because its -behavior is unspecified on systems which don't have PATH_MAX (ie. Hurd) - -I beleive this also fixes a small bug whereby 'buf' would not be freed -on 'readlink -v' with ENABLE_FEATURE_CLEANUP. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - coreutils/readlink.c | 5 ++--- - 1 files changed, 2 insertions(+), 3 deletions(-) - -diff --git a/coreutils/readlink.c b/coreutils/readlink.c -index 20df38b..2ed5e2c 100644 ---- a/coreutils/readlink.c -+++ b/coreutils/readlink.c -@@ -36,7 +36,6 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - { - char *buf; - char *fname; -- char pathbuf[PATH_MAX]; - - IF_FEATURE_READLINK_FOLLOW( - unsigned opt; -@@ -56,7 +55,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - logmode = LOGMODE_NONE; - - if (opt & 1) { /* -f */ -- buf = realpath(fname, pathbuf); -+ buf = xmalloc_realpath(fname); - } else { - buf = xmalloc_readlink_or_warn(fname); - } -@@ -65,7 +64,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - return EXIT_FAILURE; - printf((opt & 2) ? "%s" : "%s\n", buf); - -- if (ENABLE_FEATURE_CLEAN_UP && !opt) -+ if (ENABLE_FEATURE_CLEAN_UP) - free(buf); - - fflush_stdout_and_exit(EXIT_SUCCESS); --- -1.7.1 - diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 9c507a4..0000000 --- a/debian/patches/series +++ /dev/null @@ -1,45 +0,0 @@ -doc-man-name.patch -shell-ash-export-HOME.patch -applets-fallback.patch -version.patch -init-console.patch -05thumb.dpatch -06ls.dpatch -busybox-zero-ifr.ifr_hwaddr.sa_data.patch -#shell-hist.patch -top-display-rss.patch -strip.patch -make_gen_build_files_skip_quilt.patch - -# The following patches have been merged upstream and will be in version 1.18 -readlink-use-xmalloc_realpath.patch -mark-Linux-specific-configuration-options.patch -init-loginutils-termios-portability-fixes.patch -init-halt-portability-improvements.patch -init-make-the-initial-TERM-value-configurable.patch -libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch -mkdir-fix-p-on-FreeBSD.patch -libbb-conditionalize-AF_-usage-in-error-reporting.patch -tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch -less-remove-misguided-dependency-on-PLATFORM_LINUX.patch -bootchartd-mounting-tmpfs-is-Linux-specific.patch -vlock-disable-linux-console-calls-on-other-systems.patch -cttyhack-serial-console-detection-is-Linux-specific.patch -klogd-make-it-work-on-non-linux-systems.patch -stty-sort-out-preprocessor-conditionals.patch -update-scripts-kconfig-_shipped.patch -blockdev.patch - -# The following patches will likely be merged soon -u-mount-FreeBSD-support.patch -swaponoff-FreeBSD-support.patch - -# not sent upstream -init-console-CRTSCTS.patch -debian-changes-1:1.17.1-10 - -# SLP -udhcpc-fast-request.patch -smack-busybox-1.17.1.patch -smack-conflict-with-selinux.patch -make_unicode_printable.patch diff --git a/debian/patches/shell-ash-export-HOME.patch b/debian/patches/shell-ash-export-HOME.patch deleted file mode 100644 index 0d3c5ab..0000000 --- a/debian/patches/shell-ash-export-HOME.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/shell/ash.c -+++ b/shell/ash.c -@@ -1774,7 +1774,7 @@ - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail }, - #endif -- { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, -+ { VSTRFIXED|VTEXTFIXED|VEXPORT, bb_PATH_root_path, changepath }, - { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, - { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, - { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, diff --git a/debian/patches/shell-hist.patch b/debian/patches/shell-hist.patch deleted file mode 100644 index 889785a..0000000 --- a/debian/patches/shell-hist.patch +++ /dev/null @@ -1,117 +0,0 @@ ---- a/libbb/lineedit.c 2009-03-30 17:15:10.000000000 +0300 -+++ b/libbb/lineedit.c 2009-03-31 17:52:48.000000000 +0300 -@@ -959,49 +959,48 @@ - static void load_history(const char *fromfile) - { - FILE *fp; -- int hi; -+ int hi = 0; - -- /* cleanup old */ -- for (hi = state->cnt_history; hi > 0;) { -- hi--; -- free(state->history[hi]); -- } -- -- fp = fopen(fromfile, "r"); -- if (fp) { -- for (hi = 0; hi < MAX_HISTORY;) { -- char *hl = xmalloc_getline(fp); -- int l; -- -- if (!hl) -- break; -- l = strlen(hl); -- if (l >= MAX_LINELEN) -- hl[MAX_LINELEN-1] = '\0'; -- if (l == 0 || hl[0] == ' ') { -- free(hl); -- continue; -+ if (!state->cnt_history) { -+ fp = fopen(fromfile, "r"); -+ if (fp) { -+ for (hi = 0; hi < MAX_HISTORY;) { -+ char *hl = xmalloc_getline(fp); -+ int l; -+ -+ if (!hl) -+ break; -+ l = strlen(hl); -+ if (l >= MAX_LINELEN) -+ hl[MAX_LINELEN-1] = '\0'; -+ if (l == 0 || hl[0] == ' ') { -+ free(hl); -+ continue; -+ } -+ state->history[hi++] = hl; - } -- state->history[hi++] = hl; -+ fclose(fp); - } -- fclose(fp); -+ state->cur_history = state->cnt_history = hi; - } -- state->cur_history = state->cnt_history = hi; - } - - /* state->flags is already checked to be nonzero */ --static void save_history(const char *tofile) -+void save_history(line_input_t *); -+void save_history(line_input_t *st) - { - FILE *fp; - -- fp = fopen(tofile, "w"); -- if (fp) { -- int i; -+ if (st->cnt_history) { -+ fp = fopen(st->hist_file, "w"); -+ if (fp) { -+ int i; - -- for (i = 0; i < state->cnt_history; i++) { -- fprintf(fp, "%s\n", state->history[i]); -+ for (i = 0; i < st->cnt_history; i++) { -+ fprintf(fp, "%s\n", st->history[i]); -+ } -+ fclose(fp); - } -- fclose(fp); - } - } - #else -@@ -1030,10 +1029,6 @@ - state->history[i++] = xstrdup(str); - state->cur_history = i; - state->cnt_history = i; --#if ENABLE_FEATURE_EDITING_SAVEHISTORY -- if ((state->flags & SAVE_HISTORY) && state->hist_file) -- save_history(state->hist_file); --#endif - USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) - } - -diff -r -u busybox-1.10.2.legal.orig/shell/ash.c busybox-1.10.2.legal/shell/ash.c ---- busybox-1.10.2.legal.orig/shell/ash.c 2008-07-24 10:16:00.000000000 +0100 -+++ busybox-1.10.2.legal/shell/ash.c 2009-03-23 17:09:11.000000000 +0000 -@@ -1733,6 +1733,9 @@ - #if ENABLE_ASH_RANDOM_SUPPORT - static void change_random(const char *); - #endif -+#if ENABLE_FEATURE_EDITING_SAVEHISTORY -+void save_history(line_input_t *); -+#endif - - static const struct { - int flags; -@@ -12815,6 +12818,10 @@ - char *p; - int status; - -+ if (iflag && (line_input_state->flags & SAVE_HISTORY) -+ && line_input_state->hist_file && !shlvl) { -+ save_history(line_input_state); -+ } - status = exitstatus; - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc.loc)) { diff --git a/debian/patches/smack-busybox-1.17.1.patch b/debian/patches/smack-busybox-1.17.1.patch deleted file mode 100644 index a95697f..0000000 --- a/debian/patches/smack-busybox-1.17.1.patch +++ /dev/null @@ -1,1604 +0,0 @@ - -Smack updates for busybox-1.17.1 - ---- - - Config.in | 9 ++ - Makefile | 1 - coreutils/id.c | 26 +++++- - coreutils/ls.c | 28 ++++++ - coreutils/stat.c | 87 ++++++++++++++++---- - findutils/find.c | 31 +++++++ - include/applets.src.h | 4 - include/libbb.h | 21 ++++ - include/usage.src.h | 30 ++++++- - libbb/Kbuild.src | 1 - libbb/messages.c | 3 - libbb/procps.c | 6 + - libbb/smack_common.c | 178 ++++++++++++++++++++++++++++++++++++++++++ - loginutils/adduser.c | 13 ++- - loginutils/login.c | 8 + - loginutils/su.c | 8 + - loginutils/sulogin.c | 6 + - miscutils/crond.c | 11 ++ - miscutils/crontab.c | 13 +++ - procps/ps.c | 48 +++++++++-- - smack/Config.src | 40 +++++++++ - smack/Kbuild.src | 14 +++ - smack/newsmack.c | 61 ++++++++++++++ - smack/smackcipso.c | 119 ++++++++++++++++++++++++++++ - smack/smackenabled.c | 17 ++++ - smack/smackload.c | 93 +++++++++++++++++++++ - 26 files changed, 844 insertions(+), 32 deletions(-) - -diff -uprN busybox-1.17.1/Config.in busybox-1.17.1-smack/Config.in ---- busybox-1.17.1/Config.in 2010-07-24 15:12:56.000000000 -0700 -+++ busybox-1.17.1-smack/Config.in 2011-08-17 15:27:12.889107702 -0700 -@@ -370,6 +370,14 @@ config SELINUX - - Most people will leave this set to 'N'. - -+config SMACK -+ bool "Support Smack" -+ default n -+ help -+ Enable support for Smack in applets ls, ps, and id. Also provide -+ the option of compiling in Smack applets. -+ -+ - config FEATURE_PREFER_APPLETS - bool "exec prefers applets" - default n -@@ -739,4 +747,5 @@ source procps/Config.in - source runit/Config.in - source selinux/Config.in - source shell/Config.in -+source smack/Config.in - source sysklogd/Config.in -diff -uprN busybox-1.17.1/coreutils/id.c busybox-1.17.1-smack/coreutils/id.c ---- busybox-1.17.1/coreutils/id.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/id.c 2011-08-17 15:27:12.889107702 -0700 -@@ -34,6 +34,9 @@ enum { - #if ENABLE_SELINUX - JUST_CONTEXT = (1 << 5), - #endif -+#if ENABLE_SMACK -+ JUST_LABEL = (1 << 5), -+#endif - }; - - static int print_common(unsigned id, const char *name, const char *prefix) -@@ -116,11 +119,15 @@ int id_main(int argc UNUSED_PARAM, char - #if ENABLE_SELINUX - security_context_t scontext = NULL; - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+#endif - /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ - /* Don't allow more than one username */ - opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" -- IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); -- opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); -+ IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G") -+ IF_SMACK(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); -+ opt = getopt32(argv, "rnugG" IF_SELINUX("Z") IF_SMACK("Z")); - - username = argv[optind]; - if (username) { -@@ -187,6 +194,10 @@ int id_main(int argc UNUSED_PARAM, char - printf(" context=%s", scontext); - } - #endif -+#if ENABLE_SMACK -+ if (smack_from_proc(-1, smack, sizeof(smack)) == 0) -+ printf(" label=%s", smack); -+#endif - } else if (opt & PRINT_REAL) { - euid = ruid; - egid = rgid; -@@ -205,6 +216,17 @@ int id_main(int argc UNUSED_PARAM, char - } - fputs(scontext, stdout); - } -+#endif -+#if ENABLE_SMACK -+ else if (opt & JUST_LABEL) { -+ if (username || smack_from_proc(-1, smack, sizeof(smack)) < 0) { -+ bb_error_msg_and_die("can't get process label%s", -+ username ? " for a different user" : ""); -+ } -+ fputs(smack, stdout); -+ } -+#endif -+#if ENABLE_SELINUX - /* freecon(NULL) seems to be harmless */ - if (ENABLE_FEATURE_CLEAN_UP) - freecon(scontext); -diff -uprN busybox-1.17.1/coreutils/ls.c busybox-1.17.1-smack/coreutils/ls.c ---- busybox-1.17.1/coreutils/ls.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/ls.c 2011-08-17 16:23:44.839147638 -0700 -@@ -141,6 +141,7 @@ static const char ls_options[] ALIGN1 = - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ -+ IF_SMACK("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ - ; - enum { -@@ -165,6 +166,7 @@ enum { - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX -+ + 2 * ENABLE_SMACK - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_color = 1 << OPTBIT_color, - }; -@@ -191,6 +193,7 @@ static const unsigned opt_flags[] = { - 0, /* Q (quote filename) - handled via OPT_Q */ - DISP_HIDDEN, /* A */ - ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ -+ ENABLE_SMACK * LIST_CONTEXT, /* k (ignored if !SMACK) */ - #if ENABLE_FEATURE_LS_TIMESTAMPS - TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ - LIST_FULLTIME, /* e */ -@@ -216,10 +219,10 @@ static const unsigned opt_flags[] = { - #if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ - #endif --#if ENABLE_SELINUX -+#if ENABLE_SELINUX || ENABLE_SMACK - LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ - #endif --#if ENABLE_SELINUX -+#if ENABLE_SELINUX || ENABLE_SMACK - LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ - #endif - (1U<<31) -@@ -239,6 +242,7 @@ struct dnode { - smallint fname_allocated; - struct stat dstat; /* the file stat info */ - IF_SELINUX(security_context_t sid;) -+ IF_SMACK(char xattr[SMACKBUFFSIZE];) - }; - - struct globals { -@@ -288,6 +292,10 @@ static struct dnode *my_stat(const char - struct stat dstat; - struct dnode *cur; - IF_SELINUX(security_context_t sid = NULL;) -+#if ENABLE_SMACK -+ char xattr[SMACKBUFFSIZE]; -+ int i; -+#endif - - if ((all_fmt & FOLLOW_LINKS) || force_follow) { - #if ENABLE_SELINUX -@@ -295,6 +303,11 @@ static struct dnode *my_stat(const char - getfilecon(fullname, &sid); - } - #endif -+#if ENABLE_SMACK -+ i = smack_from_file(fullname, xattr, sizeof(xattr), 1); -+ if (i < 0) -+ xattr[0] = '\0'; -+#endif - if (stat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; -@@ -306,6 +319,11 @@ static struct dnode *my_stat(const char - lgetfilecon(fullname, &sid); - } - #endif -+#if ENABLE_SMACK -+ i = smack_from_file(fullname, xattr, sizeof(xattr), 0); -+ if (i < 0) -+ xattr[0] = '\0'; -+#endif - if (lstat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; -@@ -318,6 +336,7 @@ static struct dnode *my_stat(const char - cur->name = name; - cur->dstat = dstat; - IF_SELINUX(cur->sid = sid;) -+ IF_SMACK(strncpy(cur->xattr, xattr, sizeof(xattr));) - return cur; - } - -@@ -685,6 +704,10 @@ static NOINLINE unsigned list_single(con - freecon(dn->sid); - } - #endif -+#if ENABLE_SMACK -+ if (all_fmt & LIST_CONTEXT) -+ column += printf("%-23s ", dn->xattr); -+#endif - if (all_fmt & LIST_FILENAME) { - #if ENABLE_FEATURE_LS_COLOR - if (show_color) { -@@ -753,6 +776,7 @@ static void showfiles(struct dnode **dn, - } - column_width += tabstops + - IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) -+ IF_SMACK( ((all_fmt & LIST_CONTEXT) ? 24 : 0) + ) - ((all_fmt & LIST_INO) ? 8 : 0) + - ((all_fmt & LIST_BLOCKS) ? 5 : 0); - ncols = (int) (terminal_width / column_width); -diff -uprN busybox-1.17.1/coreutils/stat.c busybox-1.17.1-smack/coreutils/stat.c ---- busybox-1.17.1/coreutils/stat.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/stat.c 2011-08-18 17:01:04.060191320 -0700 -@@ -18,6 +18,7 @@ - #define OPT_TERSE (1 << 1) - #define OPT_DEREFERENCE (1 << 2) - #define OPT_SELINUX (1 << 3) -+#define OPT_SMACK (1 << 4) - - #if ENABLE_FEATURE_STAT_FORMAT - typedef bool (*statfunc_ptr)(const char *, const char *); -@@ -154,7 +155,8 @@ static void printfs(char *pformat, const - /* 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)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack)) - { - const struct statfs *statfsbuf = data; - if (m == 'n') { -@@ -192,6 +194,10 @@ static void FAST_FUNC print_statfs(char - } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { - printfs(pformat, scontext); - # endif -+#if ENABLE_SMACK -+ } else if (m == 'C' && (option_mask32 & OPT_SMACK)) { -+ printfs(pformat, smack); -+#endif - } else { - strcatc(pformat, 'c'); - printf(pformat, m); -@@ -201,7 +207,8 @@ static void FAST_FUNC print_statfs(char - /* 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)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack)) - { - #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) - struct stat *statbuf = (struct stat *) data; -@@ -296,6 +303,10 @@ static void FAST_FUNC print_stat(char *p - } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { - printfs(pformat, scontext); - # endif -+#if ENABLE_SMACK -+ } else if (m == 'C' && (option_mask32 & OPT_SMACK)) { -+ printfs(pformat, smack); -+#endif - } else { - strcatc(pformat, 'c'); - printf(pformat, m); -@@ -304,9 +315,10 @@ static void FAST_FUNC print_stat(char *p - - 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)), -+ void FAST_FUNC (*print_func)(char*, char, const char*, const void* IF_SELINUX(, security_context_t scontext) IF_SMACK(, char *smack)), - const void *data -- IF_SELINUX(, security_context_t scontext)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack) ) - { - /* Create a working copy of the format string */ - char *format = xstrdup(masterformat); -@@ -349,7 +361,7 @@ static void print_it(const char *masterf - break; - default: - /* Completes "%" with specifier and printfs */ -- print_func(dest, *p, filename, data IF_SELINUX(,scontext)); -+ print_func(dest, *p, filename, data IF_SELINUX(,scontext) IF_SMACK(,smack) ); - break; - } - } -@@ -383,6 +395,18 @@ static bool do_statfs(const char *filena - } - } - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+ -+ if (option_mask32 & OPT_SMACK) { -+ int i = option_mask32 & OPT_DEREFERENCE; -+ -+ if (smack_from_file(filename, smack, sizeof(smack), i) < 0) { -+ bb_perror_msg("%s", filename); -+ return 0; -+ } -+ } -+#endif - if (statfs(filename, &statfsbuf) != 0) { - bb_perror_msg("can't read file system information for '%s'", filename); - return 0; -@@ -390,7 +414,7 @@ static bool do_statfs(const char *filena - - #if ENABLE_FEATURE_STAT_FORMAT - if (format == NULL) { --# if !ENABLE_SELINUX -+# if !ENABLE_SELINUX && !ENABLE_SMACK - format = (option_mask32 & OPT_TERSE - ? "%n %i %l %t %s %b %f %a %c %d\n" - : " File: \"%n\"\n" -@@ -400,9 +424,9 @@ static bool do_statfs(const char *filena - "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": -+ ? (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? "%n %i %l %t %s %b %f %a %c %d %C\n": - "%n %i %l %t %s %b %f %a %c %d\n") -- : (option_mask32 & OPT_SELINUX ? -+ : (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: \"%n\"\n" - " ID: %-8i Namelen: %-7l Type: %T\n" - "Block size: %-10s\n" -@@ -415,9 +439,9 @@ static bool do_statfs(const char *filena - "Blocks: Total: %-10b Free: %-10f Available: %a\n" - "Inodes: Total: %-10c Free: %d\n") - ); --# endif /* SELINUX */ -+# endif /* SELINUX or Smack */ - } -- print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext)); -+ print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext) IF_SMACK(, smack) ); - #else /* FEATURE_STAT_FORMAT */ - format = (option_mask32 & OPT_TERSE - ? "%s %llx %lu " -@@ -433,7 +457,7 @@ static bool do_statfs(const char *filena - else - printf("Type: %s\n", human_fstype(statfsbuf.f_type)); - --# if !ENABLE_SELINUX -+# if !ENABLE_SELINUX && !ENABLE_SMACK - format = (option_mask32 & OPT_TERSE - ? "%lu %llu %llu %llu %llu %llu\n" - : "Block size: %-10lu\n" -@@ -448,8 +472,8 @@ static bool do_statfs(const char *filena - (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 -+ ? (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? "%lu %llu %llu %llu %llu %llu %C\n" : "%lu %llu %llu %llu %llu %llu\n") -+ : (option_mask32 & (OPT_SELINUX | OPT_SMACK) - ? "Block size: %-10lu\n" - "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n" - "Inodes: Total: %-10llu Free: %llu" -@@ -496,6 +520,18 @@ static bool do_stat(const char *filename - } - } - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+ -+ if (option_mask32 & OPT_SMACK) { -+ int i = option_mask32 & OPT_DEREFERENCE; -+ -+ if (smack_from_file(filename, smack, sizeof(smack), i) < 0) { -+ bb_perror_msg("%s", filename); -+ return 0; -+ } -+ } -+#endif - if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) { - bb_perror_msg("can't stat '%s'", filename); - return 0; -@@ -503,7 +539,7 @@ static bool do_stat(const char *filename - - #if ENABLE_FEATURE_STAT_FORMAT - if (format == NULL) { --# if !ENABLE_SELINUX -+#if !ENABLE_SELINUX && !ENABLE_SMACK - if (option_mask32 & OPT_TERSE) { - format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; - } else { -@@ -526,12 +562,12 @@ static bool do_stat(const char *filename - } - # else - if (option_mask32 & OPT_TERSE) { -- format = (option_mask32 & OPT_SELINUX ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - "%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 ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %-5h" -@@ -546,7 +582,7 @@ static bool do_stat(const char *filename - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n"); - } else { -- format = (option_mask32 & OPT_SELINUX ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %h\n" -@@ -562,11 +598,14 @@ static bool do_stat(const char *filename - } - # endif - } -- print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext)); -+ print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext) IF_SMACK(, smack) ); - #else /* FEATURE_STAT_FORMAT */ - if (option_mask32 & OPT_TERSE) { -+#if !ENABLE_SELINUX && !ENABLE_SMACK -+ printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu\n" -+#else - printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu" -- IF_NOT_SELINUX("\n"), -+#endif - filename, - (unsigned long long) statbuf.st_size, - (unsigned long long) statbuf.st_blocks, -@@ -589,6 +628,12 @@ static bool do_stat(const char *filename - else - bb_putchar('\n'); - # endif -+#if ENABLE_SMACK -+ if (option_mask32 & OPT_SMACK) -+ printf(" %lc\n", smack); -+ else -+ bb_putchar('\n'); -+#endif - } else { - char *linkname = NULL; - -@@ -632,6 +677,9 @@ static bool do_stat(const char *filename - # if ENABLE_SELINUX - printf(" S_Context: %lc\n", *scontext); - # endif -+#if ENABLE_SMACK -+ printf(" Smack: %lc\n", smack); -+#endif - printf("Access: %s\n" "Modify: %s\n" "Change: %s\n", - human_time(statbuf.st_atime), - human_time(statbuf.st_mtime), -@@ -653,6 +701,7 @@ int stat_main(int argc UNUSED_PARAM, cha - opt_complementary = "-1"; /* min one arg */ - opts = getopt32(argv, "ftL" - IF_SELINUX("Z") -+ IF_SMACK("Z") - IF_FEATURE_STAT_FORMAT("c:", &format) - ); - if (opts & OPT_FILESYS) /* -f */ -diff -uprN busybox-1.17.1/findutils/find.c busybox-1.17.1-smack/findutils/find.c ---- busybox-1.17.1/findutils/find.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/findutils/find.c 2011-08-18 17:39:38.790218576 -0700 -@@ -223,6 +223,13 @@ - //config: help - //config: Support the 'find -context' option for matching security context. - //config: -+//config:config FEATURE_FIND_SMACK -+//config: bool "Enable -smack: Smack label matching" -+//config: default n -+//config: depends on FIND && SMACK -+//config: help -+//config: Support the 'find -smack' option for matching Smack label. -+//config: - //config:config FEATURE_FIND_LINKS - //config: bool "Enable -links: link count matching" - //config: default y -@@ -268,6 +275,7 @@ IF_FEATURE_FIND_INUM( ACTS(inum, ino_ - IF_FEATURE_FIND_USER( ACTS(user, uid_t uid;)) - IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;)) - IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) -+IF_FEATURE_FIND_SMACK( ACTS(smack, const char *smack;)) - IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) - IF_FEATURE_FIND_PRUNE( ACTS(prune)) - IF_FEATURE_FIND_DELETE( ACTS(delete)) -@@ -573,6 +581,17 @@ ACTF(context) - return rc == 0; - } - #endif -+#if ENABLE_FEATURE_FIND_SMACK -+ACTF(smack) -+{ -+ char smack[SMACKBUFFSIZE]; -+ -+ if (smack_from_file(fileName, smack, SMACKBUFFSIZE, -+ (G.recurse_flags & ACTION_FOLLOWLINKS) ? 1 : 0) < 0) -+ return FALSE; -+ return strcmp(ap->smack, smack) == 0; -+} -+#endif - #if ENABLE_FEATURE_FIND_LINKS - ACTF(links) - { -@@ -704,6 +723,7 @@ static action*** parse_params(char **arg - IF_FEATURE_FIND_GROUP( PARM_group ,) - IF_FEATURE_FIND_SIZE( PARM_size ,) - IF_FEATURE_FIND_CONTEXT(PARM_context ,) -+ IF_FEATURE_FIND_SMACK( PARM_smack ,) - IF_FEATURE_FIND_LINKS( PARM_links ,) - }; - -@@ -738,6 +758,7 @@ static action*** parse_params(char **arg - IF_FEATURE_FIND_GROUP( "-group\0" ) - IF_FEATURE_FIND_SIZE( "-size\0" ) - IF_FEATURE_FIND_CONTEXT("-context\0") -+ IF_FEATURE_FIND_SMACK( "-smack\0" ) - IF_FEATURE_FIND_LINKS( "-links\0" ) - ; - -@@ -1028,6 +1049,13 @@ static action*** parse_params(char **arg - bb_simple_perror_msg(arg1); - } - #endif -+#if ENABLE_FEATURE_FIND_SMACK -+ else if (parm == PARM_smack) { -+ action_smack *ap; -+ ap = ALLOC_ACTION(smack); -+ ap->smack = arg1; -+ } -+#endif - #if ENABLE_FEATURE_FIND_LINKS - else if (parm == PARM_links) { - action_links *ap; -@@ -1115,6 +1143,9 @@ static action*** parse_params(char **arg - //usage: IF_FEATURE_FIND_CONTEXT( - //usage: "\n -context File has specified security context" - //usage: ) -+//usage: IF_FEATURE_FIND_CONTEXT( -+//usage: "\n -smack File has specified Smack label" -+//usage: ) - //usage: IF_FEATURE_FIND_EXEC( - //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" - //usage: "\n matching files" -diff -uprN busybox-1.17.1/include/applets.src.h busybox-1.17.1-smack/include/applets.src.h ---- busybox-1.17.1/include/applets.src.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/applets.src.h 2011-08-18 11:40:15.809964682 -0700 -@@ -279,6 +279,7 @@ IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_D - IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) - IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) -+IF_NEWSMACK(APPLET(newsmack, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) - IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) - IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -@@ -356,6 +357,9 @@ IF_SHA512SUM(APPLET_ODDNAME(sha512sum, m - IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) - IF_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_DROP, sleep)) -+IF_SMACKCIPSO(APPLET(smackcipso, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -+IF_SMACKENABLED(APPLET(smackenabled, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -+IF_SMACKLOAD(APPLET(smackload, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) - IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) - IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) - IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -diff -uprN busybox-1.17.1/include/libbb.h busybox-1.17.1-smack/include/libbb.h ---- busybox-1.17.1/include/libbb.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/libbb.h 2011-08-18 11:54:34.569974792 -0700 -@@ -52,6 +52,12 @@ - #include - #include - #endif -+#if ENABLE_SMACK -+#define SMACKBUFFSIZE 24 -+#define SMACKATTR "security.SMACK64" -+#define SMACKFLOOR "_" -+#define SMACKSTAR "*" -+#endif - #if ENABLE_LOCALE_SUPPORT - # include - #else -@@ -1183,6 +1189,16 @@ extern void selinux_preserve_fcontext(in - #endif - extern void selinux_or_die(void) FAST_FUNC; - -+#if ENABLE_SMACK -+extern int smack_from_file(const char *path, char *result, int len, int follow); -+extern int smack_from_proc(const int pid, char *result, int len); -+extern int smack_to_file(const char *path, const char *smack, int follow); -+extern int smack_to_proc(const int pid, const char *smack); -+extern int smack_user_default(const char *user, char *result, int len); -+extern int smack_user_allowed(const char *user, const char *smack); -+extern int smack_user_add(const char *user, const char *smack); -+#endif -+ - /* setup_environment: - * if chdir pw->pw_dir: ok: else if to_tmp == 1: goto /tmp else: goto / or die - * if clear_env = 1: cd(pw->pw_dir), clear environment, then set -@@ -1391,6 +1407,7 @@ typedef struct procps_status_t { - char *argv0; - char *exe; - IF_SELINUX(char *context;) -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - /* Everything below must contain no ptrs to malloc'ed data: - * it is memset(0) for each process in procps_scan() */ - unsigned long vsz, rss; /* we round it to kbytes */ -@@ -1453,6 +1470,7 @@ enum { - || ENABLE_SESTATUS - ), - PSSCAN_CONTEXT = (1 << 17) * ENABLE_SELINUX, -+ PSSCAN_SMACK = (1 << 17) * ENABLE_SMACK, - PSSCAN_START_TIME = 1 << 18, - PSSCAN_CPU = (1 << 19) * ENABLE_FEATURE_TOP_SMP_PROCESS, - PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, -@@ -1574,6 +1592,9 @@ extern const char bb_path_group_file[]; - extern const char bb_path_motd_file[]; - extern const char bb_path_wtmp_file[]; - extern const char bb_dev_null[]; -+#if ENABLE_SMACK -+extern const char bb_path_smack_user[]; -+#endif - extern const char bb_busybox_exec_path[]; - extern const char *bb_busybox_exec_paths[]; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, -diff -uprN busybox-1.17.1/include/usage.src.h busybox-1.17.1-smack/include/usage.src.h ---- busybox-1.17.1/include/usage.src.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/usage.src.h 2011-08-18 12:10:12.649985839 -0700 -@@ -1764,6 +1764,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Print the security context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Print the Smack label" \ -+ ) \ - "\n -u Print user ID" \ - "\n -g Print group ID" \ - "\n -G Print supplementary group IDs" \ -@@ -2982,6 +2985,11 @@ INSERT - "\n -p Display PID/Program name for sockets" \ - ) - -+#define newsmack_trivial_usage \ -+ "label [COMMAND [ARG] ...]" -+#define newsmack_full_usage \ -+ "Run a program or shell with the specified Smack label" \ -+ - #define nmeter_trivial_usage \ - "format_string" - #define nmeter_full_usage "\n\n" \ -@@ -3303,7 +3311,7 @@ INSERT - - #else /* !ENABLE_DESKTOP */ - --#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE -+#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE && !ENABLE_SMACK - #define USAGE_PS "\nThis version of ps accepts no options" - #else - #define USAGE_PS "\nOptions:" -@@ -3317,6 +3325,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Show selinux context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Show Smack label" \ -+ ) \ - IF_FEATURE_PS_WIDE( \ - "\n w Wide output" \ - ) -@@ -3845,6 +3856,17 @@ INSERT - "$ sleep 1d 3h 22m 8s\n" \ - "[98528 second delay results]\n") - -+#define smackcipso_trivial_usage -+#define smackcipso_full_usage \ -+ "Read and set Smack CIPSO mappings from the standard input" -+ -+#define smackenabled_trivial_usage -+#define smackenabled_full_usage -+ -+#define smackload_trivial_usage -+#define smackload_full_usage \ -+ "Read and set Smack access rules from the standard input" -+ - #define sort_trivial_usage \ - "[-nru" \ - IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") \ -@@ -3982,6 +4004,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Print security context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Print Smack label" \ -+ ) \ - IF_FEATURE_STAT_FORMAT( \ - "\n\nValid format sequences for files:\n" \ - " %a Access rights in octal\n" \ -@@ -4019,6 +4044,9 @@ INSERT - IF_SELINUX( \ - " %C Security context in selinux\n" \ - ) \ -+ IF_SMACK( \ -+ " %C Smack label\n" \ -+ ) \ - " %i File System ID in hex\n" \ - " %l Maximum length of filenames\n" \ - " %n File name\n" \ -diff -uprN busybox-1.17.1/libbb/Kbuild.src busybox-1.17.1-smack/libbb/Kbuild.src ---- busybox-1.17.1/libbb/Kbuild.src 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/Kbuild.src 2011-08-18 15:10:58.330113541 -0700 -@@ -126,6 +126,7 @@ lib-$(CONFIG_FEATURE_UTMP) += utmp.o - # A mix of optimizations (why build stuff we know won't be used) - # and objects which may fail to build (SELinux on selinux-less system) - lib-$(CONFIG_SELINUX) += selinux_common.o -+lib-$(CONFIG_SMACK) += smack_common.o - lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o - lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o - lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o -diff -uprN busybox-1.17.1/libbb/messages.c busybox-1.17.1-smack/libbb/messages.c ---- busybox-1.17.1/libbb/messages.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/messages.c 2011-08-17 15:27:12.889107702 -0700 -@@ -43,6 +43,9 @@ const char bb_path_shadow_file[] ALIGN1 - const char bb_path_group_file[] ALIGN1 = "/etc/group"; - const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow"; - const char bb_path_motd_file[] ALIGN1 = "/etc/motd"; -+#if ENABLE_SMACK -+const char bb_path_smack_user[] ALIGN1 = "/etc/smack/user"; -+#endif - const char bb_dev_null[] ALIGN1 = "/dev/null"; - const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; - const char *bb_busybox_exec_paths[] ALIGN1 = { -diff -uprN busybox-1.17.1/libbb/procps.c busybox-1.17.1-smack/libbb/procps.c ---- busybox-1.17.1/libbb/procps.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/procps.c 2011-08-17 15:27:12.909107701 -0700 -@@ -240,6 +240,12 @@ procps_status_t* FAST_FUNC procps_scan(p - sp->context = NULL; - } - #endif -+#if ENABLE_SMACK -+ if (flags & PSSCAN_SMACK) { -+ if (smack_from_proc(sp->pid, sp->smack, SMACKBUFFSIZE) < 0) -+ strcpy(sp->smack, "?"); -+ } -+#endif - - filename_tail = filename + sprintf(filename, "/proc/%u/", pid); - -diff -uprN busybox-1.17.1/libbb/smack_common.c busybox-1.17.1-smack/libbb/smack_common.c ---- busybox-1.17.1/libbb/smack_common.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/libbb/smack_common.c 2011-08-18 17:17:53.730203208 -0700 -@@ -0,0 +1,178 @@ -+/* -+ * libbb/smack_common.c -+ * -- common Smack utility functions -+ * -+ * Copyright 2007 Casey Schaufler -+ */ -+#include "libbb.h" -+#include -+ -+#define SMACKPROCPATH "/proc/%d/attr/current" -+#define SMACKUSERFILE "/etc/smack/user" -+#define SMACKFILELINE 256 -+ -+int smack_from_file(const char *path, char *result, int len, int follow) -+{ -+ char buffer[SMACKBUFFSIZE]; -+ int rc; -+ -+ if (follow) -+ rc = getxattr(path, SMACKATTR, buffer, SMACKBUFFSIZE - 1); -+ else -+ rc = lgetxattr(path, SMACKATTR, buffer, SMACKBUFFSIZE - 1); -+ -+ if (rc < 0) -+ return rc; -+ -+ buffer[rc] = '\0'; -+ if (strlen(buffer) > len) -+ return -EINVAL; -+ -+ strcpy(result, buffer); -+ return rc; -+} -+ -+int smack_from_proc(const int pid, char *result, int len) -+{ -+ char path[SMACKFILELINE]; -+ char buffer[SMACKFILELINE]; -+ int fd; -+ int i; -+ -+ sprintf(path, SMACKPROCPATH, (pid < 0) ? getpid() : pid); -+ -+ fd = open(path, O_RDONLY); -+ if (fd < 0) -+ return -EACCES; -+ -+ i = read(fd, buffer, SMACKFILELINE); -+ close(fd); -+ -+ if (i <= 0 || i >= len) -+ return -ERANGE; -+ buffer[i] = '\0'; -+ strcpy(result, buffer); -+ return 0; -+} -+ -+int smack_to_file(const char *path, const char *smack, int follow) -+{ -+ if (follow) -+ return setxattr(path, SMACKATTR, smack, strlen(smack)+1, 0); -+ return lsetxattr(path, SMACKATTR, smack, strlen(smack)+1, 0); -+} -+ -+int smack_to_proc(const int pid, const char *smack) -+{ -+ char path[SMACKFILELINE]; -+ int fd; -+ int i; -+ int slen; -+ -+ slen = strlen(smack) + 1; -+ if (slen >= SMACKBUFFSIZE) -+ return -ERANGE; -+ -+ sprintf(path, SMACKPROCPATH, (pid < 0) ? getpid() : pid); -+ -+ fd = open(path, O_RDWR); -+ if (fd < 0) -+ return -EACCES; -+ -+ i = write(fd, smack, slen); -+ close(fd); -+ -+ if (i != slen) -+ return -EINVAL; -+ return 0; -+} -+ -+int smack_user_default(const char *user, char *result, int len) -+{ -+ char line[SMACKFILELINE]; -+ char ruser[SMACKFILELINE]; -+ char rsmack[SMACKFILELINE]; -+ FILE *fp; -+ -+ fp = fopen(bb_path_smack_user, "r"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ if (sscanf(line, "%s %s", ruser, rsmack) != 2) -+ continue; -+ if (strcmp(ruser, user) != 0) -+ continue; -+ if (strlen(rsmack) >= len) -+ return -ERANGE; -+ strcpy(result, rsmack); -+ return 0; -+ } -+ return -ENOENT; -+} -+ -+int smack_user_allowed(const char *user, const char *smack) -+{ -+ char line[SMACKFILELINE]; -+ char *ruser; -+ char *rsmack; -+ FILE *fp; -+ int rc = 1; -+ -+ fp = fopen(SMACKUSERFILE, "r"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (rc == 1 && fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ -+ ruser = strtok(line, " \t\n"); -+ if (ruser == NULL) -+ continue; -+ -+ if (strcmp(ruser, user) != 0) -+ continue; -+ -+ while (rc == 1 && (rsmack = strtok(NULL, " \t\n")) != NULL) { -+ if (strcmp(rsmack, smack) == 0 || strcmp(rsmack, "+") == 0) -+ rc = 0; -+ } -+ } -+ fclose(fp); -+ return (rc == 1) ? -ENOENT : rc; -+} -+ -+int smack_user_add(const char *user, const char *smack) -+{ -+ char line[SMACKFILELINE]; -+ char *ruser; -+ FILE *fp; -+ int rc = 0; -+ -+ fp = fopen(SMACKUSERFILE, "a+"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ -+ ruser = strtok(line, " \t\n"); -+ if (ruser == NULL) -+ continue; -+ -+ if (strcmp(ruser, user) == 0) { -+ rc = -EEXIST; -+ break; -+ } -+ } -+ -+ if (rc == 0) -+ fprintf(fp, "%s %s\n", user, smack); -+ -+ fclose(fp); -+ return rc; -+} -diff -uprN busybox-1.17.1/loginutils/adduser.c busybox-1.17.1-smack/loginutils/adduser.c ---- busybox-1.17.1/loginutils/adduser.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/adduser.c 2011-08-17 15:27:12.909107701 -0700 -@@ -112,6 +112,7 @@ int adduser_main(int argc UNUSED_PARAM, - const char *usegroup = NULL; - char *p; - unsigned opts; -+ IF_SMACK(const char *smack = SMACKSTAR;) - - #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS - applet_long_options = adduser_longopts; -@@ -130,10 +131,10 @@ int adduser_main(int argc UNUSED_PARAM, - /* disable interactive passwd for system accounts */ - opt_complementary = "=1:SD:u+"; - if (sizeof(pw.pw_uid) == sizeof(int)) { -- opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid); -+ opts = getopt32(argv, "h:g:s:G:DSHu:" IF_SMACK("L:"), &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid IF_SMACK(, &smack) ); - } else { - unsigned uid; -- opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid); -+ opts = getopt32(argv, "h:g:s:G:DSHu:" IF_SMACK("L:"), &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid IF_SMACK(, &smack) ); - if (opts & OPT_UID) { - pw.pw_uid = uid; - } -@@ -220,6 +221,14 @@ int adduser_main(int argc UNUSED_PARAM, - bb_simple_perror_msg(pw.pw_dir); - } - } -+#if ENABLE_SMACK -+ if (smack_user_add(pw.pw_name, smack) < 0) -+ bb_error_msg("cannot add user smack entry"); -+ if (strtok(smack, " \t") != NULL) -+ if (smack_to_file(pw.pw_dir, smack, 0) != 0) -+ bb_error_msg("cannot set smack on home directory"); -+#endif -+ - - if (!(opts & OPT_DONT_SET_PASS)) { - /* interactively set passwd */ -diff -uprN busybox-1.17.1/loginutils/login.c busybox-1.17.1-smack/loginutils/login.c ---- busybox-1.17.1/loginutils/login.c 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/login.c 2011-08-17 15:27:12.909107701 -0700 -@@ -218,6 +218,7 @@ int login_main(int argc UNUSED_PARAM, ch - struct passwd pwdstruct; - char pwdbuf[256]; - #endif -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - username[0] = '\0'; - signal(SIGALRM, alarm_handler); -@@ -376,6 +377,13 @@ int login_main(int argc UNUSED_PARAM, ch - die_if_nologin(); - - IF_SELINUX(initselinux(username, full_tty, &user_sid)); -+#if ENABLE_SMACK -+ if (smack_user_default(pw->pw_name, smack, SMACKBUFFSIZE) < 0) -+ strcpy(smack, SMACKFLOOR); -+ if (smack_to_proc(-1, smack) < 0) -+ bb_perror_msg_and_die("cannot set smack"); -+#endif -+ - - /* Try these, but don't complain if they fail. - * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ -diff -uprN busybox-1.17.1/loginutils/su.c busybox-1.17.1-smack/loginutils/su.c ---- busybox-1.17.1/loginutils/su.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/su.c 2011-08-18 15:13:07.830115065 -0700 -@@ -44,6 +44,7 @@ int su_main(int argc UNUSED_PARAM, char - const char *tty; - char user_buf[64]; - const char *old_user; -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); - //argc -= optind; -@@ -129,6 +130,13 @@ int su_main(int argc UNUSED_PARAM, char - + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV), - pw); - IF_SELINUX(set_current_security_context(NULL);) -+#if ENABLE_SMACK -+ if (smack_from_proc(-1, smack, SMACKBUFFSIZE) < 0) -+ bb_error_msg_and_die("cannot identify process smack"); -+ if (smack_user_allowed(pw->pw_name, smack) < 0) -+ bb_error_msg_and_die("new usr not allowed current smack"); -+#endif -+ - - /* Never returns */ - run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); -diff -uprN busybox-1.17.1/loginutils/sulogin.c busybox-1.17.1-smack/loginutils/sulogin.c ---- busybox-1.17.1/loginutils/sulogin.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/sulogin.c 2011-08-17 15:27:12.909107701 -0700 -@@ -26,6 +26,7 @@ int sulogin_main(int argc UNUSED_PARAM, - char buffer[256]; - struct spwd spw; - #endif -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - logmode = LOGMODE_BOTH; - openlog(applet_name, 0, LOG_AUTH); -@@ -97,6 +98,11 @@ int sulogin_main(int argc UNUSED_PARAM, - bb_info_msg("System Maintenance Mode"); - - IF_SELINUX(renew_current_security_context()); -+#if ENABLE_SMACK -+ if (smack_to_proc(-1, SMACKFLOOR) < 0) -+ bb_error_msg("login incorrect"); -+#endif -+ - - shell = getenv("SUSHELL"); - if (!shell) -diff -uprN busybox-1.17.1/Makefile busybox-1.17.1-smack/Makefile ---- busybox-1.17.1/Makefile 2010-07-24 15:13:44.000000000 -0700 -+++ busybox-1.17.1-smack/Makefile 2011-08-17 15:27:12.909107701 -0700 -@@ -482,6 +482,7 @@ libs-y := \ - runit/ \ - selinux/ \ - shell/ \ -+ smack/ \ - sysklogd/ \ - util-linux/ \ - util-linux/volume_id/ \ -diff -uprN busybox-1.17.1/miscutils/crond.c busybox-1.17.1-smack/miscutils/crond.c ---- busybox-1.17.1/miscutils/crond.c 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/miscutils/crond.c 2011-08-17 15:27:12.909107701 -0700 -@@ -906,6 +906,7 @@ static void RunJob(const char *user, Cro - { - struct passwd *pas; - pid_t pid; -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - /* prepare things before vfork */ - pas = getpwnam(user); -@@ -919,6 +920,16 @@ static void RunJob(const char *user, Cro - pid = vfork(); - if (pid == 0) { - /* CHILD */ -+#if ENABLE_SMACK -+ if (smack_user_default(user, smack, SMACKBUFFSIZE) < 0) { -+ crondlog("\024user %s default smack unknown\n", user); -+ exit(0); -+ } -+ if (smack_to_proc(-1, smack) < 0) { -+ crondlog("\024user %s smack unsettable\n", user); -+ exit(0); -+ } -+#endif - /* change running state to the user in question */ - ChangeUser(pas); - if (DebugOpt) { -diff -uprN busybox-1.17.1/miscutils/crontab.c busybox-1.17.1-smack/miscutils/crontab.c ---- busybox-1.17.1/miscutils/crontab.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/miscutils/crontab.c 2011-08-17 15:27:12.909107701 -0700 -@@ -77,6 +77,10 @@ int crontab_main(int argc UNUSED_PARAM, - int fd; - int src_fd; - int opt_ler; -+#if ENABLE_SMACK -+ char psmack[SMACKBUFFSIZE]; -+ char dsmack[SMACKBUFFSIZE]; -+#endif - - /* file [opts] Replace crontab from file - * - [opts] Replace crontab from stdin -@@ -120,6 +124,15 @@ int crontab_main(int argc UNUSED_PARAM, - if ((opt_ler - 1) & opt_ler) /* more than one bit set? */ - bb_show_usage(); - -+#if ENABLE_SMACK -+ if (smack_user_default(pas->pw_name, dsmack, SMACKBUFFSIZE) < 0) -+ bb_perror_msg_and_die("user default smack unknown"); -+ if (smack_from_proc(-1, psmack, SMACKBUFFSIZE) < 0) -+ bb_perror_msg_and_die("user default smack unknown"); -+ if (strcmp(dsmack, psmack) != 0) -+ bb_perror_msg_and_die("current smack is not default smack"); -+#endif -+ - /* Read replacement file under user's UID/GID/group vector */ - src_fd = STDIN_FILENO; - if (!opt_ler) { /* Replace? */ -diff -uprN busybox-1.17.1/procps/ps.c busybox-1.17.1-smack/procps/ps.c ---- busybox-1.17.1/procps/ps.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/procps/ps.c 2011-08-18 17:28:10.070210464 -0700 -@@ -25,7 +25,12 @@ enum { MAX_WIDTH = 2*1024 }; - #if ENABLE_SELINUX - #define SELINUX_O_PREFIX "label," - #define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") --#else -+#endif -+#if ENABLE_SMACK -+#define SMACK_O_PREFIX "label," -+#define DEFAULT_O_STR (SMACK_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") -+#endif -+#if !ENABLE_SELINUX && !ENABLE_SMACK - #define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") - #endif - -@@ -288,6 +293,13 @@ static void func_label(char *buf, int si - } - #endif - -+#if ENABLE_SMACK -+static void func_label(char *buf, int size, const procps_status_t *ps) -+{ -+ safe_strncpy(buf, ps->smack[0] ? ps->smack : "?", size+1); -+} -+#endif -+ - /* - static void func_nice(char *buf, int size, const procps_status_t *ps) - { -@@ -327,6 +339,9 @@ static const ps_out_t out_spec[] = { - #if ENABLE_SELINUX - { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, - #endif -+#if ENABLE_SMACK -+ { 24 , "label" ,"LABEL" ,func_label ,PSSCAN_SMACK }, -+#endif - }; - - static ps_out_t* new_out_t(void) -@@ -516,6 +531,12 @@ int ps_main(int argc UNUSED_PARAM, char - strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); - } else - #endif -+#if ENABLE_SMACK -+ if (!(opt & 1)) { -+ /* no -Z : do not show LABEL */ -+ strcpy(default_o, DEFAULT_O_STR + sizeof(SMACK_O_PREFIX) -1); -+ } else -+#endif - { - strcpy(default_o, DEFAULT_O_STR); - } -@@ -557,17 +578,17 @@ int ps_main(int argc UNUSED_PARAM, char - | PSSCAN_STATE | PSSCAN_VSZ | PSSCAN_COMM; - unsigned terminal_width IF_NOT_FEATURE_PS_WIDE(= 79); - enum { -- OPT_Z = (1 << 0) * ENABLE_SELINUX, -- OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, -+ OPT_Z = (1 << 0) * (ENABLE_SELINUX | ENABLE_SMACK), -+ OPT_T = (1 << (ENABLE_SELINUX | ENABLE_SMACK)) * ENABLE_FEATURE_SHOW_THREADS, - }; - int opts = 0; - /* If we support any options, parse argv */ --#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE -+#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_SMACK - # if ENABLE_FEATURE_PS_WIDE - /* -w is a bit complicated */ - int w_count = 0; - opt_complementary = "-:ww"; -- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); -+ opts = getopt32(argv, IF_SELINUX("Z")IF_SMACK("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); - /* if w is given once, GNU ps sets the width to 132, - * if w is given more than once, it is "unlimited" - */ -@@ -582,7 +603,7 @@ int ps_main(int argc UNUSED_PARAM, char - # else - /* -w is not supported, only -Z and/or -T */ - opt_complementary = "-"; -- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); -+ opts = getopt32(argv, IF_SELINUX("Z")IF_SMACK("Z")IF_FEATURE_SHOW_THREADS("T")); - # endif - #endif - -@@ -593,6 +614,13 @@ int ps_main(int argc UNUSED_PARAM, char - puts(" PID CONTEXT STAT COMMAND"); - } else - #endif -+#if ENABLE_SMACK -+ if (opts & OPT_Z) { -+ psscan_flags = PSSCAN_PID | PSSCAN_SMACK -+ | PSSCAN_STATE | PSSCAN_COMM; -+ puts(" PID CONTEXT STAT COMMAND"); -+ } else -+#endif - { - puts(" PID USER VSZ STAT COMMAND"); - } -@@ -611,6 +639,14 @@ int ps_main(int argc UNUSED_PARAM, char - p->state); - } else - #endif -+#if ENABLE_SMACK -+ if (psscan_flags & PSSCAN_SMACK) { -+ len = printf("%5u %-24.24s %s ", -+ p->pid, -+ p->smack ? p->smack : "unknown", -+ p->state); -+ } else -+#endif - { - const char *user = get_cached_username(p->uid); - //if (p->vsz == 0) -diff -uprN busybox-1.17.1/smack/Config.src busybox-1.17.1-smack/smack/Config.src ---- busybox-1.17.1/smack/Config.src 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/Config.src 2011-08-18 11:19:44.669950186 -0700 -@@ -0,0 +1,40 @@ -+# -+# For a description of the syntax of this configuration file, -+# see scripts/kbuild/config-language.txt. -+# -+ -+menu "Smack Utilities" -+ depends on SMACK -+ -+INSERT -+ -+config SMACKLOAD -+ bool "smackload" -+ default n -+ depends on SMACK -+ help -+ Enable support to load Smack access rules. -+ -+config SMACKCIPSO -+ bool "smackcipso" -+ default n -+ depends on SMACK -+ help -+ Enable support to specify Smack CIPSO mappings. -+ -+config NEWSMACK -+ bool "newsmack" -+ default n -+ depends on SMACK -+ help -+ Enable support to run command with specified Smack label. -+ -+config SMACKENABLED -+ bool "smackenabled" -+ default n -+ depends on SMACK -+ help -+ Enable support for this command to be used within shell scripts -+ to determine if smack is enabled. -+ -+endmenu -diff -uprN busybox-1.17.1/smack/Kbuild.src busybox-1.17.1-smack/smack/Kbuild.src ---- busybox-1.17.1/smack/Kbuild.src 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/Kbuild.src 2011-08-19 13:22:11.301054005 -0700 -@@ -0,0 +1,14 @@ -+# Makefile for busybox -+# -+# Copyright (C) 1999-2005 by Erik Andersen -+# Copyright (C) 2007 by KaiGai Kohei -+# -+# Licensed under the GPL v2, see the file LICENSE in this tarball. -+ -+INSERT -+ -+lib-y:= -+lib-$(CONFIG_NEWSMACK) += newsmack.o -+lib-$(CONFIG_SMACKLOAD) += smackload.o -+lib-$(CONFIG_SMACKCIPSO) += smackcipso.o -+lib-$(CONFIG_SMACKENABLED) += smackenabled.o -diff -uprN busybox-1.17.1/smack/newsmack.c busybox-1.17.1-smack/smack/newsmack.c ---- busybox-1.17.1/smack/newsmack.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/newsmack.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,61 @@ -+/* -+ * newsmack label [ command [ arg ] ... ] -+ * -+ * Port to busybox: Casey Schaufler -+ * -+ * Copyright (C) 2007 Casey Schaufler -+ * -+ */ -+ -+#include "libbb.h" -+ -+int newsmack_main(int argc, char **argv); -+int newsmack_main(int argc, char **argv) -+{ -+ struct passwd *pwd; -+ char *newargv[256]; /* yes, I know */ -+ char *smack; -+ int i; -+ int newargc; -+ -+ if (argc <= 1) -+ bb_error_msg_and_die("No smack value specified"); -+ -+ smack = argv[1]; -+ -+ /* -+ * Start a shell if no command is specified -+ */ -+ if (argc == 2) { -+ fprintf(stderr, "%s: start a shell at \"%s\"\n", -+ argv[0], smack); -+ newargv[0] = strdup("sh"); -+ newargv[1] = NULL; -+ } else { -+ for (newargc = 0, i = 2; i < argc; newargc++, i++) -+ newargv[newargc] = argv[i]; -+ newargv[newargc] = NULL; -+ } -+ -+ /* -+ * Verify the user is allowed the Smack label -+ */ -+ pwd = getpwuid(getuid()); -+ if (pwd == NULL) -+ bb_error_msg_and_die("User name not obtained"); -+ if (smack_user_allowed(pwd->pw_name, smack) != 0) -+ bb_error_msg_and_die("User not allowed this smack label"); -+ /* -+ * Set the process label. -+ */ -+ i = smack_to_proc(-1, smack); -+ if (i < 0) -+ bb_error_msg_and_die("Cannot set smack"); -+ -+ /* -+ * Do the exec -+ */ -+ execvp(newargv[0], newargv); -+ -+ bb_error_msg_and_die("%s: exec failure.", newargv[0]); -+} -diff -uprN busybox-1.17.1/smack/smackcipso.c busybox-1.17.1-smack/smack/smackcipso.c ---- busybox-1.17.1/smack/smackcipso.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/smackcipso.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,119 @@ -+/* -+ * smackcipso - properly format smack access cipsos for -+ * loading into the kernel by writing to /smack/cipso. -+ * -+ * Copyright (C) 2007 Casey Schaufler -+ * -+ * This program is free software; 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. -+ * -+ * Authors: -+ * Casey Schaufler -+ * Ahmed S. Darwish -+ * -+ */ -+/* -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+*/ -+#include "libbb.h" -+ -+#define LSIZE 23 -+#define NSIZE 4 -+#define MAXCATNUM 239 -+#define MAXCATVAL 63 -+#define MAXLEVEL 255 -+ -+int smackcipso_main(int argc, char **argv); -+int smackcipso_main(int argc, char **argv) -+{ -+ int status = EXIT_SUCCESS; -+ int cipsofd; -+ char line[512]; -+ char cipso[LSIZE + NSIZE + NSIZE + (NSIZE * MAXCATNUM)]; -+ char cats[MAXCATNUM+1][NSIZE+1]; -+ char *cp; -+ int level; -+ int cat; -+ int catcount; -+ int i; -+ int err; -+ -+ cipsofd = open("/smack/cipso", O_RDWR); -+ if (cipsofd < 0) -+ bb_error_msg_and_die("failed opening /smack/cipso"); -+ -+ while (fgets(line, sizeof(line), stdin) != NULL) { -+ catcount = 0; -+ err = 0; -+ -+ if ((cp = strchr(line, '\n')) == NULL) { -+ fprintf(stderr, "missing newline \"%s\"\n", line); -+ continue; -+ } -+ *cp = '\0'; -+ cp = strtok(line, " \t"); -+ if (cp == NULL) { -+ fprintf(stderr, "Empty line: \"%s\"\n", line); -+ continue; -+ } -+ sprintf(cipso, "%-23s ", line); -+ if (strlen(cipso) != 24) { -+ fprintf(stderr, "Bad label starting: \"%s\"\n", line); -+ continue; -+ } -+ cp = strtok(NULL, " \t"); -+ if (cp == NULL) { -+ fprintf(stderr, "Missing level: \"%s\"\n", line); -+ continue; -+ } -+ if (!isdigit(*cp)) { -+ fprintf(stderr, "Bad level: \"%s\"\n", cp); -+ continue; -+ } -+ level = atoi(cp); -+ if (level > MAXLEVEL) { -+ fprintf(stderr, "Bad level: \"%s\"\n", cp); -+ continue; -+ } -+ sprintf(cipso+LSIZE+1, "%-4d", level); -+ -+ cp = strtok(NULL, " \t"); -+ for (i = 0; cp != NULL; cp = strtok(NULL, " \t"), i++) { -+ if (!isdigit(*cp)) { -+ fprintf(stderr, "Bad category \"%s\"\n", cp); -+ err = 1; -+ break; -+ } -+ cat = atoi(cp); -+ if (i >= MAXCATNUM) { -+ fprintf(stderr, "Maximum number of categories" -+ "exceeded \"%d\"\n", i); -+ err = 1; -+ break; -+ } -+ if (cat > MAXCATVAL) { -+ fprintf(stderr, "Bad category \"%s\"\n", cp); -+ err = 1; -+ break; -+ } -+ sprintf(cats[i], "%-4d", cat); -+ } -+ if (err) -+ continue; -+ -+ sprintf(cipso+LSIZE+1+NSIZE, "%-4d", i); -+ while (i > 0) -+ strcat(cipso, cats[--i]); -+ err = write(cipsofd, cipso, strlen(cipso)); -+ if (err < 0) -+ perror("writing /smack/cipso"); -+ } -+ return status; -+} -diff -uprN busybox-1.17.1/smack/smackenabled.c busybox-1.17.1-smack/smack/smackenabled.c ---- busybox-1.17.1/smack/smackenabled.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/smackenabled.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,17 @@ -+/* -+ * smackenabled -+ * -+ * Port to BusyBox Casey Schaufler -+ * -+ * This program is free software; 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. -+ * -+ * Author: -+ * Casey Schaufler -+ */ -+/* -+#include -+#include -+#include -+#include -+#include -+#include -+*/ -+#include "libbb.h" -+ -+#define LSIZE 23 -+#define ASIZE 4 -+ -+int smackload_main(int argc, char **argv); -+int smackload_main(int argc, char **argv) -+{ -+ int status = EXIT_SUCCESS; -+ int loadfd; -+ char line[80]; -+ char rule[LSIZE + LSIZE + ASIZE + 3]; -+ char subject[LSIZE+1]; -+ char object[LSIZE+1]; -+ char accesses[ASIZE+1]; -+ char real[ASIZE+1]; -+ char *cp; -+ int i; -+ int err; -+ -+ loadfd = open("/smack/load", O_RDWR); -+ if (loadfd < 0) -+ bb_error_msg_and_die("failed opening /smack/load"); -+ -+ while (fgets(line, 80, stdin) != NULL) { -+ err = 0; -+ if ((cp = strchr(line, '\n')) != NULL) -+ *cp = '\0'; -+ if (sscanf(line,"%23s %23s %4s",subject,object,accesses) != 3) -+ err = 1; -+ else { -+ strcpy(real, "----"); -+ for (i = 0; -+ i < ASIZE && accesses[i] != '\0' && err == 0; -+ i++) { -+ switch (accesses[i]) { -+ case 'r': -+ case 'R': -+ real[0] = 'r'; -+ break; -+ case 'w': -+ case 'W': -+ real[1] = 'w'; -+ break; -+ case 'x': -+ case 'X': -+ real[2] = 'x'; -+ break; -+ case 'a': -+ case 'A': -+ real[3] = 'a'; -+ break; -+ case '\0': -+ case '-': -+ break; -+ default: -+ err = 1; -+ break; -+ } -+ } -+ } -+ if (err == 0) { -+ sprintf(rule, "%-23s %-23s %4s", subject,object,real); -+ err = write(loadfd, rule, LSIZE + LSIZE + ASIZE + 2); -+ if (err < 0) -+ perror("writing /smack/load"); -+ } -+ else -+ fprintf(stderr, "Bad input line \"%s\"\n", line); -+ } -+ return status; -+} diff --git a/debian/patches/smack-conflict-with-selinux.patch b/debian/patches/smack-conflict-with-selinux.patch deleted file mode 100644 index 8e9d425..0000000 --- a/debian/patches/smack-conflict-with-selinux.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0bfd7de40919494aa4a2cada5ca4c475d1a87b66 Mon Sep 17 00:00:00 2001 -From: Karol Lewandowski -Date: Wed, 11 Jan 2012 11:21:15 +0100 -Subject: [PATCH] Don't allow SELINUX and SMACK to be enabled at the same time - -Source code simply doesn't support it. ---- - Config.in | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/Config.in b/Config.in -index 76c2b68..cac552c 100644 ---- a/Config.in -+++ b/Config.in -@@ -385,6 +385,7 @@ config SELINUX - config SMACK - bool "Support Smack" - default n -+ depends on !SELINUX - help - Enable support for Smack in applets ls, ps, and id. Also provide - the option of compiling in Smack applets. --- -1.7.7.3 - diff --git a/debian/patches/strip.patch b/debian/patches/strip.patch deleted file mode 100644 index 1188e67..0000000 --- a/debian/patches/strip.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/Makefile -+++ b/Makefile -@@ -690,20 +690,10 @@ - endif # ifdef CONFIG_KALLSYMS - - # busybox image - including updated kernel symbols --busybox_unstripped: $(busybox-all) FORCE -+busybox: $(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) ; diff --git a/debian/patches/stty-sort-out-preprocessor-conditionals.patch b/debian/patches/stty-sort-out-preprocessor-conditionals.patch deleted file mode 100644 index e078f3d..0000000 --- a/debian/patches/stty-sort-out-preprocessor-conditionals.patch +++ /dev/null @@ -1,705 +0,0 @@ -From 138ce54c9c1930348bc842be781accd7c50c2cef Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Fri, 30 Jul 2010 06:01:37 +0200 -Subject: [PATCH 2/2] stty: sort out preprocessor conditionals - -* Move the definitions of missing constants to the top of the file. -* Fix undefined IDX_xxx on missing termios constants. -* FreeBSD has TABDLY, TAB0 and TAB3, but no TAB1 or TAB2 -* Omit the definition of set_window_size() if TIOCGWINSZ is not available. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - coreutils/Config.src | 1 - - coreutils/stty.c | 339 +++++++++++++++++++++++++++++++------------------ - 2 files changed, 214 insertions(+), 126 deletions(-) - -diff --git a/coreutils/Config.src b/coreutils/Config.src -index 780b73f..0eb70af 100644 ---- a/coreutils/Config.src -+++ b/coreutils/Config.src -@@ -607,7 +607,6 @@ config FEATURE_STAT_FORMAT - config STTY - bool "stty" - default y -- depends on PLATFORM_LINUX - help - stty is used to change and print terminal line settings. - -diff --git a/coreutils/stty.c b/coreutils/stty.c -index c40d718..33f7b21 100644 ---- a/coreutils/stty.c -+++ b/coreutils/stty.c -@@ -115,6 +115,113 @@ - # 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 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 -+ - /* Which speeds to set */ - enum speed_setting { - input_speed, output_speed, both_speeds -@@ -167,13 +274,13 @@ enum { - IDX_cbreak, - IDX_crt, - IDX_dec, --#ifdef IXANY -+#if IXANY - IDX_decctlq, - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - IDX_tabs, - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - IDX_lcase, - IDX_LCASE, - #endif -@@ -196,13 +303,13 @@ static const char mode_name[] = - MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("crt", combination, OMIT, 0, 0 ) - MI_ENTRY("dec", combination, OMIT, 0, 0 ) --#ifdef IXANY -+#if IXANY - MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) - #endif -@@ -217,7 +324,7 @@ static const char mode_name[] = - MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) - MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) - MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) --#ifdef CRTSCTS -+#if CRTSCTS - MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) - #endif - MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) -@@ -232,74 +339,78 @@ static const char mode_name[] = - MI_ENTRY("ixon", input, REV, IXON, 0 ) - MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) --#ifdef IUCLC -+#if IUCLC - MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) - #endif --#ifdef IXANY -+#if IXANY - MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) - #endif --#ifdef IMAXBEL -+#if IMAXBEL - MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) - #endif - MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) --#ifdef OLCUC -+#if OLCUC - MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) - #endif --#ifdef OCRNL -+#if OCRNL - MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) - #endif --#ifdef ONLCR -+#if ONLCR - MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) - #endif --#ifdef ONOCR -+#if ONOCR - MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) - #endif --#ifdef ONLRET -+#if ONLRET - MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) - #endif --#ifdef OFILL -+#if OFILL - MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) - #endif --#ifdef OFDEL -+#if OFDEL - MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) - #endif --#ifdef NLDLY -+#if NLDLY - MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) - MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) - #endif --#ifdef CRDLY -+#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 - --#ifdef TABDLY -+#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 --# ifdef OXTABS -+# if OXTABS - MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) - # endif - #endif - --#ifdef BSDLY -+#if BSDLY - MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) - MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) - #endif --#ifdef VTDLY -+#if VTDLY - MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) - MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) - #endif --#ifdef FFDLY -+#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 ) --#ifdef IEXTEN -+#if IEXTEN - MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) - #endif - MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) -@@ -308,21 +419,21 @@ static const char mode_name[] = - MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) - MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) - MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) --#ifdef XCASE -+#if XCASE - MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) - #endif --#ifdef TOSTOP -+#if TOSTOP - MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) - #endif --#ifdef ECHOPRT -+#if ECHOPRT - MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) - #endif --#ifdef ECHOCTL -+#if ECHOCTL - MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) - #endif --#ifdef ECHOKE -+#if ECHOKE - MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) - #endif -@@ -346,13 +457,13 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("crt", combination, OMIT, 0, 0 ) - MI_ENTRY("dec", combination, OMIT, 0, 0 ) --#ifdef IXANY -+#if IXANY - MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) - #endif -@@ -367,7 +478,7 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) - MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) - MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) --#ifdef CRTSCTS -+#if CRTSCTS - MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) - #endif - MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) -@@ -382,74 +493,78 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("ixon", input, REV, IXON, 0 ) - MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) --#ifdef IUCLC -+#if IUCLC - MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) - #endif --#ifdef IXANY -+#if IXANY - MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) - #endif --#ifdef IMAXBEL -+#if IMAXBEL - MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) - #endif - MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) --#ifdef OLCUC -+#if OLCUC - MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) - #endif --#ifdef OCRNL -+#if OCRNL - MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) - #endif --#ifdef ONLCR -+#if ONLCR - MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) - #endif --#ifdef ONOCR -+#if ONOCR - MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) - #endif --#ifdef ONLRET -+#if ONLRET - MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) - #endif --#ifdef OFILL -+#if OFILL - MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) - #endif --#ifdef OFDEL -+#if OFDEL - MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) - #endif --#ifdef NLDLY -+#if NLDLY - MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) - MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) - #endif --#ifdef CRDLY -+#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 - --#ifdef TABDLY -+#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 --# ifdef OXTABS -+# if OXTABS - MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) - # endif - #endif - --#ifdef BSDLY -+#if BSDLY - MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) - MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) - #endif --#ifdef VTDLY -+#if VTDLY - MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) - MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) - #endif --#ifdef FFDLY -+#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 ) --#ifdef IEXTEN -+#if IEXTEN - MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) - #endif - MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) -@@ -458,21 +573,21 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) - MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) - MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) --#ifdef XCASE -+#if XCASE - MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) - #endif --#ifdef TOSTOP -+#if TOSTOP - MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) - #endif --#ifdef ECHOPRT -+#if ECHOPRT - MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) - #endif --#ifdef ECHOCTL -+#if ECHOCTL - MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) - #endif --#ifdef ECHOKE -+#if ECHOKE - MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) - #endif -@@ -497,31 +612,31 @@ enum { - CIDX_kill, - CIDX_eof, - CIDX_eol, --#ifdef VEOL2 -+#if VEOL2 - CIDX_eol2, - #endif --#ifdef VSWTCH -+#if VSWTCH - CIDX_swtch, - #endif - CIDX_start, - CIDX_stop, - CIDX_susp, --#ifdef VDSUSP -+#if VDSUSP - CIDX_dsusp, - #endif --#ifdef VREPRINT -+#if VREPRINT - CIDX_rprnt, - #endif --#ifdef VWERASE -+#if VWERASE - CIDX_werase, - #endif --#ifdef VLNEXT -+#if VLNEXT - CIDX_lnext, - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CIDX_flush, - #endif --#ifdef VSTATUS -+#if VSTATUS - CIDX_status, - #endif - CIDX_min, -@@ -538,31 +653,31 @@ static const char control_name[] = - CI_ENTRY("kill", CKILL, VKILL ) - CI_ENTRY("eof", CEOF, VEOF ) - CI_ENTRY("eol", CEOL, VEOL ) --#ifdef VEOL2 -+#if VEOL2 - CI_ENTRY("eol2", CEOL2, VEOL2 ) - #endif --#ifdef VSWTCH -+#if VSWTCH - CI_ENTRY("swtch", CSWTCH, VSWTCH ) - #endif - CI_ENTRY("start", CSTART, VSTART ) - CI_ENTRY("stop", CSTOP, VSTOP ) - CI_ENTRY("susp", CSUSP, VSUSP ) --#ifdef VDSUSP -+#if VDSUSP - CI_ENTRY("dsusp", CDSUSP, VDSUSP ) - #endif --#ifdef VREPRINT -+#if VREPRINT - CI_ENTRY("rprnt", CRPRNT, VREPRINT) - #endif --#ifdef VWERASE -+#if VWERASE - CI_ENTRY("werase", CWERASE, VWERASE ) - #endif --#ifdef VLNEXT -+#if VLNEXT - CI_ENTRY("lnext", CLNEXT, VLNEXT ) - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CI_ENTRY("flush", CFLUSHO, VFLUSHO ) - #endif --#ifdef VSTATUS -+#if VSTATUS - CI_ENTRY("status", CSTATUS, VSTATUS ) - #endif - /* These must be last because of the display routines */ -@@ -581,31 +696,31 @@ static const struct control_info control_info[] = { - CI_ENTRY("kill", CKILL, VKILL ) - CI_ENTRY("eof", CEOF, VEOF ) - CI_ENTRY("eol", CEOL, VEOL ) --#ifdef VEOL2 -+#if VEOL2 - CI_ENTRY("eol2", CEOL2, VEOL2 ) - #endif --#ifdef VSWTCH -+#if VSWTCH - CI_ENTRY("swtch", CSWTCH, VSWTCH ) - #endif - CI_ENTRY("start", CSTART, VSTART ) - CI_ENTRY("stop", CSTOP, VSTOP ) - CI_ENTRY("susp", CSUSP, VSUSP ) --#ifdef VDSUSP -+#if VDSUSP - CI_ENTRY("dsusp", CDSUSP, VDSUSP ) - #endif --#ifdef VREPRINT -+#if VREPRINT - CI_ENTRY("rprnt", CRPRNT, VREPRINT) - #endif --#ifdef VWERASE -+#if VWERASE - CI_ENTRY("werase", CWERASE, VWERASE ) - #endif --#ifdef VLNEXT -+#if VLNEXT - CI_ENTRY("lnext", CLNEXT, VLNEXT ) - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CI_ENTRY("flush", CFLUSHO, VFLUSHO ) - #endif --#ifdef VSTATUS -+#if VSTATUS - CI_ENTRY("status", CSTATUS, VSTATUS ) - #endif - /* These must be last because of the display routines */ -@@ -740,6 +855,7 @@ static void newline(void) - wrapf("\n"); - } - -+#ifdef TIOCGWINSZ - static void set_window_size(int rows, int cols) - { - struct winsize win = { 0, 0, 0, 0 }; -@@ -760,6 +876,7 @@ static void set_window_size(int rows, int cols) - bail: - perror_on_device("%s"); - } -+#endif - - static void display_window_size(int fancy) - { -@@ -973,41 +1090,6 @@ static void sane_mode(struct termios *mode) - } - } - --/* Save set_mode from #ifdef forest plague */ --#ifndef ONLCR --#define ONLCR 0 --#endif --#ifndef OCRNL --#define OCRNL 0 --#endif --#ifndef ONLRET --#define ONLRET 0 --#endif --#ifndef XCASE --#define XCASE 0 --#endif --#ifndef IXANY --#define IXANY 0 --#endif --#ifndef TABDLY --#define TABDLY 0 --#endif --#ifndef OXTABS --#define OXTABS 0 --#endif --#ifndef IUCLC --#define IUCLC 0 --#endif --#ifndef OLCUC --#define OLCUC 0 --#endif --#ifndef ECHOCTL --#define ECHOCTL 0 --#endif --#ifndef ECHOKE --#define ECHOKE 0 --#endif -- - static void set_mode(const struct mode_info *info, int reversed, - struct termios *mode) - { -@@ -1093,27 +1175,32 @@ static void set_mode(const struct mode_info *info, int reversed, - mode->c_cc[VTIME] = 0; - } - } -- else if (IXANY && info == &mode_info[IDX_decctlq]) { -+#if IXANY -+ else if (info == &mode_info[IDX_decctlq]) { - if (reversed) - mode->c_iflag |= IXANY; - else - mode->c_iflag &= ~IXANY; - } -- else if (TABDLY && info == &mode_info[IDX_tabs]) { -+#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; - } -- else if (OXTABS && info == &mode_info[IDX_tabs]) { -+#endif -+#if OXTABS -+ else if (info == &mode_info[IDX_tabs]) { - if (reversed) - mode->c_oflag |= OXTABS; - else - mode->c_oflag &= ~OXTABS; -- } else -- if (XCASE && IUCLC && OLCUC -- && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE]) -- ) { -+ } -+#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; -@@ -1123,7 +1210,9 @@ static void set_mode(const struct mode_info *info, int reversed, - mode->c_iflag |= IUCLC; - mode->c_oflag |= OLCUC; - } -- } else if (info == &mode_info[IDX_crt]) { -+ } -+#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 */ -@@ -1419,7 +1508,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) - perror_on_device_and_die("%s"); - - if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { --#ifdef CIBAUD -+#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 --- -1.7.1 - diff --git a/debian/patches/swaponoff-FreeBSD-support.patch b/debian/patches/swaponoff-FreeBSD-support.patch deleted file mode 100644 index da273f5..0000000 --- a/debian/patches/swaponoff-FreeBSD-support.patch +++ /dev/null @@ -1,138 +0,0 @@ -From a5b837c34a96bdbb53151af455912b691c9aaa52 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 21:59:54 +0200 -Subject: [PATCH 19/19] swaponoff: FreeBSD support - - -Signed-off-by: Jeremie Koenig ---- - util-linux/Config.src | 3 +-- - util-linux/swaponoff.c | 6 +++--- - util-linux/xmount.c | 10 ++++++++++ - util-linux/xmount.h | 16 ++++++++++------ - 4 files changed, 24 insertions(+), 11 deletions(-) - -diff --git a/util-linux/Config.src b/util-linux/Config.src -index 99a6fbe..cb4de95 100644 ---- a/util-linux/Config.src -+++ b/util-linux/Config.src -@@ -639,7 +639,6 @@ config SETARCH - config SWAPONOFF - bool "swaponoff" - default y -- depends on PLATFORM_LINUX - help - This option enables both the 'swapon' and the 'swapoff' utilities. - Once you have created some swap space using 'mkswap', you also need -@@ -651,7 +650,7 @@ config SWAPONOFF - config FEATURE_SWAPON_PRI - bool "Support priority option -p" - default y -- depends on SWAPONOFF -+ depends on SWAPONOFF && PLATFORM_LINUX - help - Enable support for setting swap device priority in swapon. - -diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c -index f2f52fb..d13c37e 100644 ---- a/util-linux/swaponoff.c -+++ b/util-linux/swaponoff.c -@@ -8,8 +8,8 @@ - */ - - #include "libbb.h" -+#include "xmount.h" - #include --#include - - #if ENABLE_FEATURE_MOUNT_LABEL - # include "volume_id.h" -@@ -43,9 +43,9 @@ static int swap_enable_disable(char *device) - #endif - - if (applet_name[5] == 'n') -- status = swapon(device, g_flags); -+ status = xswapon(device, g_flags); - else -- status = swapoff(device); -+ status = xswapoff(device); - - if (status != 0) { - bb_simple_perror_msg(device); -diff --git a/util-linux/xmount.c b/util-linux/xmount.c -index 3f322b8..16543f1 100644 ---- a/util-linux/xmount.c -+++ b/util-linux/xmount.c -@@ -63,4 +63,14 @@ int FAST_FUNC xumount(const char *target, int flags) - return unmount(target, flags); - } - -+int FAST_FUNC xswapon(const char *path, int swapflags UNUSED_PARAM) -+{ -+ return swapon(path); -+} -+ -+int FAST_FUNC xswapoff(const char *path) -+{ -+ return swapoff(path); -+} -+ - #endif -diff --git a/util-linux/xmount.h b/util-linux/xmount.h -index caef564..bcd6d18 100644 ---- a/util-linux/xmount.h -+++ b/util-linux/xmount.h -@@ -5,9 +5,9 @@ - * Copyright (C) 2010 by Jeremie Koenig - * Copyright (C) 2010 by Luca Favatella - * -- * The Linux prototypes for mount() and umount2() are used as a reference for -- * our xmount() and xumount(), which should be implemented as a compatibility -- * wrappers for non-Linux systems (see xmount.c). -+ * The Linux prototypes for mount(), umount2(), swapon() and swapoff() are -+ * used as a reference for our versions of them. On non-Linux system those -+ * should be implemented as compatibility wrappers (see xmount.c). - */ - - /* -@@ -17,6 +17,7 @@ - - #ifdef __linux__ - # include -+# include - /* Make sure we have all the new mount flags we actually try to use - * (grab more as needed from util-linux's mount/mount_constants.h). */ - # ifndef MS_DIRSYNC -@@ -56,6 +57,7 @@ - - #elif defined(__FreeBSD_kernel__) - # include -+# include - # define MS_NOSUID MNT_NOSUID - # define MS_NODEV MNT_NODEV - # define MS_NOEXEC MNT_NOEXEC -@@ -82,16 +84,18 @@ - #endif - - /* -- * Prototypes for xmount() and xumount(): on Linux we use the system calls -- * directly, otherwise xmount() and xumount() should be implemented as -- * compatibility wrappers (see xmount.c). -+ * Prototypes for the compatibility wrappers - */ - - #ifdef __linux__ - # define xmount mount - # define xumount umount2 -+# define xswapon swapon -+# define xswapoff swapoff - #else - int xmount(const char *source, const char *target, const char *filesystemtype, - unsigned long mountflags, const void *data) FAST_FUNC; - int xumount(const char *target, int flags) FAST_FUNC; -+int xswapon(const char *path, int swapflags) FAST_FUNC; -+int xswapoff(const char *path) FAST_FUNC; - #endif --- -1.7.1 - diff --git a/debian/patches/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch b/debian/patches/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch deleted file mode 100644 index eb797bc..0000000 --- a/debian/patches/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 2ea12d8b6d2a36c5d49df1ae97b86ba287835249 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:25 +0200 -Subject: [PATCH 9/9] tcpsvd,udpsvd: conditionalize usage of SO_ORIGINAL_DST - -On systems without this call, $TCPORIGDSTADDR is not set. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - networking/Config.src | 2 -- - networking/tcpudp.c | 5 +++++ - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/networking/Config.src b/networking/Config.src -index fc613e8..2d29c42 100644 ---- a/networking/Config.src -+++ b/networking/Config.src -@@ -733,7 +733,6 @@ config SLATTACH - config TCPSVD - bool "tcpsvd" - default y -- depends on PLATFORM_LINUX - help - tcpsvd listens on a TCP port and runs a program for each new - connection. -@@ -966,7 +965,6 @@ config IFUPDOWN_UDHCPC_CMD_OPTIONS - config UDPSVD - bool "udpsvd" - default y -- depends on PLATFORM_LINUX - help - udpsvd listens on an UDP port and runs a program for each new - connection. -diff --git a/networking/tcpudp.c b/networking/tcpudp.c -index 53e622b..40f6825 100644 ---- a/networking/tcpudp.c -+++ b/networking/tcpudp.c -@@ -30,9 +30,12 @@ - */ - - #include "libbb.h" -+ - /* Wants etc, thus included after libbb.h: */ -+#ifdef __linux__ - #include /* for __be32 etc */ - #include -+#endif - - // TODO: move into this file: - #include "tcpudp_perhost.h" -@@ -464,6 +467,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) - /* setup ucspi env */ - const char *proto = tcp ? "TCP" : "UDP"; - -+#ifdef SO_ORIGINAL_DST - /* Extract "original" destination addr:port - * from Linux firewall. Useful when you redirect - * an outbond connection to local handler, and it needs -@@ -473,6 +477,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) - xsetenv_plain("TCPORIGDSTADDR", addr); - free(addr); - } -+#endif - xsetenv_plain("PROTO", proto); - xsetenv_proto(proto, "LOCALADDR", local_addr); - xsetenv_proto(proto, "REMOTEADDR", remote_addr); --- -1.7.1 - diff --git a/debian/patches/top-display-rss.patch b/debian/patches/top-display-rss.patch deleted file mode 100644 index e7776f1..0000000 --- a/debian/patches/top-display-rss.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/procps/top.c b/procps/top.c -index ec84374..9049578 100644 ---- a/procps/top.c -+++ b/procps/top.c -@@ -35,7 +35,7 @@ - - - typedef struct top_status_t { -- unsigned long vsz; -+ unsigned long rss; - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - unsigned long ticks; - unsigned pcpu; /* delta of ticks */ -@@ -147,8 +147,8 @@ static int pid_sort(top_status_t *P, top_status_t *Q) - static int mem_sort(top_status_t *P, top_status_t *Q) - { - /* We want to avoid unsigned->signed and truncation errors */ -- if (Q->vsz < P->vsz) return -1; -- return Q->vsz != P->vsz; /* 0 if ==, 1 if > */ -+ if (Q->rss < P->rss) return -1; -+ return Q->rss != P->rss; /* 0 if ==, 1 if > */ - } - - -@@ -519,7 +519,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) - - /* what info of the processes is shown */ - printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width, -- " PID PPID USER STAT VSZ %MEM" -+ " PID PPID USER STAT RSS %MEM" - IF_FEATURE_TOP_SMP_PROCESS(" CPU") - IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") - " COMMAND"); -@@ -588,16 +588,16 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) - s = top; - while (--lines_rem >= 0) { - unsigned col; -- CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); -+ CALC_STAT(pmem, (s->rss*pmem_scale + pmem_half) >> pmem_shift); - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); - #endif - -- if (s->vsz >= 100000) -- sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); -+ if (s->rss >= 100000) -+ sprintf(vsz_str_buf, "%6ldm", s->rss/1024); - else -- sprintf(vsz_str_buf, "%7ld", s->vsz); -- /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */ -+ sprintf(vsz_str_buf, "%7ld", s->rss); -+ /* PID PPID USER STAT VSZ %RSS [%CPU] COMMAND */ - col = snprintf(line_buf, scr_width, - "\n" "%5u%6u %-8.8s %s%s" FMT - IF_FEATURE_TOP_SMP_PROCESS(" %3d") -@@ -929,7 +929,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) - top = xrealloc_vector(top, 6, ntop++); - top[n].pid = p->pid; - top[n].ppid = p->ppid; -- top[n].vsz = p->vsz; -+ top[n].rss = p->rss; - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - top[n].ticks = p->stime + p->utime; - #endif diff --git a/debian/patches/u-mount-FreeBSD-support.patch b/debian/patches/u-mount-FreeBSD-support.patch deleted file mode 100644 index 702c051..0000000 --- a/debian/patches/u-mount-FreeBSD-support.patch +++ /dev/null @@ -1,386 +0,0 @@ -From 5a075618b1deb735a6170e322052c7ba54b17d9e Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 21:16:09 +0200 -Subject: [PATCH 18/19] (u)mount: FreeBSD support - - -Signed-off-by: Jeremie Koenig ---- - util-linux/Config.src | 4 +-- - util-linux/Kbuild.src | 4 +- - util-linux/mount.c | 41 ++------------------- - util-linux/umount.c | 41 +++------------------ - util-linux/xmount.c | 66 +++++++++++++++++++++++++++++++++ - util-linux/xmount.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 174 insertions(+), 79 deletions(-) - create mode 100644 util-linux/xmount.c - create mode 100644 util-linux/xmount.h - -diff --git a/util-linux/Config.src b/util-linux/Config.src -index 98953c1..99a6fbe 100644 ---- a/util-linux/Config.src -+++ b/util-linux/Config.src -@@ -492,7 +492,6 @@ config FEATURE_USE_TERMIOS - config MOUNT - bool "mount" - default y -- depends on PLATFORM_LINUX - help - All files and filesystems in Unix are arranged into one big directory - tree. The 'mount' utility is used to graft a filesystem onto a -@@ -679,7 +678,6 @@ config SWITCH_ROOT - config UMOUNT - bool "umount" - default y -- depends on PLATFORM_LINUX - help - When you want to remove a mounted filesystem from its current mount - point, for example when you are shutting down the system, the -@@ -699,7 +697,7 @@ comment "Common options for mount/umount" - config FEATURE_MOUNT_LOOP - bool "Support loopback mounts" - default y -- depends on MOUNT || UMOUNT -+ depends on (MOUNT || UMOUNT) && PLATFORM_LINUX - help - Enabling this feature allows automatic mounting of files (containing - filesystem images) via the linux kernel's loopback devices. -diff --git a/util-linux/Kbuild.src b/util-linux/Kbuild.src -index afc0db5..312fc9e 100644 ---- a/util-linux/Kbuild.src -+++ b/util-linux/Kbuild.src -@@ -33,7 +33,7 @@ lib-$(CONFIG_MKFS_REISER) += mkfs_reiser.o - lib-$(CONFIG_MKFS_VFAT) += mkfs_vfat.o - lib-$(CONFIG_MKSWAP) += mkswap.o - lib-$(CONFIG_MORE) += more.o --lib-$(CONFIG_MOUNT) += mount.o -+lib-$(CONFIG_MOUNT) += mount.o xmount.o - lib-$(CONFIG_PIVOT_ROOT) += pivot_root.o - lib-$(CONFIG_RDATE) += rdate.o - lib-$(CONFIG_RDEV) += rdev.o -@@ -44,4 +44,4 @@ lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o - lib-$(CONFIG_SETARCH) += setarch.o - lib-$(CONFIG_SWAPONOFF) += swaponoff.o - lib-$(CONFIG_SWITCH_ROOT) += switch_root.o --lib-$(CONFIG_UMOUNT) += umount.o -+lib-$(CONFIG_UMOUNT) += umount.o xmount.o -diff --git a/util-linux/mount.c b/util-linux/mount.c -index 9107e43..a62c4e8 100644 ---- a/util-linux/mount.c -+++ b/util-linux/mount.c -@@ -18,44 +18,9 @@ - // - #include - #include --#include --// Grab more as needed from util-linux's mount/mount_constants.h --#ifndef MS_DIRSYNC --# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous --#endif --#ifndef MS_UNION --# define MS_UNION (1 << 8) --#endif --#ifndef MS_BIND --# define MS_BIND (1 << 12) --#endif --#ifndef MS_MOVE --# define MS_MOVE (1 << 13) --#endif --#ifndef MS_RECURSIVE --# define MS_RECURSIVE (1 << 14) --#endif --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --// The shared subtree stuff, which went in around 2.6.15 --#ifndef MS_UNBINDABLE --# define MS_UNBINDABLE (1 << 17) --#endif --#ifndef MS_PRIVATE --# define MS_PRIVATE (1 << 18) --#endif --#ifndef MS_SLAVE --# define MS_SLAVE (1 << 19) --#endif --#ifndef MS_SHARED --# define MS_SHARED (1 << 20) --#endif --#ifndef MS_RELATIME --# define MS_RELATIME (1 << 21) --#endif - - #include "libbb.h" -+#include "xmount.h" - #if ENABLE_FEATURE_MOUNT_LABEL - # include "volume_id.h" - #else -@@ -288,7 +253,7 @@ static int verbose_mount(const char *source, const char *target, - int rc; - - errno = 0; -- rc = mount(source, target, filesystemtype, mountflags, data); -+ rc = xmount(source, target, filesystemtype, mountflags, data); - if (verbose >= 2) - bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d", - source, target, filesystemtype, -@@ -296,7 +261,7 @@ static int verbose_mount(const char *source, const char *target, - return rc; - } - #else --#define verbose_mount(...) mount(__VA_ARGS__) -+#define verbose_mount(...) xmount(__VA_ARGS__) - #endif - - // Append mount options to string -diff --git a/util-linux/umount.c b/util-linux/umount.c -index a19f86c..781e019 100644 ---- a/util-linux/umount.c -+++ b/util-linux/umount.c -@@ -8,40 +8,9 @@ - * Licensed under GPL version 2, see file LICENSE in this tarball for details. - */ - #include --#include --/* Make sure we have all the new mount flags we actually try to use. */ --#ifndef MS_BIND --# define MS_BIND (1 << 12) --#endif --#ifndef MS_MOVE --# define MS_MOVE (1 << 13) --#endif --#ifndef MS_RECURSIVE --# define MS_RECURSIVE (1 << 14) --#endif --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --/* The shared subtree stuff, which went in around 2.6.15. */ --#ifndef MS_UNBINDABLE --# define MS_UNBINDABLE (1 << 17) --#endif --#ifndef MS_PRIVATE --# define MS_PRIVATE (1 << 18) --#endif --#ifndef MS_SLAVE --# define MS_SLAVE (1 << 19) --#endif --#ifndef MS_SHARED --# define MS_SHARED (1 << 20) --#endif --#ifndef MS_RELATIME --# define MS_RELATIME (1 << 21) --#endif -+ - #include "libbb.h" --#ifndef PATH_MAX --# define PATH_MAX (4*1024) --#endif -+#include "xmount.h" - - - #if defined(__dietlibc__) -@@ -154,11 +123,11 @@ int umount_main(int argc UNUSED_PARAM, char **argv) - if (m) zapit = m->dir; - - // Let's ask the thing nicely to unmount. -- curstat = umount(zapit); -+ curstat = xumount(zapit, 0); - - // Force the unmount, if necessary. - if (curstat && doForce) -- curstat = umount2(zapit, doForce); -+ curstat = xumount(zapit, doForce); - - // If still can't umount, maybe remount read-only? - if (curstat) { -@@ -166,7 +135,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) - // Note! Even if we succeed here, later we should not - // free loop device or erase mtab entry! - const char *msg = "%s busy - remounted read-only"; -- curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL); -+ curstat = xmount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL); - if (curstat) { - msg = "can't remount %s read-only"; - status = EXIT_FAILURE; -diff --git a/util-linux/xmount.c b/util-linux/xmount.c -new file mode 100644 -index 0000000..3f322b8 ---- /dev/null -+++ b/util-linux/xmount.c -@@ -0,0 +1,70 @@ -+#include "libbb.h" -+#include "xmount.h" -+ -+#ifdef __linux__ -+ -+/* xmount and xumount short-circuited to mount and umount2 in xmount.h */ -+ -+#elif defined(__FreeBSD_kernel__) -+ -+static void build_iovec(struct iovec **iov, int *iovlen, const char *name, -+ void *val, size_t len) -+{ -+ int i; -+ -+ if (*iovlen < 0) -+ return; -+ i = *iovlen; -+ *iov = realloc(*iov, sizeof **iov * (i + 2)); -+ if (*iov == NULL) { -+ *iovlen = -1; -+ return; -+ } -+ (*iov)[i].iov_base = strdup(name); -+ (*iov)[i].iov_len = strlen(name) + 1; -+ i++; -+ (*iov)[i].iov_base = val; -+ if (len == (size_t)-1) { -+ if (val != NULL) -+ len = strlen(val) + 1; -+ else -+ len = 0; -+ } -+ (*iov)[i].iov_len = (int)len; -+ *iovlen = ++i; -+} -+ -+int FAST_FUNC xmount(const char *source, const char *target, -+ const char *filesystemtype, unsigned long mountflags, -+ const void *data UNUSED_PARAM) -+{ -+ struct iovec *iov = NULL; -+ int iovlen = 0; -+ char *fspath, *from; -+ int ret; -+ -+ fspath = realpath(target, NULL); -+ from = realpath(source, NULL); -+ -+ build_iovec(&iov, &iovlen, "fstype", (void*)filesystemtype, (size_t)-1); -+ build_iovec(&iov, &iovlen, "fspath", fspath, (size_t)-1); -+ if (!strcmp(filesystemtype, "nullfs")) -+ /* nullfs uses a "target" instead of "from" */ -+ build_iovec(&iov, &iovlen, "target", from, (size_t)-1); -+ else -+ build_iovec(&iov, &iovlen, "from", from, (size_t)-1); -+ -+ ret = nmount(iov, iovlen, mountflags); -+ -+ free(from); -+ free(fspath); -+ -+ return ret; -+} -+ -+int FAST_FUNC xumount(const char *target, int flags) -+{ -+ return unmount(target, flags); -+} -+ -+#endif -diff --git a/util-linux/xmount.h b/util-linux/xmount.h -new file mode 100644 -index 0000000..caef564 ---- /dev/null -+++ b/util-linux/xmount.h -@@ -0,0 +1,97 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * System-specific definitions for mount. -+ * -+ * Copyright (C) 2010 by Jeremie Koenig -+ * Copyright (C) 2010 by Luca Favatella -+ * -+ * The Linux prototypes for mount() and umount2() are used as a reference for -+ * our xmount() and xumount(), which should be implemented as a compatibility -+ * wrappers for non-Linux systems (see xmount.c). -+ */ -+ -+/* -+ * Definitions for mount flags. Non-Linux systems are free to use whatever -+ * their version of xmount() will work with. -+ */ -+ -+#ifdef __linux__ -+# include -+/* Make sure we have all the new mount flags we actually try to use -+ * (grab more as needed from util-linux's mount/mount_constants.h). */ -+# ifndef MS_DIRSYNC -+# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous -+# endif -+# ifndef MS_UNION -+# define MS_UNION (1 << 8) -+# endif -+# ifndef MS_BIND -+# define MS_BIND (1 << 12) -+# endif -+# ifndef MS_MOVE -+# define MS_MOVE (1 << 13) -+# endif -+# ifndef MS_RECURSIVE -+# define MS_RECURSIVE (1 << 14) -+# endif -+# ifndef MS_SILENT -+# define MS_SILENT (1 << 15) -+# endif -+/* The shared subtree stuff, which went in around 2.6.15. */ -+# ifndef MS_UNBINDABLE -+# define MS_UNBINDABLE (1 << 17) -+# endif -+# ifndef MS_PRIVATE -+# define MS_PRIVATE (1 << 18) -+# endif -+# ifndef MS_SLAVE -+# define MS_SLAVE (1 << 19) -+# endif -+# ifndef MS_SHARED -+# define MS_SHARED (1 << 20) -+# endif -+# ifndef MS_RELATIME -+# define MS_RELATIME (1 << 21) -+# endif -+ -+#elif defined(__FreeBSD_kernel__) -+# include -+# define MS_NOSUID MNT_NOSUID -+# define MS_NODEV MNT_NODEV -+# define MS_NOEXEC MNT_NOEXEC -+# define MS_SYNCHRONOUS MNT_SYNCHRONOUS -+# define MS_DIRSYNC 0 -+# define MS_NOATIME MNT_NOATIME -+# define MS_NODIRATIME 0 -+# define MS_MANDLOCK 0 -+# define MS_RELATIME 0 -+# define MS_SILENT 0 -+# define MS_UNION MNT_UNION -+# define MS_BIND 0 -+# define MS_MOVE 0 -+# define MS_SHARED 0 -+# define MS_SLAVE 0 -+# define MS_PRIVATE 0 -+# define MS_UNBINDABLE 0 -+# define MS_RECURSIVE 0 -+# define MS_RDONLY MNT_RDONLY -+# define MS_REMOUNT MNT_UPDATE -+ -+#else -+# error There is no xmount() implementation for your system. -+#endif -+ -+/* -+ * Prototypes for xmount() and xumount(): on Linux we use the system calls -+ * directly, otherwise xmount() and xumount() should be implemented as -+ * compatibility wrappers (see xmount.c). -+ */ -+ -+#ifdef __linux__ -+# define xmount mount -+# define xumount umount2 -+#else -+int xmount(const char *source, const char *target, const char *filesystemtype, -+ unsigned long mountflags, const void *data) FAST_FUNC; -+int xumount(const char *target, int flags) FAST_FUNC; -+#endif --- -1.7.1 - diff --git a/debian/patches/udhcpc-fast-request.patch b/debian/patches/udhcpc-fast-request.patch deleted file mode 100644 index 47f5f3e..0000000 --- a/debian/patches/udhcpc-fast-request.patch +++ /dev/null @@ -1,129 +0,0 @@ -From: Hakgoo Lee -Date: Thu, 16 Sep 2010 14:51:22 +0900 -Subject: [PATCH] Add FEATURE_UDHCPC_FAST_REQUEST to udhcp. - -If selected, udhcpc will send Request if leased IP and DHCP server is specified. -So Discover/Offer routine can be skipped. It can reduce service recovery time in WiFi. ---- - include/usage.src.h | 4 ++++ - networking/udhcp/Config.src | 8 ++++++++ - networking/udhcp/dhcpc.c | 28 ++++++++++++++++++++++++++++ - 3 files changed, 40 insertions(+), 0 deletions(-) - -diff --git a/include/usage.src.h b/include/usage.src.h -index 94a3256..e3c987c 100644 ---- a/include/usage.src.h -+++ b/include/usage.src.h -@@ -4539,6 +4539,10 @@ INSERT - IF_FEATURE_UDHCPC_ARPING( \ - "\n -a,--arping Use arping to validate offered address" \ - ) \ -+ IF_FEATURE_UDHCPC_FAST_REQUEST( \ -+ "\n -d,--request-direct=IP IP address to request without discover, must be used with -D" \ -+ "\n -D,--dhcp-server=IP DHCP server IP address to get leased IP address" \ -+ ) \ - "\n -O,--request-option OPT Request DHCP option OPT (cumulative)" \ - "\n -o,--no-default-options Don't request any options (unless -O is given)" \ - "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" \ -diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src -index 331dffc..c4ec82f 100644 ---- a/networking/udhcp/Config.src -+++ b/networking/udhcp/Config.src -@@ -130,3 +130,11 @@ config UDHCPC_SLACK_FOR_BUGGY_SERVERS - maximum size of entire IP packet, and sends packets which are - 28 bytes too large. - Seednet (ISP) VDSL: sends packets 2 bytes too large. -+ -+config FEATURE_UDHCPC_FAST_REQUEST -+ bool "Send Fast Request without Discover/Offer (e.g. When same subnet is connected again like WiFi AP)." -+ default y -+ depends on UDHCPC -+ help -+ If selected, udhcpc will send Request if leased IP and DHCP server is specified. -+ So Discover/Offer routine can be skipped. It can reduce service recovery time in WiFi. -diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c -index de1b798..e740871 100644 ---- a/networking/udhcp/dhcpc.c -+++ b/networking/udhcp/dhcpc.c -@@ -767,6 +767,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - { - uint8_t *temp, *message; - const char *str_c, *str_V, *str_h, *str_F, *str_r; -+ IF_FEATURE_UDHCPC_FAST_REQUEST(char *str_d, *str_D;) - IF_FEATURE_UDHCP_PORT(char *str_P;) - llist_t *list_O = NULL; - llist_t *list_x = NULL; -@@ -812,6 +813,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - "background\0" No_argument "b" - IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") - IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("request-direct\0" Required_argument "d") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("dhcp-server\0" Required_argument "D") - ; - #endif - enum { -@@ -841,9 +844,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - USE_FOR_MMU( OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPTBIT_P,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPTBIT_d,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPTBIT_D,) - USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPT_d = 1 << OPTBIT_d,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPT_D = 1 << OPTBIT_D,) - }; - - /* Default options. */ -@@ -865,6 +872,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - USE_FOR_MMU("b") - IF_FEATURE_UDHCPC_ARPING("a") - IF_FEATURE_UDHCP_PORT("P:") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("d:D:") - "v" - , &str_c, &str_V, &str_h, &str_h, &str_F - , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ -@@ -873,6 +881,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - , &list_O - , &list_x - IF_FEATURE_UDHCP_PORT(, &str_P) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(, &str_d, &str_D) - #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose - #endif -@@ -950,6 +959,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - logmode |= LOGMODE_SYSLOG; - } - -+#if ENABLE_FEATURE_UDHCPC_FAST_REQUEST -+ if (opt & OPT_d) { -+ log1("Parsing request-direct option"); -+ requested_ip = inet_addr(str_d); -+ state = REQUESTING; -+ } -+ if (opt & OPT_D) { -+ log1("Parsing dhcp-server option"); -+ server_addr = inet_addr(str_D); -+ } -+#endif -+ - /* Make sure fd 0,1,2 are open */ - bb_sanitize_stdio(); - /* Equivalent of doing a fflush after every \n */ -@@ -963,7 +984,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - /* We want random_xid to be random... */ - srand(monotonic_us()); - -+#if ENABLE_FEATURE_UDHCPC_FAST_REQUEST -+ if (state != REQUESTING) -+ state = INIT_SELECTING; -+ log1("Initial state is %d", state); -+#else - state = INIT_SELECTING; -+#endif -+ - udhcp_run_script(NULL, "deconfig"); - change_listen_mode(LISTEN_RAW); - packet_num = 0; --- diff --git a/debian/patches/update-scripts-kconfig-_shipped.patch b/debian/patches/update-scripts-kconfig-_shipped.patch deleted file mode 100644 index 52cc64e..0000000 --- a/debian/patches/update-scripts-kconfig-_shipped.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit 6e06da5efd5d6e341ae2f5116c449994740f5613 -Author: Denys Vlasenko -Date: Mon Aug 2 02:17:25 2010 +0200 - - update _shipped file with hurd fix - - Signed-off-by: Denys Vlasenko - -diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped -index 4837bbf..51f15e1 100644 ---- a/scripts/kconfig/lex.zconf.c_shipped -+++ b/scripts/kconfig/lex.zconf.c_shipped -@@ -2235,13 +2235,14 @@ static void zconf_endhelp(void) - */ - FILE *zconf_fopen(const char *name) - { -- char *env, fullname[PATH_MAX+1]; -+ char *env; - FILE *f; - - f = fopen(name, "r"); - if (!f && name[0] != '/') { - env = getenv(SRCTREE); - if (env) { -+ char *fullname = alloca(strlen(env) + strlen(name) + 2); - sprintf(fullname, "%s/%s", env, name); - f = fopen(fullname, "r"); - } diff --git a/debian/patches/version.patch b/debian/patches/version.patch deleted file mode 100644 index a09b782..0000000 --- a/debian/patches/version.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/Makefile.flags -+++ b/Makefile.flags -@@ -4,6 +4,11 @@ - - BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) - export BB_VER -+ifndef BB_EXTRA_VERSION -+BB_BT = AUTOCONF_TIMESTAMP -+else -+BB_BT = KBUILD_STR($(BB_EXTRA_VERSION)) -+endif - SKIP_STRIP = n - - # -std=gnu99 needed for [U]LLONG_MAX on some systems -@@ -15,7 +20,7 @@ - -include include/autoconf.h \ - -D_GNU_SOURCE -DNDEBUG \ - $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ -- -D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP -+ -D"BB_VER=KBUILD_STR($(BB_VER))" -D"BB_BT=$(BB_BT)" - - CFLAGS += $(call cc-option,-Wall,) - CFLAGS += $(call cc-option,-Wshadow,) diff --git a/debian/patches/vlock-disable-linux-console-calls-on-other-systems.patch b/debian/patches/vlock-disable-linux-console-calls-on-other-systems.patch deleted file mode 100644 index f717473..0000000 --- a/debian/patches/vlock-disable-linux-console-calls-on-other-systems.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 68fca4cd55e7bf6075eb1ccd303ae57a7ec1b8da Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:52 +0200 -Subject: [PATCH 12/12] vlock: disable linux console calls on other systems - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - loginutils/Config.src | 1 - - loginutils/vlock.c | 15 +++++++++++++-- - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/loginutils/Config.src b/loginutils/Config.src -index 6ec2893..5d497c4 100644 ---- a/loginutils/Config.src -+++ b/loginutils/Config.src -@@ -295,7 +295,6 @@ config SULOGIN - config VLOCK - bool "vlock" - default y -- depends on PLATFORM_LINUX - select FEATURE_SUID - help - Build the "vlock" applet which allows you to lock (virtual) terminals. -diff --git a/loginutils/vlock.c b/loginutils/vlock.c -index 85f489c..59aeb54 100644 ---- a/loginutils/vlock.c -+++ b/loginutils/vlock.c -@@ -15,9 +15,11 @@ - /* Fixed by Erik Andersen to do passwords the tinylogin way... - * It now works with md5, sha1, etc passwords. */ - --#include - #include "libbb.h" - -+#ifdef __linux__ -+#include -+ - static void release_vt(int signo UNUSED_PARAM) - { - /* If -a, param is 0, which means: -@@ -30,14 +32,17 @@ static void acquire_vt(int signo UNUSED_PARAM) - /* ACK to kernel that switch to console is successful */ - ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); - } -+#endif - - int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int vlock_main(int argc UNUSED_PARAM, char **argv) - { -+#ifdef __linux__ - struct vt_mode vtm; -+ struct vt_mode ovtm; -+#endif - struct termios term; - struct termios oterm; -- struct vt_mode ovtm; - struct passwd *pw; - - pw = xgetpwuid(getuid()); -@@ -55,6 +60,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - + (1 << SIGINT ) - , SIG_IGN); - -+#ifdef __linux__ - /* We will use SIGUSRx for console switch control: */ - /* 1: set handlers */ - signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); -@@ -62,12 +68,14 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - /* 2: unmask them */ - sig_unblock(SIGUSR1); - sig_unblock(SIGUSR2); -+#endif - - /* Revert stdin/out to our controlling tty - * (or die if we have none) */ - xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); - xdup2(STDIN_FILENO, STDOUT_FILENO); - -+#ifdef __linux__ - xioctl(STDIN_FILENO, VT_GETMODE, &vtm); - ovtm = vtm; - /* "console switches are controlled by us, not kernel!" */ -@@ -75,6 +83,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - vtm.relsig = SIGUSR1; - vtm.acqsig = SIGUSR2; - ioctl(STDIN_FILENO, VT_SETMODE, &vtm); -+#endif - - tcgetattr(STDIN_FILENO, &oterm); - term = oterm; -@@ -95,7 +104,9 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - puts("Password incorrect"); - } while (1); - -+#ifdef __linux__ - ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); -+#endif - tcsetattr_stdin_TCSANOW(&oterm); - fflush_stdout_and_exit(EXIT_SUCCESS); - } --- -1.7.1 - diff --git a/debian/rules b/debian/rules deleted file mode 100755 index 10aeec8..0000000 --- a/debian/rules +++ /dev/null @@ -1,211 +0,0 @@ -#!/usr/bin/make -f - -SHELL := sh -e -DEB_HOST_ARCH := $(shell dpkg-architecture -qDEB_HOST_ARCH) -DEB_HOST_ARCH_OS := $(shell dpkg-architecture -qDEB_HOST_ARCH_OS) -DEB_BUILD_ARCH := $(shell dpkg-architecture -qDEB_BUILD_ARCH) -SOURCE := $(shell dpkg-parsechangelog | sed -ne 's,^Source: *\(.*\)$$,\1,p') -VERSION_DEBIAN := $(shell dpkg-parsechangelog | sed -ne 's,^Version: *\(.*\)$$,\1,p') -VERSION := $(shell echo "$(VERSION_DEBIAN)" | sed -e 's,^[^:]*:,,' -e 's,-[^-]*$$,,') - -BUILD_DIR = debian/build -STAMPS_DIR = debian/stamps - -ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS))) - CONFIG_DEBUG = y -endif -ifneq (,$(findstring thumb,$(DEB_BUILD_OPTIONS))) -THUMB := -mthumb -endif - -source: $(STAMPS_DIR)/source -patch: $(STAMPS_DIR)/patch - -$(STAMPS_DIR)/patch: - dh_testdir - @mkdir -p $(STAMPS_DIR) - QUILT_PATCHES=$(CURDIR)/debian/patches quilt --quiltrc /dev/null push -a || test $$? = 2 - touch $@ - -#setup: $(STAMPS_DIR)/setup_deb $(STAMPS_DIR)/setup_static $(STAMPS_DIR)/setup_udeb -setup: $(STAMPS_DIR)/setup_slp - -$(STAMPS_DIR)/setup_%: SOURCE_FILES = $(filter-out debian, $(wildcard *)) -$(STAMPS_DIR)/setup_%: DIR=$(BUILD_DIR)/build_$* -$(STAMPS_DIR)/setup_%: $(STAMPS_DIR)/patch - dh_testdir - rm -rf '$(DIR)' - mkdir -p '$(DIR)' - cp -a -l $(SOURCE_FILES) '$(DIR)' - cat debian/config/os/$(DEB_HOST_ARCH_OS) debian/config/pkg/$* > '$(DIR)'/.config - $(MAKE) -C '$(DIR)' oldconfig - touch $@ - -#build: $(STAMPS_DIR)/build_deb $(STAMPS_DIR)/build_static $(STAMPS_DIR)/build_udeb -build: $(STAMPS_DIR)/build_slp - -$(STAMPS_DIR)/build_slp : debian/sfdisk/sfdisk -$(STAMPS_DIR)/build_%: DIR=$(BUILD_DIR)/build_$* -$(STAMPS_DIR)/build_%: $(STAMPS_DIR)/setup_% - dh_testdir - $(MAKE) -C '$(DIR)' THUMB=$(THUMB) busybox docs/busybox.1 BB_EXTRA_VERSION="SLP $(VERSION_DEBIAN)" - $(MAKE) -C '$(DIR)' busybox.links - touch $@ - -$(STAMPS_DIR)/indepbuild_%: DIR=$(BUILD_DIR)/indepbuild_$* -$(STAMPS_DIR)/indepbuild_%: - dh_testdir - touch $@ - -debian/sfdisk/sfdisk: - $(MAKE) -C debian/sfdisk - -$(BUILD_DIR) $(STAMPS_DIR): - @[ -d $@ ] || mkdir $@ - -maintainerclean: - rm -rf $(filter-out .svn debian, $(wildcard * .[^.]*)) - -clean: - dh_testdir - rm -rf $(BUILD_DIR) $(STAMPS_DIR) - $(MAKE) -C debian/sfdisk clean - dh_clean - -#binary-indep: binary-indep_busybox-syslogd binary-indep_udhcpc binary-indep_udhcpd -binary-indep: binary-indep_systemd - -#binary-arch: binary-arch_busybox binary-arch_busybox-static binary-arch_busybox-udeb -binary-arch: binary-arch_slp - -binary-arch_slp: DIR = $(BUILD_DIR)/build_slp -binary-arch_slp: $(STAMPS_DIR)/build_slp - dh_testdir - dh_testroot - dh_clean -k -d - # verify that packages links files are in sync with BB generated one - # some other time - #debian/scripts/check-links.py $(DIR)/busybox.links debian/*.links - # verify that Busybox provides these packages - grep util-linux debian/control > /dev/null - install -D -m755 debian/sfdisk/sfdisk debian/busybox/sbin/sfdisk - #grep debianutils debian/control > /dev/null - #install -D -m755 debian/local/tempfile debian/busybox/bin/tempfile - install -D -m755 $(DIR)/busybox debian/busybox/bin/busybox - - $(MAKE) -f debian/rules binary-arch_all - -binary-arch_busybox: DIR = $(BUILD_DIR)/build_deb -binary-arch_busybox: export DH_OPTIONS = -pbusybox -binary-arch_busybox: $(STAMPS_DIR)/build_deb - dh_testdir - dh_testroot - dh_clean -k - dh_install -X.svn --sourcedir=$(DIR) - @$(MAKE) -f debian/rules binary-arch_all - -binary-arch_busybox-static: DIR = $(BUILD_DIR)/build_static -binary-arch_busybox-static: export DH_OPTIONS = -pbusybox-static -binary-arch_busybox-static: $(STAMPS_DIR)/build_static - dh_testdir - dh_testroot - dh_clean -k - dh_install -X.svn --sourcedir=$(DIR) - @$(MAKE) -f debian/rules binary-arch_all - -binary-arch_busybox-udeb: DIR = $(BUILD_DIR)/build_udeb -binary-arch_busybox-udeb: export DH_OPTIONS = -pbusybox-udeb -binary-arch_busybox-udeb: $(STAMPS_DIR)/build_udeb - dh_testdir - dh_testroot - dh_clean -k - # Remove init link, but init support is still compiled in to be - # used. - rm -f $(DIR)/_install/sbin/init - dh_install -X.svn --sourcedir=$(DIR) - @$(MAKE) -f debian/rules binary-arch_all - -binary-arch_all: export DH_OPTIONS = -Nbusybox-systemd-klogd -Nbusybox-systemd-sysklogd -binary-arch_all: - dh_installdirs - # add docs & debug only for busybox package itself - dh_installdocs -pbusybox - dh_installchangelogs -pbusybox - dh_strip -pbusybox --dbg-package=busybox-dbg - dh_compress -pbusybox - # packaging - dh_link - dh_fixperms - dh_installdeb - # only busybox package has binaries - dh_shlibdeps -pbusybox - dh_gencontrol - dh_md5sums - dh_builddeb - -binary-indep_busybox-syslogd: export DH_OPTIONS = -pbusybox-syslogd -binary-indep_busybox-syslogd: - dh_testdir - dh_testroot - dh_clean -k - dh_link - dh_installinit -u"defaults 10 90" - dh_installinit -u"defaults 11 89" --name=busybox-klogd - $(MAKE) -f debian/rules binary-indep_all - -binary-indep_udhcpc: export DH_OPTIONS = -pudhcpc -binary-indep_udhcpc: - dh_testdir - dh_testroot - dh_clean -k - dh_link - dh_install -X.svn - $(MAKE) -f debian/rules binary-indep_all - -binary-indep_udhcpd: export DH_OPTIONS = -pudhcpd -binary-indep_udhcpd: - dh_testdir - dh_testroot - dh_clean -k - dh_link - dh_installinit --onlyscripts - dh_install -X.svn - $(MAKE) -f debian/rules binary-indep_all - -binary-indep_systemd: export DH_OPTIONS = -pbusybox-systemd-klogd -pbusybox-systemd-sysklogd -binary-indep_systemd: - dh_testdir - dh_testroot - dh_clean -k - dh_link - dh_install -X.svn - $(MAKE) -f debian/rules binary-indep_all - -binary-indep_all: - dh_installdirs - dh_installdocs - dh_installchangelogs - dh_compress - dh_fixperms - dh_installdeb - dh_gencontrol - dh_md5sums - dh_builddeb - -binary: binary-indep binary-arch - -DIR_ORIG = ../orig/$(SOURCE)-$(VERSION) -TAR_ORIG_NAME = $(SOURCE)_$(VERSION).orig.tar.bz2 -TAR_ORIG = $(firstword $(wildcard ../$(TAR_ORIG_NAME)) $(wildcard ../orig/$(TAR_ORIG_NAME))) - -orig: $(DIR_ORIG) - rsync --delete --exclude debian --exclude .git --link-dest=$(DIR_ORIG)/ -a $(DIR_ORIG)/ . - -$(DIR_ORIG): -ifeq ($(TAR_ORIG),) - $(error Cannot find orig tarball $(TAR_ORIG_NAME)) -else - mkdir -p ../orig - tar -C ../orig -xjf $(TAR_ORIG) -endif - diff --git a/debian/scripts/README b/debian/scripts/README deleted file mode 100644 index fda9d2f..0000000 --- a/debian/scripts/README +++ /dev/null @@ -1,76 +0,0 @@ - -BusyBox Debian packaging Howto for SLP -======================================== - -This is a howto for creating optimal match between BusyBox -Debian package configuration and the upstream Debian packages -which BusyBox replaces. - -Files: - -- README -- this file -- create-control.py -- script to create BusyBox packaging files -- check-links.py -- script for checking at package build whether - the packaging files match BusyBox created link list -- debian-mappings.txt -- mappings between BusyBox and Debian packages, - needed by the script -- busybox-notes.txt -- some extra notes about differences vs. Debian - BusyBox -- *.dirs -- extra packaging files needed in addition to ones - created by the script - - -What updates are needed and when/where: - -When Packaging info needs to be changed (maintainer etc): --> Updating control file content excerpts in the beginning - of create-control.py - -When syncing to newer upstream Debian version: --> Updating debian-mappings.txt according to changes in Debian (if any) - -When BusyBox configuration needs to be changed (after corresponding -architecture ticket is accepted): --> Iterate through the steps below. Replace the earlier package - control, *.links, *.postinst and *.prerm files with ones created - by create-control.py - - -BusyBox configuration update steps: - -1. Enable/disable relevant things from BusyBox config - vi debian/config/pkg/slp - -2. Create initial control, postinst & links files for BusyBox - packages based on this config file: - cd debian/scripts - ./create-control.py -c ../config/pkg/slp debian-mappings.txt - -3. If any errors were reported, add the missing BB binaries - to Debian mappings and repeat from 1). May be needed if later - (>1.11) BusyBox versions have new binaries that are enabled - -4. Build BusyBox: - cd ../.. - dpkg-buildpackage -rfakeroot -b -uc - -5. Create updated control, postinst & links files for BusyBox - packages based on the BusyBox links file: - cd debian/scripts - ./create-control.py -l ../build/build_slp/busybox.links debian-mappings.txt - -6. Update BusyBox config (or mappings file) to fix the relevant - issues and repeat from 4) until no relevant warnings are given - -7. Overwrite previous packagaging with the new one: - cp *.dirs ../; mv control *.{links,postinst,prerm} ../ - -8. Cross-check from debian/rules file that everything is up to date. - Manually you can do it like this: - cd .. - scripts/check-links.py build/build_slp/busybox.links *.links - -NOTE: The script cannot deduce all the symlinks based on BusyBox -configuration at step 2), that's why BB config is used only for -initial configuration and rest of the checks at step 5) are done -based on the links file created by the BusyBox build. diff --git a/debian/scripts/busybox-notes.txt b/debian/scripts/busybox-notes.txt deleted file mode 100644 index d3e8d99..0000000 --- a/debian/scripts/busybox-notes.txt +++ /dev/null @@ -1,91 +0,0 @@ - -Changes between Diablo and Fremantle Maemo BusyBox configurations ------------------------------------------------------------------ - -- sysvinit: in Diablo, real package, in Fremantle, provided by BB - - In Fremantle "/sbin/init" comes from "upstart", not sysvinit though - - Note: In Debian Lenny sysvinit was split to sysvinit & sysvinit-tools - and the debian-mapping.txt follows that. Diablo sysvinit still - contains binaries for both of these packages like Debian Etch did -- module-init-tools: in Diablo, provided by BB, in Fremantle, real package - - -Comparison between Maemo BusyBox symlinks and Debian (Etch-Sid) binaries -======================================================================== - -Two ways for listing applets: -- ./busybox|grep -A99 addgroup|tr ',' '\n'|awk '/[^ ]/{print $1}'|sort -- make busybox.links - python -c "import os;\ - print ''.join([os.path.basename(x) for x in open('busybox.links')])" - - -Name conflicts --------------- - -pscan: BusyBox binary scans ports, Debian C-source -ftpput: BusyBox binary has regular FTP, Debian camera additions - - -Renames/replacements --------------------- - -It doesn't make sense to rename these to use same -name as Debian alternative before somebody checks -that they're compatible enough with the Debian ones. - -Debian: BusyBox: -lzcat -> lzmacat -makedev -> makedevs -udev -> mdev -microcom -> minicom -splash -> fbsplash -cron -> crond -dhttpd -> httpd -in.tftpd -> tftpd -cat -v -> catv -ip addr -> ipaddr -ip link -> iplink -ip route -> iproute -ip tunnel -> iptunnel -ip rule -> iprule - -For some reason, in Debian 'dnsd' is in (dietlibc)-dev package -and located in /usr/lib/diet/bin/dnsd. - - -Extras ------- - -[[ -> symlink to [ - - -Special cases -------------- - -'linuxrc' file in upstream source, not included into our package. - -Following ones are in our BusyBox package, but not in upstream or -Debian. - -util-linux: -/sbin/sfdisk (binary) - -debianutils: -/bin/tempfile (script) - -module-init-tools: -/sbin/update-modules (empty script) - -(no corresponding Debian package): -/bin/fsync (BusyBox applet) - - -Related files -------------- - -ifupdown (dirs): -/etc/network/if-down.d/ -/etc/network/if-post-down.d/ -/etc/network/if-pre-up.d/ -/etc/network/if-up.d/ diff --git a/debian/scripts/busybox-symlinks-ifupdown.dirs b/debian/scripts/busybox-symlinks-ifupdown.dirs deleted file mode 100644 index d7fd273..0000000 --- a/debian/scripts/busybox-symlinks-ifupdown.dirs +++ /dev/null @@ -1,4 +0,0 @@ -etc/network/if-post-down.d -etc/network/if-pre-up.d -etc/network/if-up.d -etc/network/if-down.d diff --git a/debian/scripts/busybox.dirs b/debian/scripts/busybox.dirs deleted file mode 100644 index d653148..0000000 --- a/debian/scripts/busybox.dirs +++ /dev/null @@ -1,3 +0,0 @@ -bin -sbin -usr/share/man/man1 diff --git a/debian/scripts/check-links.py b/debian/scripts/check-links.py deleted file mode 100755 index 1ba8c7b..0000000 --- a/debian/scripts/check-links.py +++ /dev/null @@ -1,92 +0,0 @@ -#!/usr/bin/python -# -# Check that the binaries for links BusyBox outputs and the ones -# in the packages *.links files match. -# -# Copyright (C) 2008 by Nokia Corporation -# -# Contact: Eero Tamminen -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You 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 - -import os, sys - -def add_links_from(filename, olditems): - "read busybox.links file and return a list of binary names" - newitems = {} - existing = [] - print "-", filename - for line in open(filename): - line = line.strip() - if not line: - continue - name = os.path.basename(line.split()[-1]) - if name in olditems and name not in newitems: - # same package may symlink same name to different - # places, but other packages may not - existing.append(name) - else: - olditems[name] = filename - newitems[name] = 1 - - if existing: - print "ERROR: following items were already in (some) previous links file:" - for name in existing: - print "-", name - print "Re-run of create-control.py needed?" - sys.exit(1) - - -def process_args(argv): - links = {} - bblinks = {} - print "Checking:" - add_links_from(argv[1], bblinks) - for filename in argv[2:]: - add_links_from(filename, links) - - missing = [] - for link in bblinks.keys(): - if link in links: - del(links[link]) - else: - missing.append(link) - - if missing: - print "WARNING: links files for packages are missing following BB links:" - for link in missing: - print "-", link - print "Are all these installed as alternatives?" - - if links: - print "ERROR: BB links file doesn't contain following packages links:" - for link in links.keys(): - print "- %s (in '%s')" % (link, links[link]) - print "Re-run of create-control.py needed?" - sys.exit(1) - - -if __name__ == "__main__": - if len(sys.argv) > 2: - process_args(sys.argv) - else: - print """ -Script to check that binary names in packages link files -match the list of binary names in the BB link file. - -usage: %s -""" % os.path.basename(sys.argv[0]) - sys.exit(1) - diff --git a/debian/scripts/create-control.py b/debian/scripts/create-control.py deleted file mode 100755 index dff4e55..0000000 --- a/debian/scripts/create-control.py +++ /dev/null @@ -1,499 +0,0 @@ -#!/usr/bin/python -# -# Output BusyBox source package debian/control file and -# relevant *.links & *.postist files for the binary packages, -# based on the Busybox configuration and Debian package -# mappings file. -# -# Copyright (C) 2008 by Nokia Corporation -# -# Contact: Eero Tamminen -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# version 2 as published by the Free Software Foundation. -# -# This program is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# General Public License for more details. -# -# You 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 -# -# Notes: -# - If some package provide only alternatives, Busybox package -# control file is set up to provide those and its postinst to -# install the alternatives. As they cannot conflict, there's -# no need to put them into separate symlink packages - -# source package, busybox and debug package descriptions -basepackages_info = """Source: busybox -Priority: optional -Section: utils -Maintainer: Rafal Krypa -Uploaders: Karol Lewandowski -X-Maemo-Maintainer: Yauheni Kaliuta -X-Original-Maintainer: Debian Install System Team -X-Original-Uploaders: Bastian Blank -Build-Depends: debhelper (>> 5), python, quilt -Standards-Version: 3.7.3 - -Package: busybox -Priority: required -Essential: yes -Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends} -Provides: %(provides)s -Replaces: %(replaces)s -Conflicts: %(conflicts)s -Description: Tiny utilities for small and embedded systems - BusyBox combines tiny versions of many common UNIX utilities into a single - small executable. It provides minimalist replacements for the most common - utilities you would usually find on your desktop system (i.e., ls, cp, mv, - mount, tar, etc.). The utilities in BusyBox generally have fewer options than - their full-featured GNU cousins; however, the options that are included - provide the expected functionality and behave very much like their GNU - counterparts. - . - This package installs: - - the BusyBox binary - - symlinks for tools included into it that correspond to binaries - in essential Debian packages - - alternatives from packages that don't have anything else - . - Symlinks to other tools included into BusyBox which correspond to binaries - in non-essential Debian packages are provided in separate symlink packages. - Those package are split and named according to the corresponding Debian - packages. - -Package: busybox-dbg -Architecture: any -Depends: busybox (= ${binary:Version}) -Section: devel -Description: Debug symbols for BusyBox - Debug symbol file for BusyBox. BusyBox provides tiny utilities for small - and embedded systems. -""" - -# description for the busybox specific tools symlinks package -symlinksbusybox_info = """ -Package: busybox-symlinks-busybox -Architecture: all -Depends: busybox (= ${binary:Version}) -Description: BusyBox specific symlinks - BusyBox symlinks for utilities without counterparts in Debian. - These are in separate package because they aren't essentials - (e.g. needed for system package upgrades). -""" - -# descriptions for the other busybox symlinks packages -symlinksother_info = """ -Package: busybox-symlinks-%s -Architecture: all -Depends: busybox (= ${binary:Version}) -Provides: %s -Replaces: %s -Conflicts: %s -Description: BusyBox symlinks to provide '%s' - BusyBox symlinks for utilities corresponding to '%s' package. -""" - -# List of packages that are in Debian Lenny marked as essential: -# awk '/Package:/{pkg=$2} /Essential: yes/{printf("\"%s\",\n", pkg)}' < /var/lib/dpkg/status|sort -# -# Because we don't have "bash", but BusyBox provides "ash", I've set -# that as Essential (instead of Bash) and specifically divert "/bin/sh" -# in code below if that is included into Busybox links (in Ubuntu -# "dash" does same kind of divert). -# -# Some essential packages in Debian "provide" packages that in earlier -# Debian versions were in separate packages. These aren't listed here -# because they're unnecessary: -# -# * coreutils provides: fileutils, shellutils, textutils -# -> no explicit dependencies for these in Lenny. In Etch "latex2html" -# requires "fileutils" without having "coreutils" as an alternative, -# but that's a versioned dependency that wouldn't work with -# BusyBox anyway -# -# * util-linux provides: linux32, schedutils -# -> these were separate packages still in Etch, but as nothing explicitly -# depends on them in Etch or Lenny and Maemo BusyBox configuration -# doesn't include binaries from Etch linux32 or schedutils, they -# don't need to be declared -# -# * grep provides: rgrep -# -> there are no dependencies to "rgrep" in Etch or Lenny and as it -# cannot even be enabled in BusyBox, it doesn't need to be declared -essentialpackages = ( - 'ash', # Maemo special case, see above - 'base-files', - 'base-passwd', - 'bash', - 'bsdutils', - 'coreutils', - 'debianutils', - 'diffutils', - 'dpkg', - 'e2fsprogs', - 'findutils', - 'grep', - 'gzip', - 'hostname', - 'login', - 'mount', - 'ncurses-base', - 'ncurses-bin', - 'perl-base', - 'sed', - 'sysvinit', - 'sysvinit-utils', - 'tar', - 'util-linux' -) - - -import os, sys -stderr = sys.stderr.write - -def error_exit(msg): - "exit with given error message" - sys.stderr.write("\nERROR: %s\n\n" % msg) - sys.exit(1) - -def check_file(filename, filetype): - "exit if given filename doesn't exist or isn't a file" - if os.path.isfile(filename): - return - error_exit("%s file '%s' doesn't exist!" % (filetype, filename)) - - -def read_mappings(filename): - """read Debian mappings file and return dicts for - - package = [list of binaries] - - binary = (package, [paths/alternative info]) - """ - check_file(filename, "Debian mappings") - binaries = {} - packages = {} - for line in open(filename): - line = line.strip() - if (not line) or (line[0] == '#'): - continue - package, data = line.split(":") - paths = data.strip().split() - binary = os.path.basename(paths[0].strip()) - binaries[binary] = (package, paths) - if package not in packages: - packages[package] = [] - packages[package].append(binary) - return packages, binaries - - -def read_links(filename): - "read busybox.links file and return a list of binary names" - check_file(filename, "links") - items = [] - for line in open(filename): - line = line.strip() - if not line: - continue - items.append(os.path.basename(line)) - items.sort() - return items - - -def read_config(filename): - "read BusyBox config and return list of enabled applets" - check_file(filename, "BusyBox config") - applets = [] - for line in open(filename): - if not line.startswith("CONFIG_"): - continue - if line.startswith("CONFIG_LFS"): - continue - # stuff after CONFIG_ - config = line[7:].split('=')[0] - if '_' in config: - # BB applet names don't have '_' - continue - applets.append(config.lower()) - - # remove busybox config crap - if "debug" in applets: - applets.remove("debug") - if "prefix" in applets: - applets.remove("prefix") - - # some applets provide multiple binary symlinks, fix - if "swaponoff" in applets: - applets.remove("swaponoff") - applets.append("swapoff") - applets.append("swapon") - if "ifupdown" in applets: - applets.remove("ifupdown") - applets.append("ifdown") - applets.append("ifup") - - applets.sort() - return applets - - -def tools2packages(tools, binaries): - """match BB tools to Debian binaries and return list of - corresponding packages. Assert that each binary is - associated to some package ("sh" is special case).""" - missing = [] - packages = {} - for tool in tools: - if tool in binaries: - package = binaries[tool][0] - if package not in packages: - packages[package] = [] - packages[package].append(tool) - # /bin/sh is special case - elif tool != "sh": - missing.append(tool) - if missing: - stderr("\nERROR: following tools didn't belong to any mapped package:\n") - for name in missing: - stderr("- %s\n" % name) - stderr("Update either %s::read_config() code or Debian mappings file!\n\n" % os.path.basename(sys.argv[0])) - sys.exit(1) - return packages - - -def check_packages(packages, bbpackages): - "warn if packages provided by BB are missing tools that BB could include" - missing = {} - for package in bbpackages.keys(): - if package == "busybox": - # ignore busybox specific tools - continue - for binary in packages[package]: - if binary not in bbpackages[package]: - if package not in missing: - missing[package] = [] - missing[package].append(binary) - for package in missing.keys(): - stderr("\nWARNING: '%s' package could include also:\n" % package) - for binary in missing[package]: - stderr(" - %s\n" % binary) - - -def collect_packages(bbpackages, tools, binaries): - "return lists of packages BB conflicts with, provides and symlinks" - base = {} # directly to Busybox package - extras = {} # alternatives for Busybox package - symlinks = {} # symlinks/alteratives for symlink packages - - for package, tools in bbpackages.items(): - # package is essential -> goes to busybox itself - if package in essentialpackages: - base[package] = tools - continue - - allalternatives = True - # check whether all tools from given pkg are alternatives - for tool in tools: - toolinfo = binaries[tool][1] - if len(toolinfo) < 2 or toolinfo[1] != "alternative": - allalternatives = False - - if allalternatives: - # only alternatives -> can be provided by busybox itself - extras[package] = tools - else: - # otherwise a separate symlinks package - symlinks[package] = tools - - return base, extras, symlinks - - -def collect_links_alternatives(tools, binaries, links, postinst): - "go through given packages and set/update links & postinst contents" - for tool in tools: - toolinfo = binaries[tool][1] - count = len(toolinfo) - if count > 1 and toolinfo[1] == "alternative": - target = "/bin/busybox" - link = toolinfo[0] - if count > 2: - priority = int(toolinfo[2]) - if count > 3: - # alternative having different name than BB symlink - # means that alternative needs to point to BB symlink - # instead of directly to BB so that BB knows which - # applet to use for the alternative (e.g. pager): - # tool -> altlink -> target -> busybox - links.append(link) - target = '/' + link - link = toolinfo[3] - tool = os.path.basename(link) - else: - priority = 1 - postinst.append(('/' + link, tool, target, priority)) - else: - for link in toolinfo: - links.append(link) - - -def write_links(package, links): - "write given package links file" - if not links: - return - name = "%s.links" % package - print "-", name - linksfile = open(name, "w") - if not linksfile: - error_exit("opening/writing package '%s' links file failed") - for link in links: - linksfile.write("bin/busybox %s\n" % link) - linksfile.close() - - -def write_alternatives(package, alternatives, diverts=[]): - "write given alternatives updates for given package postinst/prerm files" - if not (alternatives or diverts): - return - - name = "%s.postinst" % package - print "-", name - postinst = open(name, "w") - if not postinst: - error_exit("opening/writing package '%s' postinst file failed") - - postinst.write("#!/bin/sh\nset -e\n") - for link,tool,target,priority in alternatives: - postinst.write("update-alternatives --install %s %s %s %d\n" % (link, tool, target, priority)) - for divert in diverts: - # Note: as dpkg-divert --rename doesn't work as described - # in the manual page, it's not used here - postinst.write("dpkg-divert --package %s --add %s\n" % (package, divert)) - postinst.close() - - name = "%s.prerm" % package - print "-", name - prerm = open(name, "w") - if not prerm: - error_exit("opening/writing package '%s' prerm file failed") - - prerm.write("#!/bin/sh\nset -e\n") - for link,tool,target,priority in alternatives: - prerm.write("update-alternatives --remove %s %s\n" % (tool, target)) - for divert in diverts: - prerm.write("dpkg-divert --package %s --remove %s\n" % (package, divert)) - prerm.close() - - -def create_links_alternatives(bbpackages, bblinks, binaries): - """generate .postinst files for tools needing alternatives, - and .links files for required symlinks. If package would include - only alternatives, just add them to busybox package as provides - (without conflicts/replaces). - - Return lists of packages going to busybox package with which - it needs to conflict with, ones it can just provide (as they're - handled as alternatives), and packages that would contain - separate non-essential symlink packages.""" - - base, extras, symlinks = collect_packages(bbpackages, bblinks, binaries) - - links = [] - alternatives = [] - for package,tools in base.items(): - collect_links_alternatives(tools, binaries, links, alternatives) - # add extra alternatives to alternatives - for package,tools in extras.items(): - collect_links_alternatives(tools, binaries, links, alternatives) - if "bin/sh" in links: - # /bin/sh is special case as in Maemo, BusyBox should be /bin/sh. - # In Debian it's linked by Bash. In Ubuntu /bin/sh is diverted - # by Dash (by default), so let's do divert here too. - divert = ["/bin/sh"] - else: - divert = [] - write_alternatives("busybox", alternatives, divert) - links.sort() # nicer to read/verify - write_links("busybox", links) - - for package,tools in symlinks.items(): - links = [] - alternatives = [] - collect_links_alternatives(tools, binaries, links, alternatives) - pkgname = "busybox-symlinks-%s" % package - write_alternatives(pkgname, alternatives) - write_links(pkgname, links) - - return base.keys(), extras.keys(), symlinks.keys() - - -def create_control(base, extraprovides, symlinks): - "generate busybox control file based on given packages lists" - # add same list of packages for provides, replaces & conflicts - args = {} - base.sort() - args['conflicts'] = ", ".join(base) - args['replaces'] = args['conflicts'] - if extraprovides: - # busybox provides some extra packages with alternatives - provides = base + extraprovides - provides.sort() - args['provides'] = ", ".join(provides) - else: - args['provides'] = args['conflicts'] - - print "- control" - control = open("control", "w") - if not control: - error_exit("opening/writing package 'control' file failed") - control.write(basepackages_info % args) - - # special case package with it's own description - if "busybox" in symlinks: - symlinks.remove("busybox") - control.write(symlinksbusybox_info) - - # other symlink packages descriptions - symlinks.sort() - for package in symlinks: - args = 6*(package,) - control.write(symlinksother_info % args) - control.close() - - -def process_args(argv): - if len(sys.argv) == 4 and sys.argv[1] in ("-c", "-l"): - print "\nPARSING..." - if sys.argv[1] == "-l": - tools = read_links(sys.argv[2]) - else: - tools = read_config(sys.argv[2]) - packages, binaries = read_mappings(sys.argv[3]) - bbpackages = tools2packages(tools, binaries) - check_packages(packages, bbpackages) - print '\n', 66*'-', "\n\nWRITING:" - base, extras, symlinks = create_links_alternatives(bbpackages, tools, binaries) - create_control(base, extras, symlinks) - print - else: - script = os.path.basename(sys.argv[0]) - print """ -Outputs BusyBox Debian package control/links/postinst/prerm -files based on the input files. - -usage: %s <-c bb.config|-l bb.links> - -Example of first invocation using BusyBox config file: - %s -c config.maemo debian-mappings.txt - -Example of later iterations using the BusyBox generated symlinks file: - %s -l busybox.links debian-mappings.txt -""" % (script, script, script) - sys.exit(1) - -if __name__ == "__main__": - process_args(sys.argv) diff --git a/debian/scripts/debian-mappings.txt b/debian/scripts/debian-mappings.txt deleted file mode 100644 index d1e4c29..0000000 --- a/debian/scripts/debian-mappings.txt +++ /dev/null @@ -1,521 +0,0 @@ -# -# Mapping between Busybox binary name and in which package -# that binary is in Debian. The format is following: -# : [ [...]] -# or: -# : alternative [priority [altname(s)]] -# -# For example: -# - normal case: -# coreutils: bin/cp -# - multiple symlinks for given tool: -# iproute: bin/ip sbin/ip -# debianutils: bin/which usr/bin/which -# - tool is a Debian alternative (by default has priority of 1): -# awk: usr/bin/awk alternative -# - tool has regular symlink and alternative(s): -# util-linux: usr/bin/more alternative 10 usr/bin/pager -# less: usr/bin/less alternative 20 usr/bin/pager -# -# Lines starting with '#' are comments, empty lines are ignored -# -# Updating this file: -# - If create-control.py complains that this is out of date, -# check with the http://packages.debian.org/ file search form -# in which package and with which path the given binary is -# in Debian. -# - Install that package and check e.g. from the binary manual -# page and BusyBox commands references that the BB utility -# is "compatible enough" before listing it here. If it's not -# compatible, the BB utility should be renamed: -# http://busybox.net/downloads/BusyBox.html -# -# Notes: -# - In Debian "bash" provides /bin/sh. In Ubuntu "dash" diverts -# bin/sh for itself. For BusyBox I've set "ash" to provide /bin/sh. -# create-control.py sets "ash" to be Essential (unlike on Debian) -# to include its symlinks to busybox package, it also does the -# the required divert. -# - The smaller BusyBox shells: lash, hush, msh, aren't really -# Bourne shell compatible, please use ash (it's stripped down -# version of Debian dash which is improved version of BSD Ash). -# http://lists.debian.org/debian-boot/2001/07/msg00104.html -# - All paths are relative as that's what the Debian dh_link eats -# -# Hints: -# - To get the list of package names listed here, use: -# awk '/#/{next}/:/{print $1}' debian-mappings.txt|tr -d :|sort -u -# - To get list of alternatives: -# grep alternative debian-mappings.txt|grep -v '^#' -# - If a package listed below contains only Debian alternatives, -# corresponding virtual package name is used as the package name here: -# http://www.debian.org/doc/packaging-manuals/virtual-package-names-list.txt -# See "awk", "man-browser" and "editor" -# -# TODO: -# - Get Busybox to rename tools that conflict with unrelated -# Debian tools (see things commented as "Conflicts") -# - How to specify that inet services (like ftp, telnet) -# should be registered for inetd (in postinst)? -# - How to specify that services (like crond, inetd) should -# be registered for Upstart (in postinst)? -# -# Changelog: -# - 2008-12-09: link targets are relative (removed first '/'). -# comment updates -# - 2008-12-04: support alternatives and multiple symlinks -# and many other updates -# - 2008-07-11: updated against Etch & packages.debian.org -# and Busybox 1.11.0 - - -# These busybox symlinks don't have a matching binary in Debian -# and are therefore the same as in busybox.links. -# -# Some may provides same functionality as something else in Debian, -# but the compatibility should be checked before renaming. -# -# For rest of the Debian package mappings the binary path is same -# as in Debian instead of what's in busybox.links file generated -# by the Busybox build. - -# same as "[" -busybox: usr/bin/[[ -# Same as "cat -v" -busybox: usr/bin/catv -# does this correspond to Debian cron? -busybox: usr/sbin/crond -busybox: usr/sbin/dhcprelay -busybox: usr/sbin/dnsd -busybox: bin/dumpkmap -busybox: usr/bin/ether-wake -busybox: usr/sbin/fakeidentd -# does this correspond to Debian splash? -busybox: sbin/fbsplash -# maemo addition -busybox: bin/fsync -busybox: usr/bin/ftpget -# Conflicts: camstream -# (Busybox binary has regular FTP, Debian one camera additions) -busybox: usr/bin/ftpput -# Provides: httpd? -busybox: usr/sbin/httpd -busybox: sbin/ifenslave -busybox: sbin/inotifyd -# same as "ip addr" -busybox: bin/ipaddr -# same as " ip link" -busybox: bin/iplink -# same as "ip route" -busybox: bin/iproute -# same as "ip rule" -busybox: bin/iprule -busybox: usr/bin/length -busybox: linuxrc -busybox: usr/bin/loadfont -busybox: sbin/loadkmap -busybox: sbin/logread -# does this correspond to Debian makedev? -busybox: sbin/makedevs -# does this correspond to Debian udev? -busybox: sbin/mdev -# does this correspond to Debian minicom? -busybox: usr/bin/microcom -busybox: usr/bin/nmeter -busybox: bin/pipe_progress -# Conflicts: pscan (Busybox binary scans ports, Debian one C-source)? -busybox: usr/bin/pscan -busybox: sbin/raidautorun -busybox: usr/bin/readahead -busybox: sbin/setconsole -# Provides: ftp-server? -busybox: usr/sbin/tftpd -busybox: usr/bin/ttysize -busybox: bin/usleep -busybox: bin/volumeid -# Conflicts: whois -busybox: usr/bin/mkpasswd -# Conflicts: eject -busybox: usr/bin/volname - -adduser: usr/sbin/addgroup -adduser: usr/sbin/adduser -adduser: usr/sbin/delgroup -adduser: usr/sbin/deluser - -adjtimex: usr/bin/adjtimex - -# /bin/sh is special case, see Notes -ash: bin/ash -ash: bin/sh -#bash: bin/sh - -# awk is a virtual package name, this is OK for alternatives -awk: usr/bin/awk alternative - -binutils: usr/bin/ar -binutils: usr/bin/strings - -bridge-utils: usr/bin/brctl - -bsdmainutils: usr/bin/cal -bsdmainutils: usr/bin/hd -bsdmainutils: usr/bin/hexdump - -bsdutils: usr/bin/logger -bsdutils: usr/bin/renice -bsdutils: usr/bin/script -bsdutils: usr/bin/scriptreplay -bsdutils: usr/bin/wall - -bzip2: bin/bunzip2 -bzip2: bin/bzcat -bzip2: bin/bzip2 - -console-tools: bin/fgconsole -console-tools: usr/bin/chvt -console-tools: usr/bin/deallocvt -console-tools: usr/bin/kbd_mode -console-tools: usr/bin/openvt -console-tools: usr/bin/setkeycodes -console-tools: usr/bin/setlogcons -console-tools: usr/bin/showkey - -coreutils: bin/cat -coreutils: bin/chgrp -coreutils: bin/chmod -coreutils: bin/chown -coreutils: bin/cp -coreutils: bin/date -coreutils: bin/dd -coreutils: bin/df -coreutils: bin/echo -coreutils: bin/false -coreutils: bin/ln -coreutils: bin/ls -coreutils: bin/mkdir -coreutils: bin/mknod -coreutils: bin/mktemp -coreutils: bin/mv -coreutils: bin/pwd -coreutils: bin/readlink -coreutils: bin/rm -coreutils: bin/rmdir -coreutils: bin/sleep -coreutils: bin/stty -coreutils: bin/sync -coreutils: bin/touch -coreutils: bin/true -coreutils: bin/uname -coreutils: usr/bin/[ -coreutils: usr/bin/basename -coreutils: usr/bin/chcon -coreutils: usr/bin/cksum -coreutils: usr/bin/comm -coreutils: usr/bin/cut -coreutils: usr/bin/dirname -coreutils: usr/bin/du -coreutils: usr/bin/env -coreutils: usr/bin/expand -coreutils: usr/bin/expr -coreutils: usr/bin/fold -coreutils: usr/bin/head -coreutils: usr/bin/hostid -coreutils: usr/bin/id -coreutils: usr/bin/install -coreutils: usr/bin/logname -coreutils: usr/bin/md5sum -coreutils: usr/bin/mkfifo -coreutils: usr/bin/nice -coreutils: usr/bin/nohup -coreutils: usr/bin/od -coreutils: usr/bin/printenv -coreutils: usr/bin/printf -coreutils: usr/bin/runcon -coreutils: usr/bin/seq -coreutils: usr/bin/sha1sum -coreutils: usr/bin/sha256sum -coreutils: usr/bin/sha512sum -coreutils: usr/bin/sort -coreutils: usr/bin/split -coreutils: usr/bin/stat -coreutils: usr/bin/sum -coreutils: usr/bin/tac -coreutils: usr/bin/tail -coreutils: usr/bin/tee -coreutils: usr/bin/test -coreutils: usr/bin/timeout -coreutils: usr/bin/tr -coreutils: usr/bin/tty -coreutils: usr/bin/unexpand -coreutils: usr/bin/uniq -coreutils: usr/bin/wc -coreutils: usr/bin/who -coreutils: usr/bin/whoami -coreutils: usr/bin/yes -coreutils: usr/sbin/chroot - -cpio: bin/cpio -cpio: bin/mt alternative - -cron: usr/bin/crontab - -# sid/later -daemontools: usr/bin/envdir -daemontools: usr/bin/envuidgid -daemontools: usr/bin/setuidgid -daemontools: usr/bin/softlimit - -dc: usr/bin/dc - -debianutils: bin/run-parts -debianutils: bin/which usr/bin/which - -diffutils: usr/bin/cmp -diffutils: usr/bin/diff - -dnsutils: usr/bin/nslookup - -dosfstools: sbin/mkdosfs -dosfstools: sbin/mkfs.vfat - -dpkg: sbin/start-stop-daemon - -e2fsprogs: sbin/findfs -e2fsprogs: sbin/fsck -e2fsprogs: sbin/mke2fs -e2fsprogs: sbin/mkfs.ext2 -e2fsprogs: sbin/tune2fs -e2fsprogs: usr/bin/chattr -e2fsprogs: usr/bin/lsattr - -ed: bin/ed - -eject: usr/bin/eject - -ssmtp: usr/sbin/sendmail - -fbset: bin/fbset - -fdflush: bin/fdflush - -fetchmail: usr/bin/fetchmail - -findutils: usr/bin/find -findutils: usr/bin/xargs - -grep: bin/egrep -grep: bin/fgrep -grep: bin/grep - -gzip: bin/gunzip -gzip: bin/gzip -gzip: bin/uncompress -gzip: bin/zcat - -hdparm: sbin/hdparm - -hostname: bin/hostname -hostname: bin/dnsdomainname - -ifupdown: sbin/ifdown -ifupdown: sbin/ifup - -initscripts: bin/mountpoint - -ipcalc: usr/bin/ipcalc - -iproute: bin/ip sbin/ip - -ipsvd: usr/bin/tcpsvd -ipsvd: usr/bin/udpsvd - -iputils-arping: usr/bin/arping - -iputils-ping: bin/ping -iputils-ping: bin/ping6 - -klogd: sbin/klogd - -less: usr/bin/less alternative 20 usr/bin/pager - -loadlin: usr/bin/freeramdisk - -login: bin/login -login: bin/su - -lpr: usr/bin/lpd -lpr: usr/bin/lpq -lpr: usr/bin/lpr - -lrzsz: usr/bin/rx - -lzma: usr/bin/lzcat -lzma: usr/bin/lzma -lzma: usr/bin/unlzma - -lzop: usr/bin/lzop -lzop: usr/bin/lzopcat -lzop: usr/bin/unlzop - -# man-browser is a virtual package name, this is OK for alternatives -man-browser: usr/bin/man alternative - -module-init-tools: sbin/depmod -module-init-tools: sbin/insmod -module-init-tools: sbin/lsmod -module-init-tools: sbin/modprobe -module-init-tools: sbin/modinfo -module-init-tools: sbin/rmmod - -mount: bin/mount -mount: bin/umount -mount: sbin/losetup -mount: sbin/swapoff -mount: sbin/swapon - -mtd-utils: usr/sbin/flashcp -mtd-utils: usr/sbin/flash_eraseall -mtd-utils: usr/sbin/flash_lock -mtd-utils: usr/sbin/flash_unlock -mtd-utils: usr/sbin/ubiattach -mtd-utils: usr/sbin/ubidetach - -ncurses-bin: usr/bin/clear -ncurses-bin: usr/bin/reset - -# starting from lenny, netcat is a virtual package (for upgrade reasons) -netcat: bin/nc alternative - -net-tools: bin/netstat -net-tools: sbin/ifconfig -net-tools: sbin/iptunnel -net-tools: sbin/nameif -net-tools: sbin/route -net-tools: sbin/slattach -net-tools: usr/sbin/arp - -openbsd-inetd: usr/sbin/inetd - -passwd: usr/bin/passwd -passwd: usr/sbin/chpasswd - -patch: usr/bin/patch - -ppp: usr/sbin/chat - -procps: bin/kill -procps: bin/ps -procps: sbin/sysctl -procps: usr/bin/free -procps: usr/bin/pgrep -procps: usr/bin/pkill -procps: usr/bin/top -procps: usr/bin/uptime -procps: usr/bin/watch - -psmisc: bin/fuser -psmisc: usr/bin/killall - -rdate: usr/sbin/rdate - -realpath: usr/bin/realpath - -rpm: usr/bin/rpm -rpm: usr/bin/rpm2cpio - -runit: usr/bin/chpst -runit: usr/bin/runsv -runit: usr/bin/runsvdir -runit: usr/bin/sv -runit: usr/bin/svlogd - -sed: bin/sed - -sharutils: usr/bin/uudecode -sharutils: usr/bin/uuencode - -sysklogd: sbin/syslogd - -sysvinit: sbin/halt -sysvinit: sbin/init -sysvinit: sbin/poweroff -sysvinit: sbin/reboot -sysvinit: sbin/runlevel - -sysvinit-utils: bin/pidof -sysvinit-utils: sbin/killall5 -sysvinit-utils: sbin/sulogin -sysvinit-utils: usr/bin/last -sysvinit-utils: usr/bin/mesg - -tar: bin/tar - -telnetd: usr/sbin/telnetd - -# telnet-client is a virtual package name, this is OK for alternatives -telnet-client: usr/bin/telnet alternative - -tftp: usr/bin/tftp - -time: usr/bin/time - -tofrodos: usr/bin/dos2unix -tofrodos: usr/bin/unix2dos - -traceroute: usr/bin/traceroute alternative - -udhcpc: usr/bin/udhcpc - -udhcpd: usr/bin/dumpleases -udhcpd: usr/sbin/udhcpd - -unzip: usr/bin/unzip - -util-linux: bin/dmesg -util-linux: bin/more alternative 10 usr/bin/pager -util-linux: sbin/blkid -util-linux: sbin/fdisk -util-linux: sbin/fsck.minix -util-linux: sbin/getty -util-linux: sbin/hwclock -util-linux: sbin/mkfs.minix -util-linux: sbin/mkswap -util-linux: sbin/pivot_root -util-linux: sbin/switch_root -util-linux: usr/bin/flock -util-linux: usr/bin/rev -util-linux: usr/bin/rtcwake -util-linux: usr/sbin/rdev -# before lenny this binary was in schedutils package -util-linux: usr/bin/chrt -util-linux: usr/bin/fdformat -util-linux: usr/bin/getopt -util-linux: usr/bin/ionice -util-linux: usr/bin/ipcrm -util-linux: usr/bin/ipcs -# before lenny these two were in linux32 package -util-linux: usr/bin/linux32 -util-linux: usr/bin/linux64 -# this didn't exist before lenny -util-linux: usr/bin/setarch -util-linux: usr/bin/setsid -# before lenny this binary was in schedutils package -util-linux: usr/bin/taskset -util-linux: usr/sbin/readprofile -util-linux: sbin/blockdev - -# editor is (an obsolete) virtual package name, this is OK for alternatives -editor: usr/bin/vi alternative - -vlan: sbin/vconfig - -vlock: usr/bin/vlock - -watchdog: usr/sbin/watchdog - -wget: usr/bin/wget - -xterm: usr/bin/resize - -zcip: usr/bin/zcip diff --git a/debian/sfdisk/Makefile b/debian/sfdisk/Makefile deleted file mode 100644 index 36ad891..0000000 --- a/debian/sfdisk/Makefile +++ /dev/null @@ -1,15 +0,0 @@ - -OBJS = disksize.o i386_sys_types.o partname.o sfdisk.o - -#OBJS = sfdisk.o - -CFLAGS ?= -fomit-frame-pointer -Os - -all: sfdisk - - -sfdisk: $(OBJS) - $(CC) -o $@ $(OBJS) - -clean: - rm -f *.o *~ sfdisk diff --git a/debian/sfdisk/common.h b/debian/sfdisk/common.h deleted file mode 100644 index 7c1c3cd..0000000 --- a/debian/sfdisk/common.h +++ /dev/null @@ -1,32 +0,0 @@ -/* common stuff for fdisk, cfdisk, sfdisk */ - -/* including fails */ -#include -#include -#define BLKRRPART _IO(0x12,95) /* re-read partition table */ -#define BLKGETSIZE _IO(0x12,96) /* return device size */ -#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ -#define BLKSSZGET _IO(0x12,104) /* get block device sector size */ -#define BLKGETSIZE64 _IOR(0x12,114,size_t) /* size in bytes */ - -/* including also fails */ -struct hd_geometry { - unsigned char heads; - unsigned char sectors; - unsigned short cylinders; - unsigned long start; -}; - -#define HDIO_GETGEO 0x0301 /* get device geometry */ - - -struct systypes { - unsigned char type; - char *name; -}; - -extern struct systypes i386_sys_types[]; - -extern char *partname(char *dev, int pno, int lth); - -int disksize(int fd, unsigned long long *sectors); diff --git a/debian/sfdisk/defines.h b/debian/sfdisk/defines.h deleted file mode 100644 index 9aa106d..0000000 --- a/debian/sfdisk/defines.h +++ /dev/null @@ -1,3 +0,0 @@ -#define UTIL_LINUX_VERSION "2.12r" -#define util_linux_version "util-linux-2.12r" - diff --git a/debian/sfdisk/disksize.c b/debian/sfdisk/disksize.c deleted file mode 100644 index f5687d2..0000000 --- a/debian/sfdisk/disksize.c +++ /dev/null @@ -1,17 +0,0 @@ -#include "common.h" - -int disksize(int fd, unsigned long long *sectors) { - int err; - long sz; - long long b; - - err = ioctl(fd, BLKGETSIZE, &sz); - if (err) - return err; - err = ioctl(fd, BLKGETSIZE64, &b); - if (err || b == 0 || b == sz) - *sectors = sz; - else - *sectors = (b >> 9); - return 0; -} diff --git a/debian/sfdisk/i386_sys_types.c b/debian/sfdisk/i386_sys_types.c deleted file mode 100644 index e08a9b2..0000000 --- a/debian/sfdisk/i386_sys_types.c +++ /dev/null @@ -1,106 +0,0 @@ -/* DOS partition types */ -#include "common.h" -#include "nls.h" - -struct systypes i386_sys_types[] = { - {0x00, N_("Empty")}, - {0x01, N_("FAT12")}, - {0x02, N_("XENIX root")}, - {0x03, N_("XENIX usr")}, - {0x04, N_("FAT16 <32M")}, - {0x05, N_("Extended")}, /* DOS 3.3+ extended partition */ - {0x06, N_("FAT16")}, /* DOS 16-bit >=32M */ - {0x07, N_("HPFS/NTFS")}, /* OS/2 IFS, eg, HPFS or NTFS or QNX */ - {0x08, N_("AIX")}, /* AIX boot (AIX -- PS/2 port) or SplitDrive */ - {0x09, N_("AIX bootable")}, /* AIX data or Coherent */ - {0x0a, N_("OS/2 Boot Manager")},/* OS/2 Boot Manager */ - {0x0b, N_("W95 FAT32")}, - {0x0c, N_("W95 FAT32 (LBA)")},/* LBA really is `Extended Int 13h' */ - {0x0e, N_("W95 FAT16 (LBA)")}, - {0x0f, N_("W95 Ext'd (LBA)")}, - {0x10, N_("OPUS")}, - {0x11, N_("Hidden FAT12")}, - {0x12, N_("Compaq diagnostics")}, - {0x14, N_("Hidden FAT16 <32M")}, - {0x16, N_("Hidden FAT16")}, - {0x17, N_("Hidden HPFS/NTFS")}, - {0x18, N_("AST SmartSleep")}, - {0x1b, N_("Hidden W95 FAT32")}, - {0x1c, N_("Hidden W95 FAT32 (LBA)")}, - {0x1e, N_("Hidden W95 FAT16 (LBA)")}, - {0x24, N_("NEC DOS")}, - {0x39, N_("Plan 9")}, - {0x3c, N_("PartitionMagic recovery")}, - {0x40, N_("Venix 80286")}, - {0x41, N_("PPC PReP Boot")}, - {0x42, N_("SFS")}, - {0x4d, N_("QNX4.x")}, - {0x4e, N_("QNX4.x 2nd part")}, - {0x4f, N_("QNX4.x 3rd part")}, - {0x50, N_("OnTrack DM")}, - {0x51, N_("OnTrack DM6 Aux1")}, /* (or Novell) */ - {0x52, N_("CP/M")}, /* CP/M or Microport SysV/AT */ - {0x53, N_("OnTrack DM6 Aux3")}, - {0x54, N_("OnTrackDM6")}, - {0x55, N_("EZ-Drive")}, - {0x56, N_("Golden Bow")}, - {0x5c, N_("Priam Edisk")}, - {0x61, N_("SpeedStor")}, - {0x63, N_("GNU HURD or SysV")}, /* GNU HURD or Mach or Sys V/386 (such as ISC UNIX) */ - {0x64, N_("Novell Netware 286")}, - {0x65, N_("Novell Netware 386")}, - {0x70, N_("DiskSecure Multi-Boot")}, - {0x75, N_("PC/IX")}, - {0x80, N_("Old Minix")}, /* Minix 1.4a and earlier */ - {0x81, N_("Minix / old Linux")},/* Minix 1.4b and later */ - {0x82, N_("Linux swap / Solaris")}, - {0x83, N_("Linux")}, - {0x84, N_("OS/2 hidden C: drive")}, - {0x85, N_("Linux extended")}, - {0x86, N_("NTFS volume set")}, - {0x87, N_("NTFS volume set")}, - {0x88, N_("Linux plaintext")}, - {0x8e, N_("Linux LVM")}, - {0x93, N_("Amoeba")}, - {0x94, N_("Amoeba BBT")}, /* (bad block table) */ - {0x9f, N_("BSD/OS")}, /* BSDI */ - {0xa0, N_("IBM Thinkpad hibernation")}, - {0xa5, N_("FreeBSD")}, /* various BSD flavours */ - {0xa6, N_("OpenBSD")}, - {0xa7, N_("NeXTSTEP")}, - {0xa8, N_("Darwin UFS")}, - {0xa9, N_("NetBSD")}, - {0xab, N_("Darwin boot")}, - {0xb7, N_("BSDI fs")}, - {0xb8, N_("BSDI swap")}, - {0xbb, N_("Boot Wizard hidden")}, - {0xbe, N_("Solaris boot")}, - {0xbf, N_("Solaris")}, - {0xc1, N_("DRDOS/sec (FAT-12)")}, - {0xc4, N_("DRDOS/sec (FAT-16 < 32M)")}, - {0xc6, N_("DRDOS/sec (FAT-16)")}, - {0xc7, N_("Syrinx")}, - {0xda, N_("Non-FS data")}, - {0xdb, N_("CP/M / CTOS / ...")},/* CP/M or Concurrent CP/M or - Concurrent DOS or CTOS */ - {0xde, N_("Dell Utility")}, /* Dell PowerEdge Server utilities */ - {0xdf, N_("BootIt")}, /* BootIt EMBRM */ - {0xe1, N_("DOS access")}, /* DOS access or SpeedStor 12-bit FAT - extended partition */ - {0xe3, N_("DOS R/O")}, /* DOS R/O or SpeedStor */ - {0xe4, N_("SpeedStor")}, /* SpeedStor 16-bit FAT extended - partition < 1024 cyl. */ - {0xeb, N_("BeOS fs")}, - {0xee, N_("EFI GPT")}, /* Intel EFI GUID Partition Table */ - {0xef, N_("EFI (FAT-12/16/32)")},/* Intel EFI System Partition */ - {0xf0, N_("Linux/PA-RISC boot")},/* Linux/PA-RISC boot loader */ - {0xf1, N_("SpeedStor")}, - {0xf4, N_("SpeedStor")}, /* SpeedStor large partition */ - {0xf2, N_("DOS secondary")}, /* DOS 3.3+ secondary */ - {0xfd, N_("Linux raid autodetect")},/* New (2.2.x) raid partition with - autodetect using persistent - superblock */ - {0xfe, N_("LANstep")}, /* SpeedStor >1024 cyl. or LANstep */ - {0xff, N_("BBT")}, /* Xenix Bad Block Table */ - { 0, 0 } -}; diff --git a/debian/sfdisk/nls.h b/debian/sfdisk/nls.h deleted file mode 100644 index 99458d6..0000000 --- a/debian/sfdisk/nls.h +++ /dev/null @@ -1,34 +0,0 @@ -int main(int argc, char *argv[]); - -#include "defines.h" /* for HAVE_locale_h */ - -#ifndef PACKAGE -#define PACKAGE "util-linux" -#endif - -#ifndef LOCALEDIR -#define LOCALEDIR "/usr/share/locale" -#endif - -#ifdef HAVE_locale_h -# include -#endif - -#if defined MAY_ENABLE_NLS && !defined DISABLE_NLS -# include -# define _(Text) gettext (Text) -# ifdef gettext_noop -# define N_(String) gettext_noop (String) -# else -# define N_(String) (String) -# endif -#else -# undef bindtextdomain -# define bindtextdomain(Domain, Directory) /* empty */ -# undef textdomain -# define textdomain(Domain) /* empty */ -# define _(Text) (Text) -# define N_(Text) (Text) -#endif - - diff --git a/debian/sfdisk/partname.c b/debian/sfdisk/partname.c deleted file mode 100644 index e4bc42b..0000000 --- a/debian/sfdisk/partname.c +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include -#include -#include "common.h" - -/* - * return partition name - uses static storage unless buf is supplied - */ -static char * -partnamebf(char *dev, int pno, int lth, int bufsiz, char *bufp) { - static char buffer[80]; - char *p; - int w, wp; - - if (!bufp) { - bufp = buffer; - bufsiz = sizeof(buffer); - } - - w = strlen(dev); - p = ""; - - if (isdigit(dev[w-1])) - p = "p"; - - /* devfs kludge - note: fdisk partition names are not supposed - to equal kernel names, so there is no reason to do this */ - if (strcmp (dev + w - 4, "disc") == 0) { - w -= 4; - p = "part"; - } - - wp = strlen(p); - - if (lth) { - snprintf(bufp, bufsiz, "%*.*s%s%-2u", - lth-wp-2, w, dev, p, pno); - } else { - snprintf(bufp, bufsiz, "%.*s%s%-2u", w, dev, p, pno); - } - return bufp; -} - -char * -partname(char *dev, int pno, int lth) { - return partnamebf(dev, pno, lth, 0, NULL); -} diff --git a/debian/sfdisk/sfdisk.c b/debian/sfdisk/sfdisk.c deleted file mode 100644 index 7af841d..0000000 --- a/debian/sfdisk/sfdisk.c +++ /dev/null @@ -1,3105 +0,0 @@ -/* - * sfdisk version 3.0 - aeb - 950813 - * - * Copyright (C) 1995 Andries E. Brouwer (aeb@cwi.nl) - * - * This program is free software. You can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation: either Version 1 - * or (at your option) any later version. - * - * A.V. Le Blanc (LeBlanc@mcc.ac.uk) wrote Linux fdisk 1992-1994, - * patched by various people (faith@cs.unc.edu, martin@cs.unc.edu, - * leisner@sdsp.mc.xerox.com, esr@snark.thyrsus.com, aeb@cwi.nl) - * 1993-1995, with version numbers (as far as I have seen) 0.93 - 2.0e. - * This program had (head,sector,cylinder) as basic unit, and was - * (therefore) broken in several ways for the use on larger disks - - * for example, my last patch (from 2.0d to 2.0e) was required - * to allow a partition to cross cylinder 8064, and to write an - * extended partition past the 4GB mark. - * - * The current program is a rewrite from scratch, and I started a - * version numbering at 3.0. - * Andries Brouwer, aeb@cwi.nl, 950813 - * - * Well, a good user interface is still lacking. On the other hand, - * many configurations cannot be handled by any other fdisk. - * I changed the name to sfdisk to prevent confusion. - aeb, 970501 - * - * Changes: - * 19990319 - Arnaldo Carvalho de Melo - i18n - * 20040428 - Jeroen Dobbelaere - added PACKED - * 20040824 - David A. Wheeler - warnings to stderr - */ - -#define PROGNAME "sfdisk" -#define VERSION "3.08" -#define DATE "040824" - -#include -#include /* atoi, free */ -#include /* varargs */ -#include /* read, write */ -#include /* O_RDWR */ -#include /* ERANGE */ -#include /* index() */ -#include -#include -#include -#include -#include -#include /* _syscall */ -#include "nls.h" -#include "common.h" - -#define SIZE(a) (sizeof(a)/sizeof(a[0])) - -/* - * Table of contents: - * A. About seeking - * B. About sectors - * C. About heads, sectors and cylinders - * D. About system Ids - * E. About partitions - * F. The standard input - * G. The command line - * H. Listing the current situation - * I. Writing the new situation - */ -int exit_status = 0; - -int force = 0; /* 1: do what I say, even if it is stupid ... */ -int quiet = 0; /* 1: suppress all warnings */ -/* IA-64 gcc spec file currently does -DLinux... */ -#undef Linux -int Linux = 0; /* 1: suppress warnings irrelevant for Linux */ -int DOS = 0; /* 1: shift extended partitions by #sectors, not 1 */ -int DOS_extended = 0; /* 1: use starting cylinder boundary of extd partn */ -int dump = 0; /* 1: list in a format suitable for later input */ -int verify = 0; /* 1: check that listed partition is reasonable */ -int no_write = 0; /* 1: do not actually write to disk */ -int no_reread = 0; /* 1: skip the BLKRRPART ioctl test at startup */ -int leave_last = 0; /* 1: don't allocate the last cylinder */ -int opt_list = 0; -char *save_sector_file = NULL; -char *restore_sector_file = NULL; - -static void -do_warn(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - vfprintf(stderr, s, p); - fflush(stderr); - va_end(p); -} - -static void -warn(char *s, ...) { - va_list p; - - va_start(p, s); - if (!quiet) { - fflush(stdout); - vfprintf(stderr, s, p); - fflush(stderr); - } - va_end(p); -} - -static void -error(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - fprintf(stderr, "\n" PROGNAME ": "); - vfprintf(stderr, s, p); - fflush(stderr); - va_end(p); -} - -static void -fatal(char *s, ...) { - va_list p; - - va_start(p, s); - fflush(stdout); - fprintf(stderr, "\n" PROGNAME ": "); - vfprintf(stderr, s, p); - fflush(stderr); - va_end(p); - exit(1); -} - -/* - * GCC nonsense - needed for GCC 3.4.x with -O2 - * - * Maybe just test with #if (__GNUC__ >= 3) && (__GNUC_MINOR__ >= 4) ? - */ -#ifndef __GNUC_PREREQ -#define __GNUC_PREREQ(x,y) 0 -#endif -#if __GNUC_PREREQ(3,4) -#define __attribute__used __attribute__ ((used)) -#else -#define __attribute__used -#endif - -/* - * arm needs PACKED - use it everywhere? - */ -#if defined(__GNUC__) && (defined(__arm__) || defined(__alpha__)) -# define PACKED __attribute__ ((packed)) -#else -# define PACKED -#endif - - -/* - * A. About seeking - */ - -/* - * sseek: seek to specified sector - return 0 on failure - * - * For >4GB disks lseek needs a > 32bit arg, and we have to use llseek. - * On the other hand, a 32 bit sector number is OK until 2TB. - * The routines _llseek and sseek below are the only ones that - * know about the loff_t type. - * - * Note: we use 512-byte sectors here, irrespective of the hardware ss. - */ -#undef use_lseek -#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) || defined (__s390x__) -#define use_lseek -#endif - -#ifndef use_lseek -static __attribute__used -int _llseek (unsigned int fd, ulong hi, ulong lo, - loff_t *res, unsigned int wh) { - return syscall (__NR__llseek, fd, hi, lo, res, wh); -} -#endif - -static int -sseek(char *dev, unsigned int fd, unsigned long s) { - loff_t in, out; - in = ((loff_t) s << 9); - out = 1; - -#ifndef use_lseek - if (_llseek (fd, in>>32, in & 0xffffffff, &out, SEEK_SET) != 0) { -#else - if ((out = lseek(fd, in, SEEK_SET)) != in) { -#endif - perror("llseek"); - error(_("seek error on %s - cannot seek to %lu\n"), dev, s); - return 0; - } - - if (in != out) { - error(_("seek error: wanted 0x%08x%08x, got 0x%08x%08x\n"), - (unsigned int)(in>>32), (unsigned int)(in & 0xffffffff), - (unsigned int)(out>>32), (unsigned int)(out & 0xffffffff)); - return 0; - } - return 1; -} - -/* - * B. About sectors - */ - -/* - * We preserve all sectors read in a chain - some of these will - * have to be modified and written back. - */ -struct sector { - struct sector *next; - unsigned long sectornumber; - int to_be_written; - char data[512]; -} *sectorhead; - -static void -free_sectors(void) { - struct sector *s; - - while (sectorhead) { - s = sectorhead; - sectorhead = s->next; - free(s); - } -} - -static struct sector * -get_sector(char *dev, int fd, unsigned long sno) { - struct sector *s; - - for(s = sectorhead; s; s = s->next) - if (s->sectornumber == sno) - return s; - - if (!sseek(dev, fd, sno)) - return 0; - - if (!(s = (struct sector *) malloc(sizeof(struct sector)))) - fatal(_("out of memory - giving up\n")); - - if (read(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { - if (errno) /* 0 in case we read past end-of-disk */ - perror("read"); - error(_("read error on %s - cannot read sector %lu\n"), dev, sno); - free(s); - return 0; - } - - s->next = sectorhead; - sectorhead = s; - s->sectornumber = sno; - s->to_be_written = 0; - - return s; -} - -static int -msdos_signature (struct sector *s) { - unsigned char *data = s->data; - if (data[510] == 0x55 && data[511] == 0xaa) - return 1; - error(_("ERROR: sector %lu does not have an msdos signature\n"), - s->sectornumber); - return 0; -} - -static int -write_sectors(char *dev, int fd) { - struct sector *s; - - for (s = sectorhead; s; s = s->next) - if (s->to_be_written) { - if (!sseek(dev, fd, s->sectornumber)) - return 0; - if (write(fd, s->data, sizeof(s->data)) != sizeof(s->data)) { - perror("write"); - error(_("write error on %s - cannot write sector %lu\n"), - dev, s->sectornumber); - return 0; - } - s->to_be_written = 0; - } - return 1; -} - -static void -ulong_to_chars(unsigned long u, char *uu) { - int i; - - for(i=0; i<4; i++) { - uu[i] = (u & 0xff); - u >>= 8; - } -} - -static unsigned long -chars_to_ulong(unsigned char *uu) { - int i; - unsigned long u = 0; - - for(i=3; i>=0; i--) - u = (u << 8) | uu[i]; - return u; -} - -static int -save_sectors(char *dev, int fdin) { - struct sector *s; - char ss[516]; - int fdout; - - fdout = open(save_sector_file, O_WRONLY | O_CREAT, 0444); - if (fdout < 0) { - perror(save_sector_file); - error(_("cannot open partition sector save file (%s)\n"), - save_sector_file); - return 0; - } - - for (s = sectorhead; s; s = s->next) - if (s->to_be_written) { - ulong_to_chars(s->sectornumber, ss); - if (!sseek(dev, fdin, s->sectornumber)) - return 0; - if (read(fdin, ss+4, 512) != 512) { - perror("read"); - error(_("read error on %s - cannot read sector %lu\n"), - dev, s->sectornumber); - return 0; - } - if (write(fdout, ss, sizeof(ss)) != sizeof(ss)) { - perror("write"); - error(_("write error on %s\n"), save_sector_file); - return 0; - } - } - return 1; -} - -static void reread_disk_partition(char *dev, int fd); - -static int -restore_sectors(char *dev) { - int fdin, fdout, ct; - struct stat statbuf; - char *ss0, *ss; - unsigned long sno; - - if (stat(restore_sector_file, &statbuf) < 0) { - perror(restore_sector_file); - error(_("cannot stat partition restore file (%s)\n"), - restore_sector_file); - return 0; - } - if (statbuf.st_size % 516) { - error(_("partition restore file has wrong size - not restoring\n")); - return 0; - } - if (!(ss = (char *) malloc(statbuf.st_size))) { - error(_("out of memory?\n")); - return 0; - } - fdin = open(restore_sector_file, O_RDONLY); - if (fdin < 0) { - perror(restore_sector_file); - error(_("cannot open partition restore file (%s)\n"), - restore_sector_file); - return 0; - } - if (read(fdin, ss, statbuf.st_size) != statbuf.st_size) { - perror("read"); - error(_("error reading %s\n"), restore_sector_file); - return 0; - } - - fdout = open(dev, O_WRONLY); - if (fdout < 0) { - perror(dev); - error(_("cannot open device %s for writing\n"), dev); - return 0; - } - - ss0 = ss; - ct = statbuf.st_size/516; - while(ct--) { - sno = chars_to_ulong(ss); - if (!sseek(dev, fdout, sno)) - return 0; - if (write(fdout, ss+4, 512) != 512) { - perror(dev); - error(_("error writing sector %lu on %s\n"), sno, dev); - return 0; - } - ss += 516; - } - free(ss0); - - reread_disk_partition(dev, fdout); - - return 1; -} - -/* - * C. About heads, sectors and cylinders - */ - -/* - * defines HDIO_GETGEO and - * struct hd_geometry { - * unsigned char heads; - * unsigned char sectors; - * unsigned short cylinders; - * unsigned long start; - * }; - * - * For large disks g.cylinders is truncated, so we use BLKGETSIZE. - */ - -/* - * We consider several geometries for a disk: - * B - the BIOS geometry, gotten from the kernel via HDIO_GETGEO - * F - the fdisk geometry - * U - the user-specified geometry - * - * 0 means unspecified / unknown - */ -struct geometry { - unsigned long long total_size; /* in sectors */ - unsigned long cylindersize; /* in sectors */ - unsigned long heads, sectors, cylinders; - unsigned long start; -} B, F, U; - -static struct geometry -get_geometry(char *dev, int fd, int silent) { - struct hd_geometry g; - unsigned long cyls; - unsigned long long sectors; - struct geometry R; - - if (ioctl(fd, HDIO_GETGEO, &g)) { - g.heads = g.sectors = g.cylinders = g.start = 0; - if (!silent) - do_warn(_("Disk %s: cannot get geometry\n"), dev); - } - - R.start = g.start; - R.heads = g.heads; - R.sectors = g.sectors; - R.cylindersize = R.heads * R.sectors; - R.cylinders = 0; - R.total_size = 0; - - if (disksize(fd, §ors)) { - /* maybe an ordinary file */ - struct stat s; - - if (fstat(fd, &s) == 0 && S_ISREG(s.st_mode)) - R.total_size = (s.st_size >> 9); - else if (!silent) - do_warn(_("Disk %s: cannot get size\n"), dev); - } else - R.total_size = sectors; - - if (R.cylindersize && R.total_size) { - sectors /= R.cylindersize; - cyls = sectors; - if (cyls != sectors) - cyls = ~0; - R.cylinders = cyls; - } - - return R; -} - -static void -get_cylindersize(char *dev, int fd, int silent) { - struct geometry R; - - R = get_geometry(dev, fd, silent); - - B.heads = (U.heads ? U.heads : R.heads); - B.sectors = (U.sectors ? U.sectors : R.sectors); - B.cylinders = (U.cylinders ? U.cylinders : R.cylinders); - - B.cylindersize = B.heads * B.sectors; - B.total_size = R.total_size; - - if (B.cylinders == 0 && B.cylindersize != 0) - B.cylinders = B.total_size / B.cylindersize; - - if (R.start && !force) { - warn( - _("Warning: start=%lu - this looks like a partition rather than\n" - "the entire disk. Using fdisk on it is probably meaningless.\n" - "[Use the --force option if you really want this]\n"), R.start); - exit(1); - } -#if 0 - if (R.heads && B.heads != R.heads) - warn(_("Warning: HDIO_GETGEO says that there are %lu heads\n"), - R.heads); - if (R.sectors && B.sectors != R.sectors) - warn(_("Warning: HDIO_GETGEO says that there are %lu sectors\n"), - R.sectors); - if (R.cylinders && B.cylinders != R.cylinders - && B.cylinders < 65536 && R.cylinders < 65536) - warn(_("Warning: BLKGETSIZE/HDIO_GETGEO says that there are %lu cylinders\n"), - R.cylinders); -#endif - - if (B.sectors > 63) - warn(_("Warning: unlikely number of sectors (%lu) - usually at most 63\n" - "This will give problems with all software that uses C/H/S addressing.\n"), - B.sectors); - if (!silent) - printf(_("\nDisk %s: %lu cylinders, %lu heads, %lu sectors/track\n"), - dev, B.cylinders, B.heads, B.sectors); -} - -typedef struct { unsigned char h,s,c; } PACKED chs; /* has some c bits in s */ -chs zero_chs = { 0,0,0 }; - -typedef struct { unsigned long h,s,c; } longchs; -longchs zero_longchs; - -static chs -longchs_to_chs (longchs aa, struct geometry G) { - chs a; - - if (aa.h < 256 && aa.s < 64 && aa.c < 1024) { - a.h = aa.h; - a.s = aa.s | ((aa.c >> 2) & 0xc0); - a.c = (aa.c & 0xff); - } else if (G.heads && G.sectors) { - a.h = G.heads - 1; - a.s = G.sectors | 0xc0; - a.c = 0xff; - } else - a = zero_chs; - return a; -} - -static longchs -chs_to_longchs (chs a) { - longchs aa; - - aa.h = a.h; - aa.s = (a.s & 0x3f); - aa.c = (a.s & 0xc0); - aa.c = (aa.c << 2) + a.c; - return aa; -} - -static longchs -ulong_to_longchs (unsigned long sno, struct geometry G) { - longchs aa; - - if (G.heads && G.sectors && G.cylindersize) { - aa.s = 1 + sno % G.sectors; - aa.h = (sno / G.sectors) % G.heads; - aa.c = sno / G.cylindersize; - return aa; - } else { - return zero_longchs; - } -} - -static chs -ulong_to_chs (unsigned long sno, struct geometry G) { - return longchs_to_chs(ulong_to_longchs(sno, G), G); -} - -#if 0 -static unsigned long -longchs_to_ulong (longchs aa, struct geometry G) { - return (aa.c*G.cylindersize + aa.h*G.sectors + aa.s - 1); -} - -static unsigned long -chs_to_ulong (chs a, struct geometry G) { - return longchs_to_ulong(chs_to_longchs(a), G); -} -#endif - -static int -is_equal_chs (chs a, chs b) { - return (a.h == b.h && a.s == b.s && a.c == b.c); -} - -static int -chs_ok (chs a, char *v, char *w) { - longchs aa = chs_to_longchs(a); - int ret = 1; - - if (is_equal_chs(a, zero_chs)) - return 1; - if (B.heads && aa.h >= B.heads) { - warn(_("%s of partition %s has impossible value for head: " - "%lu (should be in 0-%lu)\n"), w, v, aa.h, B.heads-1); - ret = 0; - } - if (B.sectors && (aa.s == 0 || aa.s > B.sectors)) { - warn(_("%s of partition %s has impossible value for sector: " - "%lu (should be in 1-%lu)\n"), w, v, aa.s, B.sectors); - ret = 0; - } - if (B.cylinders && aa.c >= B.cylinders) { - warn(_("%s of partition %s has impossible value for cylinders: " - "%lu (should be in 0-%lu)\n"), w, v, aa.c, B.cylinders-1); - ret = 0; - } - return ret; -} - -/* - * D. About system Ids - */ - -#define EMPTY_PARTITION 0 -#define EXTENDED_PARTITION 5 -#define WIN98_EXTENDED 0x0f -#define DM6_AUX1PARTITION 0x51 -#define DM6_AUX3PARTITION 0x53 -#define DM6_PARTITION 0x54 -#define EZD_PARTITION 0x55 -#define LINUX_SWAP 0x82 -#define LINUX_NATIVE 0x83 -#define LINUX_EXTENDED 0x85 -#define BSD_PARTITION 0xa5 -#define NETBSD_PARTITION 0xa9 - -/* List of partition types now in i386_sys_types.c */ - -static const char * -sysname(unsigned char type) { - struct systypes *s; - - for (s = i386_sys_types; s->name; s++) - if (s->type == type) - return _(s->name); - return _("Unknown"); -} - -static void -list_types(void) { - struct systypes *s; - - printf(_("Id Name\n\n")); - for (s = i386_sys_types; s->name; s++) - printf("%2x %s\n", s->type, _(s->name)); -} - -static int -is_extended(unsigned char type) { - return (type == EXTENDED_PARTITION - || type == LINUX_EXTENDED - || type == WIN98_EXTENDED); -} - -static int -is_bsd(unsigned char type) { - return (type == BSD_PARTITION || type == NETBSD_PARTITION); -} - -/* - * E. About partitions - */ - -/* MS/DOS partition */ - -struct partition { - unsigned char bootable; /* 0 or 0x80 */ - chs begin_chs; - unsigned char sys_type; - chs end_chs; - unsigned int start_sect; /* starting sector counting from 0 */ - unsigned int nr_sects; /* nr of sectors in partition */ -} PACKED; - -/* Unfortunately, partitions are not aligned, and non-Intel machines - are unhappy with non-aligned integers. So, we need a copy by hand. */ -static int -copy_to_int(unsigned char *cp) { - unsigned int m; - - m = *cp++; - m += (*cp++ << 8); - m += (*cp++ << 16); - m += (*cp++ << 24); - return m; -} - -static void -copy_from_int(int m, char *cp) { - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); m >>= 8; - *cp++ = (m & 0xff); -} - -static void -copy_to_part(char *cp, struct partition *p) { - p->bootable = *cp++; - p->begin_chs.h = *cp++; - p->begin_chs.s = *cp++; - p->begin_chs.c = *cp++; - p->sys_type = *cp++; - p->end_chs.h = *cp++; - p->end_chs.s = *cp++; - p->end_chs.c = *cp++; - p->start_sect = copy_to_int(cp); - p->nr_sects = copy_to_int(cp+4); -} - -static void -copy_from_part(struct partition *p, char *cp) { - *cp++ = p->bootable; - *cp++ = p->begin_chs.h; - *cp++ = p->begin_chs.s; - *cp++ = p->begin_chs.c; - *cp++ = p->sys_type; - *cp++ = p->end_chs.h; - *cp++ = p->end_chs.s; - *cp++ = p->end_chs.c; - copy_from_int(p->start_sect, cp); - copy_from_int(p->nr_sects, cp+4); -} - -/* Roughly speaking, Linux doesn't use any of the above fields except - for partition type, start sector and number of sectors. (However, - see also linux/drivers/scsi/fdomain.c.) - The only way partition type is used (in the kernel) is the comparison - for equality with EXTENDED_PARTITION (and these Disk Manager types). */ - -struct part_desc { - unsigned long start; - unsigned long size; - unsigned long sector, offset; /* disk location of this info */ - struct partition p; - struct part_desc *ep; /* extended partition containing this one */ - int ptype; -#define DOS_TYPE 0 -#define BSD_TYPE 1 -} zero_part_desc; - -static struct part_desc * -outer_extended_partition(struct part_desc *p) { - while (p->ep) - p = p->ep; - return p; -} - -static int -is_parent(struct part_desc *pp, struct part_desc *p) { - while (p) { - if (pp == p) - return 1; - p = p->ep; - } - return 0; -} - -struct disk_desc { - struct part_desc partitions[512]; - int partno; -} oldp, newp; - -/* determine where on the disk this information goes */ -static void -add_sector_and_offset(struct disk_desc *z) { - int pno; - struct part_desc *p; - - for (pno = 0; pno < z->partno; pno++) { - p = &(z->partitions[pno]); - p->offset = 0x1be + (pno%4)*sizeof(struct partition); - p->sector = (p->ep ? p->ep->start : 0); - } -} - -/* tell the kernel to reread the partition tables */ -static int -reread_ioctl(int fd) { - if (ioctl(fd, BLKRRPART)) { - perror("BLKRRPART"); - - /* 2.6.8 returns EIO for a zero table */ - if (errno == EBUSY) - return -1; - } - return 0; -} - -static int -is_blockdev(int fd) { - struct stat statbuf; - - return(fstat(fd, &statbuf) == 0 && S_ISBLK(statbuf.st_mode)); -} - -/* reread after writing */ -static void -reread_disk_partition(char *dev, int fd) { - printf(_("Re-reading the partition table ...\n")); - fflush(stdout); - sync(); - - if (reread_ioctl(fd) && is_blockdev(fd)) - do_warn(_("The command to re-read the partition table failed\n" - "Reboot your system now, before using mkfs\n")); - - if (close(fd)) { - perror(dev); - do_warn(_("Error closing %s\n"), dev); - } - printf("\n"); -} - -/* find Linux name of this partition, assuming that it will have a name */ -static int -index_to_linux(int pno, struct disk_desc *z) { - int i, ct = 1; - struct part_desc *p = &(z->partitions[0]); - for (i=0; isize > 0 && !is_extended(p->p.sys_type))) - ct++; - return ct; -} - -static int -linux_to_index(int lpno, struct disk_desc *z) { - int i, ct = 0; - struct part_desc *p = &(z->partitions[0]); - for (i=0; ipartno && ct < lpno; i++,p++) - if ((i < 4 || (p->size > 0 && !is_extended(p->p.sys_type))) - && ++ct == lpno) - return i; - return -1; -} - -static int -asc_to_index(char *pnam, struct disk_desc *z) { - int pnum, pno; - - if (*pnam == '#') { - pno = atoi(pnam+1); - } else { - pnum = atoi(pnam); - pno = linux_to_index(pnum, z); - } - if (!(pno >= 0 && pno < z->partno)) - fatal(_("%s: no such partition\n"), pnam); - return pno; -} - -/* - * List partitions - in terms of sectors, blocks or cylinders - */ -#define F_SECTOR 1 -#define F_BLOCK 2 -#define F_CYLINDER 3 -#define F_MEGABYTE 4 - -int default_format = F_MEGABYTE; -int specified_format = 0; -int show_extended = 0; -int one_only = 0; -int one_only_pno; -int increment = 0; - -static void -set_format(char c) { - switch(c) { - default: - do_warn(_("unrecognized format - using sectors\n")); - case 'S': specified_format = F_SECTOR; break; - case 'B': specified_format = F_BLOCK; break; - case 'C': specified_format = F_CYLINDER; break; - case 'M': specified_format = F_MEGABYTE; break; - } -} - -static unsigned long -unitsize(int format) { - default_format = (B.cylindersize ? F_CYLINDER : F_MEGABYTE); - if (!format && !(format = specified_format)) - format = default_format; - - switch(format) { - default: - case F_CYLINDER: - if (B.cylindersize) - return B.cylindersize; - case F_SECTOR: - return 1; - case F_BLOCK: - return 2; - case F_MEGABYTE: - return 2048; - } -} - -static unsigned long -get_disksize(int format) { - unsigned long cs = B.cylinders; - if (cs && leave_last) - cs--; - return (cs * B.cylindersize) / unitsize(format); -} - -static void -out_partition_header(char *dev, int format, struct geometry G) { - if (dump) { - printf(_("# partition table of %s\n"), dev); - printf("unit: sectors\n\n"); - return; - } - - default_format = (G.cylindersize ? F_CYLINDER : F_MEGABYTE); - if (!format && !(format = specified_format)) - format = default_format; - - switch(format) { - default: - do_warn(_("unimplemented format - using %s\n"), - G.cylindersize ? _("cylinders") : _("sectors")); - case F_CYLINDER: - if (G.cylindersize) { - printf(_("Units = cylinders of %lu bytes, blocks of 1024 bytes" - ", counting from %d\n\n"), - G.cylindersize<<9, increment); - printf(_(" Device Boot Start End #cyls #blocks Id System\n")); - break; - } - /* fall through */ - case F_SECTOR: - printf(_("Units = sectors of 512 bytes, counting from %d\n\n"), - increment); - printf(_(" Device Boot Start End #sectors Id System\n")); - break; - case F_BLOCK: - printf(_("Units = blocks of 1024 bytes, counting from %d\n\n"), - increment); - printf(_(" Device Boot Start End #blocks Id System\n")); - break; - case F_MEGABYTE: - printf(_("Units = mebibytes of 1048576 bytes, blocks of 1024 bytes" - ", counting from %d\n\n"), increment); - printf(_(" Device Boot Start End MiB #blocks Id System\n")); - break; - } -} - -static void -out_rounddown(int width, unsigned long n, unsigned long unit, int inc) { - printf("%*lu", width, inc + n/unit); - if (unit != 1) - putchar((n % unit) ? '+' : ' '); - putchar(' '); -} - -static void -out_roundup(int width, unsigned long n, unsigned long unit, int inc) { - if (n == (unsigned long)(-1)) - printf("%*s", width, "-"); - else - printf("%*lu", width, inc + n/unit); - if (unit != 1) - putchar(((n+1) % unit) ? '-' : ' '); - putchar(' '); -} - -static void -out_roundup_size(int width, unsigned long n, unsigned long unit) { - printf("%*lu", width, (n+unit-1)/unit); - if (unit != 1) - putchar((n % unit) ? '-' : ' '); - putchar(' '); -} - -static struct geometry -get_fdisk_geometry_one(struct part_desc *p) { - struct geometry G; - - chs b = p->p.end_chs; - longchs bb = chs_to_longchs(b); - G.heads = bb.h+1; - G.sectors = bb.s; - G.cylindersize = G.heads*G.sectors; - G.cylinders = G.start = 0; - return G; -} - -static int -get_fdisk_geometry(struct disk_desc *z) { - struct part_desc *p; - int pno, agree; - struct geometry G0, G; - - agree = 0; - G0.heads = G0.sectors = 0; - for (pno=0; pno < z->partno; pno++) { - p = &(z->partitions[pno]); - if (p->size != 0 && p->p.sys_type != 0) { - G = get_fdisk_geometry_one(p); - if (!G0.heads) { - G0 = G; - agree = 1; - } else if (G.heads != G0.heads || G.sectors != G0.sectors) { - agree = 0; - break; - } - } - } - F = (agree ? G0 : B); - return (F.sectors != B.sectors || F.heads != B.heads); -} - -static void -out_partition(char *dev, int format, struct part_desc *p, - struct disk_desc *z, struct geometry G) { - unsigned long start, end, size; - int pno, lpno; - - if (!format && !(format = specified_format)) - format = default_format; - - pno = p - &(z->partitions[0]); /* our index */ - lpno = index_to_linux(pno, z); /* name of next one that has a name */ - if (pno == linux_to_index(lpno, z)) /* was that us? */ - printf("%s", partname(dev, lpno, 10)); /* yes */ - else if (show_extended) - printf(" - "); - else - return; - putchar(dump ? ':' : ' '); - - start = p->start; - end = p->start + p->size - 1; - size = p->size; - - if (dump) { - printf(" start=%9lu", start); - printf(", size=%9lu", size); - if (p->ptype == DOS_TYPE) { - printf(", Id=%2x", p->p.sys_type); - if (p->p.bootable == 0x80) - printf(", bootable"); - } - printf("\n"); - return; - } - - if (p->ptype != DOS_TYPE || p->p.bootable == 0) - printf(" "); - else if (p->p.bootable == 0x80) - printf(" * "); - else - printf(" ? "); /* garbage */ - - switch(format) { - case F_CYLINDER: - if (G.cylindersize) { - out_rounddown(6, start, G.cylindersize, increment); - out_roundup(6, end, G.cylindersize, increment); - out_roundup_size(6, size, G.cylindersize); - out_rounddown(9, size, 2, 0); - break; - } - /* fall through */ - default: - case F_SECTOR: - out_rounddown(9, start, 1, increment); - out_roundup(9, end, 1, increment); - out_rounddown(10, size, 1, 0); - break; - case F_BLOCK: -#if 0 - printf("%8lu,%3lu ", - p->sector/2, ((p->sector & 1) ? 512 : 0) + p->offset); -#endif - out_rounddown(8, start, 2, increment); - out_roundup(8, end, 2, increment); - out_rounddown(9, size, 2, 0); - break; - case F_MEGABYTE: - out_rounddown(5, start, 2048, increment); - out_roundup(5, end, 2048, increment); - out_roundup_size(5, size, 2048); - out_rounddown(9, size, 2, 0); - break; - } - if (p->ptype == DOS_TYPE) { - printf(" %2x %s\n", - p->p.sys_type, sysname(p->p.sys_type)); - } else { - printf("\n"); - } - - /* Is chs as we expect? */ - if (!quiet && p->ptype == DOS_TYPE) { - chs a, b; - longchs aa, bb; - a = (size ? ulong_to_chs(start,G) : zero_chs); - b = p->p.begin_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (a.s && !is_equal_chs(a, b)) - do_warn(_("\t\tstart: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"), - aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - a = (size ? ulong_to_chs(end,G) : zero_chs); - b = p->p.end_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (a.s && !is_equal_chs(a, b)) - do_warn(_("\t\tend: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"), - aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - if (G.cylinders && G.cylinders < 1024 && bb.c > G.cylinders) - do_warn(_("partition ends on cylinder %ld, beyond the end of the disk\n"), - bb.c); - } -} - -static void -out_partitions(char *dev, struct disk_desc *z) { - int pno, format = 0; - - if (z->partno == 0) - do_warn(_("No partitions found\n")); - else { - if (get_fdisk_geometry(z) && !dump) { - do_warn( - _("Warning: The partition table looks like it was made\n" - " for C/H/S=*/%ld/%ld (instead of %ld/%ld/%ld).\n" - "For this listing I'll assume that geometry.\n"), - F.heads, F.sectors, B.cylinders, B.heads, B.sectors); - } - - out_partition_header(dev, format, F); - for(pno=0; pno < z->partno; pno++) { - out_partition(dev, format, &(z->partitions[pno]), z, F); - if (show_extended && pno%4==3) - printf("\n"); - } - } -} - -static int -disj(struct part_desc *p, struct part_desc *q) { - return - ((p->start + p->size <= q->start) - || (is_extended(p->p.sys_type) - && q->start + q->size <= p->start + p->size)); -} - -static char * -pnumber(struct part_desc *p, struct disk_desc *z) { - static char buf[20]; - int this, next; - struct part_desc *p0 = &(z->partitions[0]); - - this = index_to_linux(p-p0, z); - next = index_to_linux(p-p0+1, z); - - if (next > this) - sprintf(buf, "%d", this); - else - sprintf(buf, "[%d]", this); - return buf; -} - -static int -partitions_ok(struct disk_desc *z) { - struct part_desc *partitions = &(z->partitions[0]), *p, *q; - int partno = z->partno; - -#define PNO(p) pnumber(p, z) - - /* Have at least 4 partitions been defined? */ - if (partno < 4) { - if (!partno) - fatal(_("no partition table present.\n")); - else - fatal(_("strange, only %d partitions defined.\n"), partno); - return 0; - } - - /* Are the partitions of size 0 marked empty? - And do they have start = 0? And bootable = 0? */ - for (p = partitions; p - partitions < partno; p++) - if (p->size == 0) { - if (p->p.sys_type != EMPTY_PARTITION) - warn(_("Warning: partition %s has size 0 but is not marked Empty\n"), - PNO(p)); - else if (p->p.bootable != 0) - warn(_("Warning: partition %s has size 0 and is bootable\n"), - PNO(p)); - else if (p->p.start_sect != 0) - warn(_("Warning: partition %s has size 0 and nonzero start\n"), - PNO(p)); - /* all this is probably harmless, no error return */ - } - - /* Are the logical partitions contained in their extended partitions? */ - for (p = partitions+4; p < partitions+partno; p++) - if (p->ptype == DOS_TYPE) - if (p->size && !is_extended(p->p.sys_type)) { - q = p->ep; - if (p->start < q->start || p->start + p->size > q->start + q->size) { - warn(_("Warning: partition %s "), PNO(p)); - warn(_("is not contained in partition %s\n"), PNO(q)); - return 0; - } - } - - /* Are the data partitions mutually disjoint? */ - for (p = partitions; p < partitions+partno; p++) - if (p->size && !is_extended(p->p.sys_type)) - for (q = p+1; q < partitions+partno; q++) - if (q->size && !is_extended(q->p.sys_type)) - if (!((p->start > q-> start) ? disj(q,p) : disj(p,q))) { - warn(_("Warning: partitions %s "), PNO(p)); - warn(_("and %s overlap\n"), PNO(q)); - return 0; - } - - /* Are the data partitions and the extended partition - table sectors disjoint? */ - for (p = partitions; p < partitions+partno; p++) - if (p->size && !is_extended(p->p.sys_type)) - for (q = partitions; q < partitions+partno; q++) - if (is_extended(q->p.sys_type)) - if (p->start <= q->start && p->start + p->size > q->start) { - warn(_("Warning: partition %s contains part of " - "the partition table (sector %lu),\n" - "and will destroy it when filled\n"), - PNO(p), q->start); - return 0; - } - - /* Do they start past zero and end before end-of-disk? */ - { unsigned long ds = get_disksize(F_SECTOR); - for (p = partitions; p < partitions+partno; p++) - if (p->size) { - if (p->start == 0) { - warn(_("Warning: partition %s starts at sector 0\n"), PNO(p)); - return 0; - } - if (p->size && p->start + p->size > ds) { - warn(_("Warning: partition %s extends past end of disk\n"), - PNO(p)); - return 0; - } - } - } - - /* At most one chain of DOS extended partitions ? */ - /* It seems that the OS/2 fdisk has the additional requirement - that the extended partition must be the fourth one */ - { int ect = 0; - for (p = partitions; p < partitions+4; p++) - if (p->p.sys_type == EXTENDED_PARTITION) - ect++; - if (ect > 1 && !Linux) { - warn(_("Among the primary partitions, at most one can be extended\n" - " (although this is not a problem under Linux)\n")); - return 0; - } - } - - /* - * Do all partitions start at a cylinder boundary ? - * (this is not required for Linux) - * The first partition starts after MBR. - * Logical partitions start slightly after the containing extended partn. - */ - if (B.cylindersize) { - for(p = partitions; p < partitions+partno; p++) - if (p->size) { - if (p->start % B.cylindersize != 0 - && (!p->ep || p->start / B.cylindersize != p->ep->start / B.cylindersize) - && (p->p.start_sect >= B.cylindersize)) { - warn(_("Warning: partition %s does not start " - "at a cylinder boundary\n"), PNO(p)); - if (!Linux) - return 0; - } - if ((p->start + p->size) % B.cylindersize) { - warn(_("Warning: partition %s does not end " - "at a cylinder boundary\n"), PNO(p)); - if (!Linux) - return 0; - } - } - } - - /* Usually, one can boot only from primary partitions. */ - /* In fact, from a unique one only. */ - /* do not warn about bootable extended partitions - - often LILO is there */ - { int pno = -1; - for(p = partitions; p < partitions+partno; p++) - if (p->p.bootable) { - if (pno == -1) - pno = p - partitions; - else if (p - partitions < 4) { - warn(_("Warning: more than one primary partition is marked " - "bootable (active)\n" - "This does not matter for LILO, but the DOS MBR will " - "not boot this disk.\n")); - break; - } - if (p - partitions >= 4) { - warn(_("Warning: usually one can boot from primary partitions " - "only\nLILO disregards the `bootable' flag.\n")); - break; - } - } - if (pno == -1 || pno >= 4) - warn(_("Warning: no primary partition is marked bootable (active)\n" - "This does not matter for LILO, but the DOS MBR will " - "not boot this disk.\n")); - } - - /* Is chs as we expect? */ - for(p = partitions; p < partitions+partno; p++) - if (p->ptype == DOS_TYPE) { - chs a, b; - longchs aa, bb; - a = p->size ? ulong_to_chs(p->start,B) : zero_chs; - b = p->p.begin_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (!chs_ok(b, PNO(p), _("start"))) - return 0; - if (a.s && !is_equal_chs(a, b)) - warn(_("partition %s: start: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"), - PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - a = p->size ? ulong_to_chs(p->start + p->size - 1, B) : zero_chs; - b = p->p.end_chs; - aa = chs_to_longchs(a); - bb = chs_to_longchs(b); - if (!chs_ok(b, PNO(p), _("end"))) - return 0; - if (a.s && !is_equal_chs(a, b)) - warn(_("partition %s: end: (c,h,s) expected (%ld,%ld,%ld) found (%ld,%ld,%ld)\n"), - PNO(p), aa.c, aa.h, aa.s, bb.c, bb.h, bb.s); - if (B.cylinders && B.cylinders < 1024 && bb.c > B.cylinders) - warn(_("partition %s ends on cylinder %ld, beyond the end of the disk\n"), - PNO(p), bb.c); - } - - return 1; - -#undef PNO -} - -static void -extended_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { - char *cp; - struct sector *s; - unsigned long start, here, next; - int i, moretodo = 1; - struct partition p; - struct part_desc *partitions = &(z->partitions[0]); - int pno = z->partno; - - here = start = ep->start; - - if (B.cylindersize && start % B.cylindersize) { - /* This is BAD */ - if (DOS_extended) { - here = start -= (start % B.cylindersize); - do_warn(_("Warning: shifted start of the extd partition " - "from %ld to %ld\n" - "(For listing purposes only. " - "Do not change its contents.)\n"), - ep->start, start); - } else { - do_warn(_("Warning: extended partition does not start at a " - "cylinder boundary.\n" - "DOS and Linux will interpret the contents differently.\n")); - } - } - - while (moretodo) { - moretodo = 0; - - if (!(s = get_sector(dev, fd, here))) - break; - - if (!msdos_signature(s)) - break; - - cp = s->data + 0x1be; - - if (pno+4 >= SIZE(z->partitions)) { - do_warn(_("too many partitions - ignoring those past nr (%d)\n"), - pno-1); - break; - } - - next = 0; - - for (i=0; i<4; i++,cp += sizeof(struct partition)) { - partitions[pno].sector = here; - partitions[pno].offset = cp - s->data; - partitions[pno].ep = ep; - copy_to_part(cp,&p); - if (is_extended(p.sys_type)) { - partitions[pno].start = start + p.start_sect; - if (next) - do_warn(_("tree of partitions?\n")); - else - next = partitions[pno].start; /* follow `upper' branch */ - moretodo = 1; - } else { - partitions[pno].start = here + p.start_sect; - } - partitions[pno].size = p.nr_sects; - partitions[pno].ptype = DOS_TYPE; - partitions[pno].p = p; - pno++; - } - here = next; - } - - z->partno = pno; -} - -#define BSD_DISKMAGIC (0x82564557UL) -#define BSD_MAXPARTITIONS 16 -#define BSD_FS_UNUSED 0 -typedef unsigned char u8; -typedef unsigned short u16; -typedef unsigned int u32; -struct bsd_disklabel { - u32 d_magic; - char d_junk1[4]; - char d_typename[16]; - char d_packname[16]; - char d_junk2[92]; - u32 d_magic2; - char d_junk3[2]; - u16 d_npartitions; /* number of partitions in following */ - char d_junk4[8]; - struct bsd_partition { /* the partition table */ - u32 p_size; /* number of sectors in partition */ - u32 p_offset; /* starting sector */ - u32 p_fsize; /* filesystem basic fragment size */ - u8 p_fstype; /* filesystem type, see below */ - u8 p_frag; /* filesystem fragments per block */ - u16 p_cpg; /* filesystem cylinders per group */ - } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ -}; - -static void -bsd_partition(char *dev, int fd, struct part_desc *ep, struct disk_desc *z) { - struct bsd_disklabel *l; - struct bsd_partition *bp, *bp0; - unsigned long start = ep->start; - struct sector *s; - struct part_desc *partitions = &(z->partitions[0]); - int pno = z->partno; - - if (!(s = get_sector(dev,fd,start+1))) - return; - l = (struct bsd_disklabel *) (s->data); - if (l->d_magic != BSD_DISKMAGIC || l->d_magic2 != BSD_DISKMAGIC) - return; - - bp = bp0 = &l->d_partitions[0]; - while (bp - bp0 < BSD_MAXPARTITIONS && bp - bp0 < l->d_npartitions) { - if (pno+1 >= SIZE(z->partitions)) { - do_warn(_("too many partitions - ignoring those " - "past nr (%d)\n"), pno-1); - break; - } - if (bp->p_fstype != BSD_FS_UNUSED) { - partitions[pno].start = bp->p_offset; - partitions[pno].size = bp->p_size; - partitions[pno].sector = start+1; - partitions[pno].offset = (char *)bp - (char *)bp0; - partitions[pno].ep = 0; - partitions[pno].ptype = BSD_TYPE; - pno++; - } - bp++; - } - z->partno = pno; -} - -#define MAKE_VERSION(p,q,r) (65536*(p) + 256*(q) + (r)) - -static int -linux_version_code(void) { - struct utsname my_utsname; - int p, q, r; - - if (uname(&my_utsname) == 0) { - p = atoi(strtok(my_utsname.release, ".")); - q = atoi(strtok(NULL, ".")); - r = atoi(strtok(NULL, ".")); - return MAKE_VERSION(p,q,r); - } - return 0; -} - -static int -msdos_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - int i; - char *cp; - struct partition pt; - struct sector *s; - struct part_desc *partitions = &(z->partitions[0]); - int pno = z->partno; - int bsd_later = (linux_version_code() >= MAKE_VERSION(2,3,40)); - - if (!(s = get_sector(dev, fd, start))) - return 0; - - if (!msdos_signature(s)) - return 0; - - cp = s->data + 0x1be; - copy_to_part(cp,&pt); - - /* If I am not mistaken, recent kernels will hide this from us, - so we will never actually see traces of a Disk Manager */ - if (pt.sys_type == DM6_PARTITION - || pt.sys_type == EZD_PARTITION - || pt.sys_type == DM6_AUX1PARTITION - || pt.sys_type == DM6_AUX3PARTITION) { - do_warn(_("detected Disk Manager - unable to handle that\n")); - return 0; - } - { unsigned int sig = *(unsigned short *)(s->data + 2); - if (sig <= 0x1ae - && *(unsigned short *)(s->data + sig) == 0x55aa - && (1 & *(unsigned char *)(s->data + sig + 2))) { - do_warn(_("DM6 signature found - giving up\n")); - return 0; - } - } - - for (pno=0; pno<4; pno++,cp += sizeof(struct partition)) { - partitions[pno].sector = start; - partitions[pno].offset = cp - s->data; - copy_to_part(cp,&pt); - partitions[pno].start = start + pt.start_sect; - partitions[pno].size = pt.nr_sects; - partitions[pno].ep = 0; - partitions[pno].p = pt; - } - - z->partno = pno; - - for (i=0; i<4; i++) { - if (is_extended(partitions[i].p.sys_type)) { - if (!partitions[i].size) { - do_warn(_("strange..., an extended partition of size 0?\n")); - continue; - } - extended_partition(dev, fd, &partitions[i], z); - } - if (!bsd_later && is_bsd(partitions[i].p.sys_type)) { - if (!partitions[i].size) { - do_warn(_("strange..., a BSD partition of size 0?\n")); - continue; - } - bsd_partition(dev, fd, &partitions[i], z); - } - } - - if (bsd_later) { - for (i=0; i<4; i++) { - if (is_bsd(partitions[i].p.sys_type)) { - if (!partitions[i].size) { - do_warn(_("strange..., a BSD partition of size 0?\n")); - continue; - } - bsd_partition(dev, fd, &partitions[i], z); - } - } - } - - return 1; -} - -static int -osf_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -static int -sun_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -static int -amiga_partition(char *dev, int fd, unsigned long start, struct disk_desc *z) { - return 0; -} - -static void -get_partitions(char *dev, int fd, struct disk_desc *z) { - z->partno = 0; - - if (!msdos_partition(dev, fd, 0, z) - && !osf_partition(dev, fd, 0, z) - && !sun_partition(dev, fd, 0, z) - && !amiga_partition(dev, fd, 0, z)) { - do_warn(_(" %s: unrecognized partition table type\n"), dev); - return; - } -} - -static int -write_partitions(char *dev, int fd, struct disk_desc *z) { - struct sector *s; - struct part_desc *partitions = &(z->partitions[0]), *p; - int pno = z->partno; - - if (no_write) { - do_warn(_("-n flag was given: Nothing changed\n")); - exit(0); - } - - for (p = partitions; p < partitions+pno; p++) { - s = get_sector(dev, fd, p->sector); - if (!s) return 0; - s->to_be_written = 1; - if (p->ptype == DOS_TYPE) { - copy_from_part(&(p->p), s->data + p->offset); - s->data[510] = 0x55; - s->data[511] = 0xaa; - } - } - if (save_sector_file) { - if (!save_sectors(dev, fd)) { - fatal(_("Failed saving the old sectors - aborting\n")); - return 0; - } - } - if (!write_sectors(dev, fd)) { - error(_("Failed writing the partition on %s\n"), dev); - return 0; - } - return 1; -} - -/* - * F. The standard input - */ - -/* - * Input format: - * - * Fields are separated by whitespace or comma or semicolon possibly - * followed by whitespace; initial and trailing whitespace is ignored. - * Numbers can be octal, decimal or hexadecimal, decimal is default - * The parts can (and probably should) be omitted. - * Bootable is specified as [*|-], with as default not-bootable. - * Type is given in hex, without the 0x prefix, or is [E|S|L|X], where - * L (LINUX_NATIVE (83)) is the default, S is LINUX_SWAP (82), and E - * is EXTENDED_PARTITION (5), X is LINUX_EXTENDED (85). - * The default value of start is the first nonassigned sector/cylinder/... - * The default value of size is as much as possible (until next - * partition or end-of-disk). - * .: end of chain of extended partitions. - * - * On interactive input an empty line means: all defaults. - * Otherwise empty lines are ignored. - */ - -int eof, eob; - -struct dumpfld { - int fldno; - char *fldname; - int is_bool; -} dumpflds[] = { - { 0, "start", 0 }, - { 1, "size", 0 }, - { 2, "Id", 0 }, - { 3, "bootable", 1 }, - { 4, "bh", 0 }, - { 5, "bs", 0 }, - { 6, "bc", 0 }, - { 7, "eh", 0 }, - { 8, "es", 0 }, - { 9, "ec", 0 } -}; - -/* - * Read a line, split it into fields - * - * (some primitive handwork, but a more elaborate parser seems - * unnecessary) - */ -#define RD_EOF (-1) -#define RD_CMD (-2) - -static int -read_stdin(unsigned char **fields, unsigned char *line, int fieldssize, int linesize) { - unsigned char *lp, *ip; - int c, fno; - - /* boolean true and empty string at start */ - line[0] = '*'; - line[1] = 0; - for (fno=0; fno < fieldssize; fno++) - fields[fno] = line + 1; - fno = 0; - - /* read a line from stdin */ - lp = fgets(line+2, linesize, stdin); - if (lp == NULL) { - eof = 1; - return RD_EOF; - } - if (!(lp = index(lp, '\n'))) - fatal(_("long or incomplete input line - quitting\n")); - *lp = 0; - - /* remove comments, if any */ - if ((lp = index(line+2, '#')) != 0) - *lp = 0; - - /* recognize a few commands - to be expanded */ - if (!strcmp(line+2, "unit: sectors")) { - specified_format = F_SECTOR; - return RD_CMD; - } - - /* dump style? - then bad input is fatal */ - if ((ip = index(line+2, ':')) != 0) { - struct dumpfld *d; - - nxtfld: - ip++; - while(isspace(*ip)) - ip++; - if (*ip == 0) - return fno; - for(d = dumpflds; d-dumpflds < SIZE(dumpflds); d++) { - if (!strncmp(ip, d->fldname, strlen(d->fldname))) { - ip += strlen(d->fldname); - while(isspace(*ip)) - ip++; - if (d->is_bool) - fields[d->fldno] = line; - else if (*ip == '=') { - while(isspace(*++ip)) ; - fields[d->fldno] = ip; - while(isalnum(*ip)) /* 0x07FF */ - ip++; - } else - fatal(_("input error: `=' expected after %s field\n"), - d->fldname); - if (fno <= d->fldno) - fno = d->fldno + 1; - if (*ip == 0) - return fno; - if (*ip != ',' && *ip != ';') - fatal(_("input error: unexpected character %c after %s field\n"), - *ip, d->fldname); - *ip = 0; - goto nxtfld; - } - } - fatal(_("unrecognized input: %s\n"), ip); - } - - /* split line into fields */ - lp = ip = line+2; - fields[fno++] = lp; - while((c = *ip++) != 0) { - if (!lp[-1] && (c == '\t' || c == ' ')) - ; - else if (c == '\t' || c == ' ' || c == ',' || c == ';') { - *lp++ = 0; - if (fno < fieldssize) - fields[fno++] = lp; - continue; - } else - *lp++ = c; - } - - if (lp == fields[fno-1]) - fno--; - return fno; -} - -/* read a number, use default if absent */ -/* a sign gives an offset from the default */ -static int -get_ul(char *u, unsigned long *up, unsigned long def, int base) { - char *nu; - int sign = 0; - unsigned long val; - - if (*u == '+') { - sign = 1; - u++; - } else if (*u == '-') { - sign = -1; - u++; - } - if (*u) { - errno = 0; - val = strtoul(u, &nu, base); - if (errno == ERANGE) { - do_warn(_("number too big\n")); - return -1; - } - if (*nu) { - do_warn(_("trailing junk after number\n")); - return -1; - } - if (sign == 1) - val = def + val; - else if (sign == -1) - val = def - val; - *up = val; - } else - *up = def; - return 0; -} - -/* There are two common ways to structure extended partitions: - as nested boxes, and as a chain. Sometimes the partitions - must be given in order. Sometimes all logical partitions - must lie inside the outermost extended partition. -NESTED: every partition is contained in the surrounding partitions - and is disjoint from all others. -CHAINED: every data partition is contained in the surrounding partitions - and disjoint from all others, but extended partitions may lie outside - (insofar as allowed by all_logicals_inside_outermost_extended). -ONESECTOR: all data partitions are mutually disjoint; extended partitions - each use one sector only (except perhaps for the outermost one). -*/ -int partitions_in_order = 0; -int all_logicals_inside_outermost_extended = 1; -enum { NESTED, CHAINED, ONESECTOR } boxes = NESTED; - -/* find the default value for - assuming entire units */ -static unsigned long -first_free(int pno, int is_extended, struct part_desc *ep, int format, - unsigned long mid, struct disk_desc *z) { - unsigned long ff, fff; - unsigned long unit = unitsize(format); - struct part_desc *partitions = &(z->partitions[0]), *pp = 0; - - /* if containing ep undefined, look at its container */ - if (ep && ep->p.sys_type == EMPTY_PARTITION) - ep = ep->ep; - - if (ep) { - if (boxes == NESTED || (boxes == CHAINED && !is_extended)) - pp = ep; - else if (all_logicals_inside_outermost_extended) - pp = outer_extended_partition(ep); - } -#if 0 - ff = pp ? (pp->start + unit - 1) / unit : 0; -#else - /* rounding up wastes almost an entire cylinder - round down - and leave it to compute_start_sect() to fix the difference */ - ff = pp ? pp->start / unit : 0; -#endif - /* MBR and 1st sector of an extended partition are never free */ - if (unit == 1) - ff++; - - again: - for(pp = partitions; pp < partitions+pno; pp++) { - if (!is_parent(pp, ep) && pp->size > 0) { - if ((partitions_in_order || pp->start / unit <= ff - || (mid && pp->start / unit <= mid)) - && (fff = (pp->start + pp->size + unit - 1) / unit) > ff) { - ff = fff; - goto again; - } - } - } - - return ff; -} - -/* find the default value for - assuming entire units */ -static unsigned long -max_length(int pno, int is_extended, struct part_desc *ep, int format, - unsigned long start, struct disk_desc *z) { - unsigned long fu; - unsigned long unit = unitsize(format); - struct part_desc *partitions = &(z->partitions[0]), *pp = 0; - - /* if containing ep undefined, look at its container */ - if (ep && ep->p.sys_type == EMPTY_PARTITION) - ep = ep->ep; - - if (ep) { - if (boxes == NESTED || (boxes == CHAINED && !is_extended)) - pp = ep; - else if (all_logicals_inside_outermost_extended) - pp = outer_extended_partition(ep); - } - fu = pp ? (pp->start + pp->size) / unit : get_disksize(format); - - for(pp = partitions; pp < partitions+pno; pp++) - if (!is_parent(pp, ep) && pp->size > 0 - && pp->start / unit >= start && pp->start / unit < fu) - fu = pp->start / unit; - - return (fu > start) ? fu - start : 0; -} - -/* compute starting sector of a partition inside an extended one */ -/* return 0 on failure */ -/* ep is 0 or points to surrounding extended partition */ -static int -compute_start_sect(struct part_desc *p, struct part_desc *ep) { - unsigned long base; - int inc = (DOS && B.sectors) ? B.sectors : 1; - int delta; - - if (ep && p->start + p->size >= ep->start + 1) - delta = p->start - ep->start - inc; - else if (p->start == 0 && p->size > 0) - delta = -inc; - else - delta = 0; - - if (delta < 0) { - p->start -= delta; - p->size += delta; - if (is_extended(p->p.sys_type) && boxes == ONESECTOR) - p->size = inc; - else if ((int)(p->size) <= 0) { - warn(_("no room for partition descriptor\n")); - return 0; - } - } - base = (!ep ? 0 - : (is_extended(p->p.sys_type) ? - outer_extended_partition(ep) : ep)->start); - p->ep = ep; - if (p->p.sys_type == EMPTY_PARTITION && p->size == 0) { - p->p.start_sect = 0; - p->p.begin_chs = zero_chs; - p->p.end_chs = zero_chs; - } else { - p->p.start_sect = p->start - base; - p->p.begin_chs = ulong_to_chs(p->start,B); - p->p.end_chs = ulong_to_chs(p->start + p->size - 1,B); - } - p->p.nr_sects = p->size; - return 1; -} - -/* build the extended partition surrounding a given logical partition */ -static int -build_surrounding_extended(struct part_desc *p, struct part_desc *ep, - struct disk_desc *z) { - int inc = (DOS && B.sectors) ? B.sectors : 1; - int format = F_SECTOR; - struct part_desc *p0 = &(z->partitions[0]), *eep = ep->ep; - - if (boxes == NESTED) { - ep->start = first_free(ep-p0, 1, eep, format, p->start, z); - ep->size = max_length(ep-p0, 1, eep, format, ep->start, z); - if (ep->start > p->start || ep->start + ep->size < p->start + p->size) { - warn(_("cannot build surrounding extended partition\n")); - return 0; - } - } else { - ep->start = p->start; - if (boxes == CHAINED) - ep->size = p->size; - else - ep->size = inc; - } - - ep->p.nr_sects = ep->size; - ep->p.bootable = 0; - ep->p.sys_type = EXTENDED_PARTITION; - if (!compute_start_sect(ep, eep) || !compute_start_sect(p, ep)) { - ep->p.sys_type = EMPTY_PARTITION; - ep->size = 0; - return 0; - } - - return 1; -} - -static int -read_line(int pno, struct part_desc *ep, char *dev, int interactive, - struct disk_desc *z) { - unsigned char line[1000]; - unsigned char *fields[11]; - int fno, pct = pno%4; - struct part_desc p, *orig; - unsigned long ff, ff1, ul, ml, ml1, def; - int format, lpno, is_extd; - - if (eof || eob) - return -1; - - lpno = index_to_linux(pno, z); - - if (interactive) { - if (pct == 0 && (show_extended || pno == 0)) - warn("\n"); - warn("%s:", partname(dev, lpno, 10)); - } - - /* read input line - skip blank lines when reading from a file */ - do { - fno = read_stdin(fields, line, SIZE(fields), SIZE(line)); - } while(fno == RD_CMD || (fno == 0 && !interactive)); - if (fno == RD_EOF) { - return -1; - } else if (fno > 10 && *(fields[10]) != 0) { - do_warn(_("too many input fields\n")); - return 0; - } - - if (fno == 1 && !strcmp(fields[0], ".")) { - eob = 1; - return -1; - } - - /* use specified format, but round to cylinders if F_MEGABYTE specified */ - format = 0; - if (B.cylindersize && specified_format == F_MEGABYTE) - format = F_CYLINDER; - - orig = (one_only ? &(oldp.partitions[pno]) : 0); - - p = zero_part_desc; - p.ep = ep; - - /* first read the type - we need to know whether it is extended */ - /* stop reading when input blank (defaults) and all is full */ - is_extd = 0; - if (fno == 0) { /* empty line */ - if (orig && is_extended(orig->p.sys_type)) - is_extd = 1; - ff = first_free(pno, is_extd, ep, format, 0, z); - ml = max_length(pno, is_extd, ep, format, ff, z); - if (ml == 0 && is_extd == 0) { - is_extd = 1; - ff = first_free(pno, is_extd, ep, format, 0, z); - ml = max_length(pno, is_extd, ep, format, ff, z); - } - if (ml == 0 && pno >= 4) { - /* no free blocks left - don't read any further */ - warn(_("No room for more\n")); - return -1; - } - } - if (fno < 3 || !*(fields[2])) - ul = orig ? orig->p.sys_type : - (is_extd || (pno > 3 && pct == 1 && show_extended)) - ? EXTENDED_PARTITION : LINUX_NATIVE; - else if (!strcmp(fields[2], "L")) - ul = LINUX_NATIVE; - else if (!strcmp(fields[2], "S")) - ul = LINUX_SWAP; - else if (!strcmp(fields[2], "E")) - ul = EXTENDED_PARTITION; - else if (!strcmp(fields[2], "X")) - ul = LINUX_EXTENDED; - else if (get_ul(fields[2], &ul, LINUX_NATIVE, 16)) - return 0; - if (ul > 255) { - warn(_("Illegal type\n")); - return 0; - } - p.p.sys_type = ul; - is_extd = is_extended(ul); - - /* find start */ - ff = first_free(pno, is_extd, ep, format, 0, z); - ff1 = ff * unitsize(format); - def = orig ? orig->start : (pno > 4 && pct > 1) ? 0 : ff1; - if (fno < 1 || !*(fields[0])) - p.start = def; - else { - if (get_ul(fields[0], &ul, def / unitsize(0), 0)) - return 0; - p.start = ul * unitsize(0); - p.start -= (p.start % unitsize(format)); - } - - /* find length */ - ml = max_length(pno, is_extd, ep, format, p.start / unitsize(format), z); - ml1 = ml * unitsize(format); - def = orig ? orig->size : (pno > 4 && pct > 1) ? 0 : ml1; - if (fno < 2 || !*(fields[1])) - p.size = def; - else { - if (get_ul(fields[1], &ul, def / unitsize(0), 0)) - return 0; - p.size = ul * unitsize(0) + unitsize(format) - 1; - p.size -= (p.size % unitsize(format)); - } - if (p.size > ml1) { - warn(_("Warning: given size (%lu) exceeds max allowable size (%lu)\n"), - (p.size + unitsize(0) - 1) / unitsize(0), ml1 / unitsize(0)); - if (!force) - return 0; - } - if (p.size == 0 && pno >= 4 && (fno < 2 || !*(fields[1]))) { - warn(_("Warning: empty partition\n")); - if (!force) - return 0; - } - p.p.nr_sects = p.size; - - if (p.size == 0 && !orig) { - if (fno < 1 || !*(fields[0])) - p.start = 0; - if (fno < 3 || !*(fields[2])) - p.p.sys_type = EMPTY_PARTITION; - } - - if (p.start < ff1 && p.size > 0) { - warn(_("Warning: bad partition start (earliest %lu)\n"), - (ff1 + unitsize(0) - 1) / unitsize(0)); - if (!force) - return 0; - } - - if (fno < 4 || !*(fields[3])) - ul = (orig ? orig->p.bootable : 0); - else if (!strcmp(fields[3], "-")) - ul = 0; - else if (!strcmp(fields[3], "*") || !strcmp(fields[3], "+")) - ul = 0x80; - else { - warn(_("unrecognized bootable flag - choose - or *\n")); - return 0; - } - p.p.bootable = ul; - - if (ep && ep->p.sys_type == EMPTY_PARTITION) { - if (!build_surrounding_extended(&p, ep, z)) - return 0; - } else - if (!compute_start_sect(&p, ep)) - return 0; - - { longchs aa = chs_to_longchs(p.p.begin_chs), bb; - - if (fno < 5) { - bb = aa; - } else if (fno < 7) { - warn(_("partial c,h,s specification?\n")); - return 0; - } else if (get_ul(fields[4], &bb.c, aa.c, 0) || - get_ul(fields[5], &bb.h, aa.h, 0) || - get_ul(fields[6], &bb.s, aa.s, 0)) - return 0; - p.p.begin_chs = longchs_to_chs(bb,B); - } - { longchs aa = chs_to_longchs(p.p.end_chs), bb; - - if (fno < 8) { - bb = aa; - } else if (fno < 10) { - warn(_("partial c,h,s specification?\n")); - return 0; - } else if (get_ul(fields[7], &bb.c, aa.c, 0) || - get_ul(fields[8], &bb.h, aa.h, 0) || - get_ul(fields[9], &bb.s, aa.s, 0)) - return 0; - p.p.end_chs = longchs_to_chs(bb, B); - } - - if (pno > 3 && p.size && show_extended && p.p.sys_type != EMPTY_PARTITION - && (is_extended(p.p.sys_type) != (pct == 1))) { - warn(_("Extended partition not where expected\n")); - if (!force) - return 0; - } - - z->partitions[pno] = p; - if (pno >= z->partno) - z->partno += 4; /* reqd for out_partition() */ - - if (interactive) - out_partition(dev, 0, &(z->partitions[pno]), z, B); - - return 1; -} - -/* ep either points to the extended partition to contain this one, - or to the empty partition that may become extended or is 0 */ -static int -read_partition(char *dev, int interactive, int pno, struct part_desc *ep, - struct disk_desc *z) { - struct part_desc *p = &(z->partitions[pno]); - int i; - - if (one_only) { - *p = oldp.partitions[pno]; - if (one_only_pno != pno) - goto ret; - } else if (!show_extended && pno > 4 && pno%4) - goto ret; - - while (!(i = read_line(pno, ep, dev, interactive, z))) - if (!interactive) - fatal(_("bad input\n")); - if (i < 0) { - p->ep = ep; - return 0; - } - - ret: - p->ep = ep; - if (pno >= z->partno) - z->partno += 4; - return 1; -} - -static void -read_partition_chain(char *dev, int interactive, struct part_desc *ep, - struct disk_desc *z) { - int i, base; - - eob = 0; - while (1) { - base = z->partno; - if (base+4 > SIZE(z->partitions)) { - do_warn(_("too many partitions\n")); - break; - } - for (i=0; i<4; i++) - if (!read_partition(dev, interactive, base+i, ep, z)) - return; - for (i=0; i<4; i++) { - ep = &(z->partitions[base+i]); - if (is_extended(ep->p.sys_type) && ep->size) - break; - } - if (i == 4) { - /* nothing found - maybe an empty partition is going - to be extended */ - if (one_only || show_extended) - break; - ep = &(z->partitions[base+1]); - if (ep->size || ep->p.sys_type != EMPTY_PARTITION) - break; - } - } -} - -static void -read_input(char *dev, int interactive, struct disk_desc *z) { - int i; - struct part_desc *partitions = &(z->partitions[0]), *ep; - - for (i=0; i < SIZE(z->partitions); i++) - partitions[i] = zero_part_desc; - z->partno = 0; - - if (interactive) - warn(_("Input in the following format; absent fields get a default value.\n" - " \n" - "Usually you only need to specify and (and perhaps ).\n")); - eof = 0; - - for (i=0; i<4; i++) - read_partition(dev, interactive, i, 0, z); - for (i=0; i<4; i++) { - ep = partitions+i; - if (is_extended(ep->p.sys_type) && ep->size) - read_partition_chain(dev, interactive, ep, z); - } - add_sector_and_offset(z); -} - -/* - * G. The command line - */ - -static void version(void) { - printf("%s %s %s (aeb@cwi.nl, %s) from util-linux-" - UTIL_LINUX_VERSION "\n", - PROGNAME, _("version"), VERSION, DATE); -} - -static void -usage(void) { - version(); - printf(_("Usage: %s [options] device ...\n"), PROGNAME); - puts (_("device: something like /dev/hda or /dev/sda")); - puts (_("useful options:")); - puts (_(" -s [or --show-size]: list size of a partition")); - puts (_(" -c [or --id]: print or change partition Id")); - puts (_(" -l [or --list]: list partitions of each device")); - puts (_(" -d [or --dump]: idem, but in a format suitable for later input")); - puts (_(" -i [or --increment]: number cylinders etc. from 1 instead of from 0")); - puts (_(" -uS, -uB, -uC, -uM: accept/report in units of sectors/blocks/cylinders/MB")); - puts (_(" -T [or --list-types]:list the known partition types")); - puts (_(" -D [or --DOS]: for DOS-compatibility: waste a little space")); - puts (_(" -R [or --re-read]: make kernel reread partition table")); - puts (_(" -N# : change only the partition with number #")); - puts (_(" -n : do not actually write to disk")); - puts (_(" -O file : save the sectors that will be overwritten to file")); - puts (_(" -I file : restore these sectors again")); - puts (_(" -v [or --version]: print version")); - puts (_(" -? [or --help]: print this message")); - puts (_("dangerous options:")); - puts (_(" -g [or --show-geometry]: print the kernel's idea of the geometry")); - puts (_(" -G [or --show-pt-geometry]: print geometry guessed from the partition table")); - puts (_(" -x [or --show-extended]: also list extended partitions on output\n" - " or expect descriptors for them on input")); - puts (_(" -L [or --Linux]: do not complain about things irrelevant for Linux")); - puts (_(" -q [or --quiet]: suppress warning messages")); - puts (_(" You can override the detected geometry using:")); - puts (_(" -C# [or --cylinders #]:set the number of cylinders to use")); - puts (_(" -H# [or --heads #]: set the number of heads to use")); - puts (_(" -S# [or --sectors #]: set the number of sectors to use")); - puts (_("You can disable all consistency checking with:")); - puts (_(" -f [or --force]: do what I say, even if it is stupid")); - exit(1); -} - -static void -activate_usage(char *progn) { - puts (_("Usage:")); - printf(_("%s device list active partitions on device\n"), progn); - printf(_("%s device n1 n2 ... activate partitions n1 ..., inactivate the rest\n"), progn); - printf(_("%s -An device activate partition n, inactivate the other ones\n"), PROGNAME); - exit(1); -} - -static void -unhide_usage(char *progn) { - exit(1); -} - -static char short_opts[] = "cdfgilnqsu:vx?1A::C:DGH:I:LN:O:RS:TU::V"; - -#define PRINT_ID 0400 -#define CHANGE_ID 01000 - -static const struct option long_opts[] = { - { "change-id", no_argument, NULL, 'c' + CHANGE_ID }, - { "print-id", no_argument, NULL, 'c' + PRINT_ID }, - { "id", no_argument, NULL, 'c' }, - { "dump", no_argument, NULL, 'd' }, - { "force", no_argument, NULL, 'f' }, - { "show-geometry", no_argument, NULL, 'g' }, - { "increment", no_argument, NULL, 'i' }, - { "list", no_argument, NULL, 'l' }, - { "quiet", no_argument, NULL, 'q' }, - { "show-size", no_argument, NULL, 's' }, - { "unit", required_argument, NULL, 'u' }, - { "version", no_argument, NULL, 'v' }, - { "show-extended", no_argument, NULL, 'x' }, - { "help", no_argument, NULL, '?' }, - { "one-only", no_argument, NULL, '1' }, - { "cylinders", required_argument, NULL, 'C' }, - { "heads", required_argument, NULL, 'H' }, - { "sectors", required_argument, NULL, 'S' }, - { "show-pt-geometry", no_argument, NULL, 'G' }, - { "activate", optional_argument, NULL, 'A' }, - { "DOS", no_argument, NULL, 'D' }, - { "DOS-extended", no_argument, NULL, 'E' }, - { "Linux", no_argument, NULL, 'L' }, - { "re-read", no_argument, NULL, 'R' }, - { "list-types", no_argument, NULL, 'T' }, - { "unhide", optional_argument, NULL, 'U' }, - { "no-reread", no_argument, NULL, 160 }, - { "IBM", no_argument, NULL, 161 }, - { "leave-last", no_argument, NULL, 161 }, -/* undocumented flags - not all completely implemented */ - { "in-order", no_argument, NULL, 128 }, - { "not-in-order", no_argument, NULL, 129 }, - { "inside-outer", no_argument, NULL, 130 }, - { "not-inside-outer", no_argument, NULL, 131 }, - { "nested", no_argument, NULL, 132 }, - { "chained", no_argument, NULL, 133 }, - { "onesector", no_argument, NULL, 134 }, - { NULL, 0, NULL, 0 } -}; - -static int -is_ide_cdrom_or_tape(char *device) { - FILE *procf; - char buf[100]; - struct stat statbuf; - int is_ide = 0; - - /* No device was given explicitly, and we are trying some - likely things. But opening /dev/hdc may produce errors like - "hdc: tray open or drive not ready" - if it happens to be a CD-ROM drive. It even happens that - the process hangs on the attempt to read a music CD. - So try to be careful. This only works since 2.1.73. */ - - if (strncmp("/dev/hd", device, 7)) - return 0; - - snprintf(buf, sizeof(buf), "/proc/ide/%s/media", device+5); - procf = fopen(buf, "r"); - if (procf != NULL && fgets(buf, sizeof(buf), procf)) - is_ide = (!strncmp(buf, "cdrom", 5) || - !strncmp(buf, "tape", 4)); - else - /* Now when this proc file does not exist, skip the - device when it is read-only. */ - if (stat(device, &statbuf) == 0) - is_ide = ((statbuf.st_mode & 0222) == 0); - - if (procf) - fclose(procf); - return is_ide; -} - -static int -is_probably_full_disk(char *name) { - struct hd_geometry geometry; - int fd, i = 0; - - fd = open(name, O_RDONLY); - if (fd >= 0) { - i = ioctl(fd, HDIO_GETGEO, &geometry); - close(fd); - } - return (fd >= 0 && i == 0 && geometry.start == 0); -} - -#define PROC_PARTITIONS "/proc/partitions" -static FILE *procf = NULL; - -static void -openproc(void) { - procf = fopen(PROC_PARTITIONS, "r"); - if (procf == NULL) - fprintf(stderr, _("cannot open %s\n"), PROC_PARTITIONS); -} - -static char * -nextproc(void) { - static char devname[120]; - char line[100], ptname[100]; - int ma, mi, sz; - - if (procf == NULL) - return NULL; - while (fgets(line, sizeof(line), procf) != NULL) { - if (sscanf (line, " %d %d %d %[^\n ]", - &ma, &mi, &sz, ptname) != 4) - continue; - snprintf(devname, sizeof(devname), "/dev/%s", ptname); - if (!is_probably_full_disk(devname)) - continue; - return devname; - } - - fclose(procf); - procf = NULL; - return NULL; -} - -static void do_list(char *dev, int silent); -static void do_size(char *dev, int silent); -static void do_geom(char *dev, int silent); -static void do_pt_geom(char *dev, int silent); -static void do_fdisk(char *dev); -static void do_reread(char *dev); -static void do_change_id(char *dev, char *part, char *id); -static void do_unhide(char **av, int ac, char *arg); -static void do_activate(char **av, int ac, char *arg); - -unsigned long long total_size; - -int -main(int argc, char **argv) { - char *progn; - int c; - char *dev; - int opt_size = 0; - int opt_out_geom = 0; - int opt_out_pt_geom = 0; - int opt_reread = 0; - int activate = 0; - int do_id = 0; - int unhide = 0; - int fdisk = 0; - char *activatearg = 0; - char *unhidearg = 0; - -/* - setlocale(LC_ALL, ""); - bindtextdomain(PACKAGE, LOCALEDIR); - textdomain(PACKAGE); -*/ - if (argc < 1) - fatal(_("no command?\n")); - if ((progn = rindex(argv[0], '/')) == NULL) - progn = argv[0]; - else - progn++; - if (!strcmp(progn, "activate")) - activate = 1; /* equivalent to `sfdisk -A' */ -#if 0 /* not important enough to deserve a name */ - else if (!strcmp(progn, "unhide")) - unhide = 1; /* equivalent to `sfdisk -U' */ -#endif - else - fdisk = 1; - - while ((c = getopt_long (argc, argv, short_opts, long_opts, NULL)) != -1) { - switch (c) { - case 'f': - force = 1; break; /* does not imply quiet */ - case 'g': - opt_out_geom = 1; break; - case 'G': - opt_out_pt_geom = 1; break; - case 'i': - increment = 1; break; - case 'c': - case 'c' + PRINT_ID: - case 'c' + CHANGE_ID: - do_id = c; break; - case 'd': - dump = 1; /* fall through */ - case 'l': - opt_list = 1; break; - case 'n': - no_write = 1; break; - case 'q': - quiet = 1; break; - case 's': - opt_size = 1; break; - case 'u': - set_format(*optarg); break; - case 'v': - version(); - exit(0); - case 'x': - show_extended = 1; break; - case 'A': - activatearg = optarg; - activate = 1; break; - case 'C': - U.cylinders = atoi(optarg); break; - case 'D': - DOS = 1; break; - case 'E': - DOS_extended = 1; break; - case 'H': - U.heads = atoi(optarg); break; - case 'L': - Linux = 1; break; - case 'N': - one_only = atoi(optarg); break; - case 'I': - restore_sector_file = optarg; break; - case 'O': - save_sector_file = optarg; break; - case 'R': - opt_reread = 1; break; - case 'S': - U.sectors = atoi(optarg); break; - case 'T': - list_types(); - exit(0); - case 'U': - unhidearg = optarg; - unhide = 1; break; - case 'V': - verify = 1; break; - case '?': - default: - usage(); break; - - /* undocumented flags */ - case 128: - partitions_in_order = 1; break; - case 129: - partitions_in_order = 0; break; - case 130: - all_logicals_inside_outermost_extended = 1; break; - case 131: - all_logicals_inside_outermost_extended = 0; break; - case 132: - boxes = NESTED; break; - case 133: - boxes = CHAINED; break; - case 134: - boxes = ONESECTOR; break; - - /* more flags */ - case 160: - no_reread = 1; break; - case 161: - leave_last = 1; break; - } - } - - if (optind == argc && - (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify)) { - /* try all known devices */ - total_size = 0; - openproc(); - while ((dev = nextproc()) != NULL) { - if (is_ide_cdrom_or_tape(dev)) - continue; - if (opt_out_geom) - do_geom(dev, 1); - if (opt_out_pt_geom) - do_pt_geom(dev, 1); - if (opt_size) - do_size(dev, 1); - if (opt_list || verify) - do_list(dev, 1); - } - - if (opt_size) - printf(_("total: %llu blocks\n"), total_size); - - exit(exit_status); - } - - if (optind == argc) { - if (activate) - activate_usage(fdisk ? "sfdisk -A" : progn); - else if (unhide) - unhide_usage(fdisk ? "sfdisk -U" : progn); - else - usage(); - } - - if (opt_list || opt_out_geom || opt_out_pt_geom || opt_size || verify) { - while (optind < argc) { - if (opt_out_geom) - do_geom(argv[optind], 0); - if (opt_out_pt_geom) - do_pt_geom(argv[optind], 0); - if (opt_size) - do_size(argv[optind], 0); - if (opt_list || verify) - do_list(argv[optind], 0); - optind++; - } - exit(exit_status); - } - - if (activate) { - do_activate(argv+optind, argc-optind, activatearg); - exit(exit_status); - } - if (unhide) { - do_unhide(argv+optind, argc-optind, unhidearg); - exit(exit_status); - } - if (do_id) { - if ((do_id & PRINT_ID) != 0 && optind != argc-2) - fatal(_("usage: sfdisk --print-id device partition-number\n")); - else if ((do_id & CHANGE_ID) != 0 && optind != argc-3) - fatal(_("usage: sfdisk --change-id device partition-number Id\n")); - else if (optind != argc-3 && optind != argc-2) - fatal(_("usage: sfdisk --id device partition-number [Id]\n")); - do_change_id(argv[optind], argv[optind+1], - (optind == argc-2) ? 0 : argv[optind+2]); - exit(exit_status); - } - - if (optind != argc-1) - fatal(_("can specify only one device (except with -l or -s)\n")); - dev = argv[optind]; - - if (opt_reread) - do_reread(dev); - else if (restore_sector_file) - restore_sectors(dev); - else - do_fdisk(dev); - - return 0; -} - -/* - * H. Listing the current situation - */ - -static int -my_open (char *dev, int rw, int silent) { - int fd, mode; - - mode = (rw ? O_RDWR : O_RDONLY); - fd = open(dev, mode); - if (fd < 0 && !silent) { - perror(dev); - if (rw) - fatal(_("cannot open %s read-write\n"), dev); - else - fatal(_("cannot open %s for reading\n"), dev); - } - return fd; -} - -static void -do_list (char *dev, int silent) { - int fd; - struct disk_desc *z; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - z = &oldp; - - free_sectors(); - get_cylindersize(dev, fd, dump ? 1 : opt_list ? 0 : 1); - get_partitions(dev, fd, z); - - if (opt_list) - out_partitions(dev, z); - - if (verify) { - if (partitions_ok(z)) - warn(_("%s: OK\n"), dev); - else - exit_status = 1; - } -} - -static void -do_geom (char *dev, int silent) { - int fd; - struct geometry R; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - R = get_geometry(dev, fd, silent); - if (R.cylinders) - printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"), - dev, R.cylinders, R.heads, R.sectors); -} - -static void -do_pt_geom (char *dev, int silent) { - int fd; - struct disk_desc *z; - struct geometry R; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - z = &oldp; - - free_sectors(); - get_cylindersize(dev, fd, 1); - get_partitions(dev, fd, z); - - R = B; - - if (z->partno != 0 && get_fdisk_geometry(z)) { - R.heads = F.heads; - R.sectors = F.sectors; - R.cylindersize = R.heads * R.sectors; - R.cylinders = (R.cylindersize == 0) ? 0 : - R.total_size / R.cylindersize; - } - - if (R.cylinders) - printf(_("%s: %ld cylinders, %ld heads, %ld sectors/track\n"), - dev, R.cylinders, R.heads, R.sectors); -} - -/* for compatibility with earlier fdisk: provide option -s */ -static void -do_size (char *dev, int silent) { - int fd; - unsigned long long size; - - fd = my_open(dev, 0, silent); - if (fd < 0) - return; - - if (disksize(fd, &size)) { - if (!silent) { - perror(dev); - fatal(_("Cannot get size of %s\n"), dev); - } - return; - } - - size /= 2; /* convert sectors to blocks */ - - /* a CDROM drive without mounted CD yields MAXINT */ - if (silent && size == ((1<<30)-1)) - return; - - if (silent) - printf("%s: %9llu\n", dev, size); - else - printf("%llu\n", size); - - total_size += size; -} - -/* - * Activate: usually one wants to have a single primary partition - * to be active. OS/2 fdisk makes non-bootable logical partitions - * active - I don't know what that means to OS/2 Boot Manager. - * - * Call: activate /dev/hda 2 5 7 make these partitions active - * and the remaining ones inactive - * Or: sfdisk -A /dev/hda 2 5 7 - * - * If only a single partition must be active, one may also use the form - * sfdisk -A2 /dev/hda - * - * With "activate /dev/hda" or "sfdisk -A /dev/hda" the active partitions - * are listed but not changed. To get zero active partitions, use - * "activate /dev/hda none" or "sfdisk -A /dev/hda none". - * Use something like `echo ",,,*" | sfdisk -N2 /dev/hda' to only make - * /dev/hda2 active, without changing other partitions. - * - * A warning will be given if after the change not precisely one primary - * partition is active. - * - * The present syntax was chosen to be (somewhat) compatible with the - * activate from the LILO package. - */ -static void -set_active (struct disk_desc *z, char *pnam) { - int pno; - - pno = asc_to_index(pnam, z); - if (z->partitions[pno].ptype == DOS_TYPE) - z->partitions[pno].p.bootable = 0x80; -} - -static void -do_activate (char **av, int ac, char *arg) { - char *dev = av[0]; - int fd; - int rw, i, pno, lpno; - struct disk_desc *z; - - z = &oldp; - - rw = (!no_write && (arg || ac > 1)); - fd = my_open(dev, rw, 0); - - free_sectors(); - get_cylindersize(dev, fd, 1); - get_partitions(dev, fd, z); - - if (!arg && ac == 1) { - /* list active partitions */ - for (pno=0; pno < z->partno; pno++) { - if (z->partitions[pno].p.bootable) { - lpno = index_to_linux(pno, z); - if (pno == linux_to_index(lpno, z)) - printf("%s\n", partname(dev, lpno, 0)); - else - printf("%s#%d\n", dev, pno); - if (z->partitions[pno].p.bootable != 0x80) - warn(_("bad active byte: 0x%x instead of 0x80\n"), - z->partitions[pno].p.bootable); - } - } - } else { - /* clear `active byte' everywhere */ - for (pno=0; pno < z->partno; pno++) - if (z->partitions[pno].ptype == DOS_TYPE) - z->partitions[pno].p.bootable = 0; - - /* then set where desired */ - if (ac == 1) - set_active(z, arg); - else for(i=1; ipartno && pno < 4; pno++) - if (z->partitions[pno].p.bootable) - i++; - if (i != 1) - warn(_("You have %d active primary partitions. This does not matter for LILO,\n" - "but the DOS MBR will only boot a disk with 1 active partition.\n"), i); -} - -static void -set_unhidden (struct disk_desc *z, char *pnam) { - int pno; - unsigned char id; - - pno = asc_to_index(pnam, z); - id = z->partitions[pno].p.sys_type; - if (id == 0x11 || id == 0x14 || id == 0x16 || id == 0x17) - id -= 0x10; - else - fatal(_("partition %s has id %x and is not hidden\n"), pnam, id); - z->partitions[pno].p.sys_type = id; -} - -/* - * maybe remove and make part of --change-id - */ -static void -do_unhide (char **av, int ac, char *arg) { - char *dev = av[0]; - int fd, rw, i; - struct disk_desc *z; - - z = &oldp; - - rw = !no_write; - fd = my_open(dev, rw, 0); - - free_sectors(); - get_cylindersize(dev, fd, 1); - get_partitions(dev, fd, z); - - /* unhide where desired */ - if (ac == 1) - set_unhidden(z, arg); - else for(i=1; ipartitions[pno].p.sys_type); - return; - } - i = strtoul(id, NULL, 16); - if (i > 255) - fatal(_("Bad Id %lx\n"), i); - z->partitions[pno].p.sys_type = i; - - if (write_partitions(dev, fd, z)) - warn(_("Done\n\n")); - else - exit_status = 1; -} - -static void -do_reread(char *dev) { - int fd; - - fd = my_open(dev, 0, 0); - if (reread_ioctl(fd)) - do_warn(_("This disk is currently in use.\n")); -} - -/* - * I. Writing the new situation - */ - -static void -do_fdisk(char *dev){ - int fd; - int c, answer; - struct stat statbuf; - int interactive = isatty(0); - struct disk_desc *z; - - if (stat(dev, &statbuf) < 0) { - perror(dev); - fatal(_("Fatal error: cannot find %s\n"), dev); - } - if (!S_ISBLK(statbuf.st_mode)) { - do_warn(_("Warning: %s is not a block device\n"), dev); - no_reread = 1; - } - fd = my_open(dev, !no_write, 0); - - if (!no_write && !no_reread) { - warn(_("Checking that no-one is using this disk right now ...\n")); - if (reread_ioctl(fd)) { - do_warn(_("\nThis disk is currently in use - repartitioning is probably a bad idea.\n" - "Umount all file systems, and swapoff all swap partitions on this disk.\n" - "Use the --no-reread flag to suppress this check.\n")); - if (!force) { - do_warn(_("Use the --force flag to overrule all checks.\n")); - exit(1); - } - } else - warn(_("OK\n")); - } - - z = &oldp; - - free_sectors(); - get_cylindersize(dev, fd, 0); - get_partitions(dev, fd, z); - - printf(_("Old situation:\n")); - out_partitions(dev, z); - - if (one_only && (one_only_pno = linux_to_index(one_only, z)) < 0) - fatal(_("Partition %d does not exist, cannot change it\n"), one_only); - - z = &newp; - - while(1) { - - read_input(dev, interactive, z); - - printf(_("New situation:\n")); - out_partitions(dev, z); - - if (!partitions_ok(z) && !force) { - if (!interactive) - fatal(_("I don't like these partitions - nothing changed.\n" - "(If you really want this, use the --force option.)\n")); - else - do_warn(_("I don't like this - probably you should answer No\n")); - } - ask: - if (interactive) { - if (no_write) - printf(_("Are you satisfied with this? [ynq] ")); - else - printf(_("Do you want to write this to disk? [ynq] ")); - answer = c = getchar(); - while (c != '\n' && c != EOF) - c = getchar(); - if (c == EOF) - printf(_("\nsfdisk: premature end of input\n")); - if (c == EOF || answer == 'q' || answer == 'Q') { - fatal(_("Quitting - nothing changed\n")); - } else if (answer == 'n' || answer == 'N') { - continue; - } else if (answer == 'y' || answer == 'Y') { - break; - } else { - printf(_("Please answer one of y,n,q\n")); - goto ask; - } - } else - break; - } - - if (write_partitions(dev, fd, z)) - printf(_("Successfully wrote the new partition table\n\n")); - else - exit_status = 1; - - reread_disk_partition(dev, fd); - - warn(_("If you created or changed a DOS partition, /dev/foo7, say, then use dd(1)\n" - "to zero the first 512 bytes: dd if=/dev/zero of=/dev/foo7 bs=512 count=1\n" - "(See fdisk(8).)\n")); - - sync(); /* superstition */ - exit(exit_status); -} diff --git a/debian/sfdisk/xstrncpy.c b/debian/sfdisk/xstrncpy.c deleted file mode 100644 index 7975426..0000000 --- a/debian/sfdisk/xstrncpy.c +++ /dev/null @@ -1,10 +0,0 @@ -/* NUL-terminated version of strncpy() */ -#include -#include "xstrncpy.h" - -/* caller guarantees n > 0 */ -void -xstrncpy(char *dest, const char *src, size_t n) { - strncpy(dest, src, n-1); - dest[n-1] = 0; -} diff --git a/debian/sfdisk/xstrncpy.h b/debian/sfdisk/xstrncpy.h deleted file mode 100644 index 05c8fa2..0000000 --- a/debian/sfdisk/xstrncpy.h +++ /dev/null @@ -1 +0,0 @@ -extern void xstrncpy(char *dest, const char *src, size_t n); diff --git a/debian/source/format b/debian/source/format deleted file mode 100644 index 163aaf8..0000000 --- a/debian/source/format +++ /dev/null @@ -1 +0,0 @@ -3.0 (quilt) diff --git a/debian/tree/busybox-udeb/usr/share/udhcpc/default.script b/debian/tree/busybox-udeb/usr/share/udhcpc/default.script deleted file mode 100755 index 1284e1f..0000000 --- a/debian/tree/busybox-udeb/usr/share/udhcpc/default.script +++ /dev/null @@ -1,91 +0,0 @@ -#!/bin/sh -e - -# udhcpc client script to be used by Debian Installer -# Copyright (C) 2009, 2010 Otavio Salvador - -comma_separate() { - echo "$1" | sed 's/ /,/g' -} - -do_resolv_conf() { - local cfg=/etc/resolv.conf - - if [ -n "$domain" ] || [ -n "$dns" ]; then - echo -n > $cfg - if [ -n "$domain" ]; then - echo search $domain >> $cfg - fi - - for i in $dns ; do - echo nameserver $i >> $cfg - done - fi -} - -do_hostname() { - local current=$(cat /proc/sys/kernel/hostname) - - if [ -z "$current" ] || [ "$current" = "(none)" ]; then - echo "$hostname" > /proc/sys/kernel/hostname - fi -} - -do_leases() { - local file="/var/lib/udhcp/udhcpc.leases" - - mkdir -p /var/lib/udhcp - cat >> $file < /tmp/domain_name - - if [ -n "$ntpsrv" ]; then - printf "$ntpsrv" > /tmp/dhcp-ntp-servers - fi - - logger -t udhcpc "Got IP $ip (using $interface) and routing through $router" - - do_leases - ;; - *) - echo "udhcpc: has been called with an unknown param: $1" - ;; -esac - -exit 0 diff --git a/debian/tree/udhcpc/usr/share/udhcpc/default.script b/debian/tree/udhcpc/usr/share/udhcpc/default.script deleted file mode 100755 index 26b95c1..0000000 --- a/debian/tree/udhcpc/usr/share/udhcpc/default.script +++ /dev/null @@ -1,63 +0,0 @@ -#!/bin/sh -# Busybox udhcpc dispatcher script. Copyright (C) 2009 by Axel Beckert. -# -# Based on the busybox example scripts and the old udhcp source -# package default.* scripts. - -RESOLV_CONF="/etc/resolv.conf" - -case $1 in - bound|renew) - [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast" - [ -n "$subnet" ] && NETMASK="netmask $subnet" - - /sbin/ifconfig $interface $ip $BROADCAST $NETMASK - - if [ -n "$router" ]; then - echo "$0: Resetting default routes" - while /sbin/route del default gw 0.0.0.0 dev $interface; do :; done - - metric=0 - for i in $router; do - /sbin/route add default gw $i dev $interface metric $metric - metric=$(($metric + 1)) - done - fi - - # Update resolver configuration file - R="" - [ -n "$domain" ] && R="domain $domain -" - for i in $dns; do - echo "$0: Adding DNS $i" - R="${R}nameserver $i -" - done - - if [ -x /sbin/resolvconf ]; then - echo -n "$R" | resolvconf -a "${interface}.udhcpc" - else - echo -n "$R" > "$RESOLV_CONF" - fi - ;; - - deconfig) - if [ -x /sbin/resolvconf ]; then - resolvconf -d "${interface}.udhcpc" - fi - /sbin/ifconfig $interface 0.0.0.0 - ;; - - leasefail) - echo "$0: Lease failed: $message" - ;; - - nak) - echo "$0: Received a NAK: $message" - ;; - - *) - echo "$0: Unknown udhcpc command: $1"; - exit 1; - ;; -esac diff --git a/debian/tree/udhcpd/etc/default/udhcpd b/debian/tree/udhcpd/etc/default/udhcpd deleted file mode 100644 index 34ef72b..0000000 --- a/debian/tree/udhcpd/etc/default/udhcpd +++ /dev/null @@ -1,9 +0,0 @@ -# Comment the following line to enable -DHCPD_ENABLED="no" - -# Options to pass to busybox' udhcpd. -# -# -S Log to syslog -# -f run in foreground - -DHCPD_OPTS="-S" diff --git a/debian/tree/udhcpd/etc/init.d/udhcpd b/debian/tree/udhcpd/etc/init.d/udhcpd deleted file mode 100644 index e7f8ddd..0000000 --- a/debian/tree/udhcpd/etc/init.d/udhcpd +++ /dev/null @@ -1,61 +0,0 @@ -#! /bin/sh -# -# Written by Miquel van Smoorenburg . -# Modified for Debian GNU/Linux by Ian Murdock -# and Axel Beckert . -# -### BEGIN INIT INFO -# Provides: udhcpd -# Required-Start: $remote_fs $syslog -# Required-Stop: $remote_fs $syslog -# Default-Start: 2 3 4 5 -# Default-Stop: 0 1 6 -# Short-Description: Start busybox udhcpd at boot time -### END INIT INFO - -PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin -DAEMON=/usr/sbin/udhcpd -NAME=udhcpd -DESC="very small Busybox based DHCP server" -DHCPD_OPTS="-S" # Additional options given to the server - -test -x $DAEMON || exit 0 - -# Include defaults if available -if [ -f /etc/default/udhcpd ] ; then - . /etc/default/udhcpd -fi - -if [ "$DHCPD_ENABLED" = "no" ]; then - echo $NAME: Disabled. Edit /etc/default/udhcpd to enable it. - exit 0; -fi - -set -e - -case "$1" in - start) - echo -n "Starting $DESC: " - start-stop-daemon --start --verbose --pidfile /var/run/$NAME.pid \ - --oknodo --exec $DAEMON -- $DHCPD_OPTS - echo "$NAME." - ;; - stop) - echo -n "Stopping $DESC: " - start-stop-daemon --stop --verbose --pidfile /var/run/$NAME.pid \ - --oknodo --exec $DAEMON - echo "$NAME." - ;; - restart|force-reload) - $0 stop - sleep 1 - $0 start - ;; - *) - N=/etc/init.d/$NAME - echo "Usage: $N {start|stop|restart|force-reload}" >&2 - exit 1 - ;; -esac - -exit 0 diff --git a/debian/tree/udhcpd/etc/udhcpd.conf b/debian/tree/udhcpd/etc/udhcpd.conf deleted file mode 100644 index 672c481..0000000 --- a/debian/tree/udhcpd/etc/udhcpd.conf +++ /dev/null @@ -1,123 +0,0 @@ -# Sample udhcpd configuration file (/etc/udhcpd.conf) - -# The start and end of the IP lease block - -start 192.168.0.20 #default: 192.168.0.20 -end 192.168.0.254 #default: 192.168.0.254 - - -# The interface that udhcpd will use - -interface eth0 #default: eth0 - - -# The maximim number of leases (includes addressesd reserved -# by OFFER's, DECLINE's, and ARP conficts - -#max_leases 254 #default: 254 - - -# If remaining is true (default), udhcpd will store the time -# remaining for each lease in the udhcpd leases file. This is -# for embedded systems that cannot keep time between reboots. -# If you set remaining to no, the absolute time that the lease -# expires at will be stored in the dhcpd.leases file. - -#remaining yes #default: yes - - -# The time period at which udhcpd will write out a dhcpd.leases -# file. If this is 0, udhcpd will never automatically write a -# lease file. (specified in seconds) - -#auto_time 7200 #default: 7200 (2 hours) - - -# The amount of time that an IP will be reserved (leased) for if a -# DHCP decline message is received (seconds). - -#decline_time 3600 #default: 3600 (1 hour) - - -# The amount of time that an IP will be reserved (leased) for if an -# ARP conflct occurs. (seconds - -#conflict_time 3600 #default: 3600 (1 hour) - - -# How long an offered address is reserved (leased) in seconds - -#offer_time 60 #default: 60 (1 minute) - -# If a lease to be given is below this value, the full lease time is -# instead used (seconds). - -#min_lease 60 #defult: 60 - - -# The location of the leases file - -#lease_file /var/lib/misc/udhcpd.leases #defualt: /var/lib/misc/udhcpd.leases - -# The location of the pid file -#pidfile /var/run/udhcpd.pid #default: /var/run/udhcpd.pid - -# Everytime udhcpd writes a leases file, the below script will be called. -# Useful for writing the lease file to flash every few hours. - -#notify_file #default: (no script) - -#notify_file dumpleases # <--- useful for debugging - -# The following are bootp specific options, setable by udhcpd. - -#siaddr 192.168.0.22 #default: 0.0.0.0 - -#sname zorak #default: (none) - -#boot_file /var/nfs_root #default: (none) - -# The remainer of options are DHCP options and can be specifed with the -# keyword 'opt' or 'option'. If an option can take multiple items, such -# as the dns option, they can be listed on the same line, or multiple -# lines. The only option with a default is 'lease'. - -#Examles -opt dns 192.168.10.2 192.168.10.10 -option subnet 255.255.255.0 -opt router 192.168.10.2 -opt wins 192.168.10.10 -option dns 129.219.13.81 # appened to above DNS servers for a total of 3 -option domain local -option lease 864000 # 10 days of seconds - - -# Currently supported options, for more info, see options.c -#opt subnet -#opt timezone -#opt router -#opt timesrv -#opt namesrv -#opt dns -#opt logsrv -#opt cookiesrv -#opt lprsrv -#opt bootsize -#opt domain -#opt swapsrv -#opt rootpath -#opt ipttl -#opt mtu -#opt broadcast -#opt wins -#opt lease -#opt ntpsrv -#opt tftp -#opt bootfile -#opt wpad - -# Static leases map -#static_lease 00:60:08:11:CE:4E 192.168.0.54 -#static_lease 00:60:08:11:CE:3E 192.168.0.44 - - diff --git a/debian/tree/udhcpd/usr/share/man/man5/udhcpd.conf.5 b/debian/tree/udhcpd/usr/share/man/man5/udhcpd.conf.5 deleted file mode 100644 index 99e66ca..0000000 --- a/debian/tree/udhcpd/usr/share/man/man5/udhcpd.conf.5 +++ /dev/null @@ -1,166 +0,0 @@ -.TH UDHCPD.CONF 5 2001-09-26 GNU/Linux "GNU/Linux Administrator's Manual" -.SH NAME -udhcpd.conf \- udhcp server configuration file -.SH DESCRIPTION -The file -.I /etc/udhcpd.conf -contains configuration information specific to the udhcp server. -It should contain one configuration keyword per line, followed by -appropriate configuration information. -.SH OPTIONS -.TP -.BI start\ ADDRESS -The starting address of the IP lease block is -.IR ADDRESS . -The default is -.BR 192.168.0.20 . -.TP -.BI end\ ADDRESS -The ending address of the IP lease block is -.IR ADDRESS . -The default is -.BR 192.168.0.254 . -.TP -.BI interface\ INTERFACE -The udhcp server should listen on -.IR INTERFACE . -The default is -.BR eth0 . -.TP -.BI max_leases\ LEASES -Offer at most -.I LEASES -leases (including those reserved by OFFERs, DECLINEs, and ARP -conflicts). The default is -.BR 254 . -.TP -.BI remaining\ REMAINING -If -.I REMAINING -is -.BR yes , -store the time remaining for each lease. If it is -.BR no , -store the expiration time for each lease. The default is -.BR yes . -.TP -.BI auto_time\ SECONDS -Write the lease information to a file every -.I SECONDS -seconds. The default is -.BR 7200 . -.TP -.BI decline_time\ SECONDS -Reserve an IP for -.I SECONDS -seconds if a DHCP decline message is received. The default is -.BR 3600 . -.TP -.BI conflict_time\ SECONDS -Reserve an IP for -.I SECONDS -seconds if an ARP conflict occurs. The default is -.BR 3600 . -.TP -.BI offer_time\ SECONDS -Reserve an IP for -.I SECONDS -seconds if it is offered. The default is -.BR 60 . -.TP -.BI min_lease\ SECONDS -Reserve an IP for the full lease time if the lease to be given is less than -.I SECONDS -seconds. The default is -.BR 60 . -.TP -.BI lease_file\ FILE -Write the lease information to -.IR FILE . -The default is -.BR /var/lib/misc/udhcpd.leases . -.TP -.BI pidfile\ FILE -Write the process ID to -.IR FILE . -The default is -.BR /var/run/udhcpd.pid . -.TP -.BI notify_file\ FILE -Execute -.I FILE -after the lease information is written. By default, no file is executed. -.TP -.BI siaddr\ ADDRESS -BOOTP specific option. The default is -.BR 0.0.0.0 . -.TP -.BI sname\ NAME -BOOTP specific option. There is no default. -.TP -.BI boot_file\ FILE -BOOTP specific option. There is no default. -.TP -.BI option\ OPTION -DHCP specific option. -.RS -.TP -.BI subnet\ ADDRESS -.TP -.BI timezone\ OFFSET -.TP -.BI router\ ADDRESS... -.TP -.BI timesvr\ ADDRESS... -.TP -.BI namesvr\ ADDRESS... -.TP -.BI dns\ ADDRESS... -.TP -.BI logsvr\ ADDRESS... -.TP -.BI cookiesvr\ ADDRESS... -.TP -.BI lprsvr\ ADDRESS... -.TP -.BI hostname\ HOSTNAME -.TP -.BI bootsize\ SIZE -.TP -.BI domain\ DOMAIN -.TP -.BI swapsvr\ ADDRESS -.TP -.BI rootpath\ PATH -.TP -.BI ipttl\ TTL -.TP -.BI mtu\ MTU -.TP -.BI broadcast\ ADDRESS -.TP -.BI ntpsrv\ ADDRESS... -.TP -.BI wins\ ADDRESS... -.TP -.BI requestip\ ADDRESS -.TP -.BI lease\ SECONDS -.TP -.BI dhcptype\ TYPE -.TP -.BI serverid\ ADDRESS -.TP -.BI tftp\ FILE -.TP -.BI wpad\ URL -.TP -.BI bootfile\ FILE -The default for -.B lease -is -.BR 864000 . -There are no defaults for the other options. -.RE -.SH SEE ALSO -.BR udhcpd (8). diff --git a/debian/udhcpc.install b/debian/udhcpc.install deleted file mode 100644 index eaf43e3..0000000 --- a/debian/udhcpc.install +++ /dev/null @@ -1 +0,0 @@ -debian/tree/udhcpc/* / diff --git a/debian/udhcpd.install b/debian/udhcpd.install deleted file mode 100644 index 0d57ee8..0000000 --- a/debian/udhcpd.install +++ /dev/null @@ -1 +0,0 @@ -debian/tree/udhcpd/* / diff --git a/debianutils/Config.src b/debianutils/Config.src index 838d8f0..cbc09b5 100644 --- a/debianutils/Config.src +++ b/debianutils/Config.src @@ -83,4 +83,3 @@ config WHICH print out their pathnames. endmenu - diff --git a/debianutils/Kbuild.src b/debianutils/Kbuild.src index da34e4e..d41b5c8 100644 --- a/debianutils/Kbuild.src +++ b/debianutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/debianutils/mktemp.c b/debianutils/mktemp.c index 2c4e196..983d7a2 100644 --- a/debianutils/mktemp.c +++ b/debianutils/mktemp.c @@ -6,7 +6,7 @@ * Copyright (C) 2000 by Daniel Jacobowitz * Written by Daniel Jacobowitz * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Coreutils 6.12 man page says: @@ -31,6 +31,25 @@ * -p; else /tmp [deprecated] */ +//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" @@ -40,28 +59,55 @@ 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, + }; path = getenv("TMPDIR"); if (!path || path[0] == '\0') path = "/tmp"; - /* -q and -t are ignored */ opt_complementary = "?1"; /* 1 argument max */ - opts = getopt32(argv, "dqtp:", &path); + opts = getopt32(argv, "dqtp:u", &path); - chp = argv[optind] ? argv[optind] : xstrdup("tmp.XXXXXX"); - if (chp[0] != '/' || (opts & 8)) + 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)) chp = concat_path_file(path, chp); - if (opts & 1) { /* -d */ + if (opts & OPT_u) { + chp = mktemp(chp); + if (chp[0] == '\0') + goto error; + } else if (opts & OPT_d) { if (mkdtemp(chp) == NULL) - return EXIT_FAILURE; + goto error; } else { if (mkstemp(chp) < 0) - return EXIT_FAILURE; + 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/debianutils/pipe_progress.c b/debianutils/pipe_progress.c index 6adefac..2c7444f 100644 --- a/debianutils/pipe_progress.c +++ b/debianutils/pipe_progress.c @@ -4,8 +4,12 @@ * * Copyright (C) 2003 by Rob Landley , Joey Hess * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define pipe_progress_trivial_usage NOUSAGE_STR +//usage:#define pipe_progress_full_usage "" + #include "libbb.h" #define PIPE_PROGRESS_SIZE 4096 diff --git a/debianutils/run_parts.c b/debianutils/run_parts.c index ba05897..527fae2 100644 --- a/debianutils/run_parts.c +++ b/debianutils/run_parts.c @@ -4,60 +4,81 @@ * * Copyright (C) 2007 Bernhard Reutner-Fischer * - * Based on a older version that was in busybox which was 1k big.. + * 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 GPL v2 or later, see file LICENSE in this tarball for details. + * 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 a the + * 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. - * The supported options are: - * -t test. Print the name of the files to be executed, without - * execute them. - * -a ARG argument. Pass ARG as an argument the program executed. It can - * be repeated to pass multiple arguments. - * -u MASK umask. Set the umask of the program executed to MASK. */ +//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" struct globals { char **names; int cur; - char *cmd[1]; + 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 { } while (0) enum { NUM_CMD = (COMMON_BUFSIZE - sizeof(G)) / sizeof(cmd[0]) - 1 }; enum { - OPT_r = (1 << 0), - OPT_a = (1 << 1), - OPT_u = (1 << 2), - OPT_t = (1 << 3), - OPT_l = (1 << 4) * ENABLE_FEATURE_RUN_PARTS_FANCY, + 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, }; -#if ENABLE_FEATURE_RUN_PARTS_FANCY -#define list_mode (option_mask32 & OPT_l) -#else -#define list_mode 0 -#endif - /* Is this a valid filename (upper/lower alpha, digits, * underscores, and hyphens only?) */ @@ -85,7 +106,7 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS if (depth == 2 && ( !(statbuf->st_mode & (S_IFREG | S_IFLNK)) || invalid_name(file) - || (!list_mode && access(file, X_OK) != 0)) + || (!(option_mask32 & OPT_l) && access(file, X_OK) != 0)) ) { return SKIP; } @@ -101,11 +122,12 @@ static int FAST_FUNC act(const char *file, struct stat *statbuf, void *args UNUS static const char runparts_longopts[] ALIGN1 = "arg\0" Required_argument "a" "umask\0" Required_argument "u" - "test\0" No_argument "t" -#if ENABLE_FEATURE_RUN_PARTS_FANCY - "list\0" No_argument "l" - "reverse\0" No_argument "r" //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 ; #endif @@ -118,12 +140,14 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) unsigned n; int ret; + INIT_G(); + #if ENABLE_FEATURE_RUN_PARTS_LONG_OPTIONS applet_long_options = runparts_longopts; #endif /* We require exactly one argument: the directory name */ opt_complementary = "=1:a::"; - getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p); + getopt32(argv, "a:u:", &arg_list, &umask_p); umask(xstrtou_range(umask_p, 8, 0, 07777)); @@ -166,6 +190,9 @@ int run_parts_main(int argc UNUSED_PARAM, char **argv) bb_perror_msg("can't execute '%s'", name); else /* ret > 0 */ bb_error_msg("%s exited with code %d", name, ret & 0xff); + + if (option_mask32 & OPT_e) + xfunc_die(); } return n; diff --git a/debianutils/start_stop_daemon.c b/debianutils/start_stop_daemon.c index 665f38f..7dadc3c 100644 --- a/debianutils/start_stop_daemon.c +++ b/debianutils/start_stop_daemon.c @@ -5,7 +5,7 @@ * Written by Marek Michalkiewicz , * Adapted for busybox David Kimdon * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -31,7 +31,8 @@ Options controlling process matching [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/cmdline. + 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 @@ -56,6 +57,69 @@ Misc options: -v,--verbose Verbose */ +//usage:#define start_stop_daemon_trivial_usage +//usage: "[OPTIONS] [-S|-K] ... [-- ARGS...]" +//usage:#define start_stop_daemon_full_usage "\n\n" +//usage: "Search for matching processes, and then\n" +//usage: "-K: stop all matching processes.\n" +//usage: "-S: start a process unless a matching process is found.\n" +//usage: IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( +//usage: "\nProcess matching:" +//usage: "\n -u,--user USERNAME|UID Match only this user's processes" +//usage: "\n -n,--name NAME Match processes with NAME" +//usage: "\n in comm field in /proc/PID/stat" +//usage: "\n -x,--exec EXECUTABLE Match processes with this command" +//usage: "\n in /proc/PID/{exe,cmdline}" +//usage: "\n -p,--pidfile FILE Match a process with PID from the file" +//usage: "\n All specified conditions must match" +//usage: "\n-S only:" +//usage: "\n -x,--exec EXECUTABLE Program to run" +//usage: "\n -a,--startas NAME Zeroth argument" +//usage: "\n -b,--background Background" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -N,--nicelevel N Change nice level" +//usage: ) +//usage: "\n -c,--chuid USER[:[GRP]] Change to user/group" +//usage: "\n -m,--make-pidfile Write PID to the pidfile specified by -p" +//usage: "\n-K only:" +//usage: "\n -s,--signal SIG Signal to send" +//usage: "\n -t,--test Match only, exit with 0 if a process is found" +//usage: "\nOther:" +//usage: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -o,--oknodo Exit with status 0 if nothing is done" +//usage: "\n -v,--verbose Verbose" +//usage: ) +//usage: "\n -q,--quiet Quiet" +//usage: ) +//usage: IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( +//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 command in /proc/PID/cmdline" +//usage: "\n -p FILE Match a process with PID from the 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: IF_FEATURE_START_STOP_DAEMON_FANCY( +//usage: "\n -N N Change nice level" +//usage: ) +//usage: "\n -c USER[:[GRP]] Change to user/group" +//usage: "\n -m Write PID to the pidfile specified by -p" +//usage: "\n-K only:" +//usage: "\n -s SIG Signal to send" +//usage: "\n -t Match only, exit with 0 if a process is 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: ) +//usage: "\n -q Quiet" +//usage: ) + #include /* Override ENABLE_FEATURE_PIDFILE */ @@ -135,8 +199,18 @@ 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; - sprintf(buf, "/proc/%u/cmdline", (unsigned)pid); + strcpy(procname, "cmdline"); bytes = open_read_close(buf, G.execname_cmpbuf, G.execname_sizeof); if (bytes > 0) { G.execname_cmpbuf[bytes] = '\0'; @@ -274,11 +348,17 @@ static int do_stop(void) goto ret; } for (p = G.found_procs; p; p = p->next) { - if (TEST || kill(p->pid, signal_nr) == 0) { + if (kill(p->pid, TEST ? 0 : signal_nr) == 0) { killed++; } else { - p->pid = 0; 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) { @@ -373,7 +453,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) // IF_FEATURE_START_STOP_DAEMON_FANCY( // if (retry_arg) -// retries = xatoi_u(retry_arg); +// retries = xatoi_positive(retry_arg); // ) //argc -= optind; argv += optind; @@ -405,7 +485,7 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) *--argv = startas; if (opt & OPT_BACKGROUND) { #if BB_MMU - bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS); + bb_daemonize(DAEMON_DEVNULL_STDIO + DAEMON_CLOSE_EXTRA_FDS + DAEMON_DOUBLE_FORK); /* DAEMON_DEVNULL_STDIO is superfluous - * it's always done by bb_daemonize() */ #else @@ -433,8 +513,16 @@ int start_stop_daemon_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_c) { struct bb_uidgid_t ugid = { -1, -1 }; parse_chown_usergroup_or_die(&ugid, chuid); - if (ugid.gid != (gid_t) -1) xsetgid(ugid.gid); - if (ugid.uid != (uid_t) -1) xsetuid(ugid.uid); + if (ugid.uid != (uid_t) -1) { + struct passwd *pw = xgetpwuid(ugid.uid); + if (ugid.gid != (gid_t) -1) + pw->pw_gid = ugid.gid; + /* initgroups, setgid, setuid: */ + change_identity(pw); + } else if (ugid.gid != (gid_t) -1) { + xsetgid(ugid.gid); + setgroups(1, &ugid.gid); + } } #if ENABLE_FEATURE_START_STOP_DAEMON_FANCY if (opt & OPT_NICELEVEL) { diff --git a/debianutils/which.c b/debianutils/which.c index 1558e5c..15fd598 100644 --- a/debianutils/which.c +++ b/debianutils/which.c @@ -5,11 +5,20 @@ * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2006 Gabriel Somlo * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Based on which from debianutils */ +//usage:#define which_trivial_usage +//usage: "[COMMAND]..." +//usage:#define which_full_usage "\n\n" +//usage: "Locate a COMMAND" +//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; diff --git a/docs/.gitignore b/docs/.gitignore index 9d1b7c2..3d1c5bd 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -1,4 +1,5 @@ -/BusyBox.1 +/busybox.1 /BusyBox.html +/busybox.net /BusyBox.txt /busybox.pod diff --git a/docs/busybox_footer.pod b/docs/busybox_footer.pod index 5ed9379..c346c73 100644 --- a/docs/busybox_footer.pod +++ b/docs/busybox_footer.pod @@ -252,5 +252,34 @@ Tito Ragusa devfsd and size optimizations in strings, openvt and deallocvt. -=cut +=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/docs/busybox_header.pod b/docs/busybox_header.pod index 2a99636..85a173e 100644 --- a/docs/busybox_header.pod +++ b/docs/busybox_header.pod @@ -80,4 +80,3 @@ been enabled, more detailed usage information will also be available. =head1 COMMANDS Currently available applets include: - diff --git a/docs/cgi/cl.html b/docs/cgi/cl.html index 5779d62..4f8faae 100644 --- a/docs/cgi/cl.html +++ b/docs/cgi/cl.html @@ -43,4 +43,4 @@ CGI - Common Gateway Interface

cgi@ncsa.uiuc.edu
- \ No newline at end of file + diff --git a/docs/cgi/env.html b/docs/cgi/env.html index 924026b..b83c750 100644 --- a/docs/cgi/env.html +++ b/docs/cgi/env.html @@ -146,4 +146,4 @@ interface specification

CGI - Common Gateway Interface

cgi@ncsa.uiuc.edu
- \ No newline at end of file + diff --git a/docs/cgi/in.html b/docs/cgi/in.html index 679306a..7ee5fe6 100644 --- a/docs/cgi/in.html +++ b/docs/cgi/in.html @@ -30,4 +30,4 @@ interface specification

CGI - Common Gateway Interface

cgi@ncsa.uiuc.edu
- \ No newline at end of file + diff --git a/docs/cgi/interface.html b/docs/cgi/interface.html index ea73ce3..0be016b 100644 --- a/docs/cgi/interface.html +++ b/docs/cgi/interface.html @@ -26,4 +26,4 @@ the following is a hotlink to graphic detail.

CGI - Common Gateway Interface

cgi@ncsa.uiuc.edu
- \ No newline at end of file + diff --git a/docs/cgi/out.html b/docs/cgi/out.html index 2203ee5..5266985 100644 --- a/docs/cgi/out.html +++ b/docs/cgi/out.html @@ -123,4 +123,4 @@ interface specification

CGI - Common Gateway Interface

cgi@ncsa.uiuc.edu
- \ No newline at end of file + diff --git a/docs/contributing.txt b/docs/contributing.txt index d06e4a2..e3289fd 100644 --- a/docs/contributing.txt +++ b/docs/contributing.txt @@ -229,8 +229,11 @@ Here are some guidelines on how to submit a patch to Busybox. Making A Patch ~~~~~~~~~~~~~~ -If you've got anonymous CVS access set up, making a patch is simple. Just make -sure you're in the busybox/ directory and type 'cvs diff -bwu > mychanges.patch'. +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 @@ -238,8 +241,12 @@ not required. Also, feel free to help test other people's patches and reply to them with comments. You can apply a patch by saving it into your busybox/ directory and -typing 'patch < mychanges.patch'. Then you can recompile, see if it runs, test -if it works as advertised, and post your findings to the mailing list. +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, @@ -252,7 +259,7 @@ Testing Guidelines ~~~~~~~~~~~~~~~~~~ It's considered good form to test your new feature before you submit a patch -to the mailing list, and especially before you commit a change to CVS. Here +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 @@ -348,7 +355,7 @@ responses from queries to applet maintainer or positive responses from folks on the mailing list. We've made strident efforts to put a useful "collaboration" infrastructure in -place in the form of mailing lists, the bug tracking system, and CVS. Please +place in the form of mailing lists, the bug tracking system, and Git. Please use these resources. @@ -373,39 +380,43 @@ opposite effect. -Committing Changes to CVS -------------------------- +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 commit -changes directly to CVS. This is nice because you don't have to wait for -someone else to commit your change for you, you can just do it yourself. +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 commit them. You should also talk to an +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 Commit -~~~~~~~~~~~~~~ -Generally, you should feel free to commit a change if: +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 commit a change -directly to CVS. +The more of the above are true, the better it is to just push a change +directly to Git. -When Not To Commit -~~~~~~~~~~~~~~~~~~ +When Not To Push +~~~~~~~~~~~~~~~~ -Even if you have commit rights, you should probably still post a patch to the +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 @@ -414,7 +425,7 @@ mailing list if: - You are not the maintainer and your changes make the maintainer cringe The more of the above are true, the better it is to post a patch to the -mailing list instead of committing. +mailing list instead of pushing. @@ -426,5 +437,3 @@ you're having difficulty following some of the steps outlined in this document don't worry, the folks on the Busybox mailing list are a fairly good-natured bunch and will work with you to help get your patches into shape or help you make contributions. - - diff --git a/docs/ctty.htm b/docs/ctty.htm index 8f466cd..3cb2dd2 100644 --- a/docs/ctty.htm +++ b/docs/ctty.htm @@ -9,6 +9,8 @@

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. @@ -277,6 +279,7 @@ and inspect it by 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

diff --git a/docs/ifupdown_design.txt b/docs/ifupdown_design.txt index 8008e45..8ab4e51 100644 --- a/docs/ifupdown_design.txt +++ b/docs/ifupdown_design.txt @@ -10,27 +10,27 @@ 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", ........ }, + { "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 (exists_execable(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); + int i ; + for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { + if (exists_execable(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); + return execute("kill " + "`cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", ifd, exec); #else - return 0; /* no dhcp support */ + return 0; /* no dhcp support */ #endif } diff --git a/docs/keep_data_small.txt b/docs/keep_data_small.txt index 01c0d3c..9fc7996 100644 --- a/docs/keep_data_small.txt +++ b/docs/keep_data_small.txt @@ -59,7 +59,7 @@ wait Example 1 One example how to reduce global data usage is in -archival/libunarchive/decompress_unzip.c: +archival/libarchive/decompress_unzip.c: /* This is somewhat complex-looking arrangement, but it allows * to place decompressor state either in bss or in @@ -138,13 +138,6 @@ less readable, use #defines: #define sector (G.sector) - Word of caution - -If applet doesn't use much of global data, converting it to use -one of above methods is not worth the resulting code obfuscation. -If you have less than ~300 bytes of global data - don't bother. - - Finding non-shared duplicated strings strings busybox | sort | uniq -c | sort -nr @@ -224,6 +217,14 @@ Result (non-static busybox built against glibc): 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 diff --git a/docs/mdev.txt b/docs/mdev.txt index 2d03bd8..b24025f 100644 --- a/docs/mdev.txt +++ b/docs/mdev.txt @@ -51,19 +51,25 @@ device nodes if your system needs something more than the default root/root 660 permissions. The file has the format: - : - or @ : + [-][envmatch] : +or + [envmatch]@ : +or + $envvar= : For example: - hd[a-z][0-9]* 0:3 660 + hd[a-z][0-9]* 0:3 660 The config file parsing stops at the first matching line. 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/ diff --git a/docs/new-applet-HOWTO.txt b/docs/new-applet-HOWTO.txt index 0646e72..6a8054d 100644 --- a/docs/new-applet-HOWTO.txt +++ b/docs/new-applet-HOWTO.txt @@ -8,7 +8,7 @@ Matt Kraai - initial writeup Mark Whitley - the remix Thomas Lundquist - Trying to keep it updated. -When doing this you should consider using the latest svn trunk. +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 @@ -19,8 +19,7 @@ such as who you stole the code from and so forth. Also include the mini-GPL boilerplate. Be sure to name the main function _main instead of main. And be sure to put it in .c. Usage does not have to be taken care of by your applet. -Make sure to #include "libbb.h" as the first include file in your applet so -the bb_config.h and appropriate platform specific files are included properly. +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: @@ -36,7 +35,7 @@ For a new applet mu, here is the code that would go in mu.c: * * Copyright (C) [YEAR] by [YOUR NAME] * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -99,14 +98,14 @@ int function(char *a) ----end example code------ Add .o in the right alphabetically sorted place -in libbb/Kbuild. You should look at the conditional part of -libbb/Kbuild aswell. +in libbb/Kbuild.src. You should look at the conditional part of +libbb/Kbuild.src as well. 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.in and try to find out if the function is +You can look at libbb/Config.src and try to find out if the function is tunable and add it there if it is. @@ -118,11 +117,11 @@ Find the appropriate directory for your new applet. Make sure you find the appropriate places in the files, the applets are sorted alphabetically. -Add the applet to Kbuild in the chosen directory: +Add the applet to Kbuild.src in the chosen directory: lib-$(CONFIG_MU) += mu.o -Add the applet to Config.in in the chosen directory: +Add the applet to Config.src in the chosen directory: config MU bool "MU" @@ -134,7 +133,7 @@ config MU Usage String(s) --------------- -Next, add usage information for you applet to include/usage.h. +Next, add usage information for you applet to include/usage.src.h. This should look like the following: #define mu_trivial_usage \ @@ -149,32 +148,33 @@ This should look like the following: If your program supports flags, the flags should be mentioned on the first line (-[abcde]) and a detailed description of each flag should go in the mu_full_usage section, one flag per line. (Numerous examples of this -currently exist in usage.h.) +currently exist in usage.src.h.) Header Files ------------ -Next, add an entry to include/applets.h. Be *sure* to keep the list +Next, add an entry to include/applets.src.h. Be *sure* to keep the list in alphabetical order, or else it will break the binary-search lookup algorithm in busybox.c and the Gods of BusyBox smite you. Yea, verily: -Be sure to read the top of applets.h before adding your applet. +Be sure to read the top of applets.src.h before adding your applet. /* all programs above here are alphabetically "less than" 'mu' */ - IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_DROP)) + IF_MU(APPLET(mu, BB_DIR_USR_BIN, BB_SUID_DROP)) /* all programs below here are alphabetically "greater than" 'mu' */ The Grand Announcement ---------------------- -Then create a diff by adding the new files with svn (remember your libbb files) - svn add /mu.c +Then create a diff by adding the new files to git (remember your libbb files) + git add /mu.c eventually also: - svn add libbb/function.c + git add libbb/function.c then - svn diff + git commit + git format-patch HEAD^ and send it to the mailing list: busybox@busybox.net http://busybox.net/mailman/listinfo/busybox diff --git a/docs/nofork_noexec.txt b/docs/nofork_noexec.txt index 06c789a..c58f5a8 100644 --- a/docs/nofork_noexec.txt +++ b/docs/nofork_noexec.txt @@ -44,9 +44,11 @@ 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 can do it). This poses much more serious limitations -on what applet can/cannot do: +_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 ever exit() or exec(). @@ -56,7 +58,7 @@ on what applet can/cannot do: 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 - prior to returning. (e.g. bb_common_bufsiz1 is off-limits). + (e.g. bb_common_bufsiz1) prior to returning. - getopt32() is ok to use. You do not need to save/restore option_mask32, it is already done by core code. * if you allocate memory, you can use xmalloc() only on the very first @@ -77,3 +79,20 @@ script loops. Applets which mess with signal handlers, termios etc are probably not worth the effort. Any NOFORK applet is also a NOEXEC applet. + + + Relevant CONFIG options + +FEATURE_PREFER_APPLETS + BB_EXECVP(cmd, argv) will try to exec /proc/self/exe + if command's name matches some applet name + applet tables will contain NOFORK/NOEXEC bits + spawn_and_wait(argv) will do NOFORK/NOEXEC tricks + +FEATURE_SH_STANDALONE (needs FEATURE_PREFER_APPLETS=y) + shells will try to exec /proc/self/exe if command's name matches + some applet name + shells will do NOEXEC trick on NOEXEC applets + +FEATURE_SH_NOFORK (needs FEATURE_PREFER_APPLETS=y) + shells will do NOFORK trick on NOFORK applets diff --git a/docs/posix_conformance.txt b/docs/posix_conformance.txt index d9fa116..5b616d7 100644 --- a/docs/posix_conformance.txt +++ b/docs/posix_conformance.txt @@ -739,4 +739,3 @@ xargs Busybox specific options: zcat POSIX options: None zcat Busybox specific options: None - diff --git a/docs/smallint.txt b/docs/smallint.txt new file mode 100644 index 0000000..b57dfd7 --- /dev/null +++ b/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/docs/style-guide.txt b/docs/style-guide.txt index fdf6cfe..10ed893 100644 --- a/docs/style-guide.txt +++ b/docs/style-guide.txt @@ -679,11 +679,10 @@ line in the midst of your #includes, if you need to parse long options: Then have long options defined: - static const struct option _long_options[] = { - { "list", 0, NULL, 't' }, - { "extract", 0, NULL, 'x' }, - { NULL, 0, NULL, 0 } - }; + 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: @@ -691,7 +690,7 @@ routine: char *str_b; opt_complementary = "cryptic_string"; - applet_long_options = _long_options; /* if you have them */ + applet_long_options = _longopts; /* if you have them */ opt = getopt32(argc, argv, "ab:c", &str_b); if (opt & 1) { handle_option_a(); diff --git a/docs/syslog.conf.txt b/docs/syslog.conf.txt new file mode 100644 index 0000000..6d9c4a1 --- /dev/null +++ b/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/docs/tcp.txt b/docs/tcp.txt new file mode 100644 index 0000000..2000f31 --- /dev/null +++ b/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/docs/unicode.txt b/docs/unicode.txt index 32df24d..9c159ce 100644 --- a/docs/unicode.txt +++ b/docs/unicode.txt @@ -29,7 +29,7 @@ But we also need to handle the following problematic moments: Editors (vi, ed) This case is a bit similar to "shell input", but unlike shell, -editors may encounder many more unexpected unicode sequences +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. diff --git a/e2fsprogs/Config.src b/e2fsprogs/Config.src index 62bc810..743e1e1 100644 --- a/e2fsprogs/Config.src +++ b/e2fsprogs/Config.src @@ -33,6 +33,7 @@ config FSCK config LSATTR bool "lsattr" default y + select PLATFORM_LINUX help lsattr lists the file attributes on a second extended file system. diff --git a/e2fsprogs/Kbuild.src b/e2fsprogs/Kbuild.src index 31c2712..b7a14c3 100644 --- a/e2fsprogs/Kbuild.src +++ b/e2fsprogs/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/e2fsprogs/chattr.c b/e2fsprogs/chattr.c index ab52cb0..f1cc838 100644 --- a/e2fsprogs/chattr.c +++ b/e2fsprogs/chattr.c @@ -19,6 +19,29 @@ * 98/12/29 - Display version info only when -V specified (G M Sipe) */ +//usage:#define chattr_trivial_usage +//usage: "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." +//usage:#define chattr_full_usage "\n\n" +//usage: "Change file attributes on an ext2 fs\n" +//usage: "\nModifiers:" +//usage: "\n - Remove attributes" +//usage: "\n + Add attributes" +//usage: "\n = Set attributes" +//usage: "\nAttributes:" +//usage: "\n A Don't track atime" +//usage: "\n a Append mode only" +//usage: "\n c Enable compress" +//usage: "\n D Write dir contents synchronously" +//usage: "\n d Don't backup with dump" +//usage: "\n i Cannot be modified (immutable)" +//usage: "\n j Write all data to journal first" +//usage: "\n s Zero disk storage when deleted" +//usage: "\n S Write file contents synchronously" +//usage: "\n t Disable tail-merging of partial blocks with other files" +//usage: "\n u Allow file to be undeleted" +//usage: "\n -R Recurse" +//usage: "\n -v Set the file's version/generation number" + #include "libbb.h" #include "e2fs_lib.h" diff --git a/e2fsprogs/e2fs_lib.c b/e2fsprogs/e2fs_lib.c index f033a19..a6aec94 100644 --- a/e2fsprogs/e2fs_lib.c +++ b/e2fsprogs/e2fs_lib.c @@ -2,7 +2,7 @@ /* * See README for additional information * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/e2fsprogs/e2fs_lib.h b/e2fsprogs/e2fs_lib.h index 3905ee7..f2ae56f 100644 --- a/e2fsprogs/e2fs_lib.h +++ b/e2fsprogs/e2fs_lib.h @@ -7,7 +7,7 @@ */ /* Constants and structures */ -#include "e2fs_defs.h" +#include "bb_e2fs_defs.h" PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN diff --git a/e2fsprogs/fsck.c b/e2fsprogs/fsck.c index 7c449e3..d32f396 100644 --- a/e2fsprogs/fsck.c +++ b/e2fsprogs/fsck.c @@ -20,7 +20,7 @@ * 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 tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* All filesystem specific hooks have been removed. @@ -34,6 +34,19 @@ * It doesn't guess filesystem types from on-disk format. */ +//usage:#define fsck_trivial_usage +//usage: "[-ANPRTV] [-C FD] [-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" +//usage: "\n -C n Write status information to specified filedescriptor" +//usage: "\n -t TYPE List of filesystem types to check" + #include "libbb.h" /* "progress indicator" code is somewhat buggy and ext[23] specific. @@ -303,7 +316,6 @@ static void load_fs_info(const char *filename) { FILE *fstab; struct mntent mte; - struct fs_info *fs; fstab = setmntent(filename, "r"); if (!fstab) { @@ -316,7 +328,7 @@ static void load_fs_info(const char *filename) //bb_info_msg("CREATE[%s][%s][%s][%s][%d]", mte.mnt_fsname, mte.mnt_dir, // mte.mnt_type, mte.mnt_opts, // mte.mnt_passno); - fs = create_fs_device(mte.mnt_fsname, mte.mnt_dir, + create_fs_device(mte.mnt_fsname, mte.mnt_dir, mte.mnt_type, mte.mnt_opts, mte.mnt_passno); } @@ -466,7 +478,7 @@ static int wait_one(int flags) instance_list = inst->next; if (verbose > 1) printf("Finished with %s (exit status %d)\n", - inst->device, status); + inst->device, status); num_running--; free_instance(inst); @@ -832,7 +844,7 @@ static int check_all(void) if (verbose > 1) printf("--waiting-- (pass %d)\n", passno); status |= wait_many(pass_done ? FLAG_WAIT_ALL : - FLAG_WAIT_ATLEAST_ONE); + FLAG_WAIT_ATLEAST_ONE); if (pass_done) { if (verbose > 1) puts("----------------------------------"); @@ -972,13 +984,13 @@ int fsck_main(int argc UNUSED_PARAM, char **argv) case 'C': progress = 1; if (arg[++j]) { /* -Cn */ - progress_fd = xatoi_u(&arg[j]); + progress_fd = xatoi_positive(&arg[j]); goto next_arg; } /* -C n */ if (!*++argv) bb_show_usage(); - progress_fd = xatoi_u(*argv); + progress_fd = xatoi_positive(*argv); goto next_arg; #endif case 'V': diff --git a/e2fsprogs/lsattr.c b/e2fsprogs/lsattr.c index 7d475a9..1312fe7 100644 --- a/e2fsprogs/lsattr.c +++ b/e2fsprogs/lsattr.c @@ -18,6 +18,16 @@ * 98/12/29 - Display version info only when -V specified (G M Sipe) */ +//usage:#define lsattr_trivial_usage +//usage: "[-Radlv] [FILE]..." +//usage:#define lsattr_full_usage "\n\n" +//usage: "List file attributes on an ext2 fs\n" +//usage: "\n -R Recurse" +//usage: "\n -a Don't hide entries starting with ." +//usage: "\n -d List directory entries instead of contents" +//usage: "\n -l List long flag names" +//usage: "\n -v List the file's version/generation number" + #include "libbb.h" #include "e2fs_lib.h" diff --git a/e2fsprogs/old_e2fsprogs/Kbuild.src b/e2fsprogs/old_e2fsprogs/Kbuild.src index 07a09ca..fff1a0d 100644 --- a/e2fsprogs/old_e2fsprogs/Kbuild.src +++ b/e2fsprogs/old_e2fsprogs/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/e2fsprogs/old_e2fsprogs/blkid/Kbuild.src b/e2fsprogs/old_e2fsprogs/blkid/Kbuild.src index bae77fe..02b4d24 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/Kbuild.src +++ b/e2fsprogs/old_e2fsprogs/blkid/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. NEEDED-$(CONFIG_E2FSCK) = y NEEDED-$(CONFIG_FSCK) = y diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkidP.h b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h index d6b2b42..bbadc8e 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/blkidP.h +++ b/e2fsprogs/old_e2fsprogs/blkid/blkidP.h @@ -179,8 +179,4 @@ extern int blkid_set_tag(blkid_dev dev, const char *name, extern blkid_dev blkid_new_dev(void); extern void blkid_free_dev(blkid_dev dev); -#ifdef __cplusplus -} -#endif - #endif diff --git a/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c b/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c index 941efa4..e1f6ba6 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c +++ b/e2fsprogs/old_e2fsprogs/blkid/blkid_getsize.c @@ -96,9 +96,9 @@ blkid_loff_t blkid_get_dev_size(int fd) #ifdef BLKGETSIZE64 #ifdef __linux__ - if ((uname(&ut) == 0) && - ((ut.release[0] == '2') && (ut.release[1] == '.') && - (ut.release[2] < '6') && (ut.release[3] == '.'))) + uname(&ut); + if ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] < '6') && (ut.release[3] == '.')) valid_blkgetsize64 = 0; #endif if (valid_blkgetsize64 && diff --git a/e2fsprogs/old_e2fsprogs/blkid/cache.c b/e2fsprogs/old_e2fsprogs/blkid/cache.c index d1d2914..251e499 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/cache.c +++ b/e2fsprogs/old_e2fsprogs/blkid/cache.c @@ -115,7 +115,7 @@ int main(int argc, char** argv) argv[0], ret); exit(1); } - if ((ret = blkid_probe_all(cache) < 0)) + if ((ret = blkid_probe_all(cache)) < 0) fprintf(stderr, "error probing devices\n"); blkid_put_cache(cache); diff --git a/e2fsprogs/old_e2fsprogs/blkid/dev.c b/e2fsprogs/old_e2fsprogs/blkid/dev.c index bb0cc91..260e49c 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/dev.c +++ b/e2fsprogs/old_e2fsprogs/blkid/dev.c @@ -153,7 +153,7 @@ extern int optind; void usage(char *prog) { fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask]\n", prog); - fprintf(stderr, "\tList all devices and exit\n", prog); + fprintf(stderr, "\tList all devices and exit\n"); exit(1); } @@ -176,7 +176,7 @@ int main(int argc, char **argv) case 'm': blkid_debug_mask = strtoul (optarg, &tmp, 0); if (*tmp) { - fprintf(stderr, "Invalid debug mask: %d\n", + fprintf(stderr, "Invalid debug mask: %s\n", optarg); exit(1); } diff --git a/e2fsprogs/old_e2fsprogs/blkid/probe.c b/e2fsprogs/old_e2fsprogs/blkid/probe.c index 77bfc73..651193b 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/probe.c +++ b/e2fsprogs/old_e2fsprogs/blkid/probe.c @@ -575,8 +575,12 @@ blkid_dev blkid_verify(blkid_cache cache, blkid_dev dev) printf("need to revalidate %s (time since last check %lu)\n", dev->bid_name, diff)); - if (((fd = open(dev->bid_name, O_RDONLY)) < 0) || - (fstat(fd, &st) < 0)) { + fd = open(dev->bid_name, O_RDONLY); + if (fd < 0 + || fstat(fd, &st) < 0 + ) { + if (fd >= 0) + close(fd); if (errno == ENXIO || errno == ENODEV || errno == ENOENT) { blkid_free_dev(dev); return NULL; @@ -653,6 +657,7 @@ try_again: if (!dev->bid_type) { blkid_free_dev(dev); + close(fd); return NULL; } diff --git a/e2fsprogs/old_e2fsprogs/blkid/read.c b/e2fsprogs/old_e2fsprogs/blkid/read.c index f795a5d..feeda51 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/read.c +++ b/e2fsprogs/old_e2fsprogs/blkid/read.c @@ -385,7 +385,7 @@ void blkid_read_cache(blkid_cache cache) continue; end = strlen(buf) - 1; /* Continue reading next line if it ends with a backslash */ - while (buf[end] == '\\' && end < sizeof(buf) - 2 && + while (end < sizeof(buf) - 2 && buf[end] == '\\' && fgets(buf + end, sizeof(buf) - end, file)) { end = strlen(buf) - 1; lineno++; diff --git a/e2fsprogs/old_e2fsprogs/blkid/tag.c b/e2fsprogs/old_e2fsprogs/blkid/tag.c index 8337b46..7424ede 100644 --- a/e2fsprogs/old_e2fsprogs/blkid/tag.c +++ b/e2fsprogs/old_e2fsprogs/blkid/tag.c @@ -356,7 +356,7 @@ void usage(char *prog) fprintf(stderr, "Usage: %s [-f blkid_file] [-m debug_mask] device " "[type value]\n", prog); - fprintf(stderr, "\tList all tags for a device and exit\n", prog); + fprintf(stderr, "\tList all tags for a device and exit\n"); exit(1); } @@ -382,7 +382,7 @@ int main(int argc, char **argv) case 'm': blkid_debug_mask = strtoul (optarg, &tmp, 0); if (*tmp) { - fprintf(stderr, "Invalid debug mask: %d\n", + fprintf(stderr, "Invalid debug mask: %s\n", optarg); exit(1); } @@ -407,7 +407,7 @@ int main(int argc, char **argv) dev = blkid_get_dev(cache, devname, flags); if (!dev) { - fprintf(stderr, "%s: cannot find device in blkid cache\n"); + fprintf(stderr, "%s: cannot find device in blkid cache\n", devname); exit(1); } if (search_type) { diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.c b/e2fsprogs/old_e2fsprogs/e2fsck.c index 4c4c78d..8400a92 100644 --- a/e2fsprogs/old_e2fsprogs/e2fsck.c +++ b/e2fsprogs/old_e2fsprogs/e2fsck.c @@ -26,8 +26,29 @@ * Journal recovery routines for the generic filesystem journaling code; * part of the ext2fs journaling system. * - * Licensed under GPLv2 or later, see file License in this tarball for details. - */ + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* +//usage:#define e2fsck_trivial_usage +//usage: "[-panyrcdfvstDFSV] [-b superblock] [-B blocksize] " +//usage: "[-I inode_buffer_blocks] [-P process_inode_size] " +//usage: "[-l|-L bad_blocks_file] [-C fd] [-j external_journal] " +//usage: "[-E extended-options] device" +//usage:#define e2fsck_full_usage "\n\n" +//usage: "Check ext2/ext3 file system\n" +//usage: "\n -p Automatic repair (no questions)" +//usage: "\n -n Make no changes to the filesystem" +//usage: "\n -y Assume 'yes' to all questions" +//usage: "\n -c Check for bad blocks and add them to the badblock list" +//usage: "\n -f Force checking even if filesystem is marked clean" +//usage: "\n -v Verbose" +//usage: "\n -b superblock Use alternative superblock" +//usage: "\n -B blocksize Force blocksize when looking for superblock" +//usage: "\n -j journal Set location of the external journal" +//usage: "\n -l file Add to badblocks list" +//usage: "\n -L file Set badblocks list" +*/ #include "e2fsck.h" /*Put all of our defines here to clean things up*/ @@ -517,7 +538,6 @@ static void dict_insert(dict_t *dict, dnode_t *node, const void *key) } dict_root(dict)->color = dnode_black; - } /* @@ -561,7 +581,7 @@ static dnode_t *dict_first(dict_t *dict) /* * Return the given node's successor node---the node which has the - * next key in the the left to right ordering. If the node has + * next key in the left to right ordering. If the node has * no successor, a null pointer is returned rather than a pointer to * the nil node. */ @@ -801,7 +821,6 @@ static void e2fsck_add_dx_dir(e2fsck_t ctx, ext2_ino_t ino, int num_blocks) dir->dx_block = e2fsck_allocate_memory(ctx, num_blocks * sizeof (struct dx_dirblock_info), "dx_block info array"); - } /* @@ -1031,7 +1050,7 @@ static errcode_t ea_refcount_create(int size, ext2_refcount_t *ret) refcount->size = size; bytes = (size_t) (size * sizeof(struct ea_refcount_el)); #ifdef DEBUG - printf("Refcount allocated %d entries, %d bytes.\n", + printf("Refcount allocated %d entries, %lu bytes.\n", refcount->size, bytes); #endif retval = ext2fs_get_mem(bytes, &refcount->list); @@ -1724,7 +1743,6 @@ errout: ext2fs_free_mem(&j_inode); ext2fs_free_mem(&journal); return retval; - } static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx, @@ -3375,7 +3393,6 @@ static void e2fsck_pass1(e2fsck_t ctx) e2fsck_write_inode(ctx, ino, inode, "pass1"); } - } /* * If dtime is set, offer to clear it. mke2fs @@ -3407,7 +3424,7 @@ static void e2fsck_pass1(e2fsck_t ctx) continue; } if ((inode->i_links_count || inode->i_blocks || - inode->i_blocks || inode->i_block[0]) && + inode->i_block[0]) && fix_problem(ctx, PR_1_JOURNAL_INODE_NOT_CLEAR, &pctx)) { memset(inode, 0, inode_size); @@ -3678,7 +3695,6 @@ endit: ext2fs_free_mem(&block_buf); ext2fs_free_mem(&inode); - } /* @@ -4451,8 +4467,7 @@ static void mark_table_blocks(e2fsck_t ctx) ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(ctx->block_found_map, - b); + ext2fs_mark_block_bitmap(ctx->block_found_map, b); } } } @@ -4469,10 +4484,9 @@ static void mark_table_blocks(e2fsck_t ctx) ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(ctx->block_found_map, - fs->group_desc[i].bg_block_bitmap); - } - + ext2fs_mark_block_bitmap(ctx->block_found_map, + fs->group_desc[i].bg_block_bitmap); + } } /* * Mark block used for the inode bitmap @@ -4486,8 +4500,8 @@ static void mark_table_blocks(e2fsck_t ctx) ctx->invalid_bitmaps++; } } else { - ext2fs_mark_block_bitmap(ctx->block_found_map, - fs->group_desc[i].bg_inode_bitmap); + ext2fs_mark_block_bitmap(ctx->block_found_map, + fs->group_desc[i].bg_inode_bitmap); } } block += fs->super->s_blocks_per_group; @@ -5588,7 +5602,6 @@ static void e2fsck_pass2(e2fsck_t ctx) ext2fs_mark_super_dirty(fs); } } - } #define MAX_DEPTH 32000 @@ -9748,7 +9761,6 @@ int fix_problem(e2fsck_t ctx, problem_t code, struct problem_context *pctx) if (print_answer) printf("%s.\n", answer ? _(preen_msg[(int) ptr->prompt]) : _("IGNORED")); - } if ((ptr->prompt == PROMPT_ABORT) && answer) @@ -11324,7 +11336,7 @@ static int release_inode_block(ext2_filsys fs, blk_t *block_nr, if ((blk < fs->super->s_first_data_block) || (blk >= fs->super->s_blocks_count)) { fix_problem(ctx, PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, pctx); - return_abort: + return_abort: pb->abort = 1; return BLOCK_ABORT; } @@ -11537,7 +11549,7 @@ static int release_orphan_inodes(e2fsck_t ctx) } ext2fs_free_mem(&block_buf); return 0; -return_abort: + return_abort: ext2fs_free_mem(&block_buf); return 1; } @@ -11565,7 +11577,7 @@ static void check_resize_inode(e2fsck_t ctx) * s_reserved_gdt_blocks must be zero. */ if (!(fs->super->s_feature_compat & - EXT2_FEATURE_COMPAT_RESIZE_INODE)) { + EXT2_FEATURE_COMPAT_RESIZE_INO)) { if (fs->super->s_reserved_gdt_blocks) { pctx.num = fs->super->s_reserved_gdt_blocks; if (fix_problem(ctx, PR_0_NONZERO_RESERVED_GDT_BLOCKS, @@ -11581,7 +11593,7 @@ static void check_resize_inode(e2fsck_t ctx) retval = ext2fs_read_inode(fs, EXT2_RESIZE_INO, &inode); if (retval) { if (fs->super->s_feature_compat & - EXT2_FEATURE_COMPAT_RESIZE_INODE) + EXT2_FEATURE_COMPAT_RESIZE_INO) ctx->flags |= E2F_FLAG_RESIZE_INODE; return; } @@ -11591,7 +11603,7 @@ static void check_resize_inode(e2fsck_t ctx) * the resize inode is cleared; then we're done. */ if (!(fs->super->s_feature_compat & - EXT2_FEATURE_COMPAT_RESIZE_INODE)) { + EXT2_FEATURE_COMPAT_RESIZE_INO)) { for (i=0; i < EXT2_N_BLOCKS; i++) { if (inode.i_block[i]) break; @@ -11618,7 +11630,7 @@ static void check_resize_inode(e2fsck_t ctx) !(inode.i_mode & LINUX_S_IFREG) || (blk < fs->super->s_first_data_block || blk >= fs->super->s_blocks_count)) { - resize_inode_invalid: + resize_inode_invalid: if (fix_problem(ctx, PR_0_RESIZE_INODE_INVALID, &pctx)) { memset(&inode, 0, sizeof(inode)); e2fsck_write_inode(ctx, EXT2_RESIZE_INO, &inode, @@ -11660,10 +11672,9 @@ static void check_resize_inode(e2fsck_t ctx) } } -cleanup: + cleanup: ext2fs_free_mem(&dind_buf); - - } +} static void check_super_block(e2fsck_t ctx) { @@ -11842,7 +11853,6 @@ static void check_super_block(e2fsck_t ctx) (gd->bg_free_inodes_count > sb->s_inodes_per_group) || (gd->bg_used_dirs_count > sb->s_inodes_per_group)) ext2fs_unmark_valid(fs); - } /* @@ -11902,7 +11912,6 @@ static void check_super_block(e2fsck_t ctx) fs->super->s_feature_incompat &= ~EXT2_FEATURE_INCOMPAT_FILETYPE; ext2fs_mark_super_dirty(fs); - } } @@ -12186,11 +12195,7 @@ static void swap_filesys(e2fsck_t ctx) void *e2fsck_allocate_memory(e2fsck_t ctx, unsigned int size, const char *description) { - void *ret; - char buf[256]; - - ret = xzalloc(size); - return ret; + return xzalloc(size); } static char *string_copy(const char *str, int len) diff --git a/e2fsprogs/old_e2fsprogs/e2fsck.h b/e2fsprogs/old_e2fsprogs/e2fsck.h index 73d398f..c159fab 100644 --- a/e2fsprogs/old_e2fsprogs/e2fsck.h +++ b/e2fsprogs/old_e2fsprogs/e2fsck.h @@ -258,7 +258,7 @@ The following defines are used in the 'flags' field of a dx_dirblock_info #define PR_1_SET_IMAGIC 0x01002F /* Imagic flag set on an inode when filesystem doesn't support it */ #define PR_1_SET_IMMUTABLE 0x010030 /* Immutable flag set on a device or socket inode */ #define PR_1_COMPR_SET 0x010031 /* Compression flag set on a non-compressed filesystem */ -#define PR_1_SET_NONZSIZE 0x010032 /* Non-zero size on on device, fifo or socket inode */ +#define PR_1_SET_NONZSIZE 0x010032 /* Non-zero size on device, fifo or socket inode */ #define PR_1_FS_REV_LEVEL 0x010033 /* Filesystem revision is 0, but feature flags are set */ #define PR_1_JOURNAL_INODE_NOT_CLEAR 0x010034 /* Journal inode not in use, needs clearing */ #define PR_1_JOURNAL_BAD_MODE 0x010035 /* Journal inode has wrong mode */ @@ -629,12 +629,10 @@ struct e2fsck_struct { }; -#define tid_gt(x, y) ((x - y) > 0) +#define tid_gt(x, y) ((x - y) > 0) static inline int tid_geq(tid_t x, tid_t y) { int difference = (x - y); return (difference >= 0); } - - diff --git a/e2fsprogs/old_e2fsprogs/e2p/Kbuild.src b/e2fsprogs/old_e2fsprogs/e2p/Kbuild.src index 1948707..482630c 100644 --- a/e2fsprogs/old_e2fsprogs/e2p/Kbuild.src +++ b/e2fsprogs/old_e2fsprogs/e2p/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. NEEDED-$(CONFIG_CHATTR) = y NEEDED-$(CONFIG_LSATTR) = y diff --git a/e2fsprogs/old_e2fsprogs/e2p/feature.c b/e2fsprogs/old_e2fsprogs/e2p/feature.c index b45754f..2102ed8 100644 --- a/e2fsprogs/old_e2fsprogs/e2p/feature.c +++ b/e2fsprogs/old_e2fsprogs/e2p/feature.c @@ -34,7 +34,7 @@ static const struct feature feature_list[] = { "ext_attr" }, { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_DIR_INDEX, "dir_index" }, - { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INODE, + { E2P_FEATURE_COMPAT, EXT2_FEATURE_COMPAT_RESIZE_INO, "resize_inode" }, { E2P_FEATURE_RO_INCOMPAT, EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER, "sparse_super" }, diff --git a/e2fsprogs/old_e2fsprogs/e2p/ostype.c b/e2fsprogs/old_e2fsprogs/e2p/ostype.c index 1abe2ba..6a2f178 100644 --- a/e2fsprogs/old_e2fsprogs/e2p/ostype.c +++ b/e2fsprogs/old_e2fsprogs/e2p/ostype.c @@ -70,5 +70,3 @@ int main(int argc, char **argv) exit(0); } #endif - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild.src b/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild.src index 8ca65ee..12adc6e 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild.src +++ b/e2fsprogs/old_e2fsprogs/ext2fs/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. NEEDED-$(CONFIG_E2FSCK) = y NEEDED-$(CONFIG_FSCK) = y diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c index 5021d72..cbb63e1 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc.c @@ -171,4 +171,3 @@ errcode_t ext2fs_get_free_blocks(ext2_filsys fs, blk_t start, blk_t finish, } while (b != finish); return EXT2_ET_BLOCK_ALLOC_FAIL; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c index b2d786e..7c60e2b 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/alloc_tables.c @@ -97,12 +97,9 @@ errcode_t ext2fs_allocate_group_table(ext2_filsys fs, dgrp_t group, fs->group_desc[group].bg_inode_table = new_blk; } - return 0; } - - errcode_t ext2fs_allocate_tables(ext2_filsys fs) { errcode_t retval; @@ -115,4 +112,3 @@ errcode_t ext2fs_allocate_tables(ext2_filsys fs) } return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c b/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c index 1deae54..a967896 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/bb_inode.c @@ -260,9 +260,3 @@ static int set_bad_block_proc(ext2_filsys fs, blk_t *block_nr, *block_nr = blk; return BLOCK_CHANGED; } - - - - - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c index 9870611..3d08394 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/bitops.c @@ -65,7 +65,7 @@ int ext2fs_test_bit(unsigned int nr, const void * addr) return (mask & *ADDR); } -#endif /* !_EXT2_HAVE_ASM_BITOPS_ */ +#endif /* !_EXT2_HAVE_ASM_BITOPS_ */ void ext2fs_warn_bitmap(errcode_t errcode, unsigned long arg, const char *description) @@ -88,4 +88,3 @@ void ext2fs_warn_bitmap2(ext2fs_generic_bitmap bitmap, bb_error_msg("#%lu", arg); #endif } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/block.c b/e2fsprogs/old_e2fsprogs/ext2fs/block.c index 4980969..dbd04f8 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/block.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/block.c @@ -435,4 +435,3 @@ errcode_t ext2fs_block_iterate(ext2_filsys fs, return ext2fs_block_iterate2(fs, ino, BLOCK_FLAG_NO_LARGE | flags, block_buf, xlate_func, &xl); } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c b/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c index b2d0279..796b0e4 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/bmap.c @@ -259,6 +259,3 @@ done: } return retval; } - - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c b/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c index 635410d..ec9244d 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/bmove.c @@ -153,4 +153,3 @@ errcode_t ext2fs_move_blocks(ext2_filsys fs, } return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/brel.h b/e2fsprogs/old_e2fsprogs/ext2fs/brel.h index 216fd13..87bf72b 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/brel.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/brel.h @@ -84,4 +84,3 @@ errcode_t ext2fs_brel_memarray_create(char *name, blk_t max_block, #define ext2fs_brel_move(brel, old, new) ((brel)->move((brel), old, new)) #define ext2fs_brel_delete(brel, old) ((brel)->delete((brel), old)) #define ext2fs_brel_free(brel) ((brel)->free((brel))) - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c b/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c index 7ba7f22..bfa15e2 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/closefs.c @@ -378,4 +378,3 @@ errcode_t ext2fs_close(ext2_filsys fs) ext2fs_free(fs); return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c b/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c index 05b8eb8..7f78ff8 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/cmp_bitmaps.c @@ -70,4 +70,3 @@ errcode_t ext2fs_compare_inode_bitmap(ext2fs_inode_bitmap bm1, return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c b/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c index b7d8735..eb5dae0 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/dir_iterate.c @@ -217,4 +217,3 @@ next: return BLOCK_ABORT; return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c b/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c index f651338..f9c5a10 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/dirblock.c @@ -130,4 +130,3 @@ errcode_t ext2fs_write_dir_block(ext2_filsys fs, blk_t block, { return ext2fs_write_dir_block2(fs, block, inbuf, 0); } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c b/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c index 203c29f..d187937 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/dupfs.c @@ -92,6 +92,4 @@ errcode_t ext2fs_dup_handle(ext2_filsys src, ext2_filsys *dest) errout: ext2fs_free(fs); return retval; - } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h b/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h index 8d38ecc..a598d01 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/e2image.h @@ -37,16 +37,3 @@ struct ext2_image_hdr { __u32 offset_blockmap; /* Byte offset of the inode bitmaps */ __u32 offset_reserved[8]; }; - - - - - - - - - - - - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h index cc91bb8..ca309c0 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_ext_attr.h @@ -50,4 +50,3 @@ struct ext2_ext_attr_entry { sizeof(struct ext2_xattr_entry)) & ~EXT2_EXT_ATTR_ROUND) #define EXT2_XATTR_SIZE(size) \ (((size) + EXT2_EXT_ATTR_ROUND) & ~EXT2_EXT_ATTR_ROUND) - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h index 6f4f708..80ea2cb 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2_fs.h @@ -475,7 +475,7 @@ struct ext2_super_block { #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h index 9f77201..39fb116 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs.h @@ -383,7 +383,7 @@ typedef struct ext2_icount *ext2_icount_t; #define EXT2_LIB_FEATURE_COMPAT_SUPP (EXT2_FEATURE_COMPAT_DIR_PREALLOC|\ EXT2_FEATURE_COMPAT_IMAGIC_INODES|\ EXT3_FEATURE_COMPAT_HAS_JOURNAL|\ - EXT2_FEATURE_COMPAT_RESIZE_INODE|\ + EXT2_FEATURE_COMPAT_RESIZE_INO|\ EXT2_FEATURE_COMPAT_DIR_INDEX|\ EXT2_FEATURE_COMPAT_EXT_ATTR) diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h index 908b5d9..7a02e9a 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fsP.h @@ -85,5 +85,3 @@ extern int ext2fs_process_dir_block(ext2_filsys fs, blk_t ref_block, int ref_offset, void *priv_data); - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c index b9aab44..7d37d23 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ext2fs_inline.c @@ -155,8 +155,8 @@ int ext2fs_group_of_ino(ext2_filsys fs, ext2_ino_t ino) blk_t ext2fs_inode_data_blocks(ext2_filsys fs, struct ext2_inode *inode) { - return inode->i_blocks - - (inode->i_file_acl ? fs->blocksize >> 9 : 0); + return inode->i_blocks - + (inode->i_file_acl ? fs->blocksize >> 9 : 0); } diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c b/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c index e429826..45ed765 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/flushb.c @@ -23,7 +23,7 @@ #endif #if HAVE_SYS_MOUNT_H #include -#include /* This may define BLKFLSBUF */ +#include /* This may define BLKFLSBUF */ #endif #include "ext2_fs.h" @@ -38,10 +38,10 @@ */ #ifdef __linux__ #ifndef BLKFLSBUF -#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ +#define BLKFLSBUF _IO(0x12,97) /* flush buffer cache */ #endif #ifndef FDFLUSH -#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */ +#define FDFLUSH _IO(2,0x4b) /* flush floppy disk */ #endif #endif diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c b/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c index 65c4ee7..0c5d48b 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/freefs.c @@ -125,4 +125,3 @@ void ext2fs_free_dblist(ext2_dblist dblist) dblist->magic = 0; ext2fs_free_mem(&dblist); } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c b/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c index a98b2b9..2bb1cc2 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/get_pathname.c @@ -15,7 +15,7 @@ * string, placing the result in . is the containing * directory inode, and is the inode number itself. If * is zero, then ext2fs_get_pathname will return pathname - * of the the directory . + * of the directory . * */ @@ -153,5 +153,4 @@ errcode_t ext2fs_get_pathname(ext2_filsys fs, ext2_ino_t dir, ext2_ino_t ino, retval = ext2fs_get_pathname_int(fs, dir, ino, 32, buf, name); ext2fs_free_mem(&buf); return retval; - } diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c b/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c index ff11fe9..ee4bbb7 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/getsize.c @@ -174,9 +174,9 @@ errcode_t ext2fs_get_device_size(const char *file, int blocksize, #ifdef BLKGETSIZE64 #ifdef __linux__ - if ((uname(&ut) == 0) && - ((ut.release[0] == '2') && (ut.release[1] == '.') && - (ut.release[2] < '6') && (ut.release[3] == '.'))) + uname(&ut); + if ((ut.release[0] == '2') && (ut.release[1] == '.') && + (ut.release[2] < '6') && (ut.release[3] == '.')) valid_blkgetsize64 = 0; #endif if (valid_blkgetsize64 && diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c b/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c index c86a1c5..a103830 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ind_block.c @@ -67,5 +67,3 @@ errcode_t ext2fs_write_ind_block(ext2_filsys fs, blk_t blk, void *buf) #endif return io_channel_write_blk(fs->io, blk, 1, buf); } - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c index ef1d343..240335b 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/initialize.c @@ -83,7 +83,7 @@ static int calc_reserved_gdt_blocks(ext2_filsys fs) if (rsv_gdb > EXT2_ADDR_PER_BLOCK(sb)) rsv_gdb = EXT2_ADDR_PER_BLOCK(sb); #ifdef RES_GDT_DEBUG - printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %lu\n", + printf("max_blocks %lu, rsv_groups = %lu, rsv_gdb = %u\n", max_blocks, rsv_groups, rsv_gdb); #endif @@ -284,7 +284,7 @@ retry: /* * check the number of reserved group descriptor table blocks */ - if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) + if (super->s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) rsv_gdt = calc_reserved_gdt_blocks(fs); else rsv_gdt = 0; diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inline.c b/e2fsprogs/old_e2fsprogs/ext2fs/inline.c index 9b620a7..7457b93 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/inline.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/inline.c @@ -1,8 +1,8 @@ /* vi: set sw=4 ts=4: */ /* * inline.c --- Includes the inlined functions defined in the header - * files as standalone functions, in case the application program - * is compiled with inlining turned off. + * files as standalone functions, in case the application program + * is compiled with inlining turned off. * * Copyright (C) 1993, 1994 Theodore Ts'o. * @@ -30,4 +30,3 @@ #include "ext2_fs.h" #define INCLUDE_INLINE_FUNCS #include "ext2fs.h" - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inode.c b/e2fsprogs/old_e2fsprogs/ext2fs/inode.c index 5e0d081..7a1d5c9 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/inode.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/inode.c @@ -764,4 +764,3 @@ errcode_t ext2fs_check_directory(ext2_filsys fs, ext2_ino_t ino) return EXT2_ET_NO_DIRECTORY; return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c index 4bfa93a..b861d5f 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/inode_io.c @@ -268,4 +268,3 @@ static errcode_t inode_flush(io_channel channel) return ext2fs_file_flush(data->file); } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c b/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c index 7f24f9b..f5f6f31 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/ismounted.c @@ -59,7 +59,7 @@ static errcode_t check_mntent_file(const char *mtab_file, const char *file, if (S_ISBLK(st_buf.st_mode)) { #ifndef __GNU__ /* The GNU hurd is broken with respect to stat devices */ file_rdev = st_buf.st_rdev; -#endif /* __GNU__ */ +#endif /* __GNU__ */ } else { file_dev = st_buf.st_dev; file_ino = st_buf.st_ino; @@ -73,7 +73,7 @@ static errcode_t check_mntent_file(const char *mtab_file, const char *file, #ifndef __GNU__ if (file_rdev && (file_rdev == st_buf.st_rdev)) break; -#endif /* __GNU__ */ +#endif /* __GNU__ */ } else { if (file_dev && ((file_dev == st_buf.st_dev) && (file_ino == st_buf.st_ino))) @@ -99,7 +99,7 @@ static errcode_t check_mntent_file(const char *mtab_file, const char *file, goto is_root; } } -#endif /* __GNU__ */ +#endif /* __GNU__ */ goto errout; } #ifndef __GNU__ /* The GNU hurd is deficient; what else is new? */ @@ -247,7 +247,7 @@ static int is_swap_device(const char *file) if ((stat(file, &st_buf) == 0) && S_ISBLK(st_buf.st_mode)) file_dev = st_buf.st_rdev; -#endif /* __GNU__ */ +#endif /* __GNU__ */ if (!(f = fopen_for_read("/proc/swaps"))) return 0; @@ -271,7 +271,7 @@ static int is_swap_device(const char *file) ret++; break; } -#endif /* __GNU__ */ +#endif /* __GNU__ */ } fclose(f); return ret; diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h b/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h index 136635d..17c586a 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h +++ b/e2fsprogs/old_e2fsprogs/ext2fs/jfs_dat.h @@ -60,6 +60,4 @@ typedef struct journal_superblock_s /* Dynamic information describing the current state of the log */ __u32 s_sequence; /* first commit ID expected in log */ __u32 s_start; /* blocknr of start of log */ - } journal_superblock_t; - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c b/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c index 31b30a1..b2e8de8 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/lookup.c @@ -66,5 +66,3 @@ errcode_t ext2fs_lookup(ext2_filsys fs, ext2_ino_t dir, const char *name, return (ls.found) ? 0 : EXT2_ET_FILE_NOT_FOUND; } - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c b/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c index 93f47b0..a86ac8e 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/mkdir.c @@ -136,7 +136,4 @@ errcode_t ext2fs_mkdir(ext2_filsys fs, ext2_ino_t parent, ext2_ino_t inum, cleanup: ext2fs_free_mem(&block); return retval; - } - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c b/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c index db1c8bf..748d9ab 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/mkjournal.c @@ -188,7 +188,6 @@ static int mkjournal_proc(ext2_filsys fs, return (BLOCK_CHANGED | BLOCK_ABORT); else return BLOCK_CHANGED; - } /* @@ -423,6 +422,5 @@ main(int argc, char **argv) } ext2fs_close(fs); exit(0); - } #endif diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/namei.c b/e2fsprogs/old_e2fsprogs/ext2fs/namei.c index 14d48fb..1824461 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/namei.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/namei.c @@ -202,4 +202,3 @@ errcode_t ext2fs_follow_link(ext2_filsys fs, ext2_ino_t root, ext2_ino_t cwd, ext2fs_free_mem(&buf); return retval; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c b/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c index 9470e7f..9f15662 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/newdir.c @@ -66,7 +66,6 @@ errcode_t ext2fs_new_dir_block(ext2_filsys fs, ext2_ino_t dir_ino, dir->name_len = 2 | filetype; dir->name[0] = '.'; dir->name[1] = '.'; - } *block = buf; return 0; diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c index 4766157..ce77bc9 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb.c @@ -94,5 +94,3 @@ errcode_t ext2fs_read_bb_inode(ext2_filsys fs, ext2_badblocks_list *bb_list) return rb.err; } - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c index 831adcc..bf1fc32 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/read_bb_file.c @@ -94,5 +94,3 @@ errcode_t ext2fs_read_bb_FILE(ext2_filsys fs, FILE *f, return ext2fs_read_bb_FILE2(fs, f, bb_list, (void *) invalid, call_compat_invalid); } - - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c b/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c index 3c550d5..403463a 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/res_gdt.c @@ -218,4 +218,3 @@ out_free: ext2fs_free_mem((void *)&dindir_buf); return retval; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c b/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c index e932b3c..32e87b7 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/rs_bitmap.c @@ -104,4 +104,3 @@ errcode_t ext2fs_resize_block_bitmap(__u32 new_end, __u32 new_real_end, bmap->magic = EXT2_ET_MAGIC_BLOCK_BITMAP; return retval; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c b/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c index 0ae0a82..bba4326 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/rw_bitmaps.c @@ -266,7 +266,6 @@ errcode_t ext2fs_read_block_bitmap(ext2_filsys fs) errcode_t ext2fs_read_bitmaps(ext2_filsys fs) { - EXT2_CHECK_MAGIC(fs, EXT2_ET_MAGIC_EXT2FS_FILSYS); if (fs->inode_map && fs->block_map) @@ -293,4 +292,3 @@ errcode_t ext2fs_write_bitmaps(ext2_filsys fs) } return 0; } - diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c b/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c index 2fca3cf..07b757a 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/swapfs.c @@ -66,7 +66,6 @@ void ext2fs_swap_super(struct ext2_super_block * sb) sb->s_hash_seed[i] = ext2fs_swab32(sb->s_hash_seed[i]); for (i=0; i < 17; i++) sb->s_jnl_blocks[i] = ext2fs_swab32(sb->s_jnl_blocks[i]); - } void ext2fs_swap_group_desc(struct ext2_group_desc *gdp) @@ -222,7 +221,6 @@ void ext2fs_swap_inode_full(ext2_filsys fs, struct ext2_inode_large *t, ext2fs_swap_ext_attr((char *) (eat + 1), (char *) (eaf + 1), bufsize - sizeof(struct ext2_inode) - t->i_extra_isize - sizeof(__u32), 0); - } void ext2fs_swap_inode(ext2_filsys fs, struct ext2_inode *t, diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c index 474f073..3c95829 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/unix_io.c @@ -544,7 +544,7 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block, /* If it's in the cache, use it! */ if ((cache = find_cached_block(data, block, &reuse[0]))) { #ifdef DEBUG - printf("Using cached block %d\n", block); + printf("Using cached block %lu\n", block); #endif memcpy(cp, cache->buf, channel->block_size); count--; @@ -560,7 +560,7 @@ static errcode_t unix_read_blk(io_channel channel, unsigned long block, if (find_cached_block(data, block+i, &reuse[i])) break; #ifdef DEBUG - printf("Reading %d blocks starting at %d\n", i, block); + printf("Reading %d blocks starting at %lu\n", i, block); #endif if ((retval = raw_read_blk(channel, data, block, i, cp))) return retval; diff --git a/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c b/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c index 83ac271..71a9ffc 100644 --- a/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c +++ b/e2fsprogs/old_e2fsprogs/ext2fs/unlink.c @@ -97,4 +97,3 @@ errcode_t ext2fs_unlink(ext2_filsys fs, ext2_ino_t dir, return (ls.done) ? 0 : EXT2_ET_DIR_NO_SPACE; } - diff --git a/e2fsprogs/old_e2fsprogs/fsck.c b/e2fsprogs/old_e2fsprogs/fsck.c index 2a66d72..91cce97 100644 --- a/e2fsprogs/old_e2fsprogs/fsck.c +++ b/e2fsprogs/old_e2fsprogs/fsck.c @@ -20,7 +20,7 @@ * 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 tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include @@ -349,15 +349,7 @@ static void parse_escape(char *word) if (!word) return; - for (p = q = word; *p; q++) { - c = *p++; - if (c != '\\') { - *q = c; - } else { - *q = bb_process_escape_sequence(&p); - } - } - *q = 0; + strcpy_and_process_escape_sequences(word, word); } static void free_instance(struct fsck_instance *i) @@ -1247,7 +1239,6 @@ static void PRS(int argc, char **argv) progress_fd = 0; else { goto next_arg; - i++; } } break; diff --git a/e2fsprogs/old_e2fsprogs/lsattr.c b/e2fsprogs/old_e2fsprogs/lsattr.c index 294bf2f..9eab68b 100644 --- a/e2fsprogs/old_e2fsprogs/lsattr.c +++ b/e2fsprogs/old_e2fsprogs/lsattr.c @@ -12,10 +12,10 @@ /* * History: - * 93/10/30 - Creation - * 93/11/13 - Replace stat() calls by lstat() to avoid loops - * 94/02/27 - Integrated in Ted's distribution - * 98/12/29 - Display version info only when -V specified (G M Sipe) + * 93/10/30 - Creation + * 93/11/13 - Replace stat() calls by lstat() to avoid loops + * 94/02/27 - Integrated in Ted's distribution + * 98/12/29 - Display version info only when -V specified (G M Sipe) */ #include @@ -93,7 +93,7 @@ static int lsattr_dir_proc(const char *dir_name, struct dirent *de, path = concat_path_file(dir_name, de->d_name); if (lstat(path, &st) == -1) - bb_perror_msg(path); + bb_simple_perror_msg(path); else { if (de->d_name[0] != '.' || (flags & OPT_ALL)) { list_attributes(path); diff --git a/e2fsprogs/old_e2fsprogs/mke2fs.c b/e2fsprogs/old_e2fsprogs/mke2fs.c index 5203645..ebcb46c 100644 --- a/e2fsprogs/old_e2fsprogs/mke2fs.c +++ b/e2fsprogs/old_e2fsprogs/mke2fs.c @@ -5,7 +5,7 @@ * Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, * 2003, 2004, 2005 by Theodore Ts'o. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* Usage: mke2fs [options] device @@ -239,7 +239,7 @@ static void test_disk(ext2_filsys fs, badblocks_list *bb_list) errcode_t retval; char buf[1024]; - sprintf(buf, "badblocks -b %d %s%s%s %d", fs->blocksize, + sprintf(buf, "badblocks -b %u %s%s%s %d", fs->blocksize, quiet ? "" : "-s ", (cflag > 1) ? "-w " : "", fs->device_name, fs->super->s_blocks_count); mke2fs_verbose("Running command: %s\n", buf); @@ -385,7 +385,7 @@ static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num, struct progress_struct *progress, blk_t *ret_blk, int *ret_count) { - int j, count, next_update, next_update_incr; + int j, count, next_update; static char *buf; errcode_t retval; @@ -403,9 +403,7 @@ static errcode_t zero_blocks(ext2_filsys fs, blk_t blk, int num, } /* OK, do the write loop */ next_update = 0; - next_update_incr = num / 100; - if (next_update_incr < 1) - next_update_incr = 1; + for (j=0; j < num; j += STRIDE_LENGTH, blk += STRIDE_LENGTH) { count = num - j; if (count > STRIDE_LENGTH) @@ -757,7 +755,7 @@ static void parse_extended_opts(struct ext2_super_block *sb_param, if (rsv_gdb > 0) { sb_param->s_feature_compat |= - EXT2_FEATURE_COMPAT_RESIZE_INODE; + EXT2_FEATURE_COMPAT_RESIZE_INO; sb_param->s_reserved_gdt_blocks = rsv_gdb; } @@ -778,7 +776,7 @@ static void parse_extended_opts(struct ext2_super_block *sb_param, static __u32 ok_features[3] = { EXT3_FEATURE_COMPAT_HAS_JOURNAL | - EXT2_FEATURE_COMPAT_RESIZE_INODE | + EXT2_FEATURE_COMPAT_RESIZE_INO | EXT2_FEATURE_COMPAT_DIR_INDEX, /* Compat */ EXT2_FEATURE_INCOMPAT_FILETYPE| /* Incompat */ EXT3_FEATURE_INCOMPAT_JOURNAL_DEV| @@ -895,7 +893,7 @@ static int PRS(int argc, char **argv) creator_os = optarg; break; case 'r': - param.s_rev_level = xatoi_u(optarg); + param.s_rev_level = xatoi_positive(optarg); if (param.s_rev_level == EXT2_GOOD_OLD_REV) { param.s_feature_incompat = 0; param.s_feature_compat = 0; @@ -912,11 +910,11 @@ static int PRS(int argc, char **argv) break; #ifdef EXT2_DYNAMIC_REV case 'I': - inode_size = xatoi_u(optarg); + inode_size = xatoi_positive(optarg); break; #endif case 'N': - num_inodes = xatoi_u(optarg); + num_inodes = xatoi_positive(optarg); break; case 'v': quiet = 0; @@ -1123,7 +1121,7 @@ static int PRS(int argc, char **argv) /* Since sparse_super is the default, we would only have a problem * here if it was explicitly disabled. */ - if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INODE) && + if ((param.s_feature_compat & EXT2_FEATURE_COMPAT_RESIZE_INO) && !(param.s_feature_ro_compat&EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER)) { bb_error_msg_and_die("reserved online resize blocks not supported " "on non-sparse filesystem"); @@ -1312,7 +1310,7 @@ int mke2fs_main (int argc, char **argv) reserve_inodes(fs); create_bad_block_inode(fs, bb_list); if (fs->super->s_feature_compat & - EXT2_FEATURE_COMPAT_RESIZE_INODE) { + EXT2_FEATURE_COMPAT_RESIZE_INO) { retval = ext2fs_create_resize_inode(fs); mke2fs_error_msg_and_die(retval, "reserve blocks for online resize"); } diff --git a/e2fsprogs/old_e2fsprogs/tune2fs.c b/e2fsprogs/old_e2fsprogs/tune2fs.c index 00f8682..bbe30e5 100644 --- a/e2fsprogs/old_e2fsprogs/tune2fs.c +++ b/e2fsprogs/old_e2fsprogs/tune2fs.c @@ -8,7 +8,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* @@ -607,7 +607,7 @@ int tune2fs_main(int argc, char **argv) if (e_flag) { sb->s_errors = errors; ext2fs_mark_super_dirty(fs); - printf("Setting error behavior to %d\n", errors); + printf("Setting error behavior to %u\n", errors); } if (g_flag) { sb->s_def_resgid = resgid; diff --git a/e2fsprogs/old_e2fsprogs/util.c b/e2fsprogs/old_e2fsprogs/util.c index 64cca05..3e7ee8e 100644 --- a/e2fsprogs/old_e2fsprogs/util.c +++ b/e2fsprogs/old_e2fsprogs/util.c @@ -4,7 +4,7 @@ * * Copyright 1995, 1996, 1997, 1998, 1999, 2000 by Theodore Ts'o. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include @@ -95,7 +95,6 @@ force_check: bb_error_msg("%s is apparently in use by the system", device); goto force_check; } - } void parse_journal_opts(char **journal_device, int *journal_flags, @@ -118,7 +117,7 @@ void parse_journal_opts(char **journal_device, int *journal_flags, } if (strcmp(token, "device") == 0) { *journal_device = blkid_get_devname(NULL, arg, NULL); - if (!journal_device) { + if (!*journal_device) { journal_usage++; continue; } @@ -240,7 +239,7 @@ void make_journal_blocks(ext2_filsys fs, int journal_size, int journal_flags, in return; } if (!quiet) - printf("Creating journal (%ld blocks): ", journal_blocks); + printf("Creating journal (%lu blocks): ", journal_blocks); fflush(stdout); retval = ext2fs_add_journal_inode(fs, journal_blocks, journal_flags); diff --git a/e2fsprogs/old_e2fsprogs/uuid/Kbuild.src b/e2fsprogs/old_e2fsprogs/uuid/Kbuild.src index 9454fab..b8c687d 100644 --- a/e2fsprogs/old_e2fsprogs/uuid/Kbuild.src +++ b/e2fsprogs/old_e2fsprogs/uuid/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. NEEDED-$(CONFIG_E2FSCK) = y NEEDED-$(CONFIG_FSCK) = y diff --git a/e2fsprogs/tune2fs.c b/e2fsprogs/tune2fs.c index 00ede4f..46a745e 100644 --- a/e2fsprogs/tune2fs.c +++ b/e2fsprogs/tune2fs.c @@ -4,11 +4,11 @@ * * Busybox'ed (2009) by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include -#include +#include "bb_e2fs_defs.h" // storage helpers char BUG_wrong_field_size(void); @@ -27,24 +27,42 @@ do { \ #define FETCH_LE32(field) \ (sizeof(field) == 4 ? SWAP_LE32(field) : BUG_wrong_field_size()) +//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" + enum { - OPT_L = 1 << 0, // label + 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; + const char *label, *str_c, *str_i, *str_C; struct ext2_super_block *sb; int fd; opt_complementary = "=1"; - opts = getopt32(argv, "L:", &label); - argv += optind; // argv[0] -- device - + opts = getopt32(argv, "L:c:i:C:", &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); @@ -54,9 +72,28 @@ int tune2fs_main(int argc UNUSED_PARAM, char **argv) // 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 (1 /*opts & OPT_L*/) + 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); diff --git a/editors/Config.src b/editors/Config.src index fc824cc..c6e9d92 100644 --- a/editors/Config.src +++ b/editors/Config.src @@ -7,189 +7,6 @@ menu "Editors" INSERT -config AWK - bool "awk" - default y - help - Awk is used as a pattern scanning and processing language. This is - the BusyBox implementation of that programming language. - -config FEATURE_AWK_LIBM - bool "Enable math functions (requires libm)" - default y - depends on AWK - help - Enable math functions of the Awk programming language. - NOTE: This will require libm to be present for linking. - -config CMP - bool "cmp" - default y - help - cmp is used to compare two files and returns the result - to standard output. - -config DIFF - bool "diff" - default y - help - diff compares two files or directories and outputs the - differences between them in a form that can be given to - the patch command. - -config FEATURE_DIFF_LONG_OPTIONS - bool "Enable long options" - default y - depends on DIFF && LONG_OPTS - help - Enable use of long options. - -config FEATURE_DIFF_DIR - bool "Enable directory support" - default y - depends on DIFF - help - This option enables support for directory and subdirectory - comparison. - -config ED - bool "ed" - default y - help - The original 1970's Unix text editor, from the days of teletypes. - Small, simple, evil. Part of SUSv3. If you're not already using - this, you don't need it. - -config PATCH - bool "patch" - default y - help - Apply a unified diff formatted patch. - -config SED - bool "sed" - default y - help - sed is used to perform text transformations on a file - or input from a pipeline. - -config VI - bool "vi" - default y - help - 'vi' is a text editor. More specifically, it is the One True - text editor . It does, however, have a rather steep - learning curve. If you are not already comfortable with 'vi' - you may wish to use something else. - -config FEATURE_VI_MAX_LEN - int "Maximum screen width in vi" - range 256 16384 - default 4096 - depends on VI - help - Contrary to what you may think, this is not eating much. - Make it smaller than 4k only if you are very limited on memory. - -config FEATURE_VI_8BIT - bool "Allow vi to display 8-bit chars (otherwise shows dots)" - default n - depends on VI - help - If your terminal can display characters with high bit set, - you may want to enable this. Note: vi is not Unicode-capable. - If your terminal combines several 8-bit bytes into one character - (as in Unicode mode), this will not work properly. - -config FEATURE_VI_COLON - bool "Enable \":\" colon commands (no \"ex\" mode)" - default y - depends on VI - help - Enable a limited set of colon commands for vi. This does not - provide an "ex" mode. - -config FEATURE_VI_YANKMARK - bool "Enable yank/put commands and mark cmds" - default y - depends on VI - help - This will enable you to use yank and put, as well as mark in - busybox vi. - -config FEATURE_VI_SEARCH - bool "Enable search and replace cmds" - default y - depends on VI - help - Select this if you wish to be able to do search and replace in - busybox vi. - -config FEATURE_VI_USE_SIGNALS - bool "Catch signals" - default y - depends on VI - help - Selecting this option will make busybox vi signal aware. This will - make busybox vi support SIGWINCH to deal with Window Changes, catch - Ctrl-Z and Ctrl-C and alarms. - -config FEATURE_VI_DOT_CMD - bool "Remember previous cmd and \".\" cmd" - default y - depends on VI - help - Make busybox vi remember the last command and be able to repeat it. - -config FEATURE_VI_READONLY - bool "Enable -R option and \"view\" mode" - default y - depends on VI - help - Enable the read-only command line option, which allows the user to - open a file in read-only mode. - -config FEATURE_VI_SETOPTS - bool "Enable set-able options, ai ic showmatch" - default y - depends on VI - help - Enable the editor to set some (ai, ic, showmatch) options. - -config FEATURE_VI_SET - bool "Support for :set" - default y - depends on VI - help - Support for ":set". - -config FEATURE_VI_WIN_RESIZE - bool "Handle window resize" - default y - depends on VI - help - Make busybox vi behave nicely with terminals that get resized. - -config FEATURE_VI_ASK_TERMINAL - bool "Use 'tell me cursor position' ESC sequence to measure window" - default y - depends on VI - help - If terminal size can't be retrieved and $LINES/$COLUMNS are not set, - this option makes vi perform a last-ditch effort to find it: - vi positions cursor to 999,999 and asks terminal to report real - cursor position using "ESC [ 6 n" escape sequence, then reads stdin. - - This is not clean but helps a lot on serial lines and such. - -config FEATURE_VI_OPTIMIZE_CURSOR - bool "Optimize cursor movement" - default y - depends on VI - help - This will make the cursor movement faster, but requires more memory - and it makes the applet a tiny bit larger. - config FEATURE_ALLOW_EXEC bool "Allow vi and awk to execute shell commands" default y diff --git a/editors/Kbuild.src b/editors/Kbuild.src index 9d4b9d0..6b4fb74 100644 --- a/editors/Kbuild.src +++ b/editors/Kbuild.src @@ -2,15 +2,8 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= INSERT -lib-$(CONFIG_AWK) += awk.o -lib-$(CONFIG_CMP) += cmp.o -lib-$(CONFIG_DIFF) += diff.o -lib-$(CONFIG_ED) += ed.o -lib-$(CONFIG_PATCH) += patch.o -lib-$(CONFIG_SED) += sed.o -lib-$(CONFIG_VI) += vi.o diff --git a/editors/awk.c b/editors/awk.c index 83c5b47..d0e3781 100644 --- a/editors/awk.c +++ b/editors/awk.c @@ -4,9 +4,49 @@ * * Copyright (C) 2002 by Dmitry Zakharov * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config AWK +//config: bool "awk" +//config: default y +//config: help +//config: Awk is used as a pattern scanning and processing language. This is +//config: the BusyBox implementation of that programming 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 will require 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: Ex: 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 FILE Read program from FILE" +//usage: IF_FEATURE_AWK_GNU_EXTENSIONS( +//usage: "\n -e AWK_PROGRAM" +//usage: ) + #include "libbb.h" #include "xregex.h" #include @@ -17,12 +57,39 @@ /* 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__)) +#endif +#define OPTSTR_AWK \ + "F:v:f:" \ + IF_FEATURE_AWK_GNU_EXTENSIONS("e:") \ + "W:" +#define OPTCOMPLSTR_AWK \ + "v::f::" \ + IF_FEATURE_AWK_GNU_EXTENSIONS("e::") +enum { + OPTBIT_F, /* define field separator */ + OPTBIT_v, /* define variable */ + OPTBIT_f, /* pull in awk program from file */ + IF_FEATURE_AWK_GNU_EXTENSIONS(OPTBIT_e,) /* -e AWK_PROGRAM */ + OPTBIT_W, /* -W ignored */ + OPT_F = 1 << OPTBIT_F, + OPT_v = 1 << OPTBIT_v, + OPT_f = 1 << OPTBIT_f, + OPT_e = IF_FEATURE_AWK_GNU_EXTENSIONS((1 << OPTBIT_e)) + 0, + OPT_W = 1 << OPTBIT_W +}; #define MAXVARFMT 240 #define MINNVBLOCK 64 @@ -140,7 +207,7 @@ typedef struct tsplitter_s { /* simple token classes */ /* Order and hex values are very important!!! See next_token() */ -#define TC_SEQSTART 1 /* ( */ +#define TC_SEQSTART 1 /* ( */ #define TC_SEQTERM (1 << 1) /* ) */ #define TC_REGEXP (1 << 2) /* /.../ */ #define TC_OUTRDR (1 << 3) /* | > >> */ @@ -175,7 +242,7 @@ typedef struct tsplitter_s { /* combined token classes */ #define TC_BINOP (TC_BINOPX | TC_COMMA | TC_PIPE | TC_IN) -#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) +//#define TC_UNARYOP (TC_UOPPRE | TC_UOPPOST) #define TC_OPERAND (TC_VARIABLE | TC_ARRAY | TC_FUNCTION \ | TC_BUILTIN | TC_GETLINE | TC_SEQSTART | TC_STRING | TC_NUMBER) @@ -227,6 +294,9 @@ typedef struct tsplitter_s { * For builtins it has different meaning: n n s3 s2 s1 v3 v2 v1, * n - min. number of args, vN - resolve Nth arg to var, sN - resolve to string */ +#undef P +#undef PRIMASK +#undef PRIMASK2 #define P(x) (x << 24) #define PRIMASK 0x7F000000 #define PRIMASK2 0x7E000000 @@ -273,94 +343,86 @@ enum { /* tokens and their corresponding info values */ -#define NTC "\377" /* switch to next token class (tc<<1) */ -#define NTCC '\377' +#define NTC "\377" /* switch to next token class (tc<<1) */ +#define NTCC '\377' -#define OC_B OC_BUILTIN +#define OC_B OC_BUILTIN static const char tokenlist[] ALIGN1 = - "\1(" NTC - "\1)" NTC - "\1/" NTC /* REGEXP */ - "\2>>" "\1>" "\1|" NTC /* OUTRDR */ - "\2++" "\2--" NTC /* UOPPOST */ - "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ - "\2==" "\1=" "\2+=" "\2-=" /* 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 - "\1," NTC - "\1|" NTC - "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ - "\1]" NTC - "\1{" NTC - "\1}" NTC - "\1;" NTC - "\1\n" NTC - "\2if" "\2do" "\3for" "\5break" /* STATX */ - "\10continue" "\6delete" "\5print" - "\6printf" "\4next" "\10nextfile" - "\6return" "\4exit" NTC - "\5while" NTC - "\4else" NTC - - "\3and" "\5compl" "\6lshift" "\2or" - "\6rshift" "\3xor" - "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ - "\3cos" "\3exp" "\3int" "\3log" - "\4rand" "\3sin" "\4sqrt" "\5srand" - "\6gensub" "\4gsub" "\5index" "\6length" - "\5match" "\5split" "\7sprintf" "\3sub" - "\6substr" "\7systime" "\10strftime" "\6mktime" - "\7tolower" "\7toupper" NTC - "\7getline" NTC - "\4func" "\10function" NTC - "\5BEGIN" NTC - "\3END" "\0" + "\1(" NTC + "\1)" NTC + "\1/" NTC /* REGEXP */ + "\2>>" "\1>" "\1|" NTC /* OUTRDR */ + "\2++" "\2--" NTC /* UOPPOST */ + "\2++" "\2--" "\1$" NTC /* UOPPRE1 */ + "\2==" "\1=" "\2+=" "\2-=" /* 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 + "\1," NTC + "\1|" NTC + "\1+" "\1-" "\1!" NTC /* UOPPRE2 */ + "\1]" NTC + "\1{" NTC + "\1}" NTC + "\1;" NTC + "\1\n" NTC + "\2if" "\2do" "\3for" "\5break" /* STATX */ + "\10continue" "\6delete" "\5print" + "\6printf" "\4next" "\10nextfile" + "\6return" "\4exit" NTC + "\5while" NTC + "\4else" NTC + + "\3and" "\5compl" "\6lshift" "\2or" + "\6rshift" "\3xor" + "\5close" "\6system" "\6fflush" "\5atan2" /* BUILTIN */ + "\3cos" "\3exp" "\3int" "\3log" + "\4rand" "\3sin" "\4sqrt" "\5srand" + "\6gensub" "\4gsub" "\5index" "\6length" + "\5match" "\5split" "\7sprintf" "\3sub" + "\6substr" "\7systime" "\10strftime" "\6mktime" + "\7tolower" "\7toupper" NTC + "\7getline" NTC + "\4func" "\10function" NTC + "\5BEGIN" NTC + "\3END" + /* compiler adds trailing "\0" */ ; static const uint32_t tokeninfo[] = { 0, 0, OC_REGEXP, - xS|'a', xS|'w', xS|'|', - OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', - OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', - 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)|'-', - 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, - OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', - OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), - OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', - OC_COLON|xx|P(67)|':', - OC_IN|SV|P(49), + xS|'a', xS|'w', xS|'|', + OC_UNARY|xV|P(9)|'p', OC_UNARY|xV|P(9)|'m', + OC_UNARY|xV|P(9)|'P', OC_UNARY|xV|P(9)|'M', 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)|'-', + 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, + OC_COMPARE|VV|P(39)|2, OC_MATCH|Sx|P(45)|'!', OC_MATCH|Sx|P(45)|'~', OC_LAND|Vx|P(55), + OC_LOR|Vx|P(59), OC_TERNARY|Vx|P(64)|'?', OC_COLON|xx|P(67)|':', + OC_IN|SV|P(49), /* in */ OC_COMMA|SS|P(80), OC_PGETLINE|SV|P(37), - OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', - OC_UNARY|xV|P(19)|'!', - 0, + OC_UNARY|xV|P(19)|'+', OC_UNARY|xV|P(19)|'-', OC_UNARY|xV|P(19)|'!', + 0, /* ] */ 0, 0, 0, - 0, - ST_IF, ST_DO, ST_FOR, OC_BREAK, - OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, - OC_PRINTF, OC_NEXT, OC_NEXTFILE, - OC_RETURN|Vx, OC_EXIT|Nx, + 0, /* \n */ + ST_IF, ST_DO, ST_FOR, OC_BREAK, + OC_CONTINUE, OC_DELETE|Vx, OC_PRINT, + OC_PRINTF, OC_NEXT, OC_NEXTFILE, + OC_RETURN|Vx, OC_EXIT|Nx, ST_WHILE, - 0, + 0, /* else */ OC_B|B_an|P(0x83), OC_B|B_co|P(0x41), OC_B|B_ls|P(0x83), OC_B|B_or|P(0x83), OC_B|B_rs|P(0x83), OC_B|B_xo|P(0x83), @@ -372,9 +434,9 @@ static const uint32_t tokeninfo[] = { OC_B|B_ss|P(0x8f), OC_FBLTIN|F_ti, OC_B|B_ti|P(0x0b), OC_B|B_mt|P(0x0b), OC_B|B_lo|P(0x49), OC_B|B_up|P(0x49), OC_GETLINE|SV|P(0), - 0, 0, + 0, 0, 0, - 0 + 0 /* END */ }; /* internal variable names and their initial values */ @@ -384,7 +446,7 @@ enum { ORS, RS, RT, FILENAME, SUBSEP, F0, ARGIND, ARGC, ARGV, ERRNO, FNR, NR, - NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS + NF, IGNORECASE, ENVIRON, NUM_INTERNAL_VARS }; static const char vNames[] ALIGN1 = @@ -429,13 +491,13 @@ struct globals { smallint nextrec; smallint nextfile; smallint is_f0_split; + smallint t_rollback; }; struct globals2 { uint32_t t_info; /* often used */ uint32_t t_tclass; char *t_string; int t_lineno; - int t_rollback; var *intvar[NUM_INTERNAL_VARS]; /* often used */ @@ -493,11 +555,11 @@ struct globals2 { #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 t_rollback (G.t_rollback ) #define intvar (G.intvar ) #define fsplitter (G.fsplitter ) #define rsplitter (G.rsplitter ) @@ -528,9 +590,7 @@ static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin"; 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"; -#if !ENABLE_FEATURE_AWK_LIBM static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in"; -#endif static void zero_out_var(var *vp) { @@ -688,11 +748,27 @@ static char nextchar(char **s) pps = *s; if (c == '\\') c = bb_process_escape_sequence((const char**)s); - if (c == '\\' && *s == pps) - c = *(*s)++; + /* Example awk statement: + * s = "abc\"def" + * we must treat \" as " + */ + if (c == '\\' && *s == pps) { /* unrecognized \z? */ + c = *(*s); /* yes, fetch z */ + if (c) + (*s)++; /* advance unless z = NUL */ + } 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 == '_'); @@ -700,14 +776,25 @@ static ALWAYS_INLINE int isalnum_(int c) static double my_strtod(char **pp) { -#if ENABLE_DESKTOP - if ((*pp)[0] == '0' - && ((((*pp)[1] | 0x20) == 'x') || isdigit((*pp)[1])) - ) { - return strtoull(*pp, pp, 0); + char *cp = *pp; + if (ENABLE_DESKTOP && 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. + */ + } } -#endif - return strtod(*pp, pp); + return strtod(cp, pp); } /* -------- working with variables (set/get/copy/etc) -------- */ @@ -817,17 +904,21 @@ static double getvar_i(var *v) v->number = 0; s = v->string; if (s && *s) { + debug_printf_eval("getvar_i: '%s'->", s); v->number = my_strtod(&s); + debug_printf_eval("%f (s:'%s')\n", v->number, s); if (v->type & VF_USER) { 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; } @@ -849,6 +940,7 @@ 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); @@ -965,7 +1057,6 @@ static uint32_t next_token(uint32_t expected) const char *tl; uint32_t tc; const uint32_t *ti; - int l; if (t_rollback) { t_rollback = FALSE; @@ -989,20 +1080,23 @@ static uint32_t next_token(uint32_t expected) if (*p == '\0') { tc = TC_EOF; + debug_printf_parse("%s: token found: TC_EOF\n", __func__); } else if (*p == '\"') { /* it's a string */ t_string = s = ++p; while (*p != '\"') { - char *pp = 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 */ @@ -1025,15 +1119,17 @@ static uint32_t next_token(uint32_t expected) 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(&pp); p = pp; - if (*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 { /* search for something known */ @@ -1041,53 +1137,56 @@ static uint32_t next_token(uint32_t expected) tc = 0x00000001; ti = tokeninfo; while (*tl) { - l = *tl++; - if (l == NTCC) { + 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, - * then this is what we are looking for + /* if token class is expected, + * token matches, + * and it's not a longer word, */ if ((tc & (expected | TC_WORD | TC_NEWLINE)) - && *tl == *p && strncmp(p, tl, l) == 0 + && strncmp(p, tl, l) == 0 && !((tc & TC_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; - break; + goto token_found; } ti++; tl += l; } - - if (!*tl) { - /* it's a name (var/array/function), - * otherwise it's something wrong - */ - if (!isalnum_(*p)) - syntax_error(EMSG_UNEXP_TOKEN); - - t_string = --p; - while (isalnum_(*++p)) { - p[-1] = *p; - } - p[-1] = '\0'; - tc = TC_VARIABLE; - /* also consume whitespace between functionname and bracket */ - if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY)) - p = skip_spaces(p); - if (*p == '(') { - tc = TC_FUNCTION; - } else { - if (*p == '[') { - p++; - tc = TC_ARRAY; - } - } + /* 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[-1] = *p; + } + p[-1] = '\0'; + tc = TC_VARIABLE; + /* also consume whitespace between functionname and bracket */ + if (!(expected & TC_VARIABLE) || (expected & TC_ARRAY)) + p = skip_spaces(p); + if (*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 + debug_printf_parse("%s: token found:'%s' TC_VARIABLE\n", __func__, t_string); } } + token_found: g_pos = p; /* skipping newlines in some cases */ @@ -1159,19 +1258,24 @@ static node *parse_expr(uint32_t iexp) uint32_t tc, xtc; var *v; + debug_printf_parse("%s(%x)\n", __func__, iexp); + sn.info = PRIMASK; sn.r.n = glptr = NULL; xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP | iexp; while (!((tc = next_token(xtc)) & iexp)) { + if (glptr && (t_info == (OC_COMPARE | VV | P(39) | 2))) { /* input redirection (<) attached to glptr node */ + debug_printf_parse("%s: input redir\n", __func__); cn = glptr->l.n = new_node(OC_CONCAT | SS | P(37)); cn->a.n = glptr; xtc = TC_OPERAND | TC_UOPPRE; glptr = NULL; } else if (tc & (TC_BINOP | TC_UOPPOST)) { + debug_printf_parse("%s: TC_BINOP | TC_UOPPOST\n", __func__); /* for binary and postfix-unary operators, jump back over * previous operators with higher priority */ vn = cn; @@ -1201,6 +1305,7 @@ static node *parse_expr(uint32_t iexp) vn->a.n = cn; } else { + debug_printf_parse("%s: other\n", __func__); /* for operands and prefix-unary operators, attach them * to last node */ vn = cn; @@ -1208,12 +1313,14 @@ static node *parse_expr(uint32_t iexp) cn->a.n = vn; xtc = TC_OPERAND | TC_UOPPRE | TC_REGEXP; if (tc & (TC_OPERAND | TC_REGEXP)) { + debug_printf_parse("%s: TC_OPERAND | TC_REGEXP\n", __func__); xtc = TC_UOPPRE | TC_UOPPOST | TC_BINOP | TC_OPERAND | iexp; /* one should be very careful with switch on tclass - * only simple tclasses should be used! */ switch (tc) { 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) { @@ -1230,6 +1337,7 @@ static node *parse_expr(uint32_t iexp) case TC_NUMBER: case TC_STRING: + debug_printf_parse("%s: TC_NUMBER | TC_STRING\n", __func__); cn->info = OC_VAR; v = cn->l.v = xzalloc(sizeof(var)); if (tc & TC_NUMBER) @@ -1239,32 +1347,41 @@ static node *parse_expr(uint32_t iexp) 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 = condition(); break; case TC_SEQSTART: + debug_printf_parse("%s: TC_SEQSTART\n", __func__); cn = vn->r.n = parse_expr(TC_SEQTERM); + if (!cn) + syntax_error("Empty sequence"); cn->a.n = vn; break; case TC_GETLINE: + debug_printf_parse("%s: TC_GETLINE\n", __func__); glptr = cn; xtc = TC_OPERAND | TC_UOPPRE | TC_BINOP | iexp; break; case TC_BUILTIN: + debug_printf_parse("%s: TC_BUILTIN\n", __func__); cn->l.n = condition(); break; } } } } + + debug_printf_parse("%s() returns %p\n", __func__, sn.r.n); return sn.r.n; } @@ -1333,18 +1450,25 @@ static void chain_group(void) } while (c & TC_NEWLINE); if (c & TC_GRPSTART) { + debug_printf_parse("%s: TC_GRPSTART\n", __func__); while (next_token(TC_GRPSEQ | TC_GRPTERM) != TC_GRPTERM) { + debug_printf_parse("%s: !TC_GRPTERM\n", __func__); if (t_tclass & TC_NEWLINE) continue; rollback_token(); chain_group(); } + debug_printf_parse("%s: TC_GRPTERM\n", __func__); } else if (c & (TC_OPSEQ | TC_OPTERM)) { + debug_printf_parse("%s: TC_OPSEQ | TC_OPTERM\n", __func__); rollback_token(); chain_expr(OC_EXEC | Vx); - } else { /* TC_STATEMNT */ + } else { + /* TC_STATEMNT */ + debug_printf_parse("%s: TC_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 = condition(); chain_group(); @@ -1359,12 +1483,14 @@ static void chain_group(void) break; case ST_WHILE: + debug_printf_parse("%s: ST_WHILE\n", __func__); n2 = condition(); 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; @@ -1373,6 +1499,7 @@ static void chain_group(void) break; case ST_FOR: + debug_printf_parse("%s: ST_FOR\n", __func__); next_token(TC_SEQSTART); n2 = parse_expr(TC_SEMICOL | TC_SEQTERM); if (t_tclass & TC_SEQTERM) { /* for-in */ @@ -1398,6 +1525,7 @@ static void chain_group(void) 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_OPTERM | TC_OUTRDR | TC_GRPTERM); if (t_tclass & TC_OUTRDR) { @@ -1409,17 +1537,20 @@ static void chain_group(void) break; case OC_BREAK: + debug_printf_parse("%s: OC_BREAK\n", __func__); n = chain_node(OC_EXEC); n->a.n = break_ptr; break; case OC_CONTINUE: + debug_printf_parse("%s: OC_CONTINUE\n", __func__); n = chain_node(OC_EXEC); n->a.n = continue_ptr; break; /* delete, next, nextfile, return, exit */ default: + debug_printf_parse("%s: default\n", __func__); chain_expr(t_info); } } @@ -1437,19 +1568,24 @@ static void parse_program(char *p) while ((tclass = next_token(TC_EOF | TC_OPSEQ | TC_GRPSTART | TC_OPTERM | TC_BEGIN | TC_END | TC_FUNCDECL)) != TC_EOF) { - if (tclass & TC_OPTERM) + if (tclass & TC_OPTERM) { + debug_printf_parse("%s: TC_OPTERM\n", __func__); continue; + } seq = &mainseq; if (tclass & TC_BEGIN) { + debug_printf_parse("%s: TC_BEGIN\n", __func__); seq = &beginseq; chain_group(); } else if (tclass & TC_END) { + debug_printf_parse("%s: TC_END\n", __func__); seq = &endseq; chain_group(); } else if (tclass & TC_FUNCDECL) { + debug_printf_parse("%s: TC_FUNCDECL\n", __func__); next_token(TC_FUNCTION); g_pos++; f = newfunc(t_string); @@ -1467,22 +1603,27 @@ static void parse_program(char *p) clear_array(ahash); } else if (tclass & TC_OPSEQ) { + debug_printf_parse("%s: TC_OPSEQ\n", __func__); rollback_token(); cn = chain_node(OC_TEST); cn->l.n = parse_expr(TC_OPTERM | TC_EOF | TC_GRPSTART); if (t_tclass & TC_GRPSTART) { + debug_printf_parse("%s: TC_GRPSTART\n", __func__); rollback_token(); chain_group(); } else { + debug_printf_parse("%s: !TC_GRPSTART\n", __func__); chain_node(OC_PRINT); } cn->r.n = mainseq.last; } else /* if (tclass & TC_GRPSTART) */ { + debug_printf_parse("%s: TC_GRPSTART(?)\n", __func__); rollback_token(); chain_group(); } } + debug_printf_parse("%s: TC_EOF\n", __func__); } @@ -1500,10 +1641,10 @@ static node *mk_splitter(const char *s, tsplitter *spl) regfree(re); regfree(ire); // TODO: nuke ire, use re+1? } - if (strlen(s) > 1) { + if (s[0] && s[1]) { /* strlen(s) > 1 */ mk_re_node(s, n, re); } else { - n->info = (uint32_t) *s; + n->info = (uint32_t) s[0]; } return n; @@ -1560,24 +1701,22 @@ static void fsrealloc(int size) if (size >= maxfields) { i = maxfields; maxfields = size + 16; - Fields = xrealloc(Fields, maxfields * sizeof(var)); + Fields = xrealloc(Fields, maxfields * sizeof(Fields[0])); for (; i < maxfields; i++) { Fields[i].type = VF_SPECIAL; Fields[i].string = NULL; } } - - if (size < nfields) { - for (i = size; i < nfields; i++) { - clrvar(Fields + i); - } + /* if size < nfields, clear extra field variables */ + for (i = size; i < nfields; i++) { + clrvar(Fields + i); } nfields = size; } static int awk_split(const char *s, node *spl, char **slist) { - int l, n = 0; + int l, n; char c[4]; char *s1; regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough... @@ -1591,6 +1730,7 @@ static int awk_split(const char *s, node *spl, char **slist) if (*getvar_s(intvar[RS]) == '\0') c[2] = '\n'; + n = 0; if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */ if (!*s) return n; /* "": zero fields */ @@ -1636,7 +1776,7 @@ static int awk_split(const char *s, node *spl, char **slist) } if (*s1) n++; - while ((s1 = strpbrk(s1, c))) { + while ((s1 = strpbrk(s1, c)) != NULL) { *s1++ = '\0'; n++; } @@ -1724,6 +1864,18 @@ static void handle_special(var *v) 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]) { @@ -1816,6 +1968,8 @@ static int awk_getline(rstream *rsm, var *v) int fd, so, eo, r, rp; char c, *m, *s; + debug_printf_eval("entered %s()\n", __func__); + /* we're using our own buffer since we need access to accumulating * characters */ @@ -1902,6 +2056,8 @@ static int awk_getline(rstream *rsm, var *v) rsm->pos = p - eo; rsm->size = size; + debug_printf_eval("returning from %s(): %d\n", __func__, r); + return r; } @@ -1911,8 +2067,8 @@ static int fmt_num(char *b, int size, const char *format, double n, int int_as_i char c; const char *s = format; - if (int_as_int && n == (int)n) { - r = snprintf(b, size, "%d", (int)n); + if (int_as_int && n == (long long)n) { + r = snprintf(b, size, "%lld", (long long)n); } else { do { c = *s; } while (c && *++s); if (strchr("diouxX", c)) { @@ -2148,11 +2304,10 @@ static NOINLINE var *exec_builtin(node *op, var *res) 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); -#endif + 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: { @@ -2320,13 +2475,15 @@ static var *evaluate(node *op, var *res) #define fnargs (G.evaluate__fnargs) /* seed is initialized to 1 */ #define seed (G.evaluate__seed) -#define sreg (G.evaluate__sreg) +#define sreg (G.evaluate__sreg) var *v1; if (!op) return setvar_s(res, NULL); + debug_printf_eval("entered %s()\n", __func__); + v1 = nvalloc(2); while (op) { @@ -2347,19 +2504,27 @@ static var *evaluate(node *op, var *res) opn = (opinfo & OPNMASK); g_lineno = op->lineno; op1 = op->l.n; + debug_printf_eval("opinfo:%08x opn:%08x\n", opinfo, opn); /* execute inevitable things */ if (opinfo & OF_RES1) L.v = evaluate(op1, v1); if (opinfo & OF_RES2) R.v = evaluate(op->r.n, v1+1); - if (opinfo & OF_STR1) + if (opinfo & OF_STR1) { L.s = getvar_s(L.v); - if (opinfo & OF_STR2) + debug_printf_eval("L.s:'%s'\n", L.s); + } + if (opinfo & OF_STR2) { R.s = getvar_s(R.v); - if (opinfo & OF_NUM1) + debug_printf_eval("R.s:'%s'\n", R.s); + } + if (opinfo & OF_NUM1) { L_d = getvar_i(L.v); + debug_printf_eval("L_d:%f\n", L_d); + } + debug_printf_eval("switch(0x%x)\n", XC(opinfo & OPCLSMASK)); switch (XC(opinfo & OPCLSMASK)) { /* -- iterative node type -- */ @@ -2526,6 +2691,7 @@ static var *evaluate(node *op, var *res) break; case XC( OC_MOVE ): + debug_printf_eval("MOVE\n"); /* if source is a temporary string, jusk relink it to dest */ //Disabled: if R.v is numeric but happens to have cached R.v->string, //then L.v ends up being a string, which is wrong @@ -2547,7 +2713,8 @@ static var *evaluate(node *op, var *res) var *vbeg, *v; const char *sv_progname; - if (!op->r.f->body.first) + /* The body might be empty, still has to eval the args */ + if (!op->r.n->info && !op->r.f->body.first) syntax_error(EMSG_UNDEF_FUNC); vbeg = v = nvalloc(op->r.f->nargs + 1); @@ -2585,7 +2752,7 @@ static var *evaluate(node *op, var *res) rsm->F = popen(L.s, "r"); rsm->is_pipe = TRUE; } else { - rsm->F = fopen_for_read(L.s); /* not xfopen! */ + rsm->F = fopen_for_read(L.s); /* not xfopen! */ } } } else { @@ -2594,7 +2761,7 @@ static var *evaluate(node *op, var *res) rsm = iF; } - if (!rsm->F) { + if (!rsm || !rsm->F) { setvar_i(intvar[ERRNO], errno); setvar_i(res, -1); break; @@ -2614,47 +2781,50 @@ static var *evaluate(node *op, var *res) /* simple builtins */ case XC( OC_FBLTIN ): { - int i; - rstream *rsm; double R_d = R_d; /* for compiler */ switch (opn) { case F_in: - R_d = (int)L_d; + R_d = (long long)L_d; break; case F_rn: R_d = (double)rand() / (double)RAND_MAX; break; -#if ENABLE_FEATURE_AWK_LIBM + case F_co: - R_d = cos(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = cos(L_d); + break; + } case F_ex: - R_d = exp(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = exp(L_d); + break; + } case F_lg: - R_d = log(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = log(L_d); + break; + } case F_si: - R_d = sin(L_d); - break; + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sin(L_d); + break; + } case F_sq: - R_d = sqrt(L_d); - break; -#else - case F_co: - case F_ex: - case F_lg: - case F_si: - case F_sq: + if (ENABLE_FEATURE_AWK_LIBM) { + R_d = sqrt(L_d); + break; + } + syntax_error(EMSG_NO_MATH); break; -#endif + case F_sr: R_d = (double)seed; seed = op1 ? (unsigned)L_d : (unsigned)time(NULL); @@ -2666,8 +2836,16 @@ static var *evaluate(node *op, var *res) break; case F_le: - if (!op1) + 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; @@ -2681,26 +2859,37 @@ static var *evaluate(node *op, var *res) if (!op1) { fflush(stdout); } else if (L.s && *L.s) { - rsm = newfile(L.s); + rstream *rsm = newfile(L.s); fflush(rsm->F); } else { fflush_all(); } break; - case F_cl: - i = 0; + case F_cl: { + rstream *rsm; + int err = 0; rsm = (rstream *)hash_search(fdhash, L.s); + debug_printf_eval("OC_FBLTIN F_cl rsm:%p\n", rsm); if (rsm) { - i = rsm->is_pipe ? pclose(rsm->F) : fclose(rsm->F); + 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); } - if (i != 0) + if (err) setvar_i(intvar[ERRNO], errno); - R_d = (double)i; + R_d = (double)err; break; } + } /* switch */ setvar_i(res, R_d); break; } @@ -2777,6 +2966,7 @@ static var *evaluate(node *op, var *res) case XC( OC_BINARY ): case XC( OC_REPLACE ): { double R_d = getvar_i(R.v); + debug_printf_eval("BINARY/REPLACE: R_d:%f opn:%c\n", R_d, opn); switch (opn) { case '+': L_d += R_d; @@ -2793,18 +2983,18 @@ static var *evaluate(node *op, var *res) L_d /= R_d; break; case '&': -#if ENABLE_FEATURE_AWK_LIBM - L_d = pow(L_d, R_d); -#else - syntax_error(EMSG_NO_MATH); -#endif + 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 -= (int)(L_d / R_d) * R_d; + 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; } @@ -2847,6 +3037,7 @@ static var *evaluate(node *op, var *res) } /* while (op) */ nvfree(v1); + debug_printf_eval("returning from %s(): %p\n", __func__, res); return res; #undef fnargs #undef seed @@ -2887,21 +3078,18 @@ static int awk_exit(int r) * otherwise return 0 */ static int is_assignment(const char *expr) { - char *exprc, *s, *s0, *s1; + char *exprc, *val; - exprc = xstrdup(expr); - if (!isalnum_(*exprc) || (s = strchr(exprc, '=')) == NULL) { - free(exprc); + if (!isalnum_(*expr) || (val = strchr(expr, '=')) == NULL) { return FALSE; } - *s++ = '\0'; - s0 = s1 = s; - while (*s) - *s1++ = nextchar(&s); + exprc = xstrdup(expr); + val = exprc + (val - expr); + *val++ = '\0'; - *s1 = '\0'; - setvar_u(newvar(exprc), s0); + unescape_string_in_place(val); + setvar_u(newvar(exprc), val); free(exprc); return TRUE; } @@ -2912,7 +3100,7 @@ static rstream *next_input_file(void) #define rsm (G.next_input_file__rsm) #define files_happen (G.next_input_file__files_happen) - FILE *F = NULL; + FILE *F; const char *fname, *ind; if (rsm.F) @@ -2920,19 +3108,21 @@ static rstream *next_input_file(void) rsm.F = NULL; rsm.pos = rsm.adv = 0; - do { + for (;;) { if (getvar_i(intvar[ARGIND])+1 >= getvar_i(intvar[ARGC])) { if (files_happen) return NULL; fname = "-"; F = stdin; - } else { - ind = getvar_s(incvar(intvar[ARGIND])); - fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); - if (fname && *fname && !is_assignment(fname)) - F = xfopen_stdin(fname); + break; } - } while (!F); + ind = getvar_s(incvar(intvar[ARGIND])); + fname = getvar_s(findvar(iamarray(intvar[ARGV]), ind)); + if (fname && *fname && !is_assignment(fname)) { + F = xfopen_stdin(fname); + break; + } + } files_happen = TRUE; setvar_s(intvar[FILENAME], fname); @@ -2946,9 +3136,12 @@ int awk_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int awk_main(int argc, char **argv) { unsigned opt; - char *opt_F, *opt_W; + char *opt_F; llist_t *list_v = NULL; llist_t *list_f = NULL; +#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS + llist_t *list_e = NULL; +#endif int i, j; var *v; var tv; @@ -3007,45 +3200,51 @@ int awk_main(int argc, char **argv) *s1 = '='; } } - opt_complementary = "v::f::"; /* -v and -f can occur multiple times */ - opt = getopt32(argv, "F:v:f:W:", &opt_F, &list_v, &list_f, &opt_W); + opt_complementary = OPTCOMPLSTR_AWK; + opt = getopt32(argv, OPTSTR_AWK, &opt_F, &list_v, &list_f, IF_FEATURE_AWK_GNU_EXTENSIONS(&list_e,) NULL); argv += optind; argc -= optind; - if (opt & 0x1) - setvar_s(intvar[FS], opt_F); // -F - while (list_v) { /* -v */ + if (opt & OPT_W) + bb_error_msg("warning: option -W is ignored"); + if (opt & OPT_F) { + unescape_string_in_place(opt_F); + setvar_s(intvar[FS], opt_F); + } + while (list_v) { if (!is_assignment(llist_pop(&list_v))) bb_show_usage(); } - if (list_f) { /* -f */ - do { - char *s = NULL; - FILE *from_file; - - g_progname = llist_pop(&list_f); - from_file = xfopen_stdin(g_progname); - /* one byte is reserved for some trick in next_token */ - for (i = j = 1; j > 0; i += j) { - s = xrealloc(s, i + 4096); - j = fread(s + i, 1, 4094, from_file); - } - s[i] = '\0'; - fclose(from_file); - parse_program(s + 1); - free(s); - } while (list_f); - argc++; - } else { // no -f: take program from 1st parameter - if (!argc) + while (list_f) { + char *s = NULL; + FILE *from_file; + + g_progname = llist_pop(&list_f); + from_file = xfopen_stdin(g_progname); + /* one byte is reserved for some trick in next_token */ + for (i = j = 1; j > 0; i += j) { + s = xrealloc(s, i + 4096); + j = fread(s + i, 1, 4094, from_file); + } + s[i] = '\0'; + fclose(from_file); + parse_program(s + 1); + free(s); + } + g_progname = "cmd. line"; +#if ENABLE_FEATURE_AWK_GNU_EXTENSIONS + while (list_e) { + parse_program(llist_pop(&list_e)); + } +#endif + if (!(opt & (OPT_f | OPT_e))) { + if (!*argv) bb_show_usage(); - g_progname = "cmd. line"; parse_program(*argv++); + argc--; } - if (opt & 0x8) // -W - bb_error_msg("warning: unrecognized option '-W %s' ignored", opt_W); /* fill in ARGV array */ - setvar_i(intvar[ARGC], argc); + setvar_i(intvar[ARGC], argc + 1); setari_u(intvar[ARGV], 0, "awk"); i = 0; while (*argv) diff --git a/editors/cmp.c b/editors/cmp.c index dbfa4be..a4af6f4 100644 --- a/editors/cmp.c +++ b/editors/cmp.c @@ -4,12 +4,31 @@ * * Copyright (C) 2000,2001 by Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 (virtually) compliant -- uses nicer GNU format for -l. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/cmp.html */ +//config:config CMP +//config: bool "cmp" +//config: default y +//config: help +//config: cmp is used to compare two files and returns the result +//config: to standard output. + +//kbuild:lib-$(CONFIG_CMP) += cmp.o + +//applet:IF_CMP(APPLET(cmp, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//usage:#define cmp_trivial_usage +//usage: "[-l] [-s] 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" + #include "libbb.h" static const char fmt_eof[] ALIGN1 = "cmp: EOF on %s\n"; @@ -33,8 +52,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) unsigned opt; int retval = 0; - xfunc_error_retval = 2; /* 1 is returned if files are different. */ - opt_complementary = "-1" IF_DESKTOP(":?4") IF_NOT_DESKTOP(":?2") @@ -43,8 +60,6 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) argv += optind; filename1 = *argv; - fp1 = xfopen_stdin(filename1); - if (*++argv) { filename2 = *argv; if (ENABLE_DESKTOP && *++argv) { @@ -55,6 +70,10 @@ int cmp_main(int argc UNUSED_PARAM, char **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. @@ -63,6 +82,7 @@ int cmp_main(int argc UNUSED_PARAM, char **argv) */ return 0; } + logmode = LOGMODE_STDIO; if (opt & CMP_OPT_l) fmt = fmt_l_opt; diff --git a/editors/diff.c b/editors/diff.c index a3ca2b6..a78a0ee 100644 --- a/editors/diff.c +++ b/editors/diff.c @@ -10,7 +10,7 @@ * 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 tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -76,12 +76,60 @@ * 6n words for files of length n. */ +//config:config DIFF +//config: bool "diff" +//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: help +//config: Enable use of long options. +//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. + +//kbuild:lib-$(CONFIG_DIFF) += diff.o + +//applet:IF_DIFF(APPLET(diff, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//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" #if 0 -//#define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) #else -#define dbg_error_msg(...) ((void)0) +# define dbg_error_msg(...) ((void)0) #endif enum { /* print_status() and diffreg() return values */ @@ -230,7 +278,7 @@ 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 */ + if (list[c[k]].y < y) /* quick look for typical case */ return k + 1; for (i = 0, j = k + 1;;) { @@ -479,7 +527,7 @@ start: 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 lenght, + /* 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] */ @@ -672,10 +720,12 @@ static bool diff(FILE* fp[2], char *file[2]) static int diffreg(char *file[2]) { - FILE *fp[2] = { stdin, stdin }; + 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 = open_or_warn_stdin(file[i]); if (fd == -1) @@ -685,9 +735,8 @@ static int diffreg(char *file[2]) */ if (lseek(fd, 0, SEEK_SET) == -1 && errno == ESPIPE) { char name[] = "/tmp/difXXXXXX"; - int fd_tmp = mkstemp(name); - if (fd_tmp < 0) - bb_perror_msg_and_die("mkstemp"); + int fd_tmp = xmkstemp(name); + unlink(name); if (bb_copyfd_eof(fd, fd_tmp) < 0) xfunc_die(); @@ -795,7 +844,9 @@ static int FAST_FUNC skip_dir(const char *filename, free(othername); if (r != 0 || !S_ISDIR(osb.st_mode)) { /* other dir doesn't have similarly named - * directory, don't recurse */ + * directory, don't recurse; return 1 upon + * exit, just like diffutils' diff */ + exit_status |= 1; return SKIP; } } @@ -819,7 +870,7 @@ static void diffdir(char *p[2], const char *s_start) * 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], 0); + add_to_dirlist, skip_dir, &list[i], 0); /* Sort dl alphabetically. * GNU diff does this ignoring any number of trailing dots. * We don't, so for us dotted files almost always are @@ -847,9 +898,10 @@ static void diffdir(char *p[2], const char *s_start) break; pos = !dp[0] ? 1 : (!dp[1] ? -1 : strcmp(dp[0], dp[1])); k = pos > 0; - if (pos && !(option_mask32 & FLAG(N))) + if (pos && !(option_mask32 & FLAG(N))) { printf("Only in %s: %s\n", p[k], dp[k]); - else { + exit_status |= 1; + } else { char *fullpath[2], *path[2]; /* if -N */ for (i = 0; i < 2; i++) { @@ -950,6 +1002,31 @@ int diff_main(int argc UNUSED_PARAM, char **argv) if (gotstdin && (S_ISDIR(stb[0].st_mode) || S_ISDIR(stb[1].st_mode))) bb_error_msg_and_die("can't compare stdin to a directory"); + /* Compare metadata to check if the files are the same physical file. + * + * Comment from diffutils source says: + * POSIX says that two files are identical if st_ino and st_dev are + * the same, but many file systems incorrectly assign the same (device, + * inode) pair to two distinct files, including: + * GNU/Linux NFS servers that export all local file systems as a + * single NFS file system, if a local device number (st_dev) exceeds + * 255, or if a local inode number (st_ino) exceeds 16777215. + */ + if (ENABLE_DESKTOP + && stb[0].st_ino == stb[1].st_ino + && stb[0].st_dev == stb[1].st_dev + && stb[0].st_size == stb[1].st_size + && stb[0].st_mtime == stb[1].st_mtime + && stb[0].st_ctime == stb[1].st_ctime + && stb[0].st_mode == stb[1].st_mode + && stb[0].st_nlink == stb[1].st_nlink + && stb[0].st_uid == stb[1].st_uid + && stb[0].st_gid == stb[1].st_gid + ) { + /* files are physically the same; no need to compare them */ + return STATUS_SAME; + } + if (S_ISDIR(stb[0].st_mode) && S_ISDIR(stb[1].st_mode)) { #if ENABLE_FEATURE_DIFF_DIR diffdir(file, s_start); diff --git a/editors/ed.c b/editors/ed.c index 516b8d7..3087fb0 100644 --- a/editors/ed.c +++ b/editors/ed.c @@ -7,6 +7,21 @@ * The "ed" built-in command (much simplified) */ +//config:config ED +//config: bool "ed" +//config: default y +//config: help +//config: The original 1970's Unix text editor, from the days of teletypes. +//config: Small, simple, evil. Part of SUSv3. If you're not already using +//config: this, you don't need it. + +//kbuild:lib-$(CONFIG_ED) += ed.o + +//applet:IF_ED(APPLET(ed, BB_DIR_BIN, BB_SUID_DROP)) + +//usage:#define ed_trivial_usage "" +//usage:#define ed_full_usage "" + #include "libbb.h" typedef struct LINE { @@ -129,7 +144,7 @@ static void doCommands(void) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input(": ", buf, sizeof(buf), NULL); + len = read_line_input(NULL, ": ", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) return; endbuf = &buf[len - 1]; @@ -227,7 +242,7 @@ static void doCommands(void) } if (!dirty) return; - len = read_line_input("Really quit? ", buf, 16, NULL); + len = read_line_input(NULL, "Really quit? ", buf, 16, /*timeout*/ -1); /* read error/EOF - no way to continue */ if (len < 0) return; @@ -451,7 +466,7 @@ static void subCommand(const char *cmd, int num1, int num2) /* * The new string is larger, so allocate a new line - * structure and use that. Link it in in place of + * structure and use that. Link it in place of * the old line structure. */ nlp = xmalloc(sizeof(LINE) + lp->len + deltaLen); @@ -541,7 +556,7 @@ static void addLines(int num) * 0 on ctrl-C, * >0 length of input string, including terminating '\n' */ - len = read_line_input("", buf, sizeof(buf), NULL); + len = read_line_input(NULL, "", buf, sizeof(buf), /*timeout*/ -1); if (len <= 0) { /* Previously, ctrl-C was exiting to shell. * Now we exit to ed prompt. Is in important? */ @@ -671,7 +686,7 @@ static int readLines(const char *file, int num) fd = open(file, 0); if (fd < 0) { - perror(file); + bb_simple_perror_msg(file); return FALSE; } @@ -721,7 +736,7 @@ static int readLines(const char *file, int num) } while (cc > 0); if (cc < 0) { - perror(file); + bb_simple_perror_msg(file); close(fd); return FALSE; } @@ -761,7 +776,7 @@ static int writeLines(const char *file, int num1, int num2) fd = creat(file, 0666); if (fd < 0) { - perror(file); + bb_simple_perror_msg(file); return FALSE; } @@ -776,7 +791,7 @@ static int writeLines(const char *file, int num1, int num2) while (num1++ <= num2) { if (full_write(fd, lp->data, lp->len) != lp->len) { - perror(file); + bb_simple_perror_msg(file); close(fd); return FALSE; } @@ -786,7 +801,7 @@ static int writeLines(const char *file, int num1, int num2) } if (close(fd) < 0) { - perror(file); + bb_simple_perror_msg(file); return FALSE; } diff --git a/editors/patch.c b/editors/patch.c index 62477af..13785ef 100644 --- a/editors/patch.c +++ b/editors/patch.c @@ -1,306 +1,552 @@ -/* vi: set sw=4 ts=4: */ -/* - * busybox patch applet to handle the unified diff format. - * Copyright (C) 2003 Glenn McGrath +/* vi: set sw=4 ts=4: * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Apply a "universal" diff. + * Adapted from toybox's patch implementation. * - * This applet is written to work with patches generated by GNU diff, - * where there is equivalent functionality busybox patch shall behave - * as per GNU patch. + * Copyright 2007 Rob Landley * - * There is a SUSv3 specification for patch, however it looks to be - * incomplete, it doesnt even mention unified diff format. - * http://www.opengroup.org/onlinepubs/007904975/utilities/patch.html + * see http://www.opengroup.org/onlinepubs/009695399/utilities/patch.html + * (But only does -u, because who still cares about "ed"?) * - * Issues - * - Non-interactive - * - Patches must apply cleanly or patch (not just one hunk) will fail. - * - Reject file isnt saved + * TODO: + * -b backup + * -l treat all whitespace as a single space + * -d chdir first + * -D define wrap #ifdef and #ifndef around changes + * -o outfile output here instead of in place + * -r rejectfile write rejected hunks to this file + * --dry-run (regression!) + * + * -f force (no questions asked) + * -F fuzz (number, default 2) + * [file] which file to patch */ +//config:config PATCH +//config: bool "patch" +//config: default y +//config: help +//config: Apply a unified diff formatted patch. + +//applet:IF_PATCH(APPLET(patch, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PATCH) += patch.o + +//usage:#define patch_trivial_usage +//usage: "[OPTIONS] [ORIGFILE [PATCHFILE]]" +//usage:#define patch_full_usage "\n\n" +//usage: IF_LONG_OPTS( +//usage: " -p,--strip N Strip N leading components from file names" +//usage: "\n -i,--input DIFF Read DIFF instead of stdin" +//usage: "\n -R,--reverse Reverse patch" +//usage: "\n -N,--forward Ignore already applied patches" +/*usage: "\n --dry-run Don't actually change files" - TODO */ +//usage: "\n -E,--remove-empty-files Remove output files if they become empty" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: " -p N Strip N leading components from file names" +//usage: "\n -i DIFF Read DIFF instead of stdin" +//usage: "\n -R Reverse patch" +//usage: "\n -N Ignore already applied patches" +//usage: "\n -E Remove output files if they become empty" +//usage: ) +/* -u "interpret as unified diff" is supported but not documented: this info is not useful for --help */ +/* -x "debug" is supported but does nothing */ +//usage: +//usage:#define patch_example_usage +//usage: "$ patch -p1 < example.diff\n" +//usage: "$ patch -p0 -i example.diff" + #include "libbb.h" -static unsigned copy_lines(FILE *src_stream, FILE *dst_stream, unsigned lines_count) + +// libbb candidate? + +struct double_list { + struct double_list *next; + struct double_list *prev; + char *data; +}; + +// Free all the elements of a linked list +// Call freeit() on each element before freeing it. +static void dlist_free(struct double_list *list, void (*freeit)(void *data)) { - while (src_stream && lines_count) { - char *line; - line = xmalloc_fgets(src_stream); - if (line == NULL) { - break; - } - if (fputs(line, dst_stream) == EOF) { - bb_perror_msg_and_die("error writing to new file"); + while (list) { + void *pop = list; + list = list->next; + freeit(pop); + // Bail out also if list is circular. + if (list == pop) break; + } +} + +// Add an entry before "list" element in (circular) doubly linked list +static struct double_list *dlist_add(struct double_list **list, char *data) +{ + struct double_list *llist; + struct double_list *line = xmalloc(sizeof(*line)); + + line->data = data; + llist = *list; + if (llist) { + struct double_list *p; + line->next = llist; + p = line->prev = llist->prev; + // (list is circular, we assume p is never NULL) + p->next = line; + llist->prev = line; + } else + *list = line->next = line->prev = line; + + return line; +} + + +struct globals { + char *infile; + long prefix; + + struct double_list *current_hunk; + + long oldline, oldlen, newline, newlen; + long linenum; + int context, state, hunknum; + int filein, fileout; + char *tempname; + + int exitval; +}; +#define TT (*ptr_to_globals) +#define INIT_TT() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(TT))); \ +} while (0) + + +#define FLAG_STR "Rup:i:NEx" +/* FLAG_REVERSE must be == 1! Code uses this fact. */ +#define FLAG_REVERSE (1 << 0) +#define FLAG_u (1 << 1) +#define FLAG_PATHLEN (1 << 2) +#define FLAG_INPUT (1 << 3) +#define FLAG_IGNORE (1 << 4) +#define FLAG_RMEMPTY (1 << 5) +/* Enable this bit and use -x for debug output: */ +#define FLAG_DEBUG (0 << 6) + +// Dispose of a line of input, either by writing it out or discarding it. + +// state < 2: just free +// state = 2: write whole line to stderr +// state = 3: write whole line to fileout +// state > 3: write line+1 to fileout when *line != state + +#define PATCH_DEBUG (option_mask32 & FLAG_DEBUG) + +static void do_line(void *data) +{ + struct double_list *dlist = data; + + if (TT.state>1 && *dlist->data != TT.state) + fdprintf(TT.state == 2 ? 2 : TT.fileout, + "%s\n", dlist->data+(TT.state>3 ? 1 : 0)); + + if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); + + free(dlist->data); + free(dlist); +} + +static void finish_oldfile(void) +{ + if (TT.tempname) { + // Copy the rest of the data and replace the original with the copy. + char *temp; + + if (TT.filein != -1) { + bb_copyfd_eof(TT.filein, TT.fileout); + xclose(TT.filein); } - free(line); - lines_count--; + xclose(TT.fileout); + + temp = xstrdup(TT.tempname); + temp[strlen(temp) - 6] = '\0'; + rename(TT.tempname, temp); + free(temp); + + free(TT.tempname); + TT.tempname = NULL; } - return lines_count; + TT.fileout = TT.filein = -1; } -/* If patch_level is -1 it will remove all directory names - * char *line must be greater than 4 chars - * returns NULL if the file doesnt exist or error - * returns malloc'ed filename - * NB: frees 1st argument! - */ -static char *extract_filename(char *line, int patch_level, const char *pat) +static void fail_hunk(void) +{ + if (!TT.current_hunk) return; + + fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); + TT.exitval = 1; + + // If we got to this point, we've seeked to the end. Discard changes to + // this file and advance to next file. + + TT.state = 2; + TT.current_hunk->prev->next = NULL; + dlist_free(TT.current_hunk, do_line); + TT.current_hunk = NULL; + + // Abort the copy and delete the temporary file. + close(TT.filein); + close(TT.fileout); + unlink(TT.tempname); + free(TT.tempname); + TT.tempname = NULL; + + TT.state = 0; +} + +// Given a hunk of a unified diff, make the appropriate change to the file. +// This does not use the location information, but instead treats a hunk +// as a sort of regex. Copies data from input to output until it finds +// the change to be made, then outputs the changed data and returns. +// (Finding EOF first is an error.) This is a single pass operation, so +// multiple hunks must occur in order in the file. + +static int apply_one_hunk(void) { - char *temp = NULL, *filename_start_ptr = line + 4; - - if (strncmp(line, pat, 4) == 0) { - /* Terminate string at end of source filename */ - line[strcspn(line, "\t\n\r")] = '\0'; - - /* Skip over (patch_level) number of leading directories */ - while (patch_level--) { - temp = strchr(filename_start_ptr, '/'); - if (!temp) - break; - filename_start_ptr = temp + 1; + struct double_list *plist, *buf = NULL, *check; + int matcheof = 0, reverse = option_mask32 & FLAG_REVERSE, backwarn = 0; + /* Do we try "dummy" revert to check whether + * to silently skip this hunk? Used to implement -N. + */ + int dummy_revert = 0; + + // Break doubly linked list so we can use singly linked traversal function. + TT.current_hunk->prev->next = NULL; + + // Match EOF if there aren't as many ending context lines as beginning + for (plist = TT.current_hunk; plist; plist = plist->next) { + if (plist->data[0]==' ') matcheof++; + else matcheof = 0; + if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); + } + matcheof = !matcheof || matcheof < TT.context; + + if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); + + // Loop through input data searching for this hunk. Match all context + // lines and all lines to be removed until we've found the end of a + // complete hunk. + plist = TT.current_hunk; + buf = NULL; + if (reverse ? TT.oldlen : TT.newlen) for (;;) { + char *data = xmalloc_reads(TT.filein, NULL); + + TT.linenum++; + + // Figure out which line of hunk to compare with next. (Skip lines + // of the hunk we'd be adding.) + while (plist && *plist->data == "+-"[reverse]) { + if (data && !strcmp(data, plist->data+1)) { + if (!backwarn) { + backwarn = TT.linenum; + if (option_mask32 & FLAG_IGNORE) { + dummy_revert = 1; + reverse ^= 1; + continue; + } + } + } + plist = plist->next; + } + + // Is this EOF? + if (!data) { + if (PATCH_DEBUG) fdprintf(2, "INEOF\n"); + + // Does this hunk need to match EOF? + if (!plist && matcheof) break; + + if (backwarn) + fdprintf(2,"Possibly reversed hunk %d at %ld\n", + TT.hunknum, TT.linenum); + + // File ended before we found a place for this hunk. + fail_hunk(); + goto done; + } + + if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); + check = dlist_add(&buf, data); + + // Compare this line with next expected line of hunk. + // todo: teach the strcmp() to ignore whitespace. + + // A match can fail because the next line doesn't match, or because + // we hit the end of a hunk that needed EOF, and this isn't EOF. + + // If match failed, flush first line of buffered data and + // recheck buffered data for a new match until we find one or run + // out of buffer. + + for (;;) { + if (!plist || strcmp(check->data, plist->data+1)) { + // Match failed. Write out first line of buffered data and + // recheck remaining buffered data for a new match. + + if (PATCH_DEBUG) + fdprintf(2, "NOT: %s\n", plist->data); + + TT.state = 3; + check = buf; + buf = buf->next; + check->prev->next = buf; + buf->prev = check->prev; + do_line(check); + plist = TT.current_hunk; + + // If we've reached the end of the buffer without confirming a + // match, read more lines. + if (check == buf) { + buf = NULL; + break; + } + check = buf; + } else { + if (PATCH_DEBUG) + fdprintf(2, "MAYBE: %s\n", plist->data); + // This line matches. Advance plist, detect successful match. + plist = plist->next; + if (!plist && !matcheof) goto out; + check = check->next; + if (check == buf) break; + } } - temp = xstrdup(filename_start_ptr); } - free(line); - return temp; +out: + // We have a match. Emit changed data. + TT.state = "-+"[reverse ^ dummy_revert]; + dlist_free(TT.current_hunk, do_line); + TT.current_hunk = NULL; + TT.state = 1; +done: + if (buf) { + buf->prev->next = NULL; + dlist_free(buf, do_line); + } + + return TT.state; } +// Read a patch file and find hunks, opening/creating/deleting files. +// Call apply_one_hunk() on each hunk. + +// state 0: Not in a hunk, look for +++. +// state 1: Found +++ file indicator, look for @@ +// state 2: In hunk: counting initial context lines +// state 3: In hunk: getting body + int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int patch_main(int argc UNUSED_PARAM, char **argv) { - struct stat saved_stat; - char *patch_line; - FILE *patch_file; - int patch_level; - int ret = 0; - char plus = '+'; - unsigned opt; - enum { - OPT_R = (1 << 2), - OPT_N = (1 << 3), - /*OPT_f = (1 << 4), ignored */ - /*OPT_E = (1 << 5), ignored, this is the default */ - /*OPT_g = (1 << 6), ignored */ - OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS, - }; - - xfunc_error_retval = 2; - { - const char *p = "-1"; - const char *i = "-"; /* compat */ -#if ENABLE_LONG_OPTS - static const char patch_longopts[] ALIGN1 = - "strip\0" Required_argument "p" - "input\0" Required_argument "i" - "reverse\0" No_argument "R" - "forward\0" No_argument "N" - /* "Assume user knows what [s]he is doing, do not ask any questions": */ - "force\0" No_argument "f" /*ignored*/ -# if ENABLE_DESKTOP - "remove-empty-files\0" No_argument "E" /*ignored*/ - /* "Controls actions when a file is under RCS or SCCS control, - * and does not exist or is read-only and matches the default version, - * or when a file is under ClearCase control and does not exist..." - * IOW: rather obscure option. - * But Gentoo's portage does use -g0 */ - "get\0" Required_argument "g" /*ignored*/ -# endif - "dry-run\0" No_argument "\xfd" -# if ENABLE_DESKTOP - "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ - "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ -# endif - ; - applet_long_options = patch_longopts; -#endif - /* -f,-E,-g are ignored */ - opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); - if (opt & OPT_R) - plus = '-'; - patch_level = xatoi(p); /* can be negative! */ - patch_file = xfopen_stdin(i); + int opts; + int reverse, state = 0; + char *oldname = NULL, *newname = NULL; + char *opt_p, *opt_i; + long oldlen = oldlen; /* for compiler */ + long newlen = newlen; /* for compiler */ + + INIT_TT(); + + opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); + argv += optind; + reverse = opts & FLAG_REVERSE; + TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! + TT.filein = TT.fileout = -1; + if (opts & FLAG_INPUT) { + xmove_fd(xopen_stdin(opt_i), STDIN_FILENO); + } else { + if (argv[0] && argv[1]) { + xmove_fd(xopen_stdin(argv[1]), STDIN_FILENO); + } + } + if (argv[0]) { + oldname = xstrdup(argv[0]); + newname = xstrdup(argv[0]); } - patch_line = xmalloc_fgetline(patch_file); - while (patch_line) { - FILE *src_stream; - FILE *dst_stream; - //char *old_filename; - char *new_filename; - char *backup_filename = NULL; - unsigned src_cur_line = 1; - unsigned dst_cur_line = 0; - unsigned dst_beg_line; - unsigned bad_hunk_count = 0; - unsigned hunk_count = 0; - smallint copy_trailing_lines_flag = 0; - - /* Skip everything upto the "---" marker - * No need to parse the lines "Only in ", and "diff " - */ - do { - /* Extract the filename used before the patch was generated */ - new_filename = extract_filename(patch_line, patch_level, "--- "); - // was old_filename above - patch_line = xmalloc_fgetline(patch_file); - if (!patch_line) goto quit; - } while (!new_filename); - free(new_filename); // "source" filename is irrelevant - - new_filename = extract_filename(patch_line, patch_level, "+++ "); - if (!new_filename) { - bb_error_msg_and_die("invalid patch"); + // Loop through the lines in the patch + for(;;) { + char *patchline; + + patchline = xmalloc_fgetline(stdin); + if (!patchline) break; + + // Other versions of patch accept damaged patches, + // so we need to also. + if (!*patchline) { + free(patchline); + patchline = xstrdup(" "); } - /* Get access rights from the file to be patched */ - if (stat(new_filename, &saved_stat) != 0) { - char *slash = strrchr(new_filename, '/'); - if (slash) { - /* Create leading directories */ - *slash = '\0'; - bb_make_directory(new_filename, -1, FILEUTILS_RECUR); - *slash = '/'; + // Are we assembling a hunk? + if (state >= 2) { + if (*patchline==' ' || *patchline=='+' || *patchline=='-') { + dlist_add(&TT.current_hunk, patchline); + + if (*patchline != '+') oldlen--; + if (*patchline != '-') newlen--; + + // Context line? + if (*patchline==' ' && state==2) TT.context++; + else state=3; + + // If we've consumed all expected hunk lines, apply the hunk. + + if (!oldlen && !newlen) state = apply_one_hunk(); + continue; } - src_stream = NULL; - saved_stat.st_mode = 0644; - } else if (!(opt & OPT_dry_run)) { - backup_filename = xasprintf("%s.orig", new_filename); - xrename(new_filename, backup_filename); - src_stream = xfopen_for_read(backup_filename); - } else - src_stream = xfopen_for_read(new_filename); - - if (opt & OPT_dry_run) { - dst_stream = xfopen_for_write("/dev/null"); - } else { - dst_stream = xfopen_for_write(new_filename); - fchmod(fileno(dst_stream), saved_stat.st_mode); + fail_hunk(); + state = 0; + continue; } - printf("patching file %s\n", new_filename); - - /* Handle all hunks for this file */ - patch_line = xmalloc_fgets(patch_file); - while (patch_line) { - unsigned count; - unsigned src_beg_line; - unsigned hunk_offset_start; - unsigned src_last_line = 1; - unsigned dst_last_line = 1; - - if ((sscanf(patch_line, "@@ -%d,%d +%d,%d", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) - && (sscanf(patch_line, "@@ -%d +%d,%d", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) - ) { - /* No more hunks for this file */ - break; - } - if (plus != '+') { - /* reverse patch */ - unsigned tmp = src_last_line; - src_last_line = dst_last_line; - dst_last_line = tmp; - tmp = src_beg_line; - src_beg_line = dst_beg_line; - dst_beg_line = tmp; + // Open a new file? + if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { + char *s, **name = reverse ? &newname : &oldname; + int i; + + if (*patchline == '+') { + name = reverse ? &oldname : &newname; + state = 1; } - hunk_count++; - - if (src_beg_line && dst_beg_line) { - /* Copy unmodified lines upto start of hunk */ - /* src_beg_line will be 0 if it's a new file */ - count = src_beg_line - src_cur_line; - if (copy_lines(src_stream, dst_stream, count)) { - bb_error_msg_and_die("bad src file"); + + finish_oldfile(); + + if (!argv[0]) { + free(*name); + // Trim date from end of filename (if any). We don't care. + for (s = patchline+4; *s && *s!='\t'; s++) + if (*s=='\\' && s[1]) s++; + i = atoi(s); + if (i>1900 && i<=1970) + *name = xstrdup("/dev/null"); + else { + *s = 0; + *name = xstrdup(patchline+4); } - src_cur_line += count; - dst_cur_line += count; - copy_trailing_lines_flag = 1; } - src_last_line += hunk_offset_start = src_cur_line; - dst_last_line += dst_cur_line; - - while (1) { - free(patch_line); - patch_line = xmalloc_fgets(patch_file); - if (patch_line == NULL) - break; /* EOF */ - if (!*patch_line) { - /* whitespace-damaged patch with "" lines */ - free(patch_line); - patch_line = xstrdup(" "); - } - if ((*patch_line != '-') && (*patch_line != '+') - && (*patch_line != ' ') - ) { - break; /* End of hunk */ + + // We defer actually opening the file because svn produces broken + // patches that don't signal they want to create a new file the + // way the patch man page says, so you have to read the first hunk + // and _guess_. + + // Start a new hunk? Usually @@ -oldline,oldlen +newline,newlen @@ + // but a missing ,value means the value is 1. + } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { + int i; + char *s = patchline+4; + + // Read oldline[,oldlen] +newline[,newlen] + + TT.oldlen = oldlen = TT.newlen = newlen = 1; + TT.oldline = strtol(s, &s, 10); + if (*s == ',') TT.oldlen = oldlen = strtol(s+1, &s, 10); + TT.newline = strtol(s+2, &s, 10); + if (*s == ',') TT.newlen = newlen = strtol(s+1, &s, 10); + + if (oldlen < 1 && newlen < 1) + bb_error_msg_and_die("Really? %s", patchline); + + TT.context = 0; + state = 2; + + // If this is the first hunk, open the file. + if (TT.filein == -1) { + int oldsum, newsum, empty = 0; + char *name; + + oldsum = TT.oldline + oldlen; + newsum = TT.newline + newlen; + + name = reverse ? oldname : newname; + + // We're deleting oldname if new file is /dev/null (before -p) + // or if new hunk is empty (zero context) after patching + if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { + name = reverse ? newname : oldname; + empty++; } - if (*patch_line != plus) { /* '-' or ' ' */ - char *src_line = NULL; - if (src_cur_line == src_last_line) + + // handle -p path truncation. + for (i = 0, s = name; *s;) { + if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; - if (src_stream) { - src_line = xmalloc_fgets(src_stream); - if (src_line) { - int diff = strcmp(src_line, patch_line + 1); - src_cur_line++; - free(src_line); - if (diff) - src_line = NULL; - } - } - /* Do not patch an already patched hunk with -N */ - if (src_line == 0 && (opt & OPT_N)) { + if (*s++ != '/') continue; + while (*s == '/') + s++; + i++; + name = s; + } + + if (empty) { + // File is empty after the patches have been applied + state = 0; + if (option_mask32 & FLAG_RMEMPTY) { + // If flag -E or --remove-empty-files is set + printf("removing %s\n", name); + xunlink(name); + } else { + printf("patching file %s\n", name); + xclose(xopen(name, O_WRONLY | O_TRUNC)); } - if (!src_line) { - bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); - bad_hunk_count++; - break; - } - if (*patch_line != ' ') { /* '-' */ - continue; + // If we've got a file to open, do so. + } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { + struct stat statbuf; + + // If the old file was null, we're creating a new one. + if (!strcmp(oldname, "/dev/null") || !oldsum) { + printf("creating %s\n", name); + s = strrchr(name, '/'); + if (s) { + *s = 0; + bb_make_directory(name, -1, FILEUTILS_RECUR); + *s = '/'; + } + TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); + } else { + printf("patching file %s\n", name); + TT.filein = xopen(name, O_RDONLY); } + + TT.tempname = xasprintf("%sXXXXXX", name); + TT.fileout = xmkstemp(TT.tempname); + // Set permissions of output file + fstat(TT.filein, &statbuf); + fchmod(TT.fileout, statbuf.st_mode); + + TT.linenum = 0; + TT.hunknum = 0; } - if (dst_cur_line == dst_last_line) - break; - fputs(patch_line + 1, dst_stream); - dst_cur_line++; - } /* end of while loop handling one hunk */ - } /* end of while loop handling one file */ - - /* Cleanup last patched file */ - if (copy_trailing_lines_flag) { - copy_lines(src_stream, dst_stream, (unsigned)(-1)); - } - if (src_stream) { - fclose(src_stream); - } - fclose(dst_stream); - if (bad_hunk_count) { - ret = 1; - bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); - } else { - /* It worked, we can remove the backup */ - if (backup_filename) { - unlink(backup_filename); - } - if (!(opt & OPT_dry_run) - && ((dst_cur_line == 0) || (dst_beg_line == 0)) - ) { - /* The new patched file is empty, remove it */ - xunlink(new_filename); - // /* old_filename and new_filename may be the same file */ - // unlink(old_filename); } + + TT.hunknum++; + + continue; } - free(backup_filename); - //free(old_filename); - free(new_filename); - } /* end of "while there are patch lines" */ - quit: - /* 0 = SUCCESS - * 1 = Some hunks failed - * 2 = More serious problems (exited earlier) - */ - return ret; + + // If we didn't continue above, discard this line. + free(patchline); + } + + finish_oldfile(); + + if (ENABLE_FEATURE_CLEAN_UP) { + free(oldname); + free(newname); + } + + return TT.exitval; } diff --git a/editors/patch_bbox.c b/editors/patch_bbox.c new file mode 100644 index 0000000..aae7b79 --- /dev/null +++ b/editors/patch_bbox.c @@ -0,0 +1,306 @@ +/* vi: set sw=4 ts=4: */ +/* + * busybox patch applet to handle the unified diff format. + * Copyright (C) 2003 Glenn McGrath + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * This applet is written to work with patches generated by GNU diff, + * where there is equivalent functionality busybox patch shall behave + * as per GNU patch. + * + * There is a SUSv3 specification for patch, however it looks to be + * incomplete, it doesnt even mention unified diff format. + * http://www.opengroup.org/onlinepubs/007904975/utilities/patch.html + * + * Issues + * - Non-interactive + * - Patches must apply cleanly or patch (not just one hunk) will fail. + * - Reject file isnt saved + */ + +#include "libbb.h" + +static unsigned copy_lines(FILE *src_stream, FILE *dst_stream, unsigned lines_count) +{ + while (src_stream && lines_count) { + char *line; + line = xmalloc_fgets(src_stream); + if (line == NULL) { + break; + } + if (fputs(line, dst_stream) == EOF) { + bb_perror_msg_and_die("error writing to new file"); + } + free(line); + lines_count--; + } + return lines_count; +} + +/* If patch_level is -1 it will remove all directory names + * char *line must be greater than 4 chars + * returns NULL if the file doesnt exist or error + * returns malloc'ed filename + * NB: frees 1st argument! + */ +static char *extract_filename(char *line, int patch_level, const char *pat) +{ + char *temp = NULL, *filename_start_ptr = line + 4; + + if (strncmp(line, pat, 4) == 0) { + /* Terminate string at end of source filename */ + line[strcspn(line, "\t\n\r")] = '\0'; + + /* Skip over (patch_level) number of leading directories */ + while (patch_level--) { + temp = strchr(filename_start_ptr, '/'); + if (!temp) + break; + filename_start_ptr = temp + 1; + } + temp = xstrdup(filename_start_ptr); + } + free(line); + return temp; +} + +int patch_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int patch_main(int argc UNUSED_PARAM, char **argv) +{ + struct stat saved_stat; + char *patch_line; + FILE *patch_file; + int patch_level; + int ret = 0; + char plus = '+'; + unsigned opt; + enum { + OPT_R = (1 << 2), + OPT_N = (1 << 3), + /*OPT_f = (1 << 4), ignored */ + /*OPT_E = (1 << 5), ignored, this is the default */ + /*OPT_g = (1 << 6), ignored */ + OPT_dry_run = (1 << 7) * ENABLE_LONG_OPTS, + }; + + xfunc_error_retval = 2; + { + const char *p = "-1"; + const char *i = "-"; /* compat */ +#if ENABLE_LONG_OPTS + static const char patch_longopts[] ALIGN1 = + "strip\0" Required_argument "p" + "input\0" Required_argument "i" + "reverse\0" No_argument "R" + "forward\0" No_argument "N" + /* "Assume user knows what [s]he is doing, do not ask any questions": */ + "force\0" No_argument "f" /*ignored*/ +# if ENABLE_DESKTOP + "remove-empty-files\0" No_argument "E" /*ignored*/ + /* "Controls actions when a file is under RCS or SCCS control, + * and does not exist or is read-only and matches the default version, + * or when a file is under ClearCase control and does not exist..." + * IOW: rather obscure option. + * But Gentoo's portage does use -g0 */ + "get\0" Required_argument "g" /*ignored*/ +# endif + "dry-run\0" No_argument "\xfd" +# if ENABLE_DESKTOP + "backup-if-mismatch\0" No_argument "\xfe" /*ignored*/ + "no-backup-if-mismatch\0" No_argument "\xff" /*ignored*/ +# endif + ; + applet_long_options = patch_longopts; +#endif + /* -f,-E,-g are ignored */ + opt = getopt32(argv, "p:i:RN""fEg:", &p, &i, NULL); + if (opt & OPT_R) + plus = '-'; + patch_level = xatoi(p); /* can be negative! */ + patch_file = xfopen_stdin(i); + } + + patch_line = xmalloc_fgetline(patch_file); + while (patch_line) { + FILE *src_stream; + FILE *dst_stream; + //char *old_filename; + char *new_filename; + char *backup_filename = NULL; + unsigned src_cur_line = 1; + unsigned dst_cur_line = 0; + unsigned dst_beg_line; + unsigned bad_hunk_count = 0; + unsigned hunk_count = 0; + smallint copy_trailing_lines_flag = 0; + + /* Skip everything upto the "---" marker + * No need to parse the lines "Only in ", and "diff " + */ + do { + /* Extract the filename used before the patch was generated */ + new_filename = extract_filename(patch_line, patch_level, "--- "); + // was old_filename above + patch_line = xmalloc_fgetline(patch_file); + if (!patch_line) goto quit; + } while (!new_filename); + free(new_filename); // "source" filename is irrelevant + + new_filename = extract_filename(patch_line, patch_level, "+++ "); + if (!new_filename) { + bb_error_msg_and_die("invalid patch"); + } + + /* Get access rights from the file to be patched */ + if (stat(new_filename, &saved_stat) != 0) { + char *slash = strrchr(new_filename, '/'); + if (slash) { + /* Create leading directories */ + *slash = '\0'; + bb_make_directory(new_filename, -1, FILEUTILS_RECUR); + *slash = '/'; + } + src_stream = NULL; + saved_stat.st_mode = 0644; + } else if (!(opt & OPT_dry_run)) { + backup_filename = xasprintf("%s.orig", new_filename); + xrename(new_filename, backup_filename); + src_stream = xfopen_for_read(backup_filename); + } else + src_stream = xfopen_for_read(new_filename); + + if (opt & OPT_dry_run) { + dst_stream = xfopen_for_write("/dev/null"); + } else { + dst_stream = xfopen_for_write(new_filename); + fchmod(fileno(dst_stream), saved_stat.st_mode); + } + + printf("patching file %s\n", new_filename); + + /* Handle all hunks for this file */ + patch_line = xmalloc_fgets(patch_file); + while (patch_line) { + unsigned count; + unsigned src_beg_line; + unsigned hunk_offset_start; + unsigned src_last_line = 1; + unsigned dst_last_line = 1; + + if ((sscanf(patch_line, "@@ -%u,%u +%u,%u", &src_beg_line, &src_last_line, &dst_beg_line, &dst_last_line) < 3) + && (sscanf(patch_line, "@@ -%u +%u,%u", &src_beg_line, &dst_beg_line, &dst_last_line) < 2) + ) { + /* No more hunks for this file */ + break; + } + if (plus != '+') { + /* reverse patch */ + unsigned tmp = src_last_line; + src_last_line = dst_last_line; + dst_last_line = tmp; + tmp = src_beg_line; + src_beg_line = dst_beg_line; + dst_beg_line = tmp; + } + hunk_count++; + + if (src_beg_line && dst_beg_line) { + /* Copy unmodified lines upto start of hunk */ + /* src_beg_line will be 0 if it's a new file */ + count = src_beg_line - src_cur_line; + if (copy_lines(src_stream, dst_stream, count)) { + bb_error_msg_and_die("bad src file"); + } + src_cur_line += count; + dst_cur_line += count; + copy_trailing_lines_flag = 1; + } + src_last_line += hunk_offset_start = src_cur_line; + dst_last_line += dst_cur_line; + + while (1) { + free(patch_line); + patch_line = xmalloc_fgets(patch_file); + if (patch_line == NULL) + break; /* EOF */ + if (!*patch_line) { + /* whitespace-damaged patch with "" lines */ + free(patch_line); + patch_line = xstrdup(" "); + } + if ((*patch_line != '-') && (*patch_line != '+') + && (*patch_line != ' ') + ) { + break; /* End of hunk */ + } + if (*patch_line != plus) { /* '-' or ' ' */ + char *src_line = NULL; + if (src_cur_line == src_last_line) + break; + if (src_stream) { + src_line = xmalloc_fgets(src_stream); + if (src_line) { + int diff = strcmp(src_line, patch_line + 1); + src_cur_line++; + free(src_line); + if (diff) + src_line = NULL; + } + } + /* Do not patch an already patched hunk with -N */ + if (src_line == 0 && (opt & OPT_N)) { + continue; + } + if (!src_line) { + bb_error_msg("hunk #%u FAILED at %u", hunk_count, hunk_offset_start); + bad_hunk_count++; + break; + } + if (*patch_line != ' ') { /* '-' */ + continue; + } + } + if (dst_cur_line == dst_last_line) + break; + fputs(patch_line + 1, dst_stream); + dst_cur_line++; + } /* end of while loop handling one hunk */ + } /* end of while loop handling one file */ + + /* Cleanup last patched file */ + if (copy_trailing_lines_flag) { + copy_lines(src_stream, dst_stream, (unsigned)(-1)); + } + if (src_stream) { + fclose(src_stream); + } + fclose(dst_stream); + if (bad_hunk_count) { + ret = 1; + bb_error_msg("%u out of %u hunk FAILED", bad_hunk_count, hunk_count); + } else { + /* It worked, we can remove the backup */ + if (backup_filename) { + unlink(backup_filename); + } + if (!(opt & OPT_dry_run) + && ((dst_cur_line == 0) || (dst_beg_line == 0)) + ) { + /* The new patched file is empty, remove it */ + xunlink(new_filename); + // /* old_filename and new_filename may be the same file */ + // unlink(old_filename); + } + } + free(backup_filename); + //free(old_filename); + free(new_filename); + } /* end of "while there are patch lines" */ + quit: + /* 0 = SUCCESS + * 1 = Some hunks failed + * 2 = More serious problems (exited earlier) + */ + return ret; +} diff --git a/editors/patch_toybox.c b/editors/patch_toybox.c index 0e5c070..a60bf07 100644 --- a/editors/patch_toybox.c +++ b/editors/patch_toybox.c @@ -1,4 +1,4 @@ -/* Adapted from toybox's patch. Currently unused */ +/* Adapted from toybox's patch. */ /* vi: set sw=4 ts=4: * @@ -23,7 +23,7 @@ * -F fuzz (number, default 2) * [file] which file to patch -USE_PATCH(NEWTOY(patch, "up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) +USE_PATCH(NEWTOY(patch, USE_TOYBOX_DEBUG("x")"up#i:R", TOYFLAG_USR|TOYFLAG_BIN)) config PATCH bool "patch" @@ -223,15 +223,16 @@ void delete_tempfile(int fdin, int fdout, char **tempname) struct globals { - struct double_list *plines; - long linenum; - int context; - int hunknum; - int filein; - int fileout; - int state; + char *infile; + long prefix; + + struct double_list *current_hunk; + long oldline, oldlen, newline, newlen, linenum; + int context, state, filein, fileout, filepatch, hunknum; char *tempname; - smallint exitval; + + // was toys.foo: + int exitval; }; #define TT (*ptr_to_globals) #define INIT_TT() do { \ @@ -240,12 +241,14 @@ struct globals { //bbox had: "p:i:RN" -#define FLAG_STR "Rup:i:" +#define FLAG_STR "Rup:i:x" /* FLAG_REVERSE must be == 1! Code uses this fact. */ #define FLAG_REVERSE (1 << 0) #define FLAG_u (1 << 1) #define FLAG_PATHLEN (1 << 2) #define FLAG_INPUT (1 << 3) +//non-standard: +#define FLAG_DEBUG (1 << 4) // Dispose of a line of input, either by writing it out or discarding it. @@ -254,6 +257,8 @@ struct globals { // state = 3: write whole line to fileout // state > 3: write line+1 to fileout when *line != state +#define PATCH_DEBUG (option_mask32 & FLAG_DEBUG) + static void do_line(void *data) { struct double_list *dlist = (struct double_list *)data; @@ -262,6 +267,8 @@ static void do_line(void *data) fdprintf(TT.state == 2 ? 2 : TT.fileout, "%s\n", dlist->data+(TT.state>3 ? 1 : 0)); + if (PATCH_DEBUG) fdprintf(2, "DO %d: %s\n", TT.state, dlist->data); + free(dlist->data); free(data); } @@ -274,94 +281,118 @@ static void finish_oldfile(void) static void fail_hunk(void) { - if (!TT.plines) return; - TT.plines->prev->next = 0; + if (!TT.current_hunk) return; + TT.current_hunk->prev->next = 0; - fdprintf(2, "Hunk %d FAILED.\n", TT.hunknum); + fdprintf(2, "Hunk %d FAILED %ld/%ld.\n", TT.hunknum, TT.oldline, TT.newline); TT.exitval = 1; // If we got to this point, we've seeked to the end. Discard changes to // this file and advance to next file. TT.state = 2; - TOY_llist_free(TT.plines, do_line); - TT.plines = NULL; + TOY_llist_free(TT.current_hunk, do_line); + TT.current_hunk = NULL; delete_tempfile(TT.filein, TT.fileout, &TT.tempname); TT.state = 0; } -static int apply_hunk(void) +// Given a hunk of a unified diff, make the appropriate change to the file. +// This does not use the location information, but instead treats a hunk +// as a sort of regex. Copies data from input to output until it finds +// the change to be made, then outputs the changed data and returns. +// (Finding EOF first is an error.) This is a single pass operation, so +// multiple hunks must occur in order in the file. + +static int apply_one_hunk(void) { struct double_list *plist, *buf = NULL, *check; - int i = 0, backwards = 0, matcheof = 0, - reverse = option_mask32 & FLAG_REVERSE; + int matcheof = 0, reverse = option_mask32 & FLAG_REVERSE, backwarn = 0; // Break doubly linked list so we can use singly linked traversal function. - TT.plines->prev->next = NULL; + TT.current_hunk->prev->next = NULL; // Match EOF if there aren't as many ending context lines as beginning - for (plist = TT.plines; plist; plist = plist->next) { - if (plist->data[0]==' ') i++; - else i = 0; + for (plist = TT.current_hunk; plist; plist = plist->next) { + if (plist->data[0]==' ') matcheof++; + else matcheof = 0; + if (PATCH_DEBUG) fdprintf(2, "HUNK:%s\n", plist->data); } - if (i < TT.context) matcheof++; + matcheof = matcheof < TT.context; - // Search for a place to apply this hunk. Match all context lines and - // lines to be removed. - plist = TT.plines; - buf = NULL; - i = 0; + if (PATCH_DEBUG) fdprintf(2,"MATCHEOF=%c\n", matcheof ? 'Y' : 'N'); - // Start of for loop + // Loop through input data searching for this hunk. Match all context + // lines and all lines to be removed until we've found the end of a + // complete hunk. + plist = TT.current_hunk; + buf = NULL; if (TT.context) for (;;) { char *data = get_line(TT.filein); TT.linenum++; - // Skip lines of the hunk we'd be adding. + // Figure out which line of hunk to compare with next. (Skip lines + // of the hunk we'd be adding.) while (plist && *plist->data == "+-"[reverse]) { if (data && !strcmp(data, plist->data+1)) { - if (++backwards == TT.context) + if (!backwarn) { fdprintf(2,"Possibly reversed hunk %d at %ld\n", TT.hunknum, TT.linenum); - } else backwards=0; + backwarn++; + } + } plist = plist->next; } // Is this EOF? if (!data) { + if (PATCH_DEBUG) fdprintf(2, "INEOF\n"); + // Does this hunk need to match EOF? if (!plist && matcheof) break; // File ended before we found a place for this hunk. fail_hunk(); goto done; - } + } else if (PATCH_DEBUG) fdprintf(2, "IN: %s\n", data); check = dlist_add(&buf, data); + // Compare this line with next expected line of hunk. // todo: teach the strcmp() to ignore whitespace. - for (;;) { - // If we hit the end of a hunk that needed EOF and this isn't EOF, - // or next line doesn't match, flush first line of buffered data and - // recheck match until we find a new match or run out of buffer. + // A match can fail because the next line doesn't match, or because + // we hit the end of a hunk that needed EOF, and this isn't EOF. + + // If match failed, flush first line of buffered data and + // recheck buffered data for a new match until we find one or run + // out of buffer. + for (;;) { if (!plist || strcmp(check->data, plist->data+1)) { - // First line isn't a match, write it out. + // Match failed. Write out first line of buffered data and + // recheck remaining buffered data for a new match. + + if (PATCH_DEBUG) + fdprintf(2, "NOT: %s\n", plist->data); + TT.state = 3; check = TOY_llist_pop(&buf); check->prev->next = buf; buf->prev = check->prev; do_line(check); - plist = TT.plines; + plist = TT.current_hunk; - // Out of buffered lines? + // If we've reached the end of the buffer without confirming a + // match, read more lines. if (check==buf) { buf = 0; break; } check = buf; } else { + if (PATCH_DEBUG) + fdprintf(2, "MAYBE: %s\n", plist->data); // This line matches. Advance plist, detect successful match. plist = plist->next; if (!plist && !matcheof) goto out; @@ -371,10 +402,10 @@ static int apply_hunk(void) } } out: - // Got it. Emit changed data. + // We have a match. Emit changed data. TT.state = "-+"[reverse]; - TOY_llist_free(TT.plines, do_line); - TT.plines = NULL; + TOY_llist_free(TT.current_hunk, do_line); + TT.current_hunk = NULL; TT.state = 1; done: if (buf) { @@ -385,6 +416,9 @@ done: return TT.state; } +// Read a patch file and find hunks, opening/creating/deleting files. +// Call apply_one_hunk() on each hunk. + // state 0: Not in a hunk, look for +++. // state 1: Found +++ file indicator, look for @@ // state 2: In hunk: counting initial context lines @@ -397,24 +431,20 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int reverse, state = 0; char *oldname = NULL, *newname = NULL; char *opt_p, *opt_i; - int prefix; - - long oldline = 0, oldlen = 0, newline = 0, newlen = 0; INIT_TT(); opts = getopt32(argv, FLAG_STR, &opt_p, &opt_i); reverse = opts & FLAG_REVERSE; - - if (opts & FLAG_INPUT) xmove_fd(xopen(opt_i, O_RDONLY), STDIN_FILENO); - prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! + TT.prefix = (opts & FLAG_PATHLEN) ? xatoi(opt_p) : 0; // can be negative! + if (opts & FLAG_INPUT) TT.filepatch = xopen(opt_i, O_RDONLY); TT.filein = TT.fileout = -1; // Loop through the lines in the patch for(;;) { char *patchline; - patchline = get_line(STDIN_FILENO); + patchline = get_line(TT.filepatch); if (!patchline) break; // Other versions of patch accept damaged patches, @@ -427,17 +457,18 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // Are we assembling a hunk? if (state >= 2) { if (*patchline==' ' || *patchline=='+' || *patchline=='-') { - dlist_add(&TT.plines, patchline); + dlist_add(&TT.current_hunk, patchline); - if (*patchline != '+') oldlen--; - if (*patchline != '-') newlen--; + if (*patchline != '+') TT.oldlen--; + if (*patchline != '-') TT.newlen--; // Context line? if (*patchline==' ' && state==2) TT.context++; else state=3; // If we've consumed all expected hunk lines, apply the hunk. - if (!oldlen && !newlen) state = apply_hunk(); + + if (!TT.oldlen && !TT.newlen) state = apply_one_hunk(); continue; } fail_hunk(); @@ -447,11 +478,11 @@ int patch_main(int argc UNUSED_PARAM, char **argv) // Open a new file? if (!strncmp("--- ", patchline, 4) || !strncmp("+++ ", patchline, 4)) { - char *s, **name = &oldname; + char *s, **name = reverse ? &newname : &oldname; int i; if (*patchline == '+') { - name = &newname; + name = reverse ? &oldname : &newname; state = 1; } @@ -462,7 +493,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) for (s = patchline+4; *s && *s!='\t'; s++) if (*s=='\\' && s[1]) s++; i = atoi(s); - if (i && i<=1970) + if (i>1900 && i<=1970) *name = xstrdup("/dev/null"); else { *s = 0; @@ -478,8 +509,8 @@ int patch_main(int argc UNUSED_PARAM, char **argv) } else if (state == 1 && !strncmp("@@ -", patchline, 4)) { int i; - i = sscanf(patchline+4, "%ld,%ld +%ld,%ld", - &oldline, &oldlen, &newline, &newlen); + i = sscanf(patchline+4, "%ld,%ld +%ld,%ld", &TT.oldline, + &TT.oldlen, &TT.newline, &TT.newlen); if (i != 4) bb_error_msg_and_die("corrupt hunk %d at %ld", TT.hunknum, TT.linenum); @@ -491,22 +522,22 @@ int patch_main(int argc UNUSED_PARAM, char **argv) int oldsum, newsum, del = 0; char *s, *name; - oldsum = oldline + oldlen; - newsum = newline + newlen; + oldsum = TT.oldline + TT.oldlen; + newsum = TT.newline + TT.newlen; name = reverse ? oldname : newname; // We're deleting oldname if new file is /dev/null (before -p) // or if new hunk is empty (zero context) after patching - if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) { + if (!strcmp(name, "/dev/null") || !(reverse ? oldsum : newsum)) + { name = reverse ? newname : oldname; del++; } // handle -p path truncation. for (i=0, s = name; *s;) { - if ((option_mask32 & FLAG_PATHLEN) && prefix == i) - break; + if ((option_mask32 & FLAG_PATHLEN) && TT.prefix == i) break; if (*(s++)=='/') { name = s; i++; @@ -518,7 +549,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) xunlink(name); state = 0; // If we've got a file to open, do so. - } else if (!(option_mask32 & FLAG_PATHLEN) || i <= prefix) { + } else if (!(option_mask32 & FLAG_PATHLEN) || i <= TT.prefix) { // If the old file was null, we're creating a new one. if (!strcmp(oldname, "/dev/null") || !oldsum) { printf("creating %s\n", name); @@ -528,7 +559,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) xmkpath(name, -1); *s = '/'; } - TT.filein = xopen3(name, O_CREAT|O_EXCL|O_RDWR, 0666); + TT.filein = xopen(name, O_CREAT|O_EXCL|O_RDWR); } else { printf("patching file %s\n", name); TT.filein = xopen(name, O_RDWR); @@ -551,6 +582,7 @@ int patch_main(int argc UNUSED_PARAM, char **argv) finish_oldfile(); if (ENABLE_FEATURE_CLEAN_UP) { + close(TT.filepatch); free(oldname); free(newname); } diff --git a/editors/sed.c b/editors/sed.c index 7af8f86..e18e48a 100644 --- a/editors/sed.c +++ b/editors/sed.c @@ -10,56 +10,93 @@ * * MAINTAINER: Rob Landley * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* Code overview. + * + * Files are laid out to avoid unnecessary function declarations. So for + * example, every function add_cmd calls occurs before add_cmd in this file. + * + * add_cmd() is called on each line of sed command text (from a file or from + * the command line). It calls get_address() and parse_cmd_args(). The + * resulting sed_cmd_t structures are appended to a linked list + * (G.sed_cmd_head/G.sed_cmd_tail). + * + * process_files() does actual sedding, reading data lines from each input FILE* + * (which could be stdin) and applying the sed command list (sed_cmd_head) to + * each of the resulting lines. + * + * sed_main() is where external code calls into this, with a command line. + */ - Files are laid out to avoid unnecessary function declarations. So for - example, every function add_cmd calls occurs before add_cmd in this file. - - add_cmd() is called on each line of sed command text (from a file or from - the command line). It calls get_address() and parse_cmd_args(). The - resulting sed_cmd_t structures are appended to a linked list - (G.sed_cmd_head/G.sed_cmd_tail). - - add_input_file() adds a FILE* to the list of input files. We need to - know all input sources ahead of time to find the last line for the $ match. - - process_files() does actual sedding, reading data lines from each input FILE * - (which could be stdin) and applying the sed command list (sed_cmd_head) to - each of the resulting lines. - - sed_main() is where external code calls into this, with a command line. -*/ - - -/* - Supported features and commands in this version of sed: +/* Supported features and commands in this version of sed: + * + * - comments ('#') + * - address matching: num|/matchstr/[,num|/matchstr/|$]command + * - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) + * - edit commands: (a)ppend, (i)nsert, (c)hange + * - file commands: (r)ead + * - backreferences in substitution expressions (\0, \1, \2...\9) + * - grouped commands: {cmd1;cmd2} + * - transliteration (y/source-chars/dest-chars/) + * - pattern space hold space storing / swapping (g, h, x) + * - labels / branching (: label, b, t, T) + * + * (Note: Specifying an address (range) to match is *optional*; commands + * default to the whole pattern space if no specific address match was + * requested.) + * + * Todo: + * - Create a wrapper around regex to make libc's regex conform with sed + * + * Reference + * http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/sed.html + */ - - comments ('#') - - address matching: num|/matchstr/[,num|/matchstr/|$]command - - commands: (p)rint, (d)elete, (s)ubstitue (with g & I flags) - - edit commands: (a)ppend, (i)nsert, (c)hange - - file commands: (r)ead - - backreferences in substitution expressions (\0, \1, \2...\9) - - grouped commands: {cmd1;cmd2} - - transliteration (y/source-chars/dest-chars/) - - pattern space hold space storing / swapping (g, h, x) - - labels / branching (: label, b, t, T) +//config:config SED +//config: bool "sed" +//config: default y +//config: help +//config: sed is used to perform text transformations on a file +//config: or input from a pipeline. + +//kbuild:lib-$(CONFIG_SED) += sed.o + +//applet:IF_SED(APPLET(sed, BB_DIR_BIN, BB_SUID_DROP)) + +//usage:#define sed_trivial_usage +//usage: "[-inrE] [-f FILE]... [-e CMD]... [FILE]...\n" +//usage: "or: sed [-inrE] CMD [FILE]..." +//usage:#define sed_full_usage "\n\n" +//usage: " -e CMD Add CMD to sed commands to be executed" +//usage: "\n -f FILE Add FILE contents to sed commands to be executed" +//usage: "\n -i[SFX] Edit files in-place (otherwise sends to stdout)" +//usage: "\n Optionally back files up, appending SFX" +//usage: "\n -n Suppress automatic printing of pattern space" +//usage: "\n -r,-E Use extended regex syntax" +//usage: "\n" +//usage: "\nIf no -e or -f, the first non-option argument is the sed command string." +//usage: "\nRemaining arguments are input files (stdin if none)." +//usage: +//usage:#define sed_example_usage +//usage: "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" +//usage: "bar\n" - (Note: Specifying an address (range) to match is *optional*; commands - default to the whole pattern space if no specific address match was - requested.) +#include "libbb.h" +#include "xregex.h" - Todo: - - Create a wrapper around regex to make libc's regex conform with sed +#if 0 +# define dbg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg(...) ((void)0) +#endif - Reference http://www.opengroup.org/onlinepubs/007904975/utilities/sed.html -*/ -#include "libbb.h" -#include "xregex.h" +enum { + OPT_in_place = 1 << 0, +}; /* Each sed command turns into one of these structures. */ typedef struct sed_cmd_s { @@ -71,6 +108,7 @@ typedef struct sed_cmd_s { regex_t *end_match; /* sed -e '/match/,/end_match/cmd' */ regex_t *sub_match; /* For 's/sub_match/string/' */ int beg_line; /* 'sed 1p' 0 == apply commands to all lines */ + int beg_line_orig; /* copy of the above, needed for -i */ int end_line; /* 'sed 1,3p' 0 == one line only. -1 = last line ($) */ FILE *sw_file; /* File (sw) command writes to, -1 for none. */ @@ -94,33 +132,36 @@ static const char semicolon_whitespace[] ALIGN1 = "; \n\r\t\v"; struct globals { /* options */ int be_quiet, regex_type; + FILE *nonstdout; char *outname, *hold_space; + smallint exitcode; - /* List of input files */ - int input_file_count, current_input_file; - FILE **input_file_list; + /* list of input files */ + int current_input_file, last_input_file; + char **input_file_list; + FILE *current_fp; regmatch_t regmatch[10]; regex_t *previous_regex_ptr; /* linked list of sed commands */ - sed_cmd_t sed_cmd_head, *sed_cmd_tail; + sed_cmd_t *sed_cmd_head, **sed_cmd_tail; - /* Linked list of append lines */ + /* linked list of append lines */ llist_t *append_head; char *add_cmd_line; struct pipeline { - char *buf; /* Space to hold string */ - int idx; /* Space used */ - int len; /* Space allocated */ + char *buf; /* Space to hold string */ + int idx; /* Space used */ + int len; /* Space allocated */ } pipeline; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; #define INIT_G() do { \ G.sed_cmd_tail = &G.sed_cmd_head; \ @@ -130,7 +171,7 @@ struct BUG_G_too_big { #if ENABLE_FEATURE_CLEAN_UP static void sed_free_and_close_stuff(void) { - sed_cmd_t *sed_cmd = G.sed_cmd_head.next; + sed_cmd_t *sed_cmd = G.sed_cmd_head; llist_free(G.append_head, free); @@ -159,8 +200,8 @@ static void sed_free_and_close_stuff(void) free(G.hold_space); - while (G.current_input_file < G.input_file_count) - fclose(G.input_file_list[G.current_input_file++]); + if (G.current_fp) + fclose(G.current_fp); } #else void sed_free_and_close_stuff(void); @@ -196,11 +237,16 @@ static void parse_escapes(char *dest, const char *string, int len, char from, ch static char *copy_parsing_escapes(const char *string, int len) { + const char *s; char *dest = xmalloc(len + 1); - parse_escapes(dest, string, len, 'n', '\n'); - /* GNU sed also recognizes \t */ - parse_escapes(dest, dest, strlen(dest), 't', '\t'); + /* sed recognizes \n */ + /* GNU sed also recognizes \t and \r */ + for (s = "\nn\tt\rr"; *s; s += 2) { + parse_escapes(dest, string, len, s[1], s[0]); + string = dest; + len = strlen(dest); + } return dest; } @@ -223,11 +269,13 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) delimiter = -delimiter; } - for (; (ch = str[idx]); idx++) { + for (; (ch = str[idx]) != '\0'; idx++) { if (bracket >= 0) { - if (ch == ']' && !(bracket == idx - 1 || (bracket == idx - 2 - && str[idx - 1] == '^'))) + if (ch == ']' + && !(bracket == idx - 1 || (bracket == idx - 2 && str[idx - 1] == '^')) + ) { bracket = -1; + } } else if (escaped) escaped = 0; else if (ch == '\\') @@ -248,7 +296,7 @@ static int index_of_next_unescaped_regexp_delim(int delimiter, const char *str) static int parse_regex_delim(const char *cmdstr, char **match, char **replace) { const char *cmdstr_ptr = cmdstr; - char delimiter; + unsigned char delimiter; int idx = 0; /* verify that the 's' or 'y' is followed by something. That something @@ -263,7 +311,7 @@ static int parse_regex_delim(const char *cmdstr, char **match, char **replace) /* save the replacement string */ cmdstr_ptr += idx + 1; - idx = index_of_next_unescaped_regexp_delim(-delimiter, cmdstr_ptr); + idx = index_of_next_unescaped_regexp_delim(- (int)delimiter, cmdstr_ptr); *replace = copy_parsing_escapes(cmdstr_ptr, idx); return ((cmdstr_ptr - cmdstr) + idx); @@ -288,11 +336,12 @@ static int get_address(const char *my_str, int *linenum, regex_t ** regex) char *temp; delimiter = '/'; - if (*my_str == '\\') delimiter = *++pos; + if (*my_str == '\\') + delimiter = *++pos; next = index_of_next_unescaped_regexp_delim(delimiter, ++pos); temp = copy_parsing_escapes(pos, next); - *regex = xmalloc(sizeof(regex_t)); - xregcomp(*regex, temp, G.regex_type|REG_NEWLINE); + *regex = xzalloc(sizeof(regex_t)); + xregcomp(*regex, temp, G.regex_type); free(temp); /* Move position to next character after last delimiter */ pos += (next+1); @@ -332,7 +381,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) /* * A substitution command should look something like this: - * s/match/replace/ #gIpw + * s/match/replace/ #giIpw * || | ||| * mandatory optional */ @@ -380,6 +429,7 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) break; } /* Ignore case (gnu exension) */ + case 'i': case 'I': cflags |= REG_ICASE; break; @@ -400,8 +450,10 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) /* compile the match string into a regex */ if (*match != '\0') { /* If match is empty, we use last regex used at runtime */ - sed_cmd->sub_match = xmalloc(sizeof(regex_t)); + sed_cmd->sub_match = xzalloc(sizeof(regex_t)); + dbg("xregcomp('%s',%x)", match, cflags); xregcomp(sed_cmd->sub_match, match, cflags); + dbg("regcomp ok"); } free(match); @@ -413,13 +465,51 @@ static int parse_subst_cmd(sed_cmd_t *sed_cmd, const char *substr) */ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) { + static const char cmd_letters[] = "saicrw:btTydDgGhHlnNpPqx={}"; + enum { + IDX_s = 0, + IDX_a, + IDX_i, + IDX_c, + IDX_r, + IDX_w, + IDX_colon, + IDX_b, + IDX_t, + IDX_T, + IDX_y, + IDX_d, + IDX_D, + IDX_g, + IDX_G, + IDX_h, + IDX_H, + IDX_l, + IDX_n, + IDX_N, + IDX_p, + IDX_P, + IDX_q, + IDX_x, + IDX_equal, + IDX_lbrace, + IDX_rbrace, + IDX_nul + }; + struct chk { char chk[sizeof(cmd_letters)-1 == IDX_nul ? 1 : -1]; }; + + unsigned idx = strchrnul(cmd_letters, sed_cmd->cmd) - cmd_letters; + /* handle (s)ubstitution command */ - if (sed_cmd->cmd == 's') + if (idx == IDX_s) { cmdstr += parse_subst_cmd(sed_cmd, cmdstr); + } /* handle edit cmds: (a)ppend, (i)nsert, and (c)hange */ - else if (strchr("aic", sed_cmd->cmd)) { - if ((sed_cmd->end_line || sed_cmd->end_match) && sed_cmd->cmd != 'c') - bb_error_msg_and_die("only a beginning address can be specified for edit commands"); + else if (idx <= IDX_c) { /* a,i,c */ + if (idx < IDX_c) { /* a,i */ + if (sed_cmd->end_line || sed_cmd->end_match) + bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); + } for (;;) { if (*cmdstr == '\n' || *cmdstr == '\\') { cmdstr++; @@ -433,17 +523,21 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) /* "\anychar" -> "anychar" */ parse_escapes(sed_cmd->string, sed_cmd->string, strlen(cmdstr), '\0', '\0'); cmdstr += strlen(cmdstr); + } /* handle file cmds: (r)ead */ - } else if (strchr("rw", sed_cmd->cmd)) { - if (sed_cmd->end_line || sed_cmd->end_match) - bb_error_msg_and_die("command only uses one address"); + else if (idx <= IDX_w) { /* r,w */ + if (idx < IDX_w) { /* r */ + if (sed_cmd->end_line || sed_cmd->end_match) + bb_error_msg_and_die("command '%c' uses only one address", sed_cmd->cmd); + } cmdstr += parse_file_cmd(/*sed_cmd,*/ cmdstr, &sed_cmd->string); if (sed_cmd->cmd == 'w') { sed_cmd->sw_file = xfopen_for_write(sed_cmd->string); sed_cmd->sw_last_char = '\n'; } + } /* handle branch commands */ - } else if (strchr(":btT", sed_cmd->cmd)) { + else if (idx <= IDX_T) { /* :,b,t,T */ int length; cmdstr = skip_whitespace(cmdstr); @@ -454,7 +548,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) } } /* translation command */ - else if (sed_cmd->cmd == 'y') { + else if (idx == IDX_y) { char *match, *replace; int i = cmdstr[0]; @@ -474,7 +568,7 @@ static const char *parse_cmd_args(sed_cmd_t *sed_cmd, const char *cmdstr) /* if it wasnt a single-letter command that takes no arguments * then it must be an invalid command. */ - else if (strchr("dDgGhHlnNpPqx={}", sed_cmd->cmd) == 0) { + else if (idx >= IDX_nul) { /* not d,D,g,G,h,H,l,n,N,p,P,q,x,=,{,} */ bb_error_msg_and_die("unsupported command %c", sed_cmd->cmd); } @@ -536,6 +630,7 @@ static void add_cmd(const char *cmdstr) /* first part (if present) is an address: either a '$', a number or a /regex/ */ cmdstr += get_address(cmdstr, &sed_cmd->beg_line, &sed_cmd->beg_match); + sed_cmd->beg_line_orig = sed_cmd->beg_line; /* second part (if present) will begin with a comma */ if (*cmdstr == ',') { @@ -566,9 +661,15 @@ static void add_cmd(const char *cmdstr) sed_cmd->cmd = *cmdstr++; cmdstr = parse_cmd_args(sed_cmd, cmdstr); + /* cmdstr now points past args. + * GNU sed requires a separator, if there are more commands, + * else it complains "char N: extra characters after command". + * Example: "sed 'p;d'". We also allow "sed 'pd'". + */ + /* Add the command to the command array */ - G.sed_cmd_tail->next = sed_cmd; - G.sed_cmd_tail = G.sed_cmd_tail->next; + *G.sed_cmd_tail = sed_cmd; + G.sed_cmd_tail = &sed_cmd->next; } /* If we glued multiple lines together, free the memory. */ @@ -596,7 +697,7 @@ static void do_subst_w_backrefs(char *line, char *replace) /* go through the replacement string */ for (i = 0; replace[i]; i++) { - /* if we find a backreference (\1, \2, etc.) print the backref'ed * text */ + /* if we find a backreference (\1, \2, etc.) print the backref'ed text */ if (replace[i] == '\\') { unsigned backref = replace[++i] - '0'; if (backref <= 9) { @@ -630,8 +731,10 @@ static void do_subst_w_backrefs(char *line, char *replace) static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) { char *line = *line_p; - int altered = 0; unsigned match_count = 0; + bool altered = 0; + bool prev_match_empty = 1; + bool tried_at_eol = 0; regex_t *current_regex; current_regex = sed_cmd->sub_match; @@ -644,8 +747,12 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) G.previous_regex_ptr = current_regex; /* Find the first match */ - if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) + dbg("matching '%s'", line); + if (REG_NOMATCH == regexec(current_regex, line, 10, G.regmatch, 0)) { + dbg("no match"); return 0; + } + dbg("match"); /* Initialize temporary output buffer. */ G.pipeline.buf = xmalloc(PIPE_GROW); @@ -654,47 +761,76 @@ static int do_subst_command(sed_cmd_t *sed_cmd, char **line_p) /* Now loop through, substituting for matches */ do { + int start = G.regmatch[0].rm_so; + int end = G.regmatch[0].rm_eo; int i; - /* Work around bug in glibc regexec, demonstrated by: - echo " a.b" | busybox sed 's [^ .]* x g' - The match_count check is so not to break - echo "hi" | busybox sed 's/^/!/g' */ - if (!G.regmatch[0].rm_so && !G.regmatch[0].rm_eo && match_count) { - pipe_putc(*line++); - continue; - } - match_count++; /* If we aren't interested in this match, output old line to - end of match and continue */ + * end of match and continue */ if (sed_cmd->which_match && (sed_cmd->which_match != match_count) ) { - for (i = 0; i < G.regmatch[0].rm_eo; i++) + for (i = 0; i < end; i++) pipe_putc(*line++); - continue; + /* Null match? Print one more char */ + if (start == end && *line) + pipe_putc(*line++); + goto next; } - /* print everything before the match */ - for (i = 0; i < G.regmatch[0].rm_so; i++) + /* Print everything before the match */ + for (i = 0; i < start; i++) pipe_putc(line[i]); - /* then print the substitution string */ - do_subst_w_backrefs(line, sed_cmd->string); + /* Then print the substitution string, + * unless we just matched empty string after non-empty one. + * Example: string "cccd", pattern "c*", repl "R": + * result is "RdR", not "RRdR": first match "ccc", + * second is "" before "d", third is "" after "d". + * Second match is NOT replaced! + */ + if (prev_match_empty || start != 0 || start != end) { + //dbg("%d %d %d", prev_match_empty, start, end); + dbg("inserting replacement at %d in '%s'", start, line); + do_subst_w_backrefs(line, sed_cmd->string); + /* Flag that something has changed */ + altered = 1; + } else { + dbg("NOT inserting replacement at %d in '%s'", start, line); + } + + /* If matched string is empty (f.e. "c*" pattern), + * copy verbatim one char after it before attempting more matches + */ + prev_match_empty = (start == end); + if (prev_match_empty) { + if (!line[end]) { + tried_at_eol = 1; + } else { + pipe_putc(line[end]); + end++; + } + } - /* advance past the match */ - line += G.regmatch[0].rm_eo; - /* flag that something has changed */ - altered++; + /* Advance past the match */ + dbg("line += %d", end); + line += end; /* if we're not doing this globally, get out now */ - if (sed_cmd->which_match) + if (sed_cmd->which_match != 0) break; + next: + /* Exit if we are at EOL and already tried matching at it */ + if (*line == '\0') { + if (tried_at_eol) + break; + tried_at_eol = 1; + } -//maybe (G.regmatch[0].rm_eo ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? - } while (*line && regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); +//maybe (end ? REG_NOTBOL : 0) instead of unconditional REG_NOTBOL? + } while (regexec(current_regex, line, 10, G.regmatch, REG_NOTBOL) != REG_NOMATCH); /* Copy rest of string into output pipeline */ while (1) { @@ -714,7 +850,7 @@ static sed_cmd_t *branch_to(char *label) { sed_cmd_t *sed_cmd; - for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { if (sed_cmd->cmd == ':' && sed_cmd->string && !strcmp(sed_cmd->string, label)) { return sed_cmd; } @@ -724,46 +860,100 @@ static sed_cmd_t *branch_to(char *label) static void append(char *s) { - llist_add_to_end(&G.append_head, xstrdup(s)); + llist_add_to_end(&G.append_head, s); +} + +/* Output line of text. */ +/* Note: + * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed. + * Without them, we had this: + * echo -n thingy >z1 + * echo -n again >z2 + * >znull + * sed "s/i/z/" z1 z2 znull | hexdump -vC + * output: + * gnu sed 4.1.5: + * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| + * bbox: + * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| + */ +enum { + NO_EOL_CHAR = 1, + LAST_IS_NUL = 2, +}; +static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char) +{ + char lpc = *last_puts_char; + + /* Need to insert a '\n' between two files because first file's + * last line wasn't terminated? */ + if (lpc != '\n' && lpc != '\0') { + fputc('\n', file); + lpc = '\n'; + } + fputs(s, file); + + /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */ + if (s[0]) + lpc = 'x'; + + /* had trailing '\0' and it was last char of file? */ + if (last_gets_char == LAST_IS_NUL) { + fputc('\0', file); + lpc = 'x'; /* */ + } else + /* had trailing '\n' or '\0'? */ + if (last_gets_char != NO_EOL_CHAR) { + fputc(last_gets_char, file); + lpc = last_gets_char; + } + + if (ferror(file)) { + xfunc_error_retval = 4; /* It's what gnu sed exits with... */ + bb_error_msg_and_die(bb_msg_write_error); + } + *last_puts_char = lpc; } -static void flush_append(void) +static void flush_append(char *last_puts_char, char last_gets_char) { char *data; /* Output appended lines. */ while ((data = (char *)llist_pop(&G.append_head))) { - fprintf(G.nonstdout, "%s\n", data); + puts_maybe_newline(data, G.nonstdout, last_puts_char, last_gets_char); free(data); } } -static void add_input_file(FILE *file) -{ - G.input_file_list = xrealloc_vector(G.input_file_list, 2, G.input_file_count); - G.input_file_list[G.input_file_count++] = file; -} - /* Get next line of input from G.input_file_list, flushing append buffer and * noting if we ran out of files without a newline on the last line we read. */ -enum { - NO_EOL_CHAR = 1, - LAST_IS_NUL = 2, -}; -static char *get_next_line(char *gets_char) +static char *get_next_line(char *gets_char, char *last_puts_char, char last_gets_char) { char *temp = NULL; int len; char gc; - flush_append(); + flush_append(last_puts_char, last_gets_char); /* will be returned if last line in the file * doesn't end with either '\n' or '\0' */ gc = NO_EOL_CHAR; - while (G.current_input_file < G.input_file_count) { - FILE *fp = G.input_file_list[G.current_input_file]; + for (; G.current_input_file <= G.last_input_file; G.current_input_file++) { + FILE *fp = G.current_fp; + if (!fp) { + const char *path = G.input_file_list[G.current_input_file]; + fp = stdin; + if (path != bb_msg_standard_input) { + fp = fopen_or_warn(path, "r"); + if (!fp) { + G.exitcode = EXIT_FAILURE; + continue; + } + } + G.current_fp = fp; + } /* Read line up to a newline or NUL byte, inclusive, * return malloc'ed char[]. length of the chunk read * is stored in len. NULL if EOF/error */ @@ -794,61 +984,13 @@ static char *get_next_line(char *gets_char) * (note: *no* newline after "b bang"!) */ } /* Close this file and advance to next one */ - fclose(fp); - G.current_input_file++; + fclose_if_not_stdin(fp); + G.current_fp = NULL; } *gets_char = gc; return temp; } -/* Output line of text. */ -/* Note: - * The tricks with NO_EOL_CHAR and last_puts_char are there to emulate gnu sed. - * Without them, we had this: - * echo -n thingy >z1 - * echo -n again >z2 - * >znull - * sed "s/i/z/" z1 z2 znull | hexdump -vC - * output: - * gnu sed 4.1.5: - * 00000000 74 68 7a 6e 67 79 0a 61 67 61 7a 6e |thzngy.agazn| - * bbox: - * 00000000 74 68 7a 6e 67 79 61 67 61 7a 6e |thzngyagazn| - */ -static void puts_maybe_newline(char *s, FILE *file, char *last_puts_char, char last_gets_char) -{ - char lpc = *last_puts_char; - - /* Need to insert a '\n' between two files because first file's - * last line wasn't terminated? */ - if (lpc != '\n' && lpc != '\0') { - fputc('\n', file); - lpc = '\n'; - } - fputs(s, file); - - /* 'x' - just something which is not '\n', '\0' or NO_EOL_CHAR */ - if (s[0]) - lpc = 'x'; - - /* had trailing '\0' and it was last char of file? */ - if (last_gets_char == LAST_IS_NUL) { - fputc('\0', file); - lpc = 'x'; /* */ - } else - /* had trailing '\n' or '\0'? */ - if (last_gets_char != NO_EOL_CHAR) { - fputc(last_gets_char, file); - lpc = last_gets_char; - } - - if (ferror(file)) { - xfunc_error_retval = 4; /* It's what gnu sed exits with... */ - bb_error_msg_and_die(bb_msg_write_error); - } - *last_puts_char = lpc; -} - #define sed_puts(s, n) (puts_maybe_newline(s, G.nonstdout, &last_puts_char, n)) static int beg_match(sed_cmd_t *sed_cmd, const char *pattern_space) @@ -871,7 +1013,7 @@ static void process_files(void) int substituted; /* Prime the pump */ - next_line = get_next_line(&next_gets_char); + next_line = get_next_line(&next_gets_char, &last_puts_char, '\n' /*last_gets_char*/); /* Go through every line in each file */ again: @@ -885,29 +1027,29 @@ static void process_files(void) /* Read one line in advance so we can act on the last line, * the '$' address */ - next_line = get_next_line(&next_gets_char); + next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char); linenum++; /* For every line, go through all the commands */ restart: - for (sed_cmd = G.sed_cmd_head.next; sed_cmd; sed_cmd = sed_cmd->next) { + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { int old_matched, matched; old_matched = sed_cmd->in_match; /* Determine if this command matches this line: */ - //bb_error_msg("match1:%d", sed_cmd->in_match); - //bb_error_msg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line - // && !sed_cmd->beg_match && !sed_cmd->end_match)); - //bb_error_msg("match3:%d", (sed_cmd->beg_line > 0 - // && (sed_cmd->end_line || sed_cmd->end_match - // ? (sed_cmd->beg_line <= linenum) - // : (sed_cmd->beg_line == linenum) - // ) - // ) - //bb_error_msg("match4:%d", (beg_match(sed_cmd, pattern_space))); - //bb_error_msg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); + dbg("match1:%d", sed_cmd->in_match); + dbg("match2:%d", (!sed_cmd->beg_line && !sed_cmd->end_line + && !sed_cmd->beg_match && !sed_cmd->end_match)); + dbg("match3:%d", (sed_cmd->beg_line > 0 + && (sed_cmd->end_line || sed_cmd->end_match + ? (sed_cmd->beg_line <= linenum) + : (sed_cmd->beg_line == linenum) + ) + )); + dbg("match4:%d", (beg_match(sed_cmd, pattern_space))); + dbg("match5:%d", (sed_cmd->beg_line == -1 && next_line == NULL)); /* Are we continuing a previous multi-line match? */ sed_cmd->in_match = sed_cmd->in_match @@ -918,7 +1060,14 @@ static void process_files(void) || (sed_cmd->beg_line > 0 && (sed_cmd->end_line || sed_cmd->end_match /* note: even if end is numeric and is < linenum too, - * GNU sed matches! We match too */ + * GNU sed matches! We match too, therefore we don't + * check here that linenum <= end. + * Example: + * printf '1\n2\n3\n4\n' | sed -n '1{N;N;d};1p;2,3p;3p;4p' + * first three input lines are deleted; + * 4th line is matched and printed + * by "2,3" (!) and by "4" ranges + */ ? (sed_cmd->beg_line <= linenum) /* N,end */ : (sed_cmd->beg_line == linenum) /* N */ ) @@ -931,27 +1080,29 @@ static void process_files(void) /* Snapshot the value */ matched = sed_cmd->in_match; - //bb_error_msg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", - //sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); + dbg("cmd:'%c' matched:%d beg_line:%d end_line:%d linenum:%d", + sed_cmd->cmd, matched, sed_cmd->beg_line, sed_cmd->end_line, linenum); /* Is this line the end of the current match? */ if (matched) { /* once matched, "n,xxx" range is dead, disabling it */ - if (sed_cmd->beg_line > 0) + if (sed_cmd->beg_line > 0) { sed_cmd->beg_line = -2; + } sed_cmd->in_match = !( /* has the ending line come, or is this a single address command? */ - (sed_cmd->end_line ? - sed_cmd->end_line == -1 ? - !next_line + (sed_cmd->end_line + ? sed_cmd->end_line == -1 + ? !next_line : (sed_cmd->end_line <= linenum) : !sed_cmd->end_match ) /* or does this line matches our last address regex */ || (sed_cmd->end_match && old_matched && (regexec(sed_cmd->end_match, - pattern_space, 0, NULL, 0) == 0)) + pattern_space, 0, NULL, 0) == 0) + ) ); } @@ -985,6 +1136,8 @@ static void process_files(void) } /* actual sedding */ + dbg("pattern_space:'%s' next_line:'%s' cmd:%c", + pattern_space, next_line, sed_cmd->cmd); switch (sed_cmd->cmd) { /* Print line number */ @@ -1031,6 +1184,7 @@ static void process_files(void) case 's': if (!do_subst_command(sed_cmd, &pattern_space)) break; + dbg("do_subst_command succeeded:'%s'", pattern_space); substituted |= 1; /* handle p option */ @@ -1045,7 +1199,7 @@ static void process_files(void) /* Append line to linked list to be printed later */ case 'a': - append(sed_cmd->string); + append(xstrdup(sed_cmd->string)); break; /* Insert text before this line */ @@ -1067,11 +1221,10 @@ static void process_files(void) rfile = fopen_for_read(sed_cmd->string); if (rfile) { char *line; - while ((line = xmalloc_fgetline(rfile)) != NULL) append(line); - xprint_and_close_file(rfile); + fclose(rfile); } break; @@ -1092,7 +1245,7 @@ static void process_files(void) free(pattern_space); pattern_space = next_line; last_gets_char = next_gets_char; - next_line = get_next_line(&next_gets_char); + next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char); substituted = 0; linenum++; break; @@ -1111,10 +1264,16 @@ static void process_files(void) { int len; /* If no next line, jump to end of script and exit. */ + /* http://www.gnu.org/software/sed/manual/sed.html: + * "Most versions of sed exit without printing anything + * when the N command is issued on the last line of + * a file. GNU sed prints pattern space before exiting + * unless of course the -n command switch has been + * specified. This choice is by design." + */ if (next_line == NULL) { - free(next_line); - next_line = NULL; - goto discard_line; + //goto discard_line; + goto discard_commands; /* GNU behavior */ } /* Append next_line, read new next_line. */ len = strlen(pattern_space); @@ -1122,7 +1281,7 @@ static void process_files(void) pattern_space[len] = '\n'; strcpy(pattern_space + len+1, next_line); last_gets_char = next_gets_char; - next_line = get_next_line(&next_gets_char); + next_line = get_next_line(&next_gets_char, &last_puts_char, last_gets_char); linenum++; break; } @@ -1226,7 +1385,7 @@ static void process_files(void) /* Delete and such jump here. */ discard_line: - flush_append(); + flush_append(&last_puts_char, last_gets_char); free(pattern_space); goto again; @@ -1235,7 +1394,7 @@ static void process_files(void) /* It is possible to have a command line argument with embedded * newlines. This counts as multiple command lines. * However, newline can be escaped: 's/e/z\z/' - * We check for this. + * add_cmd() handles this. */ static void add_cmd_block(char *cmdstr) @@ -1245,22 +1404,8 @@ static void add_cmd_block(char *cmdstr) cmdstr = sv = xstrdup(cmdstr); do { eol = strchr(cmdstr, '\n'); - next: - if (eol) { - /* Count preceding slashes */ - int slashes = 0; - char *sl = eol; - - while (sl != cmdstr && *--sl == '\\') - slashes++; - /* Odd number of preceding slashes - newline is escaped */ - if (slashes & 1) { - overlapping_strcpy(eol - 1, eol); - eol = strchr(eol, '\n'); - goto next; - } + if (eol) *eol = '\0'; - } add_cmd(cmdstr); cmdstr = eol + 1; } while (eol); @@ -1270,12 +1415,20 @@ static void add_cmd_block(char *cmdstr) int sed_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sed_main(int argc UNUSED_PARAM, char **argv) { - enum { - OPT_in_place = 1 << 0, - }; unsigned opt; llist_t *opt_e, *opt_f; - int status = EXIT_SUCCESS; + char *opt_i; + +#if ENABLE_LONG_OPTS + static const char sed_longopts[] ALIGN1 = + /* name has_arg short */ + "in-place\0" Optional_argument "i" + "regexp-extended\0" No_argument "r" + "quiet\0" No_argument "n" + "silent\0" No_argument "n" + "expression\0" Required_argument "e" + "file\0" Required_argument "f"; +#endif INIT_G(); @@ -1283,24 +1436,35 @@ int sed_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_CLEAN_UP) atexit(sed_free_and_close_stuff); /* Lie to autoconf when it starts asking stupid questions. */ - if (argv[1] && !strcmp(argv[1], "--version")) { + if (argv[1] && strcmp(argv[1], "--version") == 0) { puts("This is not GNU sed version 4.0"); return 0; } /* do normal option parsing */ opt_e = opt_f = NULL; + opt_i = NULL; opt_complementary = "e::f::" /* can occur multiple times */ "nn"; /* count -n */ - opt = getopt32(argv, "irne:f:", &opt_e, &opt_f, + + IF_LONG_OPTS(applet_long_options = sed_longopts); + + /* -i must be first, to match OPT_in_place definition */ + /* -E is a synonym of -r: + * GNU sed 4.2.1 mentions it in neither --help + * nor manpage, but does recognize it. + */ + opt = getopt32(argv, "i::rEne:f:", &opt_i, &opt_e, &opt_f, &G.be_quiet); /* counter for -n */ //argc -= optind; argv += optind; if (opt & OPT_in_place) { // -i atexit(cleanup_outname); } - if (opt & 0x2) G.regex_type |= REG_EXTENDED; // -r - //if (opt & 0x4) G.be_quiet++; // -n + if (opt & (2|4)) + G.regex_type |= REG_EXTENDED; // -r or -E + //if (opt & 8) + // G.be_quiet++; // -n (implemented with a counter instead) while (opt_e) { // -e add_cmd_block(llist_pop(&opt_e)); } @@ -1315,7 +1479,7 @@ int sed_main(int argc UNUSED_PARAM, char **argv) fclose(cmdfile); } /* if we didn't get a pattern from -e or -f, use argv[0] */ - if (!(opt & 0x18)) { + if (!(opt & 0x30)) { if (!*argv) bb_show_usage(); add_cmd_block(*argv++); @@ -1329,62 +1493,70 @@ int sed_main(int argc UNUSED_PARAM, char **argv) /* argv[0..(argc-1)] should be names of file to process. If no * files were specified or '-' was specified, take input from stdin. * Otherwise, we process all the files specified. */ - if (argv[0] == NULL) { + G.input_file_list = argv; + if (!argv[0]) { if (opt & OPT_in_place) bb_error_msg_and_die(bb_msg_requires_arg, "-i"); - add_input_file(stdin); + argv[0] = (char*)bb_msg_standard_input; + /* G.last_input_file = 0; - already is */ } else { - int i; - FILE *file; + goto start; - for (i = 0; argv[i]; i++) { + for (; *argv; argv++) { struct stat statbuf; int nonstdoutfd; + sed_cmd_t *sed_cmd; - if (LONE_DASH(argv[i]) && !(opt & OPT_in_place)) { - add_input_file(stdin); - process_files(); - continue; - } - file = fopen_or_warn(argv[i], "r"); - if (!file) { - status = EXIT_FAILURE; - continue; - } + G.last_input_file++; + start: if (!(opt & OPT_in_place)) { - add_input_file(file); + if (LONE_DASH(*argv)) { + *argv = (char*)bb_msg_standard_input; + process_files(); + } continue; } - G.outname = xasprintf("%sXXXXXX", argv[i]); - nonstdoutfd = mkstemp(G.outname); - if (-1 == nonstdoutfd) - bb_perror_msg_and_die("can't create temp file %s", G.outname); + /* -i: process each FILE separately: */ + + G.outname = xasprintf("%sXXXXXX", *argv); + nonstdoutfd = xmkstemp(G.outname); G.nonstdout = xfdopen_for_write(nonstdoutfd); /* Set permissions/owner of output file */ - fstat(fileno(file), &statbuf); + stat(*argv, &statbuf); /* chmod'ing AFTER chown would preserve suid/sgid bits, * but GNU sed 4.2.1 does not preserve them either */ fchmod(nonstdoutfd, statbuf.st_mode); fchown(nonstdoutfd, statbuf.st_uid, statbuf.st_gid); - add_input_file(file); + process_files(); fclose(G.nonstdout); - G.nonstdout = stdout; - /* unlink(argv[i]); */ - xrename(G.outname, argv[i]); + + if (opt_i) { + char *backupname = xasprintf("%s%s", *argv, opt_i); + xrename(*argv, backupname); + free(backupname); + } + /* else unlink(*argv); - rename below does this */ + xrename(G.outname, *argv); //TODO: rollback backup on error? free(G.outname); G.outname = NULL; + + /* Re-enable disabled range matches */ + for (sed_cmd = G.sed_cmd_head; sed_cmd; sed_cmd = sed_cmd->next) { + sed_cmd->beg_line = sed_cmd->beg_line_orig; + } } /* Here, to handle "sed 'cmds' nonexistent_file" case we did: - * if (G.current_input_file >= G.input_file_count) - * return status; + * if (G.current_input_file[G.current_input_file] == NULL) + * return G.exitcode; * but it's not needed since process_files() works correctly * in this case too. */ } + process_files(); - return status; + return G.exitcode; } diff --git a/editors/vi.c b/editors/vi.c index 73e095c..097f309 100644 --- a/editors/vi.c +++ b/editors/vi.c @@ -3,7 +3,7 @@ * tiny vi.c: A small 'vi' clone * Copyright (C) 2000, 2001 Sterling Huxley * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -14,14 +14,150 @@ * add :help command * :map macros * if mark[] values were line numbers rather than pointers - * it would be easier to change the mark when add/delete lines + * it would be easier to change the mark when add/delete lines * More intelligence in refresh() * ":r !cmd" and "!cmd" to filter text through an external command * A true "undo" facility * An "ex" line oriented mode- maybe using "cmdedit" */ +//config:config VI +//config: bool "vi" +//config: default y +//config: help +//config: 'vi' is a text editor. More specifically, it is the One True +//config: text editor . It does, however, have a rather steep +//config: learning curve. If you are not already comfortable with 'vi' +//config: you may wish to use something else. +//config: +//config:config FEATURE_VI_MAX_LEN +//config: int "Maximum screen width in vi" +//config: range 256 16384 +//config: default 4096 +//config: depends on VI +//config: help +//config: Contrary to what you may think, this is not eating much. +//config: Make it smaller than 4k only if you are very limited on memory. +//config: +//config:config FEATURE_VI_8BIT +//config: bool "Allow vi to display 8-bit chars (otherwise shows dots)" +//config: default n +//config: depends on VI +//config: help +//config: If your terminal can display characters with high bit set, +//config: you may want to enable this. Note: vi is not Unicode-capable. +//config: If your terminal combines several 8-bit bytes into one character +//config: (as in Unicode mode), this will not work properly. +//config: +//config:config FEATURE_VI_COLON +//config: bool "Enable \":\" colon commands (no \"ex\" mode)" +//config: default y +//config: depends on VI +//config: help +//config: Enable a limited set of colon commands for vi. This does not +//config: provide an "ex" mode. +//config: +//config:config FEATURE_VI_YANKMARK +//config: bool "Enable yank/put commands and mark cmds" +//config: default y +//config: depends on VI +//config: help +//config: This will enable you to use yank and put, as well as mark in +//config: busybox vi. +//config: +//config:config FEATURE_VI_SEARCH +//config: bool "Enable search and replace cmds" +//config: default y +//config: depends on VI +//config: help +//config: Select this if you wish to be able to do search and replace in +//config: busybox vi. +//config: +//config:config FEATURE_VI_REGEX_SEARCH +//config: bool "Enable regex in search and replace" +//config: default n # Uses GNU regex, which may be unavailable. FIXME +//config: depends on FEATURE_VI_SEARCH +//config: help +//config: Use extended regex search. +//config: +//config:config FEATURE_VI_USE_SIGNALS +//config: bool "Catch signals" +//config: default y +//config: depends on VI +//config: help +//config: Selecting this option will make busybox vi signal aware. This will +//config: make busybox vi support SIGWINCH to deal with Window Changes, catch +//config: Ctrl-Z and Ctrl-C and alarms. +//config: +//config:config FEATURE_VI_DOT_CMD +//config: bool "Remember previous cmd and \".\" cmd" +//config: default y +//config: depends on VI +//config: help +//config: Make busybox vi remember the last command and be able to repeat it. +//config: +//config:config FEATURE_VI_READONLY +//config: bool "Enable -R option and \"view\" mode" +//config: default y +//config: depends on VI +//config: help +//config: Enable the read-only command line option, which allows the user to +//config: open a file in read-only mode. +//config: +//config:config FEATURE_VI_SETOPTS +//config: bool "Enable set-able options, ai ic showmatch" +//config: default y +//config: depends on VI +//config: help +//config: Enable the editor to set some (ai, ic, showmatch) options. +//config: +//config:config FEATURE_VI_SET +//config: bool "Support for :set" +//config: default y +//config: depends on VI +//config: help +//config: Support for ":set". +//config: +//config:config FEATURE_VI_WIN_RESIZE +//config: bool "Handle window resize" +//config: default y +//config: depends on VI +//config: help +//config: Make busybox vi behave nicely with terminals that get resized. +//config: +//config:config FEATURE_VI_ASK_TERMINAL +//config: bool "Use 'tell me cursor position' ESC sequence to measure window" +//config: default y +//config: depends on VI +//config: help +//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, +//config: this option makes vi perform a last-ditch effort to find it: +//config: position cursor to 999,999 and ask terminal to report real +//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. +//config: +//config: This is not clean but helps a lot on serial lines and such. + +//applet:IF_VI(APPLET(vi, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_VI) += vi.o + +//usage:#define vi_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define vi_full_usage "\n\n" +//usage: "Edit FILE\n" +//usage: IF_FEATURE_VI_COLON( +//usage: "\n -c CMD Initial command to run ($EXINIT also available)" +//usage: ) +//usage: IF_FEATURE_VI_READONLY( +//usage: "\n -R Read-only" +//usage: ) +//usage: "\n -H List available features" + #include "libbb.h" +/* Should be after libbb.h: on some systems regex.h needs sys/types.h: */ +#if ENABLE_FEATURE_VI_REGEX_SEARCH +# include +#endif /* the CRASHME code is unmaintained, and doesn't currently build */ #define ENABLE_FEATURE_VI_CRASHME 0 @@ -40,9 +176,9 @@ /* 0x9b is Meta-ESC */ #if ENABLE_FEATURE_VI_8BIT -#define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) +# define Isprint(c) ((unsigned char)(c) >= ' ' && (c) != 0x7f && (unsigned char)(c) != 0x9b) #else -#define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) +# define Isprint(c) ((unsigned char)(c) >= ' ' && (unsigned char)(c) < 0x7f) #endif #endif @@ -58,20 +194,29 @@ enum { MAX_SCR_ROWS = CONFIG_FEATURE_VI_MAX_LEN, }; -/* vt102 typical ESC sequence */ -/* terminal standout start/normal ESC sequence */ -#define SOs "\033[7m" -#define SOn "\033[0m" -/* terminal bell sequence */ -#define bell "\007" -/* Clear-end-of-line and Clear-end-of-screen ESC sequence */ -#define Ceol "\033[K" -#define Ceos "\033[J" -/* Cursor motion arbitrary destination ESC sequence */ -#define CMrc "\033[%u;%uH" -/* Cursor motion up and down ESC sequence */ -#define CMup "\033[A" -#define CMdown "\n" +/* VT102 ESC sequences. + * See "Xterm Control Sequences" + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + */ +/* Inverse/Normal text */ +#define ESC_BOLD_TEXT "\033[7m" +#define ESC_NORM_TEXT "\033[0m" +/* Bell */ +#define ESC_BELL "\007" +/* Clear-to-end-of-line */ +#define ESC_CLEAR2EOL "\033[K" +/* Clear-to-end-of-screen. + * (We use default param here. + * Full sequence is "ESC [ J", + * is 0/1/2 = "erase below/above/all".) + */ +#define ESC_CLEAR2EOS "\033[J" +/* Cursor to given coordinate (1,1: top left) */ +#define ESC_SET_CURSOR_POS "\033[%u;%uH" +//UNUSED +///* Cursor up and down */ +//#define ESC_CURSOR_UP "\033[A" +//#define ESC_CURSOR_DOWN "\n" #if ENABLE_FEATURE_VI_DOT_CMD || ENABLE_FEATURE_VI_YANKMARK // cmds modifying text[] @@ -134,7 +279,6 @@ struct globals { smallint cmd_mode; // 0=command 1=insert 2=replace int file_modified; // buffer contents changed (counter, not flag!) int last_file_modified; // = -1; - int fn_start; // index of first cmd line file name int save_argc; // how many file names on cmd line int cmdcnt; // repetition count unsigned rows, columns; // the terminal screen is this size @@ -160,9 +304,6 @@ struct globals { int lmc_len; // length of last_modifying_cmd char *ioq, *ioq_start; // pointer to string for get_one_char to "read" #endif -#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR - int last_row; // where the cursor was last moved to -#endif #if ENABLE_FEATURE_VI_USE_SIGNALS || ENABLE_FEATURE_VI_CRASHME int my_pid; #endif @@ -219,7 +360,6 @@ struct globals { #define cmd_mode (G.cmd_mode ) #define file_modified (G.file_modified ) #define last_file_modified (G.last_file_modified ) -#define fn_start (G.fn_start ) #define save_argc (G.save_argc ) #define cmdcnt (G.cmdcnt ) #define rows (G.rows ) @@ -247,7 +387,6 @@ struct globals { #define lmc_len (G.lmc_len ) #define ioq (G.ioq ) #define ioq_start (G.ioq_start ) -#define last_row (G.last_row ) #define my_pid (G.my_pid ) #define last_search_pattern (G.last_search_pattern) @@ -328,10 +467,7 @@ static int file_size(const char *); // what is the byte size of "fn" // file_insert might reallocate text[]! static int file_insert(const char *, char *, int); static int file_write(char *, char *, char *); -#if !ENABLE_FEATURE_VI_OPTIMIZE_CURSOR -#define place_cursor(a, b, optimize) place_cursor(a, b) -#endif -static void place_cursor(int, int, int); +static void place_cursor(int, int); static void screen_erase(void); static void clear_to_eol(void); static void clear_to_eos(void); @@ -342,6 +478,7 @@ static void flash(int); // flash the terminal screen static void show_status_line(void); // put a message on the bottom line static void status_line(const char *, ...); // print to status buf static void status_line_bold(const char *, ...); +static void status_line_bold_errno(const char *fn); static void not_implemented(const char *); // display "Not implemented" message static int format_edit_status(void); // format file status on status line static void redraw(int); // force a full screen refresh @@ -354,7 +491,6 @@ static void Hit_Return(void); #if ENABLE_FEATURE_VI_SEARCH static char *char_search(char *, const char *, int, int); // search for pattern starting at p -static int mycmp(const char *, const char *, int); // string cmp based in "ignorecase" #endif #if ENABLE_FEATURE_VI_COLON static char *get_one_address(char *, int *); // get colon addr, if present @@ -417,7 +553,8 @@ int vi_main(int argc, char **argv) } #endif - vi_setops = VI_AUTOINDENT | VI_SHOWMATCH | VI_IGNORECASE; + // autoindent is not default in vim 7.3 + vi_setops = /*VI_AUTOINDENT |*/ VI_SHOWMATCH | VI_IGNORECASE; // 1- process $HOME/.exrc file (not inplemented yet) // 2- process EXINIT variable from environment // 3- process command line args @@ -443,7 +580,7 @@ int vi_main(int argc, char **argv) #if ENABLE_FEATURE_VI_COLON case 'c': // cmd line vi command if (*optarg) - initial_cmds[initial_cmds[0] != 0] = xstrndup(optarg, MAX_INPUT_LEN); + initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); break; #endif case 'H': @@ -456,16 +593,21 @@ int vi_main(int argc, char **argv) } // The argv array can be used by the ":next" and ":rewind" commands - // save optind. - fn_start = optind; // remember first file name for :next and :rew - save_argc = argc; + argv += optind; + argc -= optind; //----- This is the main file handling loop -------------- + save_argc = argc; + optind = 0; + // "Save cursor, use alternate screen buffer, clear screen" + write1("\033[?1049h"); while (1) { edit_file(argv[optind]); /* param might be NULL */ if (++optind >= argc) break; } + // "Use normal screen buffer, restore cursor" + write1("\033[?1049l"); //----------------------------------------------------------- return 0; @@ -523,7 +665,6 @@ static void edit_file(char *fn) #define cur_line edit_file__cur_line #endif int c; - int size; #if ENABLE_FEATURE_VI_USE_SIGNALS int sig; #endif @@ -532,7 +673,6 @@ static void edit_file(char *fn) rawmode(); rows = 24; columns = 80; - size = 0; IF_FEATURE_VI_ASK_TERMINAL(G.get_rowcol_error =) query_screen_dimensions(); #if ENABLE_FEATURE_VI_ASK_TERMINAL if (G.get_rowcol_error /* TODO? && no input on stdin */) { @@ -880,7 +1020,7 @@ static void colon(char *buf) } else if (strncmp(cmd, "edit", i) == 0) { // Edit a file // don't edit, if the current file has been modified if (file_modified && !useforce) { - status_line_bold("No write since last change (:edit! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } if (args[0]) { @@ -899,18 +1039,18 @@ static void colon(char *buf) goto ret; #if ENABLE_FEATURE_VI_YANKMARK - if (Ureg >= 0 && Ureg < 28 && reg[Ureg] != 0) { + if (Ureg >= 0 && Ureg < 28) { free(reg[Ureg]); // free orig line reg- for 'U' - reg[Ureg]= 0; + reg[Ureg] = NULL; } - if (YDreg >= 0 && YDreg < 28 && reg[YDreg] != 0) { + if (YDreg >= 0 && YDreg < 28) { free(reg[YDreg]); // free default yank/delete register - reg[YDreg]= 0; + reg[YDreg] = NULL; } #endif // how many lines in text[]? li = count_lines(text, end - 1); - status_line("\"%s\"%s" + status_line("'%s'%s" IF_FEATURE_VI_READONLY("%s") " %dL, %dC", current_filename, (file_size(fn) < 0 ? " [New file]" : ""), @@ -970,11 +1110,12 @@ static void colon(char *buf) Hit_Return(); } else if (strncmp(cmd, "quit", i) == 0 // quit || strncmp(cmd, "next", i) == 0 // edit next file + || strncmp(cmd, "prev", i) == 0 // edit previous file ) { int n; if (useforce) { - // force end of argv list if (*cmd == 'q') { + // force end of argv list optind = save_argc; } editing = 0; @@ -982,8 +1123,7 @@ static void colon(char *buf) } // don't exit if the file been modified if (file_modified) { - status_line_bold("No write since last change (:%s! overrides)", - (*cmd == 'q' ? "quit" : "next")); + status_line_bold("No write since last change (:%s! overrides)", cmd); goto ret; } // are there other file to edit @@ -996,6 +1136,14 @@ static void colon(char *buf) status_line_bold("No more files to edit"); goto ret; } + if (*cmd == 'p') { + // are there previous files to edit + if (optind < 1) { + status_line_bold("No previous files to edit"); + goto ret; + } + optind -= 2; + } editing = 0; } else if (strncmp(cmd, "read", i) == 0) { // read file into text[] fn = args; @@ -1018,7 +1166,7 @@ static void colon(char *buf) goto ret; // nothing was inserted // how many lines in text[]? li = count_lines(q, q + ch - 1); - status_line("\"%s\"" + status_line("'%s'" IF_FEATURE_VI_READONLY("%s") " %dL, %dC", fn, IF_FEATURE_VI_READONLY((readonly_mode ? " [Readonly]" : ""),) @@ -1031,10 +1179,10 @@ static void colon(char *buf) } } else if (strncmp(cmd, "rewind", i) == 0) { // rewind cmd line args if (file_modified && !useforce) { - status_line_bold("No write since last change (:rewind! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", cmd); } else { // reset the filenames to edit - optind = fn_start - 1; + optind = -1; /* start from 0th file */ editing = 0; } #if ENABLE_FEATURE_VI_SET @@ -1043,7 +1191,7 @@ static void colon(char *buf) char *argp; #endif i = 0; // offset into args - // only blank is regarded as args delmiter. What about tab '\t' ? + // only blank is regarded as args delimiter. What about tab '\t'? if (!args[0] || strcasecmp(args, "all") == 0) { // print out values of all options #if ENABLE_FEATURE_VI_SETOPTS @@ -1084,51 +1232,53 @@ static void colon(char *buf) #endif /* FEATURE_VI_SET */ #if ENABLE_FEATURE_VI_SEARCH } else if (cmd[0] == 's') { // substitute a pattern with a replacement pattern - char *ls, *F, *R; - int gflag; + char *F, *R, *flags; + size_t len_F, len_R; + int gflag; // global replace flag // F points to the "find" pattern // R points to the "replace" pattern - // replace the cmd line delimiters "/" with NULLs - gflag = 0; // global replace flag + // replace the cmd line delimiters "/" with NULs c = orig_buf[1]; // what is the delimiter F = orig_buf + 2; // start of "find" R = strchr(F, c); // middle delimiter if (!R) goto colon_s_fail; + len_F = R - F; *R++ = '\0'; // terminate "find" - buf1 = strchr(R, c); - if (!buf1) + flags = strchr(R, c); + if (!flags) goto colon_s_fail; - *buf1++ = '\0'; // terminate "replace" - if (*buf1 == 'g') { // :s/foo/bar/g - buf1++; - gflag++; // turn on gflag - } + len_R = flags - R; + *flags++ = '\0'; // terminate "replace" + gflag = *flags; + q = begin_line(q); if (b < 0) { // maybe :s/foo/bar/ - q = begin_line(dot); // start with cur line - b = count_lines(text, q); // cur line number + q = begin_line(dot); // start with cur line + b = count_lines(text, q); // cur line number } if (e < 0) e = b; // maybe :.s/foo/bar/ + for (i = b; i <= e; i++) { // so, :20,23 s \0 find \0 replace \0 - ls = q; // orig line start + char *ls = q; // orig line start + char *found; vc4: - buf1 = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" - if (buf1) { + found = char_search(q, F, FORWARD, LIMITED); // search cur line only for "find" + if (found) { uintptr_t bias; // we found the "find" pattern - delete it - text_hole_delete(buf1, buf1 + strlen(F) - 1); + text_hole_delete(found, found + len_F - 1); // inset the "replace" patern - bias = string_insert(buf1, R); // insert the string - buf1 += bias; + bias = string_insert(found, R); // insert the string + found += bias; ls += bias; /*q += bias; - recalculated anyway */ // check for "global" :s/foo/bar/g - if (gflag == 1) { - if ((buf1 + strlen(R)) < end_line(ls)) { - q = buf1 + strlen(R); + if (gflag == 'g') { + if ((found + len_R) < end_line(ls)) { + q = found + len_R; goto vc4; // don't let q move past cur line } } @@ -1149,7 +1299,7 @@ static void colon(char *buf) } #if ENABLE_FEATURE_VI_READONLY if (readonly_mode && !useforce) { - status_line_bold("\"%s\" File is read only", fn); + status_line_bold("'%s' is read only", fn); goto ret; } #endif @@ -1172,9 +1322,9 @@ static void colon(char *buf) } if (l < 0) { if (l == -1) - status_line_bold("\"%s\" %s", fn, strerror(errno)); + status_line_bold_errno(fn); } else { - status_line("\"%s\" %dL, %dC", fn, li, l); + status_line("'%s' %dL, %dC", fn, li, l); if (q == text && r == end - 1 && l == ch) { file_modified = 0; last_file_modified = -1; @@ -1551,24 +1701,84 @@ static char *new_screen(int ro, int co) } #if ENABLE_FEATURE_VI_SEARCH + +# if ENABLE_FEATURE_VI_REGEX_SEARCH + +// search for pattern starting at p +static char *char_search(char *p, const char *pat, int dir, int range) +{ + struct re_pattern_buffer preg; + const char *err; + char *q; + int i; + int size; + + re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; + if (ignorecase) + re_syntax_options = RE_SYNTAX_POSIX_EXTENDED | RE_ICASE; + + memset(&preg, 0, sizeof(preg)); + err = re_compile_pattern(pat, strlen(pat), &preg); + if (err != NULL) { + status_line_bold("bad search pattern '%s': %s", pat, err); + return p; + } + + // assume a LIMITED forward search + q = end - 1; + if (dir == BACK) + q = text; + // RANGE could be negative if we are searching backwards + range = q - p; + q = p; + size = range; + if (range < 0) { + size = -size; + q = p - size; + if (q < text) + q = text; + } + // search for the compiled pattern, preg, in p[] + // range < 0: search backward + // range > 0: search forward + // 0 < start < size + // re_search() < 0: not found or error + // re_search() >= 0: index of found pattern + // struct pattern char int int int struct reg + // re_search(*pattern_buffer, *string, size, start, range, *regs) + i = re_search(&preg, q, size, /*start:*/ 0, range, /*struct re_registers*:*/ NULL); + regfree(&preg); + if (i < 0) + return NULL; + if (dir == FORWARD) + p = p + i; + else + p = p - i; + return p; +} + +# else + +# if ENABLE_FEATURE_VI_SETOPTS static int mycmp(const char *s1, const char *s2, int len) { - if (ENABLE_FEATURE_VI_SETOPTS && ignorecase) { + if (ignorecase) { return strncasecmp(s1, s2, len); } return strncmp(s1, s2, len); } +# else +# define mycmp strncmp +# endif -// search for pattern starting at p static char *char_search(char *p, const char *pat, int dir, int range) { -#ifndef REGEX_SEARCH char *start, *stop; int len; len = strlen(pat); if (dir == FORWARD) { - stop = end - 1; // assume range is p - end-1 + stop = end - 1; // assume range is p..end-1 if (range == LIMITED) stop = next_line(p); // range is to next line for (start = p; start < stop; start++) { @@ -1577,7 +1787,7 @@ static char *char_search(char *p, const char *pat, int dir, int range) } } } else if (dir == BACK) { - stop = text; // assume range is text - p + stop = text; // assume range is text..p if (range == LIMITED) stop = prev_line(p); // range is to prev line for (start = p - len; start >= stop; start--) { @@ -1588,69 +1798,10 @@ static char *char_search(char *p, const char *pat, int dir, int range) } // pattern not found return NULL; -#else /* REGEX_SEARCH */ - char *q; - struct re_pattern_buffer preg; - int i; - int size, range; - - re_syntax_options = RE_SYNTAX_POSIX_EXTENDED; - preg.translate = 0; - preg.fastmap = 0; - preg.buffer = 0; - preg.allocated = 0; - - // assume a LIMITED forward search - q = next_line(p); - q = end_line(q); - q = end - 1; - if (dir == BACK) { - q = prev_line(p); - q = text; - } - // count the number of chars to search over, forward or backward - size = q - p; - if (size < 0) - size = p - q; - // RANGE could be negative if we are searching backwards - range = q - p; +} - q = re_compile_pattern(pat, strlen(pat), &preg); - if (q != 0) { - // The pattern was not compiled - status_line_bold("bad search pattern: \"%s\": %s", pat, q); - i = 0; // return p if pattern not compiled - goto cs1; - } +# endif - q = p; - if (range < 0) { - q = p - size; - if (q < text) - q = text; - } - // search for the compiled pattern, preg, in p[] - // range < 0- search backward - // range > 0- search forward - // 0 < start < size - // re_search() < 0 not found or error - // re_search() > 0 index of found pattern - // struct pattern char int int int struct reg - // re_search (*pattern_buffer, *string, size, start, range, *regs) - i = re_search(&preg, q, size, 0, range, 0); - if (i == -1) { - p = 0; - i = 0; // return NULL if pattern not found - } - cs1: - if (dir == FORWARD) { - p = p + i; - } else { - p = p - i; - } - return p; -#endif /* REGEX_SEARCH */ -} #endif /* FEATURE_VI_SEARCH */ static char *char_insert(char *p, char c) // insert the char c at 'p' @@ -1677,12 +1828,16 @@ static char *char_insert(char *p, char c) // insert the char c at 'p' p = text_hole_delete(p, p); // shrink buffer 1 char } } else { +#if ENABLE_FEATURE_VI_SETOPTS // insert a char into text[] char *sp; // "save p" +#endif if (c == 13) c = '\n'; // translate \r to \n +#if ENABLE_FEATURE_VI_SETOPTS sp = p; // remember addr of insert +#endif p += 1 + stupid_insert(p, c); // insert the char #if ENABLE_FEATURE_VI_SETOPTS if (showmatch && strchr(")]}", *sp) != NULL) { @@ -1763,11 +1918,11 @@ static int find_range(char **start, char **stop, char c) dot_end(); // find NL q = dot; } else { - // nothing -- this causes any other values of c to - // represent the one-character range under the - // cursor. this is correct for ' ' and 'l', but - // perhaps no others. - // + // nothing -- this causes any other values of c to + // represent the one-character range under the + // cursor. this is correct for ' ' and 'l', but + // perhaps no others. + // } if (q < p) { t = q; @@ -1915,6 +2070,14 @@ static uintptr_t text_hole_make(char *p, int size) // at "p", make a 'size' byte dot += bias; end += bias; p += bias; +#if ENABLE_FEATURE_VI_YANKMARK + { + int i; + for (i = 0; i < ARRAY_SIZE(mark); i++) + if (mark[i]) + mark[i] += bias; + } +#endif text = new_text; } memmove(p + size, p, end - size - p); @@ -2001,18 +2164,18 @@ static void show_help(void) "\n\tPattern searches with / and ?" #endif #if ENABLE_FEATURE_VI_DOT_CMD - "\n\tLast command repeat with \'.\'" + "\n\tLast command repeat with ." #endif #if ENABLE_FEATURE_VI_YANKMARK "\n\tLine marking with 'x" "\n\tNamed buffers with \"x" #endif #if ENABLE_FEATURE_VI_READONLY - "\n\tReadonly if vi is called as \"view\"" - "\n\tReadonly with -R command line arg" + //not implemented: "\n\tReadonly if vi is called as \"view\"" + //redundant: usage text says this too: "\n\tReadonly with -R command line arg" #endif #if ENABLE_FEATURE_VI_SET - "\n\tSome colon mode commands with \':\'" + "\n\tSome colon mode commands with :" #endif #if ENABLE_FEATURE_VI_SETOPTS "\n\tSettable options with \":set\"" @@ -2146,7 +2309,7 @@ static void rawmode(void) { tcgetattr(0, &term_orig); term_vi = term_orig; - term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG ON- allow intr's + term_vi.c_lflag &= (~ICANON & ~ECHO); // leave ISIG on - allow intr's term_vi.c_iflag &= (~IXON & ~ICRNL); term_vi.c_oflag &= (~ONLCR); term_vi.c_cc[VMIN] = 1; @@ -2329,12 +2492,12 @@ static int file_insert(const char *fn, char *p, int update_ro_status) /* Validate file */ if (stat(fn, &statbuf) < 0) { - status_line_bold("\"%s\" %s", fn, strerror(errno)); + status_line_bold_errno(fn); goto fi0; } if (!S_ISREG(statbuf.st_mode)) { // This is not a regular file - status_line_bold("\"%s\" Not a regular file", fn); + status_line_bold("'%s' is not a regular file", fn); goto fi0; } if (p < text || p > end) { @@ -2345,19 +2508,19 @@ static int file_insert(const char *fn, char *p, int update_ro_status) // read file to buffer fd = open(fn, O_RDONLY); if (fd < 0) { - status_line_bold("\"%s\" %s", fn, strerror(errno)); + status_line_bold_errno(fn); goto fi0; } - size = statbuf.st_size; + size = (statbuf.st_size < INT_MAX ? (int)statbuf.st_size : INT_MAX); p += text_hole_make(p, size); cnt = safe_read(fd, p, size); if (cnt < 0) { - status_line_bold("\"%s\" %s", fn, strerror(errno)); + status_line_bold_errno(fn); p = text_hole_delete(p, p + size - 1); // un-do buffer insert } else if (cnt < size) { // There was a partial read, shrink unused space text[] - p = text_hole_delete(p + cnt, p + (size - cnt) - 1); // un-do buffer insert - status_line_bold("can't read all of file \"%s\"", fn); + p = text_hole_delete(p + cnt, p + size - 1); // un-do buffer insert + status_line_bold("can't read '%s'", fn); } if (cnt >= size) file_modified++; @@ -2417,107 +2580,56 @@ static int file_write(char *fn, char *first, char *last) // 23,0 ... 23,79 <- status line //----- Move the cursor to row x col (count from 0, not 1) ------- -static void place_cursor(int row, int col, int optimize) +static void place_cursor(int row, int col) { - char cm1[sizeof(CMrc) + sizeof(int)*3 * 2]; -#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR - enum { - SZ_UP = sizeof(CMup), - SZ_DN = sizeof(CMdown), - SEQ_SIZE = SZ_UP > SZ_DN ? SZ_UP : SZ_DN, - }; - char cm2[SEQ_SIZE * 5 + 32]; // bigger than worst case size -#endif - char *cm; + char cm1[sizeof(ESC_SET_CURSOR_POS) + sizeof(int)*3 * 2]; if (row < 0) row = 0; if (row >= rows) row = rows - 1; if (col < 0) col = 0; if (col >= columns) col = columns - 1; - //----- 1. Try the standard terminal ESC sequence - sprintf(cm1, CMrc, row + 1, col + 1); - cm = cm1; - -#if ENABLE_FEATURE_VI_OPTIMIZE_CURSOR - if (optimize && col < 16) { - char *screenp; - int Rrow = last_row; - int diff = Rrow - row; - - if (diff < -5 || diff > 5) - goto skip; - - //----- find the minimum # of chars to move cursor ------------- - //----- 2. Try moving with discreet chars (Newline, [back]space, ...) - cm2[0] = '\0'; - - // move to the correct row - while (row < Rrow) { - // the cursor has to move up - strcat(cm2, CMup); - Rrow--; - } - while (row > Rrow) { - // the cursor has to move down - strcat(cm2, CMdown); - Rrow++; - } - - // now move to the correct column - strcat(cm2, "\r"); // start at col 0 - // just send out orignal source char to get to correct place - screenp = &screen[row * columns]; // start of screen line - strncat(cm2, screenp, col); - - // pick the shortest cursor motion to send out - if (strlen(cm2) < strlen(cm)) { - cm = cm2; - } - skip: ; - } - last_row = row; -#endif /* FEATURE_VI_OPTIMIZE_CURSOR */ - write1(cm); + sprintf(cm1, ESC_SET_CURSOR_POS, row + 1, col + 1); + write1(cm1); } //----- Erase from cursor to end of line ----------------------- static void clear_to_eol(void) { - write1(Ceol); // Erase from cursor to end of line + write1(ESC_CLEAR2EOL); } static void go_bottom_and_clear_to_eol(void) { - place_cursor(rows - 1, 0, FALSE); // go to bottom of screen - clear_to_eol(); // erase to end of line + place_cursor(rows - 1, 0); + clear_to_eol(); } //----- Erase from cursor to end of screen ----------------------- static void clear_to_eos(void) { - write1(Ceos); // Erase from cursor to end of screen + write1(ESC_CLEAR2EOS); } //----- Start standout mode ------------------------------------ -static void standout_start(void) // send "start reverse video" sequence +static void standout_start(void) { - write1(SOs); // Start reverse video mode + write1(ESC_BOLD_TEXT); } //----- End standout mode -------------------------------------- -static void standout_end(void) // send "end reverse video" sequence +static void standout_end(void) { - write1(SOn); // End reverse video mode + write1(ESC_NORM_TEXT); } //----- Flash the screen -------------------------------------- static void flash(int h) { - standout_start(); // send "start reverse video" sequence + standout_start(); redraw(TRUE); mysleep(h); - standout_end(); // send "end reverse video" sequence + standout_end(); redraw(TRUE); } @@ -2528,7 +2640,7 @@ static void Indicate_Error(void) return; // generate a random command #endif if (!err_method) { - write1(bell); // send out a bell character + write1(ESC_BELL); } else { flash(10); } @@ -2574,7 +2686,7 @@ static void show_status_line(void) } have_status_msg = 0; } - place_cursor(crow, ccol, FALSE); // put cursor back in correct place + place_cursor(crow, ccol); // put cursor back in correct place } fflush_all(); } @@ -2586,12 +2698,17 @@ static void status_line_bold(const char *format, ...) va_list args; va_start(args, format); - strcpy(status_buffer, SOs); // Terminal standout mode on - vsprintf(status_buffer + sizeof(SOs)-1, format, args); - strcat(status_buffer, SOn); // Terminal standout mode off + strcpy(status_buffer, ESC_BOLD_TEXT); + vsprintf(status_buffer + sizeof(ESC_BOLD_TEXT)-1, format, args); + strcat(status_buffer, ESC_NORM_TEXT); va_end(args); - have_status_msg = 1 + sizeof(SOs) + sizeof(SOn) - 2; + have_status_msg = 1 + sizeof(ESC_BOLD_TEXT) + sizeof(ESC_NORM_TEXT) - 2; +} + +static void status_line_bold_errno(const char *fn) +{ + status_line_bold("'%s' %s", fn, strerror(errno)); } // format status buffer @@ -2623,8 +2740,8 @@ static void print_literal(char *buf, const char *s) c = *s; c_is_no_print = (c & 0x80) && !Isprint(c); if (c_is_no_print) { - strcpy(d, SOn); - d += sizeof(SOn)-1; + strcpy(d, ESC_NORM_TEXT); + d += sizeof(ESC_NORM_TEXT)-1; c = '.'; } if (c < ' ' || c == 0x7f) { @@ -2636,8 +2753,8 @@ static void print_literal(char *buf, const char *s) *d++ = c; *d = '\0'; if (c_is_no_print) { - strcpy(d, SOs); - d += sizeof(SOs)-1; + strcpy(d, ESC_BOLD_TEXT); + d += sizeof(ESC_BOLD_TEXT)-1; } if (*s == '\n') { *d++ = '$'; @@ -2719,8 +2836,8 @@ static int format_edit_status(void) //----- Force refresh of all Lines ----------------------------- static void redraw(int full_screen) { - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tell terminal to erase display + place_cursor(0, 0); + clear_to_eos(); screen_erase(); // erase the internal screen buffer last_status_cksum = 0; // force status update refresh(full_screen); // this will redraw the entire display @@ -2860,22 +2977,13 @@ static void refresh(int full_screen) if (changed) { // copy changed part of buffer to virtual screen memcpy(sp+cs, out_buf+cs, ce-cs+1); - - // move cursor to column of first change - //if (offset != old_offset) { - // // place_cursor is still too stupid - // // to handle offsets correctly - // place_cursor(li, cs, FALSE); - //} else { - place_cursor(li, cs, TRUE); - //} - + place_cursor(li, cs); // write line out to terminal fwrite(&sp[cs], ce - cs + 1, 1, stdout); } } - place_cursor(crow, ccol, TRUE); + place_cursor(crow, ccol); old_offset = offset; #undef old_offset @@ -2905,7 +3013,6 @@ static void refresh(int full_screen) //----- Execute a Vi Command ----------------------------------- static void do_cmd(int c) { - const char *msg = msg; // for compiler char *p, *q, *save_dot; char buf[12]; int dir; @@ -2914,8 +3021,8 @@ static void do_cmd(int c) // c1 = c; // quiet the compiler // cnt = yf = 0; // quiet the compiler -// msg = p = q = save_dot = buf; // quiet the compiler - memset(buf, '\0', 12); +// p = q = save_dot = buf; // quiet the compiler + memset(buf, '\0', sizeof(buf)); show_status_line(); @@ -3031,36 +3138,34 @@ static void do_cmd(int c) case KEYCODE_LEFT: // cursor key Left case 8: // ctrl-H- move left (This may be ERASE char) case 0x7f: // DEL- move left (This may be ERASE char) - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_left(); + do { + dot_left(); + } while (--cmdcnt > 0); break; case 10: // Newline ^J case 'j': // j- goto next line, same col case KEYCODE_DOWN: // cursor key Down - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); // go to next B-o-l - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_next(); // go to next B-o-l + // try stay in same col + dot = move_to_col(dot, ccol + offset); + } while (--cmdcnt > 0); break; case 12: // ctrl-L force redraw whole screen case 18: // ctrl-R force redraw - place_cursor(0, 0, FALSE); // put cursor in correct place - clear_to_eos(); // tel terminal to erase display - mysleep(10); + place_cursor(0, 0); + clear_to_eos(); + //mysleep(10); // why??? screen_erase(); // erase the internal screen buffer last_status_cksum = 0; // force status update refresh(TRUE); // this will redraw the entire display break; case 13: // Carriage Return ^M case '+': // +- goto next line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_next(); - dot_skip_over_ws(); + do { + dot_next(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; case 21: // ctrl-U scroll up half screen dot_scroll((rows - 2) / 2, -1); @@ -3078,10 +3183,9 @@ static void do_cmd(int c) case ' ': // move right case 'l': // move right case KEYCODE_RIGHT: // Cursor Key Right - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_right(); + do { + dot_right(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_YANKMARK case '"': // "- name a register to use for Delete/Yank @@ -3151,7 +3255,7 @@ static void do_cmd(int c) end_cmd_q(); // stop adding to q break; case 'U': // U- Undo; replace current line with original version - if (reg[Ureg] != 0) { + if (reg[Ureg] != NULL) { p = begin_line(dot); q = end_line(dot); p = text_hole_delete(p, q); // delete cur line @@ -3163,11 +3267,12 @@ static void do_cmd(int c) #endif /* FEATURE_VI_YANKMARK */ case '$': // $- goto end of line case KEYCODE_END: // Cursor Key End - if (--cmdcnt > 0) { + for (;;) { + dot = end_line(dot); + if (--cmdcnt <= 0) + break; dot_next(); - do_cmd(c); } - dot = end_line(dot); break; case '%': // %- find matching char of pair () [] {} for (q = dot; q < end && *q != '\n'; q++) { @@ -3192,38 +3297,35 @@ static void do_cmd(int c) // //**** fall through to ... ';' case ';': // ;- look at rest of line for last forward char - if (--cmdcnt > 0) { - do_cmd(';'); - } - if (last_forward_char == 0) - break; - q = dot + 1; - while (q < end - 1 && *q != '\n' && *q != last_forward_char) { - q++; - } - if (*q == last_forward_char) - dot = q; + do { + if (last_forward_char == 0) + break; + q = dot + 1; + while (q < end - 1 && *q != '\n' && *q != last_forward_char) { + q++; + } + if (*q == last_forward_char) + dot = q; + } while (--cmdcnt > 0); break; case ',': // repeat latest 'f' in opposite direction - if (--cmdcnt > 0) { - do_cmd(','); - } if (last_forward_char == 0) break; - q = dot - 1; - while (q >= text && *q != '\n' && *q != last_forward_char) { - q--; - } - if (q >= text && *q == last_forward_char) - dot = q; + do { + q = dot - 1; + while (q >= text && *q != '\n' && *q != last_forward_char) { + q--; + } + if (q >= text && *q == last_forward_char) + dot = q; + } while (--cmdcnt > 0); break; case '-': // -- goto prev line - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot_skip_over_ws(); + do { + dot_prev(); + dot_skip_over_ws(); + } while (--cmdcnt > 0); break; #if ENABLE_FEATURE_VI_DOT_CMD case '.': // .- repeat the last modifying command @@ -3255,9 +3357,6 @@ static void do_cmd(int c) // user changed mind and erased the "/"- do nothing break; case 'N': // N- backward search for last pattern - if (--cmdcnt > 0) { - do_cmd(c); - } dir = BACK; // assume BACKWARD search p = dot - 1; if (last_search_pattern[0] == '?') { @@ -3269,41 +3368,41 @@ static void do_cmd(int c) case 'n': // n- repeat search for last pattern // search rest of text[] starting at next char // if search fails return orignal "p" not the "p+1" address - if (--cmdcnt > 0) { - do_cmd(c); - } + do { + const char *msg; dc3: - dir = FORWARD; // assume FORWARD search - p = dot + 1; - if (last_search_pattern[0] == '?') { - dir = BACK; - p = dot - 1; - } + dir = FORWARD; // assume FORWARD search + p = dot + 1; + if (last_search_pattern[0] == '?') { + dir = BACK; + p = dot - 1; + } dc4: - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { - dot = q; // good search, update "dot" - msg = ""; - goto dc2; - } - // no pattern found between "dot" and "end"- continue at top - p = text; - if (dir == BACK) { - p = end - 1; - } - q = char_search(p, last_search_pattern + 1, dir, FULL); - if (q != NULL) { // found something - dot = q; // found new pattern- goto it - msg = "search hit BOTTOM, continuing at TOP"; + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { + dot = q; // good search, update "dot" + msg = NULL; + goto dc2; + } + // no pattern found between "dot" and "end"- continue at top + p = text; if (dir == BACK) { - msg = "search hit TOP, continuing at BOTTOM"; + p = end - 1; + } + q = char_search(p, last_search_pattern + 1, dir, FULL); + if (q != NULL) { // found something + dot = q; // found new pattern- goto it + msg = "search hit BOTTOM, continuing at TOP"; + if (dir == BACK) { + msg = "search hit TOP, continuing at BOTTOM"; + } + } else { + msg = "Pattern not found"; } - } else { - msg = "Pattern not found"; - } dc2: - if (*msg) - status_line_bold("%s", msg); + if (msg) + status_line_bold("%s", msg); + } while (--cmdcnt > 0); break; case '{': // {- move backward paragraph q = char_search(dot, "\n\n", BACK, FULL); @@ -3348,7 +3447,7 @@ static void do_cmd(int c) || strncmp(p, "q!", cnt) == 0 // delete lines ) { if (file_modified && p[1] != '!') { - status_line_bold("No write since last change (:quit! overrides)"); + status_line_bold("No write since last change (:%s! overrides)", p); } else { editing = 0; } @@ -3364,7 +3463,7 @@ static void do_cmd(int c) } else { file_modified = 0; last_file_modified = -1; - status_line("\"%s\" %dL, %dC", current_filename, count_lines(text, end - 1), cnt); + status_line("'%s' %dL, %dC", current_filename, count_lines(text, end - 1), cnt); if (p[0] == 'x' || p[1] == 'q' || p[1] == 'n' || p[0] == 'X' || p[1] == 'Q' || p[1] == 'N' ) { @@ -3422,18 +3521,17 @@ static void do_cmd(int c) case 'B': // B- back a blank-delimited Word case 'E': // E- end of a blank-delimited word case 'W': // W- forward a blank-delimited word - if (--cmdcnt > 0) { - do_cmd(c); - } dir = FORWARD; if (c == 'B') dir = BACK; - if (c == 'W' || isspace(dot[dir])) { - dot = skip_thing(dot, 1, dir, S_TO_WS); - dot = skip_thing(dot, 2, dir, S_OVER_WS); - } - if (c != 'W') - dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + do { + if (c == 'W' || isspace(dot[dir])) { + dot = skip_thing(dot, 1, dir, S_TO_WS); + dot = skip_thing(dot, 2, dir, S_OVER_WS); + } + if (c != 'W') + dot = skip_thing(dot, 1, dir, S_BEFORE_WS); + } while (--cmdcnt > 0); break; case 'C': // C- Change to e-o-l case 'D': // D- delete to e-o-l @@ -3484,20 +3582,19 @@ static void do_cmd(int c) case 'i': // i- insert before current char case KEYCODE_INSERT: // Cursor Key Insert dc_i: - cmd_mode = 1; // start insrting + cmd_mode = 1; // start inserting break; case 'J': // J- join current and next lines together - if (--cmdcnt > 1) { - do_cmd(c); - } - dot_end(); // move to NL - if (dot < end - 1) { // make sure not last char in text[] - *dot++ = ' '; // replace NL with space - file_modified++; - while (isblank(*dot)) { // delete leading WS - dot_delete(); + do { + dot_end(); // move to NL + if (dot < end - 1) { // make sure not last char in text[] + *dot++ = ' '; // replace NL with space + file_modified++; + while (isblank(*dot)) { // delete leading WS + dot_delete(); + } } - } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; case 'L': // L- goto bottom line on screen @@ -3541,20 +3638,19 @@ static void do_cmd(int c) case 'X': // X- delete char before dot case 'x': // x- delete the current char case 's': // s- substitute the current char - if (--cmdcnt > 0) { - do_cmd(c); - } dir = 0; if (c == 'X') dir = -1; - if (dot[dir] != '\n') { - if (c == 'X') - dot--; // delete prev char - dot = yank_delete(dot, dot, 0, YANKDEL); // delete char - } - if (c == 's') - goto dc_i; // start insrting + do { + if (dot[dir] != '\n') { + if (c == 'X') + dot--; // delete prev char + dot = yank_delete(dot, dot, 0, YANKDEL); // delete char + } + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q + if (c == 's') + goto dc_i; // start inserting break; case 'Z': // Z- if modified, {write}; exit // ZZ means to save file (if necessary), then exit @@ -3565,7 +3661,7 @@ static void do_cmd(int c) } if (file_modified) { if (ENABLE_FEATURE_VI_READONLY && readonly_mode) { - status_line_bold("\"%s\" File is read only", current_filename); + status_line_bold("'%s' is read only", current_filename); break; } cnt = file_write(current_filename, text, end - 1); @@ -3585,23 +3681,22 @@ static void do_cmd(int c) break; case 'b': // b- back a word case 'e': // e- end of word - if (--cmdcnt > 0) { - do_cmd(c); - } dir = FORWARD; if (c == 'b') dir = BACK; - if ((dot + dir) < text || (dot + dir) > end - 1) - break; - dot += dir; - if (isspace(*dot)) { - dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); - } - if (isalnum(*dot) || *dot == '_') { - dot = skip_thing(dot, 1, dir, S_END_ALNUM); - } else if (ispunct(*dot)) { - dot = skip_thing(dot, 1, dir, S_END_PUNCT); - } + do { + if ((dot + dir) < text || (dot + dir) > end - 1) + break; + dot += dir; + if (isspace(*dot)) { + dot = skip_thing(dot, (c == 'e') ? 2 : 1, dir, S_OVER_WS); + } + if (isalnum(*dot) || *dot == '_') { + dot = skip_thing(dot, 1, dir, S_END_ALNUM); + } else if (ispunct(*dot)) { + dot = skip_thing(dot, 1, dir, S_END_PUNCT); + } + } while (--cmdcnt > 0); break; case 'c': // c- change something case 'd': // d- delete something @@ -3686,11 +3781,10 @@ static void do_cmd(int c) } case 'k': // k- goto prev line, same col case KEYCODE_UP: // cursor key Up - if (--cmdcnt > 0) { - do_cmd(c); - } - dot_prev(); - dot = move_to_col(dot, ccol + offset); // try stay in same col + do { + dot_prev(); + dot = move_to_col(dot, ccol + offset); // try stay in same col + } while (--cmdcnt > 0); break; case 'r': // r- replace the current char with user input c1 = get_one_char(); // get the replacement char @@ -3708,19 +3802,18 @@ static void do_cmd(int c) last_forward_char = 0; break; case 'w': // w- forward a word - if (--cmdcnt > 0) { - do_cmd(c); - } - if (isalnum(*dot) || *dot == '_') { // we are on ALNUM - dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); - } else if (ispunct(*dot)) { // we are on PUNCT - dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); - } - if (dot < end - 1) - dot++; // move over word - if (isspace(*dot)) { - dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); - } + do { + if (isalnum(*dot) || *dot == '_') { // we are on ALNUM + dot = skip_thing(dot, 1, FORWARD, S_END_ALNUM); + } else if (ispunct(*dot)) { // we are on PUNCT + dot = skip_thing(dot, 1, FORWARD, S_END_PUNCT); + } + if (dot < end - 1) + dot++; // move over word + if (isspace(*dot)) { + dot = skip_thing(dot, 2, FORWARD, S_OVER_WS); + } + } while (--cmdcnt > 0); break; case 'z': // z- c1 = get_one_char(); // get the replacement char @@ -3736,17 +3829,16 @@ static void do_cmd(int c) dot = move_to_col(dot, cmdcnt - 1); // try to move to column break; case '~': // ~- flip the case of letters a-z -> A-Z - if (--cmdcnt > 0) { - do_cmd(c); - } - if (islower(*dot)) { - *dot = toupper(*dot); - file_modified++; - } else if (isupper(*dot)) { - *dot = tolower(*dot); - file_modified++; - } - dot_right(); + do { + if (islower(*dot)) { + *dot = toupper(*dot); + file_modified++; + } else if (isupper(*dot)) { + *dot = tolower(*dot); + file_modified++; + } + dot_right(); + } while (--cmdcnt > 0); end_cmd_q(); // stop adding to q break; //----- The Cursor and Function Keys ----------------------------- @@ -3982,7 +4074,7 @@ static void crash_test() if (msg[0]) { printf("\n\n%d: \'%c\' %s\n\n\n%s[Hit return to continue]%s", - totalcmds, last_input_char, msg, SOs, SOn); + totalcmds, last_input_char, msg, ESC_BOLD_TEXT, ESC_NORM_TEXT); fflush_all(); while (safe_read(STDIN_FILENO, d, 1) > 0) { if (d[0] == '\n' || d[0] == '\r') diff --git a/examples/android-build b/examples/android-build new file mode 100755 index 0000000..89f3b63 --- /dev/null +++ b/examples/android-build @@ -0,0 +1,32 @@ +#!/bin/sh +# Build Busybox against Android's bionic +# Originally by Dan Fandrich +# +# Configure with "make android_defconfig" +# +# This file has been tested on Android Froyo (the lack of ttyname_r in +# the android libc must be patched around) and Gingerbread. + +# Point this to the Android root directory; it's used in the defconfig CFLAGS +export A="$HOME/android" + +# Android product being built +P=zoom2 + +# Toolchain version in use by this version of Android +GCCVER=4.4.3 + +export PATH="$A/prebuilt/linux-x86/toolchain/arm-eabi-$GCCVER/bin:$PATH" + +# Set the linker flags; compiler flags are in the defconfig file +if grep "^CONFIG_STATIC=y" .config >/dev/null ; then + # Static linking + LDFLAGS="-static -Xlinker -z -Xlinker muldefs -nostdlib $A/out/target/product/$P/obj/lib/crtbegin_static.o $A/out/target/product/$P/obj/lib/crtend_android.o -L$A/out/target/product/$P/obj/lib -L$A/out/target/product/$P/obj/STATIC_LIBRARIES/libm_intermediates -L$A/out/target/product/$P/obj/STATIC_LIBRARIES/libc_intermediates" + LDLIBS="m c gcc" +else + # Dynamic linking + LDFLAGS="-Xlinker -z -Xlinker muldefs -nostdlib -Bdynamic -Xlinker -T$A/build/core/armelf.x -Xlinker -dynamic-linker -Xlinker /system/bin/linker -Xlinker -z -Xlinker nocopyreloc -Xlinker --no-undefined $A/out/target/product/$P/obj/lib/crtbegin_dynamic.o $A/out/target/product/$P/obj/lib/crtend_android.o -L$A/out/target/product/$P/obj/lib" + LDLIBS="dl m c gcc" +fi + +make EXTRA_LDFLAGS="$LDFLAGS" LDLIBS="$LDLIBS" "$@" diff --git a/examples/bootfloppy/display.txt b/examples/bootfloppy/display.txt index 399d326..7cae48b 100644 --- a/examples/bootfloppy/display.txt +++ b/examples/bootfloppy/display.txt @@ -1,4 +1,3 @@ This boot floppy is made with Busybox, uClibc, and the Linux kernel. Hit RETURN to boot or enter boot parameters at the prompt below. - diff --git a/examples/bootfloppy/etc/fstab b/examples/bootfloppy/etc/fstab index ef14ca2..b31f602 100644 --- a/examples/bootfloppy/etc/fstab +++ b/examples/bootfloppy/etc/fstab @@ -1,2 +1 @@ proc /proc proc defaults 0 0 - diff --git a/examples/bootfloppy/etc/inittab b/examples/bootfloppy/etc/inittab index eb3e979..1ac9f68 100644 --- a/examples/bootfloppy/etc/inittab +++ b/examples/bootfloppy/etc/inittab @@ -2,4 +2,3 @@ ::respawn:-/bin/sh tty2::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a -r - diff --git a/examples/bootfloppy/etc/profile b/examples/bootfloppy/etc/profile index 8a7c77d..cf68d33 100644 --- a/examples/bootfloppy/etc/profile +++ b/examples/bootfloppy/etc/profile @@ -5,4 +5,3 @@ echo -n "Processing /etc/profile... " # no-op echo "Done" echo - diff --git a/examples/bootfloppy/mkrootfs.sh b/examples/bootfloppy/mkrootfs.sh index 5cdff21..a7fc48b 100755 --- a/examples/bootfloppy/mkrootfs.sh +++ b/examples/bootfloppy/mkrootfs.sh @@ -102,4 +102,3 @@ then rmdir $TARGET_DIR gzip -9 rootfs fi - diff --git a/examples/depmod b/examples/depmod index d8c4cc5..d769590 100755 --- a/examples/depmod +++ b/examples/depmod @@ -4,7 +4,7 @@ # # Copyright (C) 2008 by Vladimir Dronnikov # -# Licensed under GPLv2 +# Licensed under GPLv2, see file LICENSE in this source tree. # local BASE="${1:-/usr/lib/modules}" diff --git a/examples/depmod.pl b/examples/depmod.pl index 8c6548d..809dc08 100755 --- a/examples/depmod.pl +++ b/examples/depmod.pl @@ -173,6 +173,9 @@ sub add_mod_deps $depth .= " "; warn "${depth}loading deps of module: $this_module\n" if $verbose; + if (length($depth) > 50) { + die "too much recursion (circular dependencies in modules?)"; + } foreach my $md (keys %{$mod->{$this_module}}) { add_mod_deps ($depth, $mod, $mod2, $module, $md); @@ -196,7 +199,7 @@ if ($stdout == 0) { open(STDOUT, ">$basedir/modules.dep") or die "cannot open $basedir/modules.dep: $!"; } -my $kseries = $basedir =~ m,/2\.6\.[^/]*, ? '2.6' : '2.4'; +my $kseries = $basedir =~ m,/2\.4\.[^/]*, ? '2.4' : 'others'; foreach my $module ( keys %$mod ) { if($kseries eq '2.4') { diff --git a/examples/inittab b/examples/inittab index 64fc4fc..01ceaef 100644 --- a/examples/inittab +++ b/examples/inittab @@ -15,10 +15,7 @@ # the specified process to run on. The contents of this field are # appended to "/dev/" and used as-is. There is no need for this field to # be unique, although if it isn't you may have strange results. If this -# field is left blank, it is completely ignored. Also note that if -# BusyBox detects that a serial console is in use, then all entries -# containing non-empty id fields will be ignored. BusyBox init does -# nothing with utmp. We don't need no stinkin' utmp. +# field is left blank, then the init's stdin/out will be used. # # : The runlevels field is completely ignored. # @@ -43,9 +40,6 @@ # ::shutdown:/sbin/swapoff -a # ::shutdown:/bin/umount -a -r # ::restart:/sbin/init -# -# if it detects that /dev/console is _not_ a serial console, it will -# also run: # tty2::askfirst:/bin/sh # tty3::askfirst:/bin/sh # tty4::askfirst:/bin/sh @@ -87,4 +81,3 @@ tty5::respawn:/sbin/getty 38400 tty6 ::ctrlaltdel:/sbin/reboot ::shutdown:/bin/umount -a -r ::shutdown:/sbin/swapoff -a - diff --git a/examples/mdev.conf b/examples/mdev.conf index cdbb4fc..5179569 100644 --- a/examples/mdev.conf +++ b/examples/mdev.conf @@ -7,8 +7,14 @@ # instead of the default 0:0 660. # # Syntax: -# %s %d:%d %s -# devicename_regex user:group mode +# [-]devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-]@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# +# [-]: do not stop on this match, continue reading mdev.conf +# =: move, >: move and create a symlink +# !: do not create device node +# @|$|*: run@cmd if $ACTION=add, $cmd if $ACTION=remove, *cmd in all cases null 0:0 666 zero 0:0 666 diff --git a/examples/mdev.conf.change_blockdev.sh b/examples/mdev.conf.change_blockdev.sh new file mode 100755 index 0000000..512e43f --- /dev/null +++ b/examples/mdev.conf.change_blockdev.sh @@ -0,0 +1,29 @@ +#!/bin/sh + +# Seconds to try to reread partition table +cnt=60 + +exec "/tmp/${0##*/}.$$.out" +exec 2>&1 + +( +echo "Running: $0" +echo "Env:" +env | sort + +while sleep 1; test $cnt != 0; do + echo "Trying to reread partition table on $DEVNAME ($cnt)" + : $((cnt--)) + # If device node doesn't exist, it means the device was removed. + # Stop trying. + test -e "$DEVNAME" || { echo "$DEVNAME doesn't exist, aborting"; exit 1; } + #echo "$DEVNAME exists" + if blockdev --rereadpt "$DEVNAME"; then + echo "blockdev --rereadpt succeeded" + exit 0 + fi + echo "blockdev --rereadpt failed, exit code: $?" +done +echo "Timed out" +) & diff --git a/examples/mdev_fat.conf b/examples/mdev_fat.conf index df329b4..f2a15f3 100644 --- a/examples/mdev_fat.conf +++ b/examples/mdev_fat.conf @@ -7,10 +7,14 @@ # instead of the default 0:0 660. # # Syntax: -# [-]devicename_regex user:group mode [>|=path] [@|$|*cmd args...] +# [-][ENVVAR=regex;]...devicename_regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-][ENVVAR=regex;]...@maj,min[-min2] user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] +# [-]$ENVVAR=regex user:group mode [=path]|[>path]|[!] [@|$|*cmd args...] # +# [-]: do not stop on this match, continue reading mdev.conf # =: move, >: move and create a symlink -# @|$|*: run $cmd on delete, @cmd on create, *cmd on both +# !: do not create device node +# @|$|*: run cmd if $ACTION=remove, @cmd if $ACTION=add, *cmd in all cases # support module loading on hotplug $MODALIAS=.* root:root 660 @modprobe "$MODALIAS" @@ -49,7 +53,7 @@ sr[0-9]* root:cdrom 660 @ln -sf $MDEV cdrom fd[0-9]* root:floppy 660 # net devices --net/.* root:root 600 @nameif +SUBSYSTEM=net;.* root:root 600 @nameif tun[0-9]* root:root 600 =net/ tap[0-9]* root:root 600 =net/ @@ -108,3 +112,33 @@ usbdev[0-9].[0-9]_.* root:root 660 # zaptel devices zap(.*) root:dialout 660 =zap/%1 dahdi!(.*) root:dialout 660 =dahdi/%1 + +# HTC Android +# Attaching it via USB cable causes a flurry of activity: +# +# mdev[1271]: 48.639459 ACTION:add SUBSYSTEM:usb DEVNAME:bus/usb/001/009 DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5 +# mdev[1271]: mknod bus/usb/001/009 (189,8) 20660 0:0 +# mdev[1272]: 48.642354 ACTION:add SUBSYSTEM:usb DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0 +# mdev[1272]: running: modprobe "$MODALIAS" +# mdev[1273]: 48.650078 ACTION:add SUBSYSTEM:scsi DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11 +# mdev[1274]: 48.651297 ACTION:add SUBSYSTEM:scsi_host DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/scsi_host/host11 +# mdev[1275]: 49.649422 ACTION:add SUBSYSTEM:scsi DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/target11:0:0 +# mdev[1276]: 49.650703 ACTION:add SUBSYSTEM:scsi DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/target11:0:0/11:0:0:0 +# mdev[1276]: running: modprobe "$MODALIAS" +# modprobe: module scsi:t-0x00 not found in modules.dep +# mdev[1277]: 49.658002 ACTION:add SUBSYSTEM:scsi_disk DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/target11:0:0/11:0:0:0/scsi_disk/11:0:0:0 +# mdev[1278]: 49.659244 ACTION:add SUBSYSTEM:scsi_device DEVNAME:(null) DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/target11:0:0/11:0:0:0/scsi_device/11:0:0: +# mdev[1279]: 49.660535 ACTION:add SUBSYSTEM:bsg DEVNAME:bsg/11:0:0:0 DEVPATH:/devices/pci0000:00/0000:00:02.1/usb1/1-5/1-5:1.0/host11/target11:0:0/11:0:0:0/bsg/11:0:0:0 +# mdev[1279]: mknod bsg/11:0:0:0 (253,1) 20660 0:0 +# mdev[1280]: 49.663516 ACTION:add SUBSYSTEM:bdi DEVNAME:(null) DEVPATH:/devices/virtual/bdi/8:16 +# mdev[1281]: 49.664748 ACTION:add SUBSYSTEM:block DEVNAME:sdb DEVPATH:/block/sdb +# mdev[1281]: mknod sdb (8,16) 60660 0:0 +# mdev[1282]: 49.677597 ACTION:change SUBSYSTEM:block DEVNAME:sdb DEVPATH:/block/sdb +# mdev[1283]: 50.692936 ACTION:change SUBSYSTEM:block DEVNAME:sdb DEVPATH:/block/sdb +# +# We are hooking to the last events. To avoid having two scripts running, +# we check for DISK_MEDIA_CHANGE=1 (prev to last event has it, +# and it's the _only_ difference in env for these two events as of kernel 3.7.7) +# Unfortunately, there is no event for "user pressed [Turn USB storage] btn"! +# Script merely backgrounds and tries to rescan partition table for 1 minute: +ACTION=change;SUBSYSTEM=block;DISK_MEDIA_CHANGE=1;.* 0:0 660 */etc/mdev.conf.change_blockdev.sh diff --git a/examples/udhcp/sample.bound b/examples/udhcp/sample.bound index 2a95d8b..bd3569c 100755 --- a/examples/udhcp/sample.bound +++ b/examples/udhcp/sample.bound @@ -28,4 +28,4 @@ for i in $dns do echo adding dns $i echo nameserver $i >> $RESOLV_CONF -done \ No newline at end of file +done diff --git a/examples/udhcp/sample.renew b/examples/udhcp/sample.renew index 842bafe..ea368fc 100755 --- a/examples/udhcp/sample.renew +++ b/examples/udhcp/sample.renew @@ -28,4 +28,4 @@ for i in $dns do echo adding dns $i echo nameserver $i >> $RESOLV_CONF -done \ No newline at end of file +done diff --git a/examples/udhcp/simple.script b/examples/udhcp/simple.script index 40ee738..2a917eb 100755 --- a/examples/udhcp/simple.script +++ b/examples/udhcp/simple.script @@ -29,18 +29,23 @@ case "$1" in metric=0 for i in $router ; do echo "Adding router $i" - route add default gw $i dev $interface metric $((metric++)) + route add default gw $i dev $interface metric $metric + : $(( metric += 1 )) done fi echo "Recreating $RESOLV_CONF" - echo -n > $RESOLV_CONF-$$ - [ -n "$domain" ] && echo "search $domain" >> $RESOLV_CONF-$$ + # If the file is a symlink somewhere (like /etc/resolv.conf + # pointing to /run/resolv.conf), make sure things work. + realconf=$(readlink -f "$RESOLV_CONF" 2>/dev/null || echo "$RESOLV_CONF") + tmpfile="$realconf-$$" + > "$tmpfile" + [ -n "$domain" ] && echo "search $domain" >> "$tmpfile" for i in $dns ; do echo " Adding DNS server $i" - echo "nameserver $i" >> $RESOLV_CONF-$$ + echo "nameserver $i" >> "$tmpfile" done - mv $RESOLV_CONF-$$ $RESOLV_CONF + mv "$tmpfile" "$realconf" ;; esac diff --git a/examples/udhcp/udhcpd.conf b/examples/udhcp/udhcpd.conf index 23fc834..eca44c0 100644 --- a/examples/udhcp/udhcpd.conf +++ b/examples/udhcp/udhcpd.conf @@ -14,11 +14,6 @@ interface eth0 # smaller than lease block. #max_leases 254 -# The time period at which udhcpd will write out a dhcpd.leases -# file. If this is 0, udhcpd will never automatically write a -# lease file. Specified in seconds. -#auto_time 7200 - # The amount of time that an IP will be reserved (leased to nobody) # if a DHCP decline message is received (seconds) #decline_time 3600 @@ -34,11 +29,16 @@ interface eth0 # to this value (seconds) #min_lease 60 +# The location of the pid file +#pidfile /var/run/udhcpd.pid + # The location of the leases file #lease_file /var/lib/misc/udhcpd.leases -# The location of the pid file -#pidfile /var/run/udhcpd.pid +# The time period at which udhcpd will write out leases file. +# If this is 0, udhcpd will never automatically write leases file. +# Specified in seconds. +#auto_time 7200 # Every time udhcpd writes a leases file, the below script will be called #notify_file # default: no script @@ -68,6 +68,8 @@ opt wins 192.168.10.10 option dns 129.219.13.81 # appended to above DNS servers for a total of 3 option domain local option lease 864000 # default: 10 days +option msstaticroutes 10.0.0.0/8 10.127.0.1 # single static route +option staticroutes 10.0.0.0/8 10.127.0.1, 10.11.12.0/24 10.11.12.1 # Arbitrary option in hex form: option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" @@ -90,6 +92,8 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" #opt wpad STRING #opt serverid IP # default: server's IP #opt message STRING # error message (udhcpd sends it on success too) +#opt vlanid NUM # 802.1P VLAN ID +#opt vlanpriority NUM # 802.1Q VLAN priority # Options specifying server(s) #opt dns IP_LIST #opt wins IP_LIST @@ -97,8 +101,15 @@ option 0x08 01020304 # option 8: "cookie server IP addr: 1.2.3.4" #opt ntpsrv IP_LIST #opt lprsrv IP_LIST #opt swapsrv IP +# Options specifying routes +#opt routes IP_PAIR_LIST +#opt staticroutes STATIC_ROUTES # RFC 3442 classless static route option +#opt msstaticroutes STATIC_ROUTES # same, using MS option number # Obsolete options, no longer supported #opt logsrv IP_LIST # 704/UDP log server (not syslog!) #opt namesrv IP_LIST # IEN 116 name server, obsolete (August 1979!!!) #opt cookiesrv IP_LIST # RFC 865 "quote of the day" server, rarely (never?) used #opt timesrv IP_LIST # RFC 868 time server, rarely (never?) used +# TODO: in development +#opt userclass STRING # RFC 3004. set of LASCII strings. "I am a printer" etc +#opt sipserv STRING LIST # RFC 3361. flag byte, then: 0: domain names, 1: IP addrs diff --git a/examples/var_service/README b/examples/var_service/README new file mode 100644 index 0000000..06817c8 --- /dev/null +++ b/examples/var_service/README @@ -0,0 +1,59 @@ +In many cases, network configuration makes it necessary to run several daemons: +dhcp, zeroconf, ppp, openvpn and such. They need to be controlled, +and in many cases you also want to babysit them. runsvdir is a good tool for this. +examples/var_service directory provides a few examples. It is meant to be used +this way: copy it somewhere (say, /var/service) and run something like + +env - PATH=... runsvdir /var/service & + +from one of system startup scripts. (Google "man runsvdir" and "man runsv" +for more info about these tools). + +Some existing examples: + +var_service/dhcp_if - +controls a udhcpc instance which provides dhpc-assigned IP +address on interface named "if". Copy/rename this directory as needed to run +udhcpc on other interfaces (var_service/dhcp_if/run script uses _foo suffix +of the parent directory as interface name). When IP address is obtained or lost, +var_service/dhcp_if/dhcp_handler is run. It saves new config data to +/var/run/service/fw/dhcp_if.ipconf and (re)starts /var/service/fw service. +This example can be used as a template for other dynamic network link services +(ppp/vpn/zcip). + +var_service/ifplugd_if - +watches link status of interface if. Downs and ups /var/service/dhcp_if +service accordingly. In effect, it allows you to unplug/plug-to-different-network +and have your IP properly re-negotiated at once. + +var_service/dhcp_if_pinger - +Uses var_service/dhcp_if's data (/var/service/dhcp_if/dhcp_if.out file) +to determine router IP. Pings it. If ping fails, restarts /var/service/dhcp_if +service. Basically, an example of watchdog service for networks +which are not reliable and need babysitting. + +var_service/fw - +A *one-shot* service which reconfigures network based on current known state +of ALL interfaces. Uses conf/*.ipconf (static config) and /var/run/service/fw/*.ipconf +(dynamic config from dhcp/ppp/vpn/etc) to determine what to do. +One-shot-ness of this service means that it shuts itself off after single run. +IOW: it is not a constantly running daemon sort of thing. +It starts, it configures the network, it shuts down, all done +(unlike infamous NetworkManagers which sit in RAM forever, doing hell knows what). + +However, any dhcp/ppp/vpn or similar service can restart it anytime +when it senses the change in network configuration. +This even works while fw service runs: if dhcp signals fw to (re)start +while fw runs, fw will not stop after its execution, but will re-execute once, +picking up dhcp's new configuration. +This is achieved very simply by having +# Make ourself one-shot +sv o . +at the very beginning of fw/run script, not at the end. +Therefore, any "sv u /var/run/service/fw" command by any other +script "undoes" o(ne-shot) command if fw still runs, thus +runsv will rerun it; or start it in a normal way if fw is not running. + +System administrators are expected to edit fw/run script, since +network configuration needs are likely to be very complex and different +for non-trivial installations. diff --git a/examples/zcip.script b/examples/zcip.script index 988e542..e543c30 100755 --- a/examples/zcip.script +++ b/examples/zcip.script @@ -20,9 +20,9 @@ config) exit 1 fi # remember $ip for $interface, to use on restart - if [ "x$IP" != x -a -w "$IP.$interface" ] + if [ "x$ip" != x -a -w "$ip.$interface" ] then - echo $ip > "$IP.$interface" + echo $ip > "$ip.$interface" fi exec ip address add dev $interface \ scope link local "$ip/16" broadcast + diff --git a/findutils/.gitignore b/findutils/.gitignore deleted file mode 100644 index 7a30caf..0000000 --- a/findutils/.gitignore +++ /dev/null @@ -1,3 +0,0 @@ -# Config.in and Kbuild are auto-generated -Config.in -Kbuild diff --git a/findutils/Kbuild.src b/findutils/Kbuild.src index 771789f..6b4fb74 100644 --- a/findutils/Kbuild.src +++ b/findutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/findutils/find.c b/findutils/find.c index 2970814..5d5e24b 100644 --- a/findutils/find.c +++ b/findutils/find.c @@ -7,7 +7,7 @@ * Reworked by David Douthitt and * Matt Kraai . * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* findutils-4.1.20: @@ -53,10 +53,6 @@ * diff -u /tmp/std_find /tmp/bb_find && echo Identical */ -//applet:IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_DROP, find)) - -//kbuild:lib-$(CONFIG_FIND) += find.o - //config:config FIND //config: bool "find" //config: default y @@ -112,11 +108,11 @@ //config: This option allows find to restrict searches to a single filesystem. //config: //config:config FEATURE_FIND_MAXDEPTH -//config: bool "Enable -maxdepth N" +//config: bool "Enable -mindepth N and -maxdepth N" //config: default y //config: depends on FIND //config: help -//config: This option enables -maxdepth N option. +//config: This option enables -mindepth N and -maxdepth N option. //config: //config:config FEATURE_FIND_NEWER //config: bool "Enable -newer: compare file modification times" @@ -124,7 +120,7 @@ //config: depends on FIND //config: help //config: Support the 'find -newer' option for finding any files which have -//config: a modified time that is more recent than the specified FILE. +//config: modification time that is more recent than the specified FILE. //config: //config:config FEATURE_FIND_INUM //config: bool "Enable -inum: inode number matching" @@ -230,11 +226,119 @@ //config: help //config: Support the 'find -links' option for matching number of links. +//applet:IF_FIND(APPLET_NOEXEC(find, find, BB_DIR_USR_BIN, BB_SUID_DROP, find)) + +//kbuild:lib-$(CONFIG_FIND) += find.o + +//usage:#define find_trivial_usage +//usage: "[-HL] [PATH]... [OPTIONS] [ACTIONS]" +//usage:#define find_full_usage "\n\n" +//usage: "Search for files and perform actions on them.\n" +//usage: "First failed action stops processing of current file.\n" +//usage: "Defaults: PATH is current directory, action is '-print'\n" +//usage: "\n -L,-follow Follow symlinks" +//usage: "\n -H ...on command line only" +//usage: IF_FEATURE_FIND_XDEV( +//usage: "\n -xdev Don't descend directories on other filesystems" +//usage: ) +//usage: IF_FEATURE_FIND_MAXDEPTH( +//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" +//usage: "\n actions to command line arguments only" +//usage: "\n -mindepth N Don't act on first N levels" +//usage: ) +//usage: IF_FEATURE_FIND_DEPTH( +//usage: "\n -depth Act on directory *after* traversing it" +//usage: ) +//usage: "\n" +//usage: "\nActions:" +//usage: IF_FEATURE_FIND_PAREN( +//usage: "\n ( ACTIONS ) Group actions for -o / -a" +//usage: ) +//usage: IF_FEATURE_FIND_NOT( +//usage: "\n ! ACT Invert ACT's success/failure" +//usage: ) +//usage: "\n ACT1 [-a] ACT2 If ACT1 fails, stop, else do ACT2" +//usage: "\n ACT1 -o ACT2 If ACT1 succeeds, stop, else do ACT2" +//usage: "\n Note: -a has higher priority than -o" +//usage: "\n -name PATTERN Match file name (w/o directory name) to PATTERN" +//usage: "\n -iname PATTERN Case insensitive -name" +//usage: IF_FEATURE_FIND_PATH( +//usage: "\n -path PATTERN Match path to PATTERN" +//usage: "\n -ipath PATTERN Case insensitive -path" +//usage: ) +//usage: IF_FEATURE_FIND_REGEX( +//usage: "\n -regex PATTERN Match path to regex PATTERN" +//usage: ) +//usage: IF_FEATURE_FIND_TYPE( +//usage: "\n -type X File type is X (one of: f,d,l,b,c,...)" +//usage: ) +//usage: IF_FEATURE_FIND_PERM( +//usage: "\n -perm MASK At least one mask bit (+MASK), all bits (-MASK)," +//usage: "\n or exactly MASK bits are set in file's mode" +//usage: ) +//usage: IF_FEATURE_FIND_MTIME( +//usage: "\n -mtime DAYS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N days in the past" +//usage: ) +//usage: IF_FEATURE_FIND_MMIN( +//usage: "\n -mmin MINS mtime is greater than (+N), less than (-N)," +//usage: "\n or exactly N minutes in the past" +//usage: ) +//usage: IF_FEATURE_FIND_NEWER( +//usage: "\n -newer FILE mtime is more recent than FILE's" +//usage: ) +//usage: IF_FEATURE_FIND_INUM( +//usage: "\n -inum N File has inode number N" +//usage: ) +//usage: IF_FEATURE_FIND_USER( +//usage: "\n -user NAME/ID File is owned by given user" +//usage: ) +//usage: IF_FEATURE_FIND_GROUP( +//usage: "\n -group NAME/ID File is owned by given group" +//usage: ) +//usage: IF_FEATURE_FIND_SIZE( +//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" +//usage: "\n +/-N: file size is bigger/smaller than N" +//usage: ) +//usage: IF_FEATURE_FIND_LINKS( +//usage: "\n -links N Number of links is greater than (+N), less than (-N)," +//usage: "\n or exactly N" +//usage: ) +//usage: IF_FEATURE_FIND_CONTEXT( +//usage: "\n -context CTX File has specified security context" +//usage: ) +//usage: IF_FEATURE_FIND_PRUNE( +//usage: "\n -prune If current file is directory, don't descend into it" +//usage: ) +//usage: "\nIf none of the following actions is specified, -print is assumed" +//usage: "\n -print Print file name" +//usage: IF_FEATURE_FIND_PRINT0( +//usage: "\n -print0 Print file name, NUL terminated" +//usage: ) +//usage: IF_FEATURE_FIND_EXEC( +//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by" +//usage: "\n file name. Fails if CMD exits with nonzero" +//usage: ) +//usage: IF_FEATURE_FIND_DELETE( +//usage: "\n -delete Delete current file/directory. Turns on -depth option" +//usage: ) +//usage: +//usage:#define find_example_usage +//usage: "$ find / -name passwd\n" +//usage: "/etc/passwd\n" + #include #include "libbb.h" #if ENABLE_FEATURE_FIND_REGEX -#include "xregex.h" +# include "xregex.h" #endif +/* GNUism: */ +#ifndef FNM_CASEFOLD +# define FNM_CASEFOLD 0 +#endif + +#define dbg(...) ((void)0) +/* #define dbg(...) bb_error_msg(__VA_ARGS__) */ /* This is a NOEXEC applet. Be very careful! */ @@ -256,7 +360,7 @@ typedef struct { ACTS(print) ACTS(name, const char *pattern; bool iname;) -IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern;)) +IF_FEATURE_FIND_PATH( ACTS(path, const char *pattern; bool ipath;)) IF_FEATURE_FIND_REGEX( ACTS(regex, regex_t compiled_pattern;)) IF_FEATURE_FIND_PRINT0( ACTS(print0)) IF_FEATURE_FIND_TYPE( ACTS(type, int type_mask;)) @@ -278,8 +382,12 @@ IF_FEATURE_FIND_LINKS( ACTS(links, char links_char; int links_count;)) struct globals { IF_FEATURE_FIND_XDEV(dev_t *xdev_dev;) IF_FEATURE_FIND_XDEV(int xdev_count;) +#if ENABLE_FEATURE_FIND_MAXDEPTH + int minmaxdepth[2]; +#endif action ***actions; - bool need_print; + smallint need_print; + smallint xdev_on; recurse_flags_t recurse_flags; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) @@ -288,7 +396,8 @@ struct globals { char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \ }; \ /* we have to zero it out because of NOEXEC */ \ - memset(&G, 0, offsetof(struct globals, need_print)); \ + memset(&G, 0, sizeof(G)); \ + IF_FEATURE_FIND_MAXDEPTH(G.minmaxdepth[1] = INT_MAX;) \ G.need_print = 1; \ G.recurse_flags = ACTION_RECURSE; \ } while (0) @@ -364,14 +473,32 @@ static int exec_actions(action ***appp, const char *fileName, const struct stat #if ENABLE_FEATURE_FIND_NOT if (ap->invert) rc ^= TRUE; #endif + dbg("grp %d action %d rc:0x%x", cur_group, cur_action, rc); if (rc & TRUE) /* current group failed, try next */ break; } } + dbg("returning:0x%x", rc ^ TRUE); return rc ^ TRUE; /* restore TRUE bit */ } +#if !FNM_CASEFOLD +static char *strcpy_upcase(char *dst, const char *src) +{ + char *d = dst; + while (1) { + unsigned char ch = *src++; + if (ch >= 'a' && ch <= 'z') + ch -= ('a' - 'A'); + *d++ = ch; + if (ch == '\0') + break; + } + return dst; +} +#endif + ACTF(name) { const char *tmp = bb_basename(fileName); @@ -387,13 +514,25 @@ ACTF(name) * but somewhere between 4.1.20 and 4.4.0 GNU find stopped using it. * find -name '*foo' should match .foo too: */ +#if FNM_CASEFOLD return fnmatch(ap->pattern, tmp, (ap->iname ? FNM_CASEFOLD : 0)) == 0; +#else + if (ap->iname) + tmp = strcpy_upcase(alloca(strlen(tmp) + 1), tmp); + return fnmatch(ap->pattern, tmp, 0) == 0; +#endif } #if ENABLE_FEATURE_FIND_PATH ACTF(path) { +# if FNM_CASEFOLD + return fnmatch(ap->pattern, fileName, (ap->ipath ? FNM_CASEFOLD : 0)) == 0; +# else + if (ap->ipath) + fileName = strcpy_upcase(alloca(strlen(fileName) + 1), fileName); return fnmatch(ap->pattern, fileName, 0) == 0; +# endif } #endif #if ENABLE_FEATURE_FIND_REGEX @@ -586,16 +725,32 @@ ACTF(links) static int FAST_FUNC fileAction(const char *fileName, struct stat *statbuf, - void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM), + void *userData UNUSED_PARAM, int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM)) { int r; -#if ENABLE_FEATURE_FIND_MAXDEPTH -#define minmaxdepth ((int*)userData) + int same_fs = 1; + +#if ENABLE_FEATURE_FIND_XDEV + if (S_ISDIR(statbuf->st_mode) && G.xdev_count) { + int i; + for (i = 0; i < G.xdev_count; i++) { + if (G.xdev_dev[i] == statbuf->st_dev) + goto found; + } + //bb_error_msg("'%s': not same fs", fileName); + same_fs = 0; + found: ; + } +#endif - if (depth < minmaxdepth[0]) - return TRUE; /* skip this, continue recursing */ - if (depth > minmaxdepth[1]) +#if ENABLE_FEATURE_FIND_MAXDEPTH + if (depth < G.minmaxdepth[0]) { + if (same_fs) + return TRUE; /* skip this, continue recursing */ + return SKIP; /* stop recursing */ + } + if (depth > G.minmaxdepth[1]) return SKIP; /* stop recursing */ #endif @@ -606,30 +761,19 @@ static int FAST_FUNC fileAction(const char *fileName, #if ENABLE_FEATURE_FIND_MAXDEPTH if (S_ISDIR(statbuf->st_mode)) { - if (depth == minmaxdepth[1]) + if (depth == G.minmaxdepth[1]) return SKIP; } #endif -#if ENABLE_FEATURE_FIND_XDEV /* -xdev stops on mountpoints, but AFTER mountpoit itself * is processed as usual */ - if (S_ISDIR(statbuf->st_mode)) { - if (G.xdev_count) { - int i; - for (i = 0; i < G.xdev_count; i++) { - if (G.xdev_dev[i] == statbuf->st_dev) - goto found; - } - return SKIP; - found: ; - } + if (!same_fs) { + return SKIP; } -#endif /* Cannot return 0: our caller, recursive_action(), * will perror() and skip dirs (if called on dir) */ return (r & SKIP) ? SKIP : TRUE; -#undef minmaxdepth } @@ -671,9 +815,37 @@ static const char* plus_minus_num(const char* str) } #endif +/* Say no to GCCism */ +#define USE_NESTED_FUNCTION 0 + +#if !USE_NESTED_FUNCTION +struct pp_locals { + action*** appp; + unsigned cur_group; + unsigned cur_action; + IF_FEATURE_FIND_NOT( bool invert_flag; ) +}; +static action* alloc_action(struct pp_locals *ppl, int sizeof_struct, action_fp f) +{ + action *ap = xzalloc(sizeof_struct); + action **app; + action ***group = &ppl->appp[ppl->cur_group]; + *group = app = xrealloc(*group, (ppl->cur_action+2) * sizeof(ppl->appp[0][0])); + app[ppl->cur_action++] = ap; + app[ppl->cur_action] = NULL; + ap->f = f; + IF_FEATURE_FIND_NOT( ap->invert = ppl->invert_flag; ) + IF_FEATURE_FIND_NOT( ppl->invert_flag = 0; ) + return ap; +} +#endif + static action*** parse_params(char **argv) { enum { + OPT_FOLLOW , + IF_FEATURE_FIND_XDEV( OPT_XDEV ,) + IF_FEATURE_FIND_DEPTH( OPT_DEPTH ,) PARM_a , PARM_o , IF_FEATURE_FIND_NOT( PARM_char_not ,) @@ -684,15 +856,20 @@ static action*** parse_params(char **argv) #endif PARM_print , IF_FEATURE_FIND_PRINT0( PARM_print0 ,) - IF_FEATURE_FIND_DEPTH( PARM_depth ,) IF_FEATURE_FIND_PRUNE( PARM_prune ,) IF_FEATURE_FIND_DELETE( PARM_delete ,) IF_FEATURE_FIND_EXEC( PARM_exec ,) IF_FEATURE_FIND_PAREN( PARM_char_brace,) - /* All options starting from here require argument */ + /* All options/actions starting from here require argument */ PARM_name , PARM_iname , IF_FEATURE_FIND_PATH( PARM_path ,) +#if ENABLE_DESKTOP + /* -wholename is a synonym for -path */ + /* We support it because Linux kernel's "make tags" uses it */ + IF_FEATURE_FIND_PATH( PARM_wholename ,) +#endif + IF_FEATURE_FIND_PATH( PARM_ipath ,) IF_FEATURE_FIND_REGEX( PARM_regex ,) IF_FEATURE_FIND_TYPE( PARM_type ,) IF_FEATURE_FIND_PERM( PARM_perm ,) @@ -705,28 +882,35 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( PARM_size ,) IF_FEATURE_FIND_CONTEXT(PARM_context ,) IF_FEATURE_FIND_LINKS( PARM_links ,) + IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,OPT_MAXDEPTH,) }; static const char params[] ALIGN1 = - "-a\0" - "-o\0" + "-follow\0" + IF_FEATURE_FIND_XDEV( "-xdev\0" ) + IF_FEATURE_FIND_DEPTH( "-depth\0" ) + "-a\0" + "-o\0" IF_FEATURE_FIND_NOT( "!\0" ) #if ENABLE_DESKTOP - "-and\0" - "-or\0" - IF_FEATURE_FIND_NOT( "-not\0" ) + "-and\0" + "-or\0" + IF_FEATURE_FIND_NOT( "-not\0" ) #endif - "-print\0" + "-print\0" IF_FEATURE_FIND_PRINT0( "-print0\0" ) - IF_FEATURE_FIND_DEPTH( "-depth\0" ) IF_FEATURE_FIND_PRUNE( "-prune\0" ) IF_FEATURE_FIND_DELETE( "-delete\0" ) IF_FEATURE_FIND_EXEC( "-exec\0" ) IF_FEATURE_FIND_PAREN( "(\0" ) - /* All options starting from here require argument */ - "-name\0" - "-iname\0" + /* All options/actions starting from here require argument */ + "-name\0" + "-iname\0" IF_FEATURE_FIND_PATH( "-path\0" ) +#if ENABLE_DESKTOP + IF_FEATURE_FIND_PATH( "-wholename\0") +#endif + IF_FEATURE_FIND_PATH( "-ipath\0" ) IF_FEATURE_FIND_REGEX( "-regex\0" ) IF_FEATURE_FIND_TYPE( "-type\0" ) IF_FEATURE_FIND_PERM( "-perm\0" ) @@ -739,54 +923,54 @@ static action*** parse_params(char **argv) IF_FEATURE_FIND_SIZE( "-size\0" ) IF_FEATURE_FIND_CONTEXT("-context\0") IF_FEATURE_FIND_LINKS( "-links\0" ) - ; + IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") + ; +#if !USE_NESTED_FUNCTION + struct pp_locals ppl; +#define appp (ppl.appp ) +#define cur_group (ppl.cur_group ) +#define cur_action (ppl.cur_action ) +#define invert_flag (ppl.invert_flag) +#define ALLOC_ACTION(name) (action_##name*)alloc_action(&ppl, sizeof(action_##name), (action_fp) func_##name) +#else action*** appp; - unsigned cur_group = 0; - unsigned cur_action = 0; - IF_FEATURE_FIND_NOT( bool invert_flag = 0; ) + unsigned cur_group; + unsigned cur_action; + IF_FEATURE_FIND_NOT( bool invert_flag; ) /* This is the only place in busybox where we use nested function. * So far more standard alternatives were bigger. */ - /* Suppress a warning "func without a prototype" */ + /* Auto decl suppresses "func without a prototype" warning: */ auto action* alloc_action(int sizeof_struct, action_fp f); action* alloc_action(int sizeof_struct, action_fp f) { action *ap; - appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(*appp)); - appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct); + appp[cur_group] = xrealloc(appp[cur_group], (cur_action+2) * sizeof(appp[0][0])); + appp[cur_group][cur_action++] = ap = xzalloc(sizeof_struct); appp[cur_group][cur_action] = NULL; ap->f = f; IF_FEATURE_FIND_NOT( ap->invert = invert_flag; ) IF_FEATURE_FIND_NOT( invert_flag = 0; ) return ap; } - #define ALLOC_ACTION(name) (action_##name*)alloc_action(sizeof(action_##name), (action_fp) func_##name) +#endif + cur_group = 0; + cur_action = 0; + IF_FEATURE_FIND_NOT( invert_flag = 0; ) appp = xzalloc(2 * sizeof(appp[0])); /* appp[0],[1] == NULL */ -/* Actions have side effects and return a true or false value - * We implement: -print, -print0, -exec - * - * The rest are tests. - * - * Tests and actions are grouped by operators - * ( expr ) Force precedence - * ! expr True if expr is false - * -not expr Same as ! expr - * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false - * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true - * expr1 , expr2 List; both expr1 and expr2 are always evaluated - * We implement: (), -a, -o - */ while (*argv) { const char *arg = argv[0]; int parm = index_in_strings(params, arg); const char *arg1 = argv[1]; + dbg("arg:'%s' arg1:'%s' parm:%d PARM_type:%d", arg, arg1, parm, PARM_type); + if (parm >= PARM_name) { - /* All options starting from -name require argument */ + /* All options/actions starting from -name require argument */ if (!arg1) bb_error_msg_and_die(bb_msg_requires_arg, arg); argv++; @@ -795,14 +979,52 @@ static action*** parse_params(char **argv) /* We can use big switch() here, but on i386 * it doesn't give smaller code. Other arches? */ - /* --- Operators --- */ - if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { +/* Options always return true. They always take effect + * rather than being processed only when their place in the + * expression is reached. + */ + /* Options */ + if (parm == OPT_FOLLOW) { + dbg("follow enabled: %d", __LINE__); + G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; + } +#if ENABLE_FEATURE_FIND_XDEV + else if (parm == OPT_XDEV) { + dbg("%d", __LINE__); + G.xdev_on = 1; + } +#endif +#if ENABLE_FEATURE_FIND_MAXDEPTH + else if (parm == OPT_MINDEPTH || parm == OPT_MINDEPTH + 1) { + dbg("%d", __LINE__); + G.minmaxdepth[parm - OPT_MINDEPTH] = xatoi_positive(arg1); + } +#endif +#if ENABLE_FEATURE_FIND_DEPTH + else if (parm == OPT_DEPTH) { + dbg("%d", __LINE__); + G.recurse_flags |= ACTION_DEPTHFIRST; + } +#endif +/* Actions are grouped by operators + * ( expr ) Force precedence + * ! expr True if expr is false + * -not expr Same as ! expr + * expr1 [-a[nd]] expr2 And; expr2 is not evaluated if expr1 is false + * expr1 -o[r] expr2 Or; expr2 is not evaluated if expr1 is true + * expr1 , expr2 List; both expr1 and expr2 are always evaluated + * We implement: (), -a, -o + */ + /* Operators */ + else if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) { + dbg("%d", __LINE__); /* no further special handling required */ } else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) { + dbg("%d", __LINE__); /* start new OR group */ cur_group++; - appp = xrealloc(appp, (cur_group+2) * sizeof(*appp)); + appp = xrealloc(appp, (cur_group+2) * sizeof(appp[0])); /*appp[cur_group] = NULL; - already NULL */ appp[cur_group+1] = NULL; cur_action = 0; @@ -811,36 +1033,31 @@ static action*** parse_params(char **argv) else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) { /* also handles "find ! ! -name 'foo*'" */ invert_flag ^= 1; + dbg("invert_flag:%d", invert_flag); } #endif - - /* --- Tests and actions --- */ + /* Actions */ else if (parm == PARM_print) { + dbg("%d", __LINE__); G.need_print = 0; - /* GNU find ignores '!' here: "find ! -print" */ - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print); } #if ENABLE_FEATURE_FIND_PRINT0 else if (parm == PARM_print0) { + dbg("%d", __LINE__); G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) (void) ALLOC_ACTION(print0); } #endif -#if ENABLE_FEATURE_FIND_DEPTH - else if (parm == PARM_depth) { - G.recurse_flags |= ACTION_DEPTHFIRST; - } -#endif #if ENABLE_FEATURE_FIND_PRUNE else if (parm == PARM_prune) { - IF_FEATURE_FIND_NOT( invert_flag = 0; ) + dbg("%d", __LINE__); (void) ALLOC_ACTION(prune); } #endif #if ENABLE_FEATURE_FIND_DELETE else if (parm == PARM_delete) { + dbg("%d", __LINE__); G.need_print = 0; G.recurse_flags |= ACTION_DEPTHFIRST; (void) ALLOC_ACTION(delete); @@ -850,20 +1067,24 @@ static action*** parse_params(char **argv) else if (parm == PARM_exec) { int i; action_exec *ap; + dbg("%d", __LINE__); G.need_print = 0; - IF_FEATURE_FIND_NOT( invert_flag = 0; ) ap = ALLOC_ACTION(exec); ap->exec_argv = ++argv; /* first arg after -exec */ - ap->exec_argc = 0; + /*ap->exec_argc = 0; - ALLOC_ACTION did it */ while (1) { if (!*argv) /* did not see ';' or '+' until end */ bb_error_msg_and_die(bb_msg_requires_arg, "-exec"); - if (LONE_CHAR(argv[0], ';')) + // find -exec echo Foo ">{}<" ";" + // executes "echo Foo >FILENAME<", + // find -exec echo Foo ">{}<" "+" + // executes "echo Foo FILENAME1 FILENAME2 FILENAME3...". + // TODO (so far we treat "+" just like ";") + if ((argv[0][0] == ';' || argv[0][0] == '+') + && argv[0][1] == '\0' + ) { break; - //TODO: implement {} + (like xargs) - // See: - // find findutils/ -exec echo ">"{}"<" \; - // find findutils/ -exec echo ">"{}"<" + + } argv++; ap->exec_argc++; } @@ -881,6 +1102,7 @@ static action*** parse_params(char **argv) char **endarg; unsigned nested = 1; + dbg("%d", __LINE__); endarg = argv; while (1) { if (!*++endarg) @@ -900,20 +1122,24 @@ static action*** parse_params(char **argv) #endif else if (parm == PARM_name || parm == PARM_iname) { action_name *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(name); ap->pattern = arg1; ap->iname = (parm == PARM_iname); } #if ENABLE_FEATURE_FIND_PATH - else if (parm == PARM_path) { + else if (parm == PARM_path IF_DESKTOP(|| parm == PARM_wholename) || parm == PARM_ipath) { action_path *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(path); ap->pattern = arg1; + ap->ipath = (parm == PARM_ipath); } #endif #if ENABLE_FEATURE_FIND_REGEX else if (parm == PARM_regex) { action_regex *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(regex); xregcomp(&ap->compiled_pattern, arg1, 0 /*cflags*/); } @@ -923,20 +1149,22 @@ static action*** parse_params(char **argv) action_type *ap; ap = ALLOC_ACTION(type); ap->type_mask = find_type(arg1); + dbg("created:type mask:%x", ap->type_mask); } #endif #if ENABLE_FEATURE_FIND_PERM -/* -perm mode File's permission bits are exactly mode (octal or symbolic). +/* -perm BITS File's mode bits are exactly BITS (octal or symbolic). * Symbolic modes use mode 0 as a point of departure. - * -perm -mode All of the permission bits mode are set for the file. - * -perm +mode Any of the permission bits mode are set for the file. + * -perm -BITS All of the BITS are set in file's mode. + * -perm +BITS At least one of the BITS is set in file's mode. */ else if (parm == PARM_perm) { action_perm *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(perm); ap->perm_char = arg1[0]; arg1 = plus_minus_num(arg1); - ap->perm_mask = 0; + /*ap->perm_mask = 0; - ALLOC_ACTION did it */ if (!bb_parse_mode(arg1, &ap->perm_mask)) bb_error_msg_and_die("invalid mode '%s'", arg1); } @@ -944,6 +1172,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_MTIME else if (parm == PARM_mtime) { action_mtime *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(mtime); ap->mtime_char = arg1[0]; ap->mtime_days = xatoul(plus_minus_num(arg1)); @@ -952,6 +1181,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_MMIN else if (parm == PARM_mmin) { action_mmin *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(mmin); ap->mmin_char = arg1[0]; ap->mmin_mins = xatoul(plus_minus_num(arg1)); @@ -961,6 +1191,7 @@ static action*** parse_params(char **argv) else if (parm == PARM_newer) { struct stat stat_newer; action_newer *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(newer); xstat(arg1, &stat_newer); ap->newer_mtime = stat_newer.st_mtime; @@ -969,6 +1200,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_INUM else if (parm == PARM_inum) { action_inum *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(inum); ap->inode_num = xatoul(arg1); } @@ -976,6 +1208,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_USER else if (parm == PARM_user) { action_user *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(user); ap->uid = bb_strtou(arg1, NULL, 10); if (errno) @@ -985,6 +1218,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_GROUP else if (parm == PARM_group) { action_group *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(group); ap->gid = bb_strtou(arg1, NULL, 10); if (errno) @@ -1013,6 +1247,7 @@ static action*** parse_params(char **argv) { "", 0 } }; action_size *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(size); ap->size_char = arg1[0]; ap->size = XATOU_SFX(plus_minus_num(arg1), find_suffixes); @@ -1021,8 +1256,9 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_CONTEXT else if (parm == PARM_context) { action_context *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(context); - ap->context = NULL; + /*ap->context = NULL; - ALLOC_ACTION did it */ /* SELinux headers erroneously declare non-const parameter */ if (selinux_raw_to_trans_context((char*)arg1, &ap->context)) bb_simple_perror_msg(arg1); @@ -1031,6 +1267,7 @@ static action*** parse_params(char **argv) #if ENABLE_FEATURE_FIND_LINKS else if (parm == PARM_links) { action_links *ap; + dbg("%d", __LINE__); ap = ALLOC_ACTION(links); ap->links_char = arg1[0]; ap->links_count = xatoul(plus_minus_num(arg1)); @@ -1042,197 +1279,94 @@ static action*** parse_params(char **argv) } argv++; } + dbg("exiting %s", __func__); return appp; #undef ALLOC_ACTION +#undef appp +#undef cur_action +#undef invert_flag } -//usage:#define find_trivial_usage -//usage: "[PATH]... [EXPRESSION]" -//usage:#define find_full_usage "\n\n" -//usage: "Search for files. The default PATH is the current directory,\n" -//usage: "default EXPRESSION is '-print'\n" -//usage: "\nEXPRESSION may consist of:" -//usage: "\n -follow Follow symlinks" -//usage: IF_FEATURE_FIND_XDEV( -//usage: "\n -xdev Don't descend directories on other filesystems" -//usage: ) -//usage: IF_FEATURE_FIND_MAXDEPTH( -//usage: "\n -maxdepth N Descend at most N levels. -maxdepth 0 applies" -//usage: "\n tests/actions to command line arguments only" -//usage: ) -//usage: "\n -mindepth N Don't act on first N levels" -//usage: "\n -name PATTERN File name (w/o directory name) matches PATTERN" -//usage: "\n -iname PATTERN Case insensitive -name" -//usage: IF_FEATURE_FIND_PATH( -//usage: "\n -path PATTERN Path matches PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_REGEX( -//usage: "\n -regex PATTERN Path matches regex PATTERN" -//usage: ) -//usage: IF_FEATURE_FIND_TYPE( -//usage: "\n -type X File type is X (X is one of: f,d,l,b,c,...)" -//usage: ) -//usage: IF_FEATURE_FIND_PERM( -//usage: "\n -perm NNN Permissions match any of (+NNN), all of (-NNN)," -//usage: "\n or exactly NNN" -//usage: ) -//usage: IF_FEATURE_FIND_MTIME( -//usage: "\n -mtime DAYS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N days" -//usage: ) -//usage: IF_FEATURE_FIND_MMIN( -//usage: "\n -mmin MINS Modified time is greater than (+N), less than (-N)," -//usage: "\n or exactly N minutes" -//usage: ) -//usage: IF_FEATURE_FIND_NEWER( -//usage: "\n -newer FILE Modified time is more recent than FILE's" -//usage: ) -//usage: IF_FEATURE_FIND_INUM( -//usage: "\n -inum N File has inode number N" -//usage: ) -//usage: IF_FEATURE_FIND_USER( -//usage: "\n -user NAME File is owned by user NAME (numeric user ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_GROUP( -//usage: "\n -group NAME File belongs to group NAME (numeric group ID allowed)" -//usage: ) -//usage: IF_FEATURE_FIND_DEPTH( -//usage: "\n -depth Process directory name after traversing it" -//usage: ) -//usage: IF_FEATURE_FIND_SIZE( -//usage: "\n -size N[bck] File size is N (c:bytes,k:kbytes,b:512 bytes(def.))" -//usage: "\n +/-N: file size is bigger/smaller than N" -//usage: ) -//usage: IF_FEATURE_FIND_LINKS( -//usage: "\n -links N Number of links is greater than (+N), less than (-N)," -//usage: "\n or exactly N" -//usage: ) -//usage: "\n -print Print (default and assumed)" -//usage: IF_FEATURE_FIND_PRINT0( -//usage: "\n -print0 Delimit output with null characters rather than" -//usage: "\n newlines" -//usage: ) -//usage: IF_FEATURE_FIND_CONTEXT( -//usage: "\n -context File has specified security context" -//usage: ) -//usage: IF_FEATURE_FIND_EXEC( -//usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" -//usage: "\n matching files" -//usage: ) -//usage: IF_FEATURE_FIND_PRUNE( -//usage: "\n -prune Stop traversing current subtree" -//usage: ) -//usage: IF_FEATURE_FIND_DELETE( -//usage: "\n -delete Delete files, turns on -depth option" -//usage: ) -//usage: IF_FEATURE_FIND_PAREN( -//usage: "\n (EXPR) Group an expression" -//usage: ) -//usage: -//usage:#define find_example_usage -//usage: "$ find / -name passwd\n" -//usage: "/etc/passwd\n" - int find_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int find_main(int argc UNUSED_PARAM, char **argv) { - static const char options[] ALIGN1 = - "-follow\0" -IF_FEATURE_FIND_XDEV( "-xdev\0" ) -IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0") - ; - enum { - OPT_FOLLOW, -IF_FEATURE_FIND_XDEV( OPT_XDEV ,) -IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,) - }; - - char *arg; - char **argp; int i, firstopt, status = EXIT_SUCCESS; -#if ENABLE_FEATURE_FIND_MAXDEPTH - int minmaxdepth[2] = { 0, INT_MAX }; -#else -#define minmaxdepth NULL -#endif + char **past_HLP, *saved; INIT_G(); - for (firstopt = 1; argv[firstopt]; firstopt++) { + /* "find -type f" + getopt("+HLP") => disaster. + * Need to avoid getopt running into a non-HLP option. + * Do this by temporarily storing NULL there: + */ + past_HLP = argv; + for (;;) { + saved = *++past_HLP; + if (!saved) + break; + if (saved[0] != '-') + break; + if (!saved[1]) + break; /* it is "-" */ + if ((saved+1)[strspn(saved+1, "HLP")] != '\0') + break; + } + *past_HLP = NULL; + /* "+": stop on first non-option */ + i = getopt32(argv, "+HLP"); + if (i & (1<<0)) + G.recurse_flags |= ACTION_FOLLOWLINKS_L0 | ACTION_DANGLING_OK; + if (i & (1<<1)) + G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; + /* -P is default and is ignored */ + argv = past_HLP; /* same result as "argv += optind;" */ + *past_HLP = saved; + + for (firstopt = 0; argv[firstopt]; firstopt++) { if (argv[firstopt][0] == '-') break; if (ENABLE_FEATURE_FIND_NOT && LONE_CHAR(argv[firstopt], '!')) break; -#if ENABLE_FEATURE_FIND_PAREN - if (LONE_CHAR(argv[firstopt], '(')) + if (ENABLE_FEATURE_FIND_PAREN && LONE_CHAR(argv[firstopt], '(')) break; -#endif } - if (firstopt == 1) { - argv[0] = (char*)"."; - argv--; + if (firstopt == 0) { + *--argv = (char*)"."; firstopt++; } -/* All options always return true. They always take effect - * rather than being processed only when their place in the - * expression is reached. - * We implement: -follow, -xdev, -maxdepth - */ - /* Process options, and replace then with -a */ - /* (-a will be ignored by recursive parser later) */ - argp = &argv[firstopt]; - while ((arg = argp[0])) { - int opt = index_in_strings(options, arg); - if (opt == OPT_FOLLOW) { - G.recurse_flags |= ACTION_FOLLOWLINKS | ACTION_DANGLING_OK; - argp[0] = (char*)"-a"; - } + G.actions = parse_params(&argv[firstopt]); + argv[firstopt] = NULL; + #if ENABLE_FEATURE_FIND_XDEV - if (opt == OPT_XDEV) { - struct stat stbuf; - if (!G.xdev_count) { - G.xdev_count = firstopt - 1; - G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); - for (i = 1; i < firstopt; i++) { - /* not xstat(): shouldn't bomb out on - * "find not_exist exist -xdev" */ - if (stat(argv[i], &stbuf) == 0) - G.xdev_dev[i-1] = stbuf.st_dev; - /* else G.xdev_dev[i-1] stays 0 and - * won't match any real device dev_t */ - } - } - argp[0] = (char*)"-a"; - } -#endif -#if ENABLE_FEATURE_FIND_MAXDEPTH - if (opt == OPT_MINDEPTH || opt == OPT_MINDEPTH + 1) { - if (!argp[1]) - bb_show_usage(); - minmaxdepth[opt - OPT_MINDEPTH] = xatoi_u(argp[1]); - argp[0] = (char*)"-a"; - argp[1] = (char*)"-a"; - argp++; + if (G.xdev_on) { + struct stat stbuf; + + G.xdev_count = firstopt; + G.xdev_dev = xzalloc(G.xdev_count * sizeof(G.xdev_dev[0])); + for (i = 0; argv[i]; i++) { + /* not xstat(): shouldn't bomb out on + * "find not_exist exist -xdev" */ + if (stat(argv[i], &stbuf) == 0) + G.xdev_dev[i] = stbuf.st_dev; + /* else G.xdev_dev[i] stays 0 and + * won't match any real device dev_t + */ } -#endif - argp++; } +#endif - G.actions = parse_params(&argv[firstopt]); - - for (i = 1; i < firstopt; i++) { + for (i = 0; argv[i]; i++) { if (!recursive_action(argv[i], G.recurse_flags,/* flags */ fileAction, /* file action */ fileAction, /* dir action */ -#if ENABLE_FEATURE_FIND_MAXDEPTH - minmaxdepth, /* user data */ -#else NULL, /* user data */ -#endif - 0)) /* depth */ + 0) /* depth */ + ) { status = EXIT_FAILURE; + } } + return status; } diff --git a/findutils/grep.c b/findutils/grep.c index ac290a9..a7bc4ca 100644 --- a/findutils/grep.c +++ b/findutils/grep.c @@ -5,7 +5,7 @@ * Copyright (C) 1999,2000,2001 by Lineo, inc. and Mark Whitley * Copyright (C) 1999,2000,2001 by Mark Whitley * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 defects - unsupported option -x "match whole line only". */ /* BB_AUDIT GNU defects - always acts as -a. */ @@ -18,9 +18,9 @@ * (C) 2006 Jac Goudsmit added -o option */ -//applet:IF_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_DROP)) -//applet:IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, egrep)) -//applet:IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_DROP, fgrep)) +//applet:IF_GREP(APPLET(grep, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, BB_DIR_BIN, BB_SUID_DROP, egrep)) +//applet:IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, BB_DIR_BIN, BB_SUID_DROP, fgrep)) //kbuild:lib-$(CONFIG_GREP) += grep.o @@ -72,7 +72,6 @@ //usage: "PATTERN/-e PATTERN.../-f FILE [FILE]..." //usage:#define grep_full_usage "\n\n" //usage: "Search for PATTERN in FILEs (or stdin)\n" -//usage: "\nOptions:" //usage: "\n -H Add 'filename:' prefix" //usage: "\n -h Do not add 'filename:' prefix" //usage: "\n -n Add 'line_no:' prefix" @@ -86,6 +85,7 @@ //usage: "\n -r Recurse" //usage: "\n -i Ignore case" //usage: "\n -w Match whole words only" +//usage: "\n -x Match whole lines only" //usage: "\n -F PATTERN is a literal (not regexp)" //usage: IF_FEATURE_GREP_EGREP_ALIAS( //usage: "\n -E PATTERN is an extended regexp" @@ -114,7 +114,7 @@ //usage:#define fgrep_full_usage "" #define OPTSTR_GREP \ - "lnqvscFiHhe:f:Lorm:w" \ + "lnqvscFiHhe:f:Lorm:wx" \ IF_FEATURE_GREP_CONTEXT("A:B:C:") \ IF_FEATURE_GREP_EGREP_ALIAS("E") \ IF_EXTRA_COMPAT("z") \ @@ -139,6 +139,7 @@ enum { OPTBIT_r, /* recurse dirs */ OPTBIT_m, /* -m MAX_MATCHES */ OPTBIT_w, /* -w whole word match */ + OPTBIT_x, /* -x whole line match */ IF_FEATURE_GREP_CONTEXT( OPTBIT_A ,) /* -A NUM: after-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_B ,) /* -B NUM: before-match context */ IF_FEATURE_GREP_CONTEXT( OPTBIT_C ,) /* -C NUM: -A and -B combined */ @@ -161,6 +162,7 @@ enum { OPT_r = 1 << OPTBIT_r, OPT_m = 1 << OPTBIT_m, OPT_w = 1 << OPTBIT_w, + OPT_x = 1 << OPTBIT_x, OPT_A = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_A)) + 0, OPT_B = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_B)) + 0, OPT_C = IF_FEATURE_GREP_CONTEXT( (1 << OPTBIT_C)) + 0, @@ -342,11 +344,40 @@ static int grep_file(FILE *file) while (pattern_ptr) { gl = (grep_list_data_t *)pattern_ptr->data; if (FGREP_FLAG) { - found |= (((option_mask32 & OPT_i) - ? strcasestr(line, gl->pattern) - : strstr(line, gl->pattern) - ) != NULL); + char *match; + char *str = line; + opt_f_again: + match = ((option_mask32 & OPT_i) + ? strcasestr(str, gl->pattern) + : strstr(str, gl->pattern) + ); + if (match) { + if (option_mask32 & OPT_x) { + if (match != str) + goto opt_f_not_found; + if (str[strlen(gl->pattern)] != '\0') + goto opt_f_not_found; + } else + if (option_mask32 & OPT_w) { + char c = (match != str) ? match[-1] : ' '; + if (!isalnum(c) && c != '_') { + c = match[strlen(gl->pattern)]; + if (!c || (!isalnum(c) && c != '_')) + goto opt_f_found; + } + str = match + 1; + goto opt_f_again; + } + opt_f_found: + found = 1; + opt_f_not_found: ; + } } else { +#if ENABLE_EXTRA_COMPAT + unsigned start_pos; +#endif + char *match_at; + if (!(gl->flg_mem_alocated_compiled & COMPILED)) { gl->flg_mem_alocated_compiled |= COMPILED; #if !ENABLE_EXTRA_COMPAT @@ -361,26 +392,55 @@ static int grep_file(FILE *file) #if !ENABLE_EXTRA_COMPAT gl->matched_range.rm_so = 0; gl->matched_range.rm_eo = 0; +#else + start_pos = 0; #endif + match_at = line; + opt_w_again: +//bb_error_msg("'%s' start_pos:%d line_len:%d", match_at, start_pos, line_len); if ( #if !ENABLE_EXTRA_COMPAT - regexec(&gl->compiled_regex, line, 1, &gl->matched_range, 0) == 0 + regexec(&gl->compiled_regex, match_at, 1, &gl->matched_range, 0) == 0 #else - re_search(&gl->compiled_regex, line, line_len, - /*start:*/ 0, /*range:*/ line_len, + re_search(&gl->compiled_regex, match_at, line_len, + start_pos, /*range:*/ line_len, &gl->matched_range) >= 0 #endif ) { - if (!(option_mask32 & OPT_w)) + if (option_mask32 & OPT_x) { + found = (gl->matched_range.rm_so == 0 + && match_at[gl->matched_range.rm_eo] == '\0'); + } else + if (!(option_mask32 & OPT_w)) { found = 1; - else { + } else { char c = ' '; if (gl->matched_range.rm_so) - c = line[gl->matched_range.rm_so - 1]; + c = match_at[gl->matched_range.rm_so - 1]; if (!isalnum(c) && c != '_') { - c = line[gl->matched_range.rm_eo]; - if (!c || (!isalnum(c) && c != '_')) + c = match_at[gl->matched_range.rm_eo]; + if (!c || (!isalnum(c) && c != '_')) { found = 1; + } else { + /* + * Why check gl->matched_range.rm_eo? + * Zero-length match makes -w skip the line: + * "echo foo | grep ^" prints "foo", + * "echo foo | grep -w ^" prints nothing. + * Without such check, we can loop forever. + */ +#if !ENABLE_EXTRA_COMPAT + if (gl->matched_range.rm_eo != 0) { + match_at += gl->matched_range.rm_eo; + goto opt_w_again; + } +#else + if (gl->matched_range.rm_eo > start_pos) { + start_pos = gl->matched_range.rm_eo; + goto opt_w_again; + } +#endif + } } } } @@ -461,15 +521,19 @@ static int grep_file(FILE *file) if (found) print_line(gl->pattern, strlen(gl->pattern), linenum, ':'); } else while (1) { + unsigned start = gl->matched_range.rm_so; unsigned end = gl->matched_range.rm_eo; + unsigned len = end - start; char old = line[end]; line[end] = '\0'; - print_line(line + gl->matched_range.rm_so, - end - gl->matched_range.rm_so, - linenum, ':'); + /* Empty match is not printed: try "echo test | grep -o ''" */ + if (len != 0) + print_line(line + start, len, linenum, ':'); if (old == '\0') break; line[end] = old; + if (len == 0) + end++; #if !ENABLE_EXTRA_COMPAT if (regexec(&gl->compiled_regex, line + end, 1, &gl->matched_range, REG_NOTBOL) != 0) @@ -559,20 +623,20 @@ static char *add_grep_list_data(char *pattern) static void load_regexes_from_file(llist_t *fopt) { - char *line; - FILE *f; - while (fopt) { + char *line; + FILE *fp; llist_t *cur = fopt; char *ffile = cur->data; fopt = cur->link; free(cur); - f = xfopen_stdin(ffile); - while ((line = xmalloc_fgetline(f)) != NULL) { + fp = xfopen_stdin(ffile); + while ((line = xmalloc_fgetline(fp)) != NULL) { llist_add_to(&pattern_head, new_grep_list_data(line, ALLOCATED)); } + fclose_if_not_stdin(fp); } } @@ -617,30 +681,33 @@ int grep_main(int argc UNUSED_PARAM, char **argv) /* do normal option parsing */ #if ENABLE_FEATURE_GREP_CONTEXT - int Copt; + int Copt, opts; /* -H unsets -h; -C unsets -A,-B; -e,-f are lists; * -m,-A,-B,-C have numeric param */ opt_complementary = "H-h:C-AB:e::f::m+:A+:B+:C+"; - getopt32(argv, + opts = getopt32(argv, OPTSTR_GREP, &pattern_head, &fopt, &max_matches, &lines_after, &lines_before, &Copt); - if (option_mask32 & OPT_C) { + if (opts & OPT_C) { /* -C unsets prev -A and -B, but following -A or -B - may override it */ - if (!(option_mask32 & OPT_A)) /* not overridden */ + * may override it */ + if (!(opts & OPT_A)) /* not overridden */ lines_after = Copt; - if (!(option_mask32 & OPT_B)) /* not overridden */ + if (!(opts & OPT_B)) /* not overridden */ lines_before = Copt; } /* sanity checks */ - if (option_mask32 & (OPT_c|OPT_q|OPT_l|OPT_L)) { + if (opts & (OPT_c|OPT_q|OPT_l|OPT_L)) { option_mask32 &= ~OPT_n; lines_before = 0; lines_after = 0; } else if (lines_before > 0) { + if (lines_before > INT_MAX / sizeof(long long)) + lines_before = INT_MAX / sizeof(long long); + /* overflow in (lines_before * sizeof(x)) is prevented (above) */ before_buf = xzalloc(lines_before * sizeof(before_buf[0])); IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));) } @@ -653,21 +720,25 @@ int grep_main(int argc UNUSED_PARAM, char **argv) #endif invert_search = ((option_mask32 & OPT_v) != 0); /* 0 | 1 */ - if (pattern_head != NULL) { - /* convert char **argv to grep_list_data_t */ + { /* convert char **argv to grep_list_data_t */ llist_t *cur; - for (cur = pattern_head; cur; cur = cur->link) cur->data = new_grep_list_data(cur->data, 0); } - if (option_mask32 & OPT_f) + if (option_mask32 & OPT_f) { load_regexes_from_file(fopt); + if (!pattern_head) { /* -f EMPTY_FILE? */ + /* GNU grep treats it as "nothing matches" */ + llist_add_to(&pattern_head, new_grep_list_data((char*) "", 0)); + invert_search ^= 1; + } + } if (ENABLE_FEATURE_GREP_FGREP_ALIAS && applet_name[0] == 'f') option_mask32 |= OPT_F; #if !ENABLE_EXTRA_COMPAT - if (!(option_mask32 & (OPT_o | OPT_w))) + if (!(option_mask32 & (OPT_o | OPT_w | OPT_x))) reflags = REG_NOSUB; #endif diff --git a/findutils/xargs.c b/findutils/xargs.c index 7b9f1fb..0d1bb43 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -9,16 +9,12 @@ * - Mike Rendell * and David MacKenzie . * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * xargs is described in the Single Unix Specification v3 at * http://www.opengroup.org/onlinepubs/007904975/utilities/xargs.html */ -//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_DROP, xargs)) - -//kbuild:lib-$(CONFIG_XARGS) += xargs.o - //config:config XARGS //config: bool "xargs" //config: default y @@ -58,6 +54,10 @@ //config: instead of whitespace, and the quotes and backslash //config: are not special. +//applet:IF_XARGS(APPLET_NOEXEC(xargs, xargs, BB_DIR_USR_BIN, BB_SUID_DROP, xargs)) + +//kbuild:lib-$(CONFIG_XARGS) += xargs.o + #include "libbb.h" /* This is a NOEXEC applet. Be very careful! */ @@ -89,7 +89,9 @@ struct globals { int idx; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) +#define INIT_G() do { \ + G.eof_str = NULL; /* need to clear by hand because we are NOEXEC applet */ \ +} while (0) /* @@ -347,7 +349,6 @@ static int xargs_ask_confirmation(void) //usage: "[OPTIONS] [PROG ARGS]" //usage:#define xargs_full_usage "\n\n" //usage: "Run PROG on every item given by stdin\n" -//usage: "\nOptions:" //usage: IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( //usage: "\n -p Ask user whether to run each command" //usage: ) @@ -412,7 +413,12 @@ int xargs_main(int argc, char **argv) INIT_G(); - G.eof_str = NULL; +#if ENABLE_DESKTOP && ENABLE_LONG_OPTS + /* For example, Fedora's build system uses --no-run-if-empty */ + applet_long_options = + "no-run-if-empty\0" No_argument "r" + ; +#endif opt = getopt32(argv, OPTION_STR, &max_args, &max_chars, &G.eof_str, &G.eof_str); /* -E ""? You may wonder why not just omit -E? diff --git a/include/.gitignore b/include/.gitignore index f0ce546..9d9b6c4 100644 --- a/include/.gitignore +++ b/include/.gitignore @@ -1,6 +1,10 @@ /config +/applets.h /applet_tables.h /autoconf.h +/bbconfigopts_bz2.h /bbconfigopts.h +/NUM_APPLETS.h /usage_compressed.h +/usage.h diff --git a/include/applet_metadata.h b/include/applet_metadata.h new file mode 100644 index 0000000..566ef35 --- /dev/null +++ b/include/applet_metadata.h @@ -0,0 +1,30 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#ifndef APPLET_METADATA_H +#define APPLET_METADATA_H 1 + +/* Note: can be included by both host and target builds! */ + +/* order matters: used as index into "install_dir[]" in appletlib.c */ +typedef enum bb_install_loc_t { + BB_DIR_ROOT = 0, + BB_DIR_BIN, + BB_DIR_SBIN, +#if ENABLE_INSTALL_NO_USR + BB_DIR_USR_BIN = BB_DIR_BIN, + BB_DIR_USR_SBIN = BB_DIR_SBIN, +#else + BB_DIR_USR_BIN, + BB_DIR_USR_SBIN, +#endif +} bb_install_loc_t; + +typedef enum bb_suid_t { + BB_SUID_DROP = 0, + BB_SUID_MAYBE, + BB_SUID_REQUIRE +} bb_suid_t; + +#endif diff --git a/include/applets.src.h b/include/applets.src.h index 9162b66..7dbd4c7 100644 --- a/include/applets.src.h +++ b/include/applets.src.h @@ -12,10 +12,14 @@ name2 - applet name, converted to C (ether-wake: name2 = ether_wake) main - corresponding _main to call (bzcat: main = bunzip2) l - location to install link to: [/usr]/[s]bin s - suid type: - _BB_SUID_REQUIRE: will complain if busybox isn't suid + BB_SUID_REQUIRE: will complain if busybox isn't suid and is run by non-root (applet_main() will not be called at all) - _BB_SUID_DROP: will drop suid prior to applet_main() - _BB_SUID_MAYBE: neither of the above + BB_SUID_DROP: will drop suid prior to applet_main() + BB_SUID_MAYBE: neither of the above + (every instance of BB_SUID_REQUIRE and BB_SUID_MAYBE + needs to be justified in comment) + NB: please update FEATURE_SUID help text whenever you add/remove + BB_SUID_REQUIRE or BB_SUID_MAYBE applet. */ #if defined(PROTOTYPES) @@ -48,6 +52,12 @@ s - suid type: # define APPLET_NOEXEC(name,main,l,s,name2) LINK l name # define APPLET_NOFORK(name,main,l,s,name2) LINK l name +#elif defined(MAKE_SUID) +# define APPLET(name,l,s) SUID s l name +# define APPLET_ODDNAME(name,main,l,s,name2) SUID s l name +# define APPLET_NOEXEC(name,main,l,s,name2) SUID s l name +# define APPLET_NOFORK(name,main,l,s,name2) SUID s l name + #else static struct bb_applet applets[] = { /* name, main, location, need_suid */ # define APPLET(name,l,s) { #name, #name, l, s }, @@ -57,385 +67,332 @@ s - suid type: #endif #if ENABLE_INSTALL_NO_USR -# define _BB_DIR_USR_BIN _BB_DIR_BIN -# define _BB_DIR_USR_SBIN _BB_DIR_SBIN +# define BB_DIR_USR_BIN BB_DIR_BIN +# define BB_DIR_USR_SBIN BB_DIR_SBIN #endif INSERT -IF_TEST(APPLET_NOFORK([, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -IF_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) -IF_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_DROP, awk)) -IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_DROP, basename)) -IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, _BB_DIR_BIN, _BB_SUID_DROP, bash)) -IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, _BB_DIR_BIN, _BB_SUID_DROP, bash)) -IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_DROP)) -//IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_BEEP(APPLET(beep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_BOOTCHARTD(APPLET(bootchartd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CAT(APPLET_NOFORK(cat, cat, _BB_DIR_BIN, _BB_SUID_DROP, cat)) -IF_CATV(APPLET(catv, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CHAT(APPLET(chat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHATTR(APPLET(chattr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CHCON(APPLET(chcon, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, _BB_DIR_BIN, _BB_SUID_DROP, chgrp)) -IF_CHMOD(APPLET_NOEXEC(chmod, chmod, _BB_DIR_BIN, _BB_SUID_DROP, chmod)) -IF_CHOWN(APPLET_NOEXEC(chown, chown, _BB_DIR_BIN, _BB_SUID_DROP, chown)) -IF_CHPASSWD(APPLET(chpasswd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CKSUM(APPLET(cksum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_DROP, cp)) -IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_DROP, cut)) -IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_DROP, dd)) -IF_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_DROP, delgroup)) -IF_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) -IF_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_DROP, dirname)) -IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_REQUIRE)) -IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, _BB_DIR_BIN, _BB_SUID_DROP, dnsdomainname)) -IF_DOS2UNIX(APPLET(dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_DROP, dpkg_deb)) -IF_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//IF_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP)) -//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP, e2label)) -IF_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_DROP, echo)) -IF_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_ENV(APPLET_NOEXEC(env, env, _BB_DIR_USR_BIN, _BB_SUID_DROP, env)) -IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, envdir)) -IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, envuidgid)) -IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_DROP, ether_wake)) -IF_EXPAND(APPLET(expand, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_EXPR(APPLET(expr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FAKEIDENTD(APPLET(fakeidentd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FALSE(APPLET_NOFORK(false, false, _BB_DIR_BIN, _BB_SUID_DROP, false)) -IF_FBSET(APPLET(fbset, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_DROP, fdflush)) -IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FGCONSOLE(APPLET(fgconsole, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE)) -IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_lock)) -IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, _BB_DIR_USR_SBIN, _BB_SUID_DROP, flash_unlock)) -IF_FLASHCP(APPLET(flashcp, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FLOCK(APPLET(flock, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_DROP)) -//IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_ext2)) -//IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_ext3)) -IF_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_DROP, fsck_minix)) -IF_FSYNC(APPLET_NOFORK(fsync, fsync, _BB_DIR_BIN, _BB_SUID_DROP, fsync)) -IF_FTPD(APPLET(ftpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_DROP, ftpget)) -IF_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_DROP, ftpput)) -IF_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hd)) -IF_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_DROP, hexdump)) -IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_DROP, hostid)) -IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifdown)) -IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_IFPLUGD(APPLET(ifplugd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_DROP, ifup)) -IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) -IF_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_DROP)) +IF_TEST(APPLET_NOFORK([, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +IF_TEST(APPLET_NOFORK([[, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) +IF_ACPID(APPLET(acpid, BB_DIR_SBIN, BB_SUID_DROP)) +IF_ADDGROUP(APPLET(addgroup, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_ADDUSER(APPLET(adduser, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_ADJTIMEX(APPLET(adjtimex, BB_DIR_SBIN, BB_SUID_DROP)) +IF_ARP(APPLET(arp, BB_DIR_SBIN, BB_SUID_DROP)) +IF_ARPING(APPLET(arping, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_BASENAME(APPLET_NOFORK(basename, basename, BB_DIR_USR_BIN, BB_SUID_DROP, basename)) +IF_BBCONFIG(APPLET(bbconfig, BB_DIR_BIN, BB_SUID_DROP)) +IF_BEEP(APPLET(beep, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_BLKID(APPLET(blkid, BB_DIR_SBIN, BB_SUID_DROP)) +IF_BRCTL(APPLET(brctl, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CAL(APPLET(cal, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CAT(APPLET_NOFORK(cat, cat, BB_DIR_BIN, BB_SUID_DROP, cat)) +IF_CATV(APPLET(catv, BB_DIR_BIN, BB_SUID_DROP)) +IF_CHAT(APPLET(chat, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CHATTR(APPLET(chattr, BB_DIR_BIN, BB_SUID_DROP)) +IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, BB_DIR_BIN, BB_SUID_DROP, chgrp)) +IF_CHMOD(APPLET_NOEXEC(chmod, chmod, BB_DIR_BIN, BB_SUID_DROP, chmod)) +IF_CHOWN(APPLET_NOEXEC(chown, chown, BB_DIR_BIN, BB_SUID_DROP, chown)) +IF_CHPASSWD(APPLET(chpasswd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CHPST(APPLET(chpst, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHROOT(APPLET(chroot, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_CHRT(APPLET(chrt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CHVT(APPLET(chvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CKSUM(APPLET_NOEXEC(cksum, cksum, BB_DIR_USR_BIN, BB_SUID_DROP, cksum)) +IF_CLEAR(APPLET(clear, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_COMM(APPLET(comm, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CP(APPLET_NOEXEC(cp, cp, BB_DIR_BIN, BB_SUID_DROP, cp)) +IF_CROND(APPLET(crond, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /var/spool/cron* files: */ +IF_CRONTAB(APPLET(crontab, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_CRYPTPW(APPLET(cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_CUT(APPLET_NOEXEC(cut, cut, BB_DIR_USR_BIN, BB_SUID_DROP, cut)) +IF_DC(APPLET(dc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DD(APPLET_NOEXEC(dd, dd, BB_DIR_BIN, BB_SUID_DROP, dd)) +IF_DEALLOCVT(APPLET(deallocvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) +IF_DELUSER(APPLET(deluser, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_DEVFSD(APPLET(devfsd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_DEVMEM(APPLET(devmem, BB_DIR_SBIN, BB_SUID_DROP)) +IF_DF(APPLET(df, BB_DIR_BIN, BB_SUID_DROP)) +IF_DHCPRELAY(APPLET(dhcprelay, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_DIRNAME(APPLET_NOFORK(dirname, dirname, BB_DIR_USR_BIN, BB_SUID_DROP, dirname)) +IF_DMESG(APPLET(dmesg, BB_DIR_BIN, BB_SUID_DROP)) +IF_DNSD(APPLET(dnsd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_HOSTNAME(APPLET_ODDNAME(dnsdomainname, hostname, BB_DIR_BIN, BB_SUID_DROP, dnsdomainname)) +IF_DOS2UNIX(APPLET_NOEXEC(dos2unix, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, dos2unix)) +IF_DU(APPLET(du, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_DUMPKMAP(APPLET(dumpkmap, BB_DIR_BIN, BB_SUID_DROP)) +IF_DUMPLEASES(APPLET(dumpleases, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_E2FSCK(APPLET(e2fsck, BB_DIR_SBIN, BB_SUID_DROP)) +//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, BB_DIR_SBIN, BB_SUID_DROP, e2label)) +IF_ECHO(APPLET_NOFORK(echo, echo, BB_DIR_BIN, BB_SUID_DROP, echo)) +IF_EJECT(APPLET(eject, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_ENV(APPLET_NOEXEC(env, env, BB_DIR_USR_BIN, BB_SUID_DROP, env)) +IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envdir)) +IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, envuidgid)) +IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, BB_DIR_USR_SBIN, BB_SUID_DROP, ether_wake)) +IF_EXPAND(APPLET(expand, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_EXPR(APPLET(expr, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FAKEIDENTD(APPLET(fakeidentd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FALSE(APPLET_NOFORK(false, false, BB_DIR_BIN, BB_SUID_DROP, false)) +IF_FBSET(APPLET(fbset, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FBSPLASH(APPLET(fbsplash, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, BB_DIR_BIN, BB_SUID_DROP, fdflush)) +IF_FDFORMAT(APPLET(fdformat, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FDISK(APPLET(fdisk, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FGCONSOLE(APPLET(fgconsole, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Benefits from suid root: better access to /dev/BLOCKDEVs: */ +IF_FINDFS(APPLET(findfs, BB_DIR_SBIN, BB_SUID_MAYBE)) +IF_FLASH_ERASEALL(APPLET(flash_eraseall, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FLASH_LOCK(APPLET_ODDNAME(flash_lock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_lock)) +IF_FLASH_UNLOCK(APPLET_ODDNAME(flash_unlock, flash_lock_unlock, BB_DIR_USR_SBIN, BB_SUID_DROP, flash_unlock)) +IF_FLASHCP(APPLET(flashcp, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FLOCK(APPLET(flock, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FOLD(APPLET_NOEXEC(fold, fold, BB_DIR_USR_BIN, BB_SUID_DROP, fold)) +IF_FREE(APPLET(free, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_FREERAMDISK(APPLET(freeramdisk, BB_DIR_SBIN, BB_SUID_DROP)) +IF_FSCK(APPLET(fsck, BB_DIR_SBIN, BB_SUID_DROP)) +//IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, fsck_ext2)) +//IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, BB_DIR_SBIN, BB_SUID_DROP, fsck_ext3)) +IF_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, BB_DIR_SBIN, BB_SUID_DROP, fsck_minix)) +IF_FSYNC(APPLET_NOFORK(fsync, fsync, BB_DIR_BIN, BB_SUID_DROP, fsync)) +IF_FTPD(APPLET(ftpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, BB_DIR_USR_BIN, BB_SUID_DROP, ftpget)) +IF_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, BB_DIR_USR_BIN, BB_SUID_DROP, ftpput)) +IF_FUSER(APPLET(fuser, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_GETENFORCE(APPLET(getenforce, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_GETOPT(APPLET(getopt, BB_DIR_BIN, BB_SUID_DROP)) +IF_GETSEBOOL(APPLET(getsebool, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_GETTY(APPLET(getty, BB_DIR_SBIN, BB_SUID_DROP)) +IF_HD(APPLET_NOEXEC(hd, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hd)) +IF_HDPARM(APPLET(hdparm, BB_DIR_SBIN, BB_SUID_DROP)) +IF_HEAD(APPLET_NOEXEC(head, head, BB_DIR_USR_BIN, BB_SUID_DROP, head)) +IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, BB_DIR_USR_BIN, BB_SUID_DROP, hexdump)) +IF_HOSTNAME(APPLET(hostname, BB_DIR_BIN, BB_SUID_DROP)) +IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_HWCLOCK(APPLET(hwclock, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFCONFIG(APPLET(ifconfig, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifdown)) +IF_IFENSLAVE(APPLET(ifenslave, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IFPLUGD(APPLET(ifplugd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, BB_DIR_SBIN, BB_SUID_DROP, ifup)) +IF_INETD(APPLET(inetd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_INOTIFYD(APPLET(inotifyd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_INSTALL(APPLET(install, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IONICE(APPLET(ionice, BB_DIR_BIN, BB_SUID_DROP)) #if ENABLE_FEATURE_IP_ADDRESS \ || ENABLE_FEATURE_IP_ROUTE \ || ENABLE_FEATURE_IP_LINK \ || ENABLE_FEATURE_IP_TUNNEL \ || ENABLE_FEATURE_IP_RULE -IF_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_DROP)) +IF_IP(APPLET(ip, BB_DIR_SBIN, BB_SUID_DROP)) #endif -IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_KBD_MODE(APPLET(kbd_mode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall)) -IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_DROP, killall5)) -IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_DROP, length)) -IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux32)) -IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_DROP, linux64)) -IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_DROP, linuxrc)) -IF_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_DROP, ln)) -IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_REQUIRE)) -IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_DROP, logname)) -IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_LPD(APPLET(lpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpq)) -IF_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_DROP, lpr)) -IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_DROP, ls)) -IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) -IF_LSPCI(APPLET(lspci, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LSUSB(APPLET(lsusb, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNLZMA(APPLET_ODDNAME(lzcat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzcat)) -IF_LZMA(APPLET_ODDNAME(lzma, unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzma)) -IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, lzopcat)) -IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, md5sum)) -IF_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_DROP, mkdir)) -IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) -IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) -IF_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext2)) -//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_ext3)) -IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_minix)) -IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_reiser)) -IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_DROP, mkfs_vfat)) -IF_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_DROP, mkpasswd)) -IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_DROP))) -IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_NTPD(APPLET(ntpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -//IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE)) -IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_MAYBE)) -IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_DROP, pkill)) -IF_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_DROP, poweroff)) -IF_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_DROP, printf)) -IF_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_DROP, pwd)) -IF_RAIDAUTORUN(APPLET(raidautorun, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RDATE(APPLET(rdate, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_RDEV(APPLET(rdev, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_DROP, reboot)) -IF_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_DROP, restorecon)) -IF_RFKILL(APPLET(rfkill, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_DROP, rm)) -IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_DROP, rmdir)) -IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_DROP, modprobe)) -IF_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_DROP, run_parts)) -IF_RUNCON(APPLET(runcon, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SCRIPTREPLAY(APPLET(scriptreplay, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_DROP, seq)) -IF_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SETFONT(APPLET(setfont, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, setuidgid)) -IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_DROP, sh)) -IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha1sum)) -IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha256sum)) -IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_DROP, sha512sum)) -IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_DROP, sleep)) -IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) -IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) -IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DIR_SBIN, _BB_SUID_DROP, start_stop_daemon)) -IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_REQUIRE)) -IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP,swapoff)) -IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_DROP, swapon)) -IF_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_DROP, sync)) -IF_BB_SYSCTL(APPLET(sysctl, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_DROP, tac)) -IF_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -/* IF_TC(APPLET(tc, _BB_DIR_SBIN, _BB_SUID_DROP)) */ -IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, tcpsvd)) -IF_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_TEST(APPLET_NOFORK(test, test, _BB_DIR_USR_BIN, _BB_SUID_DROP, test)) +IF_IPADDR(APPLET(ipaddr, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IPCALC(APPLET(ipcalc, BB_DIR_BIN, BB_SUID_DROP)) +IF_IPCRM(APPLET(ipcrm, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IPCS(APPLET(ipcs, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_IPLINK(APPLET(iplink, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IPROUTE(APPLET(iproute, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IPRULE(APPLET(iprule, BB_DIR_SBIN, BB_SUID_DROP)) +IF_IPTUNNEL(APPLET(iptunnel, BB_DIR_SBIN, BB_SUID_DROP)) +IF_KBD_MODE(APPLET(kbd_mode, BB_DIR_BIN, BB_SUID_DROP)) +IF_KILL(APPLET(kill, BB_DIR_BIN, BB_SUID_DROP)) +IF_KILLALL(APPLET_ODDNAME(killall, kill, BB_DIR_USR_BIN, BB_SUID_DROP, killall)) +IF_KILLALL5(APPLET_ODDNAME(killall5, kill, BB_DIR_USR_SBIN, BB_SUID_DROP, killall5)) +IF_KLOGD(APPLET(klogd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LAST(APPLET(last, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_LENGTH(APPLET_NOFORK(length, length, BB_DIR_USR_BIN, BB_SUID_DROP, length)) +IF_LESS(APPLET(less, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETARCH(APPLET_ODDNAME(linux32, setarch, BB_DIR_BIN, BB_SUID_DROP, linux32)) +IF_SETARCH(APPLET_ODDNAME(linux64, setarch, BB_DIR_BIN, BB_SUID_DROP, linux64)) +IF_LN(APPLET_NOEXEC(ln, ln, BB_DIR_BIN, BB_SUID_DROP, ln)) +IF_LOAD_POLICY(APPLET(load_policy, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LOADFONT(APPLET(loadfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LOADKMAP(APPLET(loadkmap, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LOGGER(APPLET(logger, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_LOGIN(APPLET(login, BB_DIR_BIN, BB_SUID_REQUIRE)) +IF_LOGNAME(APPLET_NOFORK(logname, logname, BB_DIR_USR_BIN, BB_SUID_DROP, logname)) +IF_LOGREAD(APPLET(logread, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LOSETUP(APPLET(losetup, BB_DIR_SBIN, BB_SUID_DROP)) +IF_LPD(APPLET(lpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_LPQ(APPLET_ODDNAME(lpq, lpqr, BB_DIR_USR_BIN, BB_SUID_DROP, lpq)) +IF_LPR(APPLET_ODDNAME(lpr, lpqr, BB_DIR_USR_BIN, BB_SUID_DROP, lpr)) +IF_LS(APPLET_NOEXEC(ls, ls, BB_DIR_BIN, BB_SUID_DROP, ls)) +IF_LSATTR(APPLET(lsattr, BB_DIR_BIN, BB_SUID_DROP)) +IF_LSPCI(APPLET(lspci, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_LSUSB(APPLET(lsusb, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_MAKEDEVS(APPLET(makedevs, BB_DIR_SBIN, BB_SUID_DROP)) +IF_MAKEMIME(APPLET(makemime, BB_DIR_BIN, BB_SUID_DROP)) +IF_MAN(APPLET(man, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_MATCHPATHCON(APPLET(matchpathcon, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_MD5SUM(APPLET_NOEXEC(md5sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, md5sum)) +IF_MICROCOM(APPLET(microcom, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, BB_DIR_BIN, BB_SUID_DROP, mkdir)) +IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat)) +IF_MKFS_EXT2(APPLET_ODDNAME(mke2fs, mkfs_ext2, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext2)) +IF_MKFIFO(APPLET_NOEXEC(mkfifo, mkfifo, BB_DIR_USR_BIN, BB_SUID_DROP, mkfifo)) +IF_MKFS_EXT2(APPLET_ODDNAME(mkfs.ext2, mkfs_ext2, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext2)) +//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, BB_DIR_SBIN, BB_SUID_DROP, mkfs_ext3)) +IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, BB_DIR_SBIN, BB_SUID_DROP, mkfs_minix)) +IF_MKFS_REISER(APPLET_ODDNAME(mkfs.reiser, mkfs_reiser, BB_DIR_SBIN, BB_SUID_DROP, mkfs_reiser)) +IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, BB_DIR_SBIN, BB_SUID_DROP, mkfs_vfat)) +IF_MKNOD(APPLET_NOEXEC(mknod, mknod, BB_DIR_BIN, BB_SUID_DROP, mknod)) +IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, BB_DIR_USR_BIN, BB_SUID_DROP, mkpasswd)) +IF_MKSWAP(APPLET(mkswap, BB_DIR_SBIN, BB_SUID_DROP)) +IF_MKTEMP(APPLET(mktemp, BB_DIR_BIN, BB_SUID_DROP)) +IF_MORE(APPLET(more, BB_DIR_BIN, BB_SUID_DROP)) +/* On full-blown systems, requires suid for user mounts. + * But it's not unthinkable to have it available in non-suid flavor on some systems, + * for viewing mount table. + * Therefore we use BB_SUID_MAYBE instead of BB_SUID_REQUIRE: */ +IF_MOUNT(APPLET(mount, BB_DIR_BIN, IF_DESKTOP(BB_SUID_MAYBE) IF_NOT_DESKTOP(BB_SUID_DROP))) +IF_MOUNTPOINT(APPLET(mountpoint, BB_DIR_BIN, BB_SUID_DROP)) +IF_MT(APPLET(mt, BB_DIR_BIN, BB_SUID_DROP)) +IF_MV(APPLET(mv, BB_DIR_BIN, BB_SUID_DROP)) +IF_NAMEIF(APPLET(nameif, BB_DIR_SBIN, BB_SUID_DROP)) +IF_NC(APPLET(nc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NETSTAT(APPLET(netstat, BB_DIR_BIN, BB_SUID_DROP)) +IF_NICE(APPLET(nice, BB_DIR_BIN, BB_SUID_DROP)) +IF_NOHUP(APPLET(nohup, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NSLOOKUP(APPLET(nslookup, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_NTPD(APPLET(ntpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_OD(APPLET(od, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_OPENVT(APPLET(openvt, BB_DIR_USR_BIN, BB_SUID_DROP)) +//IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change /etc/{passwd,shadow}: */ +IF_PASSWD(APPLET(passwd, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_PGREP(APPLET(pgrep, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_PIDOF(APPLET(pidof, BB_DIR_BIN, BB_SUID_DROP)) +IF_PIPE_PROGRESS(APPLET(pipe_progress, BB_DIR_BIN, BB_SUID_DROP)) +IF_PIVOT_ROOT(APPLET(pivot_root, BB_DIR_SBIN, BB_SUID_DROP)) +IF_PKILL(APPLET_ODDNAME(pkill, pgrep, BB_DIR_USR_BIN, BB_SUID_DROP, pkill)) +IF_POPMAILDIR(APPLET(popmaildir, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_PRINTENV(APPLET_NOFORK(printenv, printenv, BB_DIR_BIN, BB_SUID_DROP, printenv)) +IF_PRINTF(APPLET_NOFORK(printf, printf, BB_DIR_USR_BIN, BB_SUID_DROP, printf)) +IF_PS(APPLET(ps, BB_DIR_BIN, BB_SUID_DROP)) +IF_PSCAN(APPLET(pscan, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_PWD(APPLET_NOFORK(pwd, pwd, BB_DIR_BIN, BB_SUID_DROP, pwd)) +IF_RAIDAUTORUN(APPLET(raidautorun, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RDATE(APPLET(rdate, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_RDEV(APPLET(rdev, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_READAHEAD(APPLET(readahead, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_READLINK(APPLET(readlink, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_READPROFILE(APPLET(readprofile, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_REALPATH(APPLET(realpath, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_REFORMIME(APPLET(reformime, BB_DIR_BIN, BB_SUID_DROP)) +IF_RENICE(APPLET(renice, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESET(APPLET(reset, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESIZE(APPLET(resize, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, BB_DIR_SBIN, BB_SUID_DROP, restorecon)) +IF_RM(APPLET_NOFORK(rm, rm, BB_DIR_BIN, BB_SUID_DROP, rm)) +IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, BB_DIR_BIN, BB_SUID_DROP, rmdir)) +IF_ROUTE(APPLET(route, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RTCWAKE(APPLET(rtcwake, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, BB_DIR_BIN, BB_SUID_DROP, run_parts)) +IF_RUNCON(APPLET(runcon, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RUNLEVEL(APPLET(runlevel, BB_DIR_SBIN, BB_SUID_DROP)) +IF_RUNSV(APPLET(runsv, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RUNSVDIR(APPLET(runsvdir, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_RX(APPLET(rx, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SCRIPT(APPLET(script, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SCRIPTREPLAY(APPLET(scriptreplay, BB_DIR_BIN, BB_SUID_DROP)) +IF_SELINUXENABLED(APPLET(selinuxenabled, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SENDMAIL(APPLET(sendmail, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SEQ(APPLET_NOFORK(seq, seq, BB_DIR_USR_BIN, BB_SUID_DROP, seq)) +IF_SESTATUS(APPLET(sestatus, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETARCH(APPLET(setarch, BB_DIR_BIN, BB_SUID_DROP)) +IF_SETCONSOLE(APPLET(setconsole, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SETENFORCE(APPLET(setenforce, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETFILES(APPLET(setfiles, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SETFONT(APPLET(setfont, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETKEYCODES(APPLET(setkeycodes, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETLOGCONS(APPLET(setlogcons, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETSEBOOL(APPLET(setsebool, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SETSID(APPLET(setsid, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, setuidgid)) +IF_SHA1SUM(APPLET_NOEXEC(sha1sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha1sum)) +IF_SHA3SUM(APPLET_NOEXEC(sha3sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha3sum)) +IF_SHA256SUM(APPLET_NOEXEC(sha256sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha256sum)) +IF_SHA512SUM(APPLET_NOEXEC(sha512sum, md5_sha1_sum, BB_DIR_USR_BIN, BB_SUID_DROP, sha512sum)) +IF_SHOWKEY(APPLET(showkey, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SLATTACH(APPLET(slattach, BB_DIR_SBIN, BB_SUID_DROP)) +/* Do not make this applet NOFORK. It breaks ^C-ing of pauses in shells: */ +IF_SLEEP(APPLET(sleep, BB_DIR_BIN, BB_SUID_DROP)) +IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, BB_DIR_USR_BIN, BB_SUID_DROP, softlimit)) +IF_SORT(APPLET_NOEXEC(sort, sort, BB_DIR_USR_BIN, BB_SUID_DROP, sort)) +IF_SPLIT(APPLET(split, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, BB_DIR_SBIN, BB_SUID_DROP, start_stop_daemon)) +IF_STAT(APPLET(stat, BB_DIR_BIN, BB_SUID_DROP)) +IF_STRINGS(APPLET(strings, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_STTY(APPLET(stty, BB_DIR_BIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_SU(APPLET(su, BB_DIR_BIN, BB_SUID_REQUIRE)) +IF_SULOGIN(APPLET(sulogin, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SUM(APPLET(sum, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SV(APPLET(sv, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_SVLOGD(APPLET(svlogd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, BB_DIR_SBIN, BB_SUID_DROP, swapoff)) +IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, BB_DIR_SBIN, BB_SUID_DROP, swapon)) +IF_SWITCH_ROOT(APPLET(switch_root, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SYNC(APPLET_NOFORK(sync, sync, BB_DIR_BIN, BB_SUID_DROP, sync)) +IF_BB_SYSCTL(APPLET(sysctl, BB_DIR_SBIN, BB_SUID_DROP)) +IF_SYSLOGD(APPLET(syslogd, BB_DIR_SBIN, BB_SUID_DROP)) +IF_TAC(APPLET_NOEXEC(tac, tac, BB_DIR_USR_BIN, BB_SUID_DROP, tac)) +IF_TAIL(APPLET(tail, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TASKSET(APPLET(taskset, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* IF_TC(APPLET(tc, BB_DIR_SBIN, BB_SUID_DROP)) */ +IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, tcpsvd)) +IF_TEE(APPLET(tee, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TELNET(APPLET(telnet, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TELNETD(APPLET(telnetd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_TEST(APPLET_NOFORK(test, test, BB_DIR_USR_BIN, BB_SUID_DROP, test)) #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT -IF_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +IF_TFTP(APPLET(tftp, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TFTPD(APPLET(tftpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) #endif -IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_DROP, touch)) -IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) -IF_TRACEROUTE6(APPLET(traceroute6, _BB_DIR_USR_BIN, _BB_SUID_MAYBE)) -IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_DROP, true)) -IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_DROP, udpsvd)) -IF_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_DROP, unexpand)) -IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_DROP, unix2dos)) -IF_UNXZ(APPLET(unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_DROP, unlzop)) -IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_DROP, usleep)) -IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_VOLNAME(APPLET(volname, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WALL(APPLET(wall, _BB_DIR_USR_BIN, _BB_SUID_REQUIRE)) -IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_DROP)) -IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_DROP)) -IF_WC(APPLET(wc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WGET(APPLET(wget, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -IF_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_DROP, whoami)) -IF_UNXZ(APPLET_ODDNAME(xzcat, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xzcat)) -IF_XZ(APPLET_ODDNAME(xz, unxz, _BB_DIR_USR_BIN, _BB_SUID_DROP, xz)) -IF_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_DROP, yes)) -IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_DROP, zcat)) -IF_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_DROP)) +IF_TIME(APPLET(time, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TIMEOUT(APPLET(timeout, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TOP(APPLET(top, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TR(APPLET(tr, BB_DIR_USR_BIN, BB_SUID_DROP)) +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore BB_SUID_MAYBE: */ +IF_TRACEROUTE(APPLET(traceroute, BB_DIR_USR_BIN, BB_SUID_MAYBE)) +IF_TRACEROUTE6(APPLET(traceroute6, BB_DIR_USR_BIN, BB_SUID_MAYBE)) +IF_TRUE(APPLET_NOFORK(true, true, BB_DIR_BIN, BB_SUID_DROP, true)) +IF_TTY(APPLET(tty, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TTYSIZE(APPLET(ttysize, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_TUNCTL(APPLET(tunctl, BB_DIR_SBIN, BB_SUID_DROP)) +IF_TUNE2FS(APPLET(tune2fs, BB_DIR_SBIN, BB_SUID_DROP)) +IF_UDHCPC(APPLET(udhcpc, BB_DIR_SBIN, BB_SUID_DROP)) +IF_UDHCPD(APPLET(udhcpd, BB_DIR_USR_SBIN, BB_SUID_DROP)) +IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, BB_DIR_USR_BIN, BB_SUID_DROP, udpsvd)) +IF_UMOUNT(APPLET(umount, BB_DIR_BIN, BB_SUID_DROP)) +IF_UNAME(APPLET(uname, BB_DIR_BIN, BB_SUID_DROP)) +IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, BB_DIR_USR_BIN, BB_SUID_DROP, unexpand)) +IF_UNIQ(APPLET(uniq, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UNIX2DOS(APPLET_NOEXEC(unix2dos, dos2unix, BB_DIR_USR_BIN, BB_SUID_DROP, unix2dos)) +IF_UPTIME(APPLET(uptime, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_USLEEP(APPLET_NOFORK(usleep, usleep, BB_DIR_BIN, BB_SUID_DROP, usleep)) +IF_UUDECODE(APPLET(uudecode, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_UUENCODE(APPLET(uuencode, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_VCONFIG(APPLET(vconfig, BB_DIR_SBIN, BB_SUID_DROP)) +/* Needs to be run by root or be suid root - needs to change uid and gid: */ +IF_VLOCK(APPLET(vlock, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) +IF_VOLNAME(APPLET(volname, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WATCH(APPLET(watch, BB_DIR_BIN, BB_SUID_DROP)) +IF_WATCHDOG(APPLET(watchdog, BB_DIR_SBIN, BB_SUID_DROP)) +IF_WC(APPLET(wc, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WGET(APPLET(wget, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WHICH(APPLET(which, BB_DIR_USR_BIN, BB_SUID_DROP)) +IF_WHOAMI(APPLET_NOFORK(whoami, whoami, BB_DIR_USR_BIN, BB_SUID_DROP, whoami)) +IF_YES(APPLET_NOFORK(yes, yes, BB_DIR_USR_BIN, BB_SUID_DROP, yes)) +IF_ZCIP(APPLET(zcip, BB_DIR_SBIN, BB_SUID_DROP)) -#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) +#if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE) \ + && !defined(MAKE_LINKS) && !defined(MAKE_SUID) }; #endif diff --git a/include/ar.h b/include/ar.h index 2667889..386fe04 100644 --- a/include/ar.h +++ b/include/ar.h @@ -1,6 +1,6 @@ /* * busybox ar archive data structures - * Licensed under the GPL v2 or later, see the file LICENSE in this source tree. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef AR_H #define AR_H diff --git a/include/bb_archive.h b/include/bb_archive.h new file mode 100644 index 0000000..b82cfd8 --- /dev/null +++ b/include/bb_archive.h @@ -0,0 +1,248 @@ +/* vi: set sw=4 ts=4: */ +#ifndef UNARCHIVE_H +#define UNARCHIVE_H 1 + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + +enum { +#if BB_BIG_ENDIAN + COMPRESS_MAGIC = 0x1f9d, + GZIP_MAGIC = 0x1f8b, + BZIP2_MAGIC = 256 * 'B' + 'Z', + /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ + /* More info at: http://tukaani.org/xz/xz-file-format.txt */ + XZ_MAGIC1 = 256 * 0xfd + '7', + XZ_MAGIC2 = 256 * (unsigned)(256 * (256 * 'z' + 'X') + 'Z') + 0, + /* Different form: 32 bits, then 16 bits: */ + /* (unsigned) cast suppresses "integer overflow in expression" warning */ + XZ_MAGIC1a = 256 * (unsigned)(256 * (256 * 0xfd + '7') + 'z') + 'X', + XZ_MAGIC2a = 256 * 'Z' + 0, +#else + COMPRESS_MAGIC = 0x9d1f, + GZIP_MAGIC = 0x8b1f, + BZIP2_MAGIC = 'B' + 'Z' * 256, + XZ_MAGIC1 = 0xfd + '7' * 256, + XZ_MAGIC2 = 'z' + ('X' + ('Z' + 0 * 256) * 256) * 256, + XZ_MAGIC1a = 0xfd + ('7' + ('z' + 'X' * 256) * 256) * 256, + XZ_MAGIC2a = 'Z' + 0 * 256, +#endif +}; + +typedef struct file_header_t { + char *name; + char *link_target; +#if ENABLE_FEATURE_TAR_UNAME_GNAME + char *tar__uname; + char *tar__gname; +#endif + off_t size; + uid_t uid; + gid_t gid; + mode_t mode; + time_t mtime; + dev_t device; +} file_header_t; + +struct hardlinks_t; + +typedef struct archive_handle_t { + /* Flags. 1st since it is most used member */ + unsigned ah_flags; + + /* The raw stream as read from disk or stdin */ + int src_fd; + + /* Define if the header and data component should be processed */ + char FAST_FUNC (*filter)(struct archive_handle_t *); + /* List of files that have been accepted */ + llist_t *accept; + /* List of files that have been rejected */ + llist_t *reject; + /* List of files that have successfully been worked on */ + llist_t *passed; + + /* Currently processed file's header */ + file_header_t *file_header; + + /* Process the header component, e.g. tar -t */ + void FAST_FUNC (*action_header)(const file_header_t *); + + /* Process the data component, e.g. extract to filesystem */ + void FAST_FUNC (*action_data)(struct archive_handle_t *); + + /* Function that skips data */ + void FAST_FUNC (*seek)(int fd, off_t amount); + + /* Count processed bytes */ + off_t offset; + + /* Archiver specific. Can make it a union if it ever gets big */ +#define PAX_NEXT_FILE 0 +#define PAX_GLOBAL 1 +#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB + smallint tar__end; +# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS + char* tar__longname; + char* tar__linkname; +# endif +# if ENABLE_FEATURE_TAR_TO_COMMAND + char* tar__to_command; + const char* tar__to_command_shell; +# endif +# if ENABLE_FEATURE_TAR_SELINUX + char* tar__sctx[2]; +# endif +#endif +#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM + uoff_t cpio__blocks; + struct hardlinks_t *cpio__hardlinks_to_create; + struct hardlinks_t *cpio__created_hardlinks; +#endif +#if ENABLE_DPKG || ENABLE_DPKG_DEB + /* Temporary storage */ + char *dpkg__buffer; + /* How to process any sub archive, e.g. get_header_tar_gz */ + char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *); + /* Contains the handle to a sub archive */ + struct archive_handle_t *dpkg__sub_archive; +#endif +#if ENABLE_FEATURE_AR_CREATE + const char *ar__name; + struct archive_handle_t *ar__out; +#endif +} archive_handle_t; +/* bits in ah_flags */ +#define ARCHIVE_RESTORE_DATE (1 << 0) +#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) +#define ARCHIVE_UNLINK_OLD (1 << 2) +#define ARCHIVE_EXTRACT_QUIET (1 << 3) +#define ARCHIVE_EXTRACT_NEWER (1 << 4) +#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) +#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) +#define ARCHIVE_NUMERIC_OWNER (1 << 7) +#define ARCHIVE_O_TRUNC (1 << 8) +#define ARCHIVE_REMEMBER_NAMES (1 << 9) +#if ENABLE_RPM +#define ARCHIVE_REPLACE_VIA_RENAME (1 << 10) +#endif + + +/* POSIX tar Header Block, from POSIX 1003.1-1990 */ +#define TAR_BLOCK_SIZE 512 +#define NAME_SIZE 100 +#define NAME_SIZE_STR "100" +typedef struct tar_header_t { /* byte offset */ + char name[NAME_SIZE]; /* 0-99 */ + char mode[8]; /* 100-107 */ + char uid[8]; /* 108-115 */ + char gid[8]; /* 116-123 */ + char size[12]; /* 124-135 */ + char mtime[12]; /* 136-147 */ + char chksum[8]; /* 148-155 */ + char typeflag; /* 156-156 */ + char linkname[NAME_SIZE]; /* 157-256 */ + /* POSIX: "ustar" NUL "00" */ + /* GNU tar: "ustar " NUL */ + /* Normally it's defined as magic[6] followed by + * version[2], but we put them together to save code. + */ + char magic[8]; /* 257-264 */ + char uname[32]; /* 265-296 */ + char gname[32]; /* 297-328 */ + char devmajor[8]; /* 329-336 */ + char devminor[8]; /* 337-344 */ + char prefix[155]; /* 345-499 */ + char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ +} tar_header_t; +struct BUG_tar_header { + char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; +}; + + + +archive_handle_t *init_handle(void) FAST_FUNC; + +char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; +char filter_accept_reject_list(archive_handle_t *archive_handle) FAST_FUNC; + +void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; + +void data_skip(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; +void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; + +void header_skip(const file_header_t *file_header) FAST_FUNC; +void header_list(const file_header_t *file_header) FAST_FUNC; +void header_verbose_list(const file_header_t *file_header) FAST_FUNC; + +char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_gz(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_bz2(archive_handle_t *archive_handle) FAST_FUNC; +char get_header_tar_lzma(archive_handle_t *archive_handle) FAST_FUNC; + +void seek_by_jump(int fd, off_t amount) FAST_FUNC; +void seek_by_read(int fd, off_t amount) FAST_FUNC; + +const char *strip_unsafe_prefix(const char *str) FAST_FUNC; + +void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; +const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; +const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; + +/* A bit of bunzip2 internals are exposed for compressed help support: */ +typedef struct bunzip_data bunzip_data; +int start_bunzip(bunzip_data **bdp, int in_fd, const void *inbuf, int len) FAST_FUNC; +/* 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: */ +int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; +void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; + +/* Meaning and direction (input/output) of the fields are transformer-specific */ +typedef struct transformer_aux_data_t { + smallint check_signature; /* most often referenced member */ + off_t bytes_out; + off_t bytes_in; /* used in unzip code only: needs to know packed size */ + uint32_t crc32; + time_t mtime; /* gunzip code may set this on exit */ +} transformer_aux_data_t; + +void init_transformer_aux_data(transformer_aux_data_t *aux) FAST_FUNC; +int FAST_FUNC check_signature16(transformer_aux_data_t *aux, int src_fd, unsigned magic16) FAST_FUNC; + +IF_DESKTOP(long long) int inflate_unzip(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_Z_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_gz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_bz2_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_lzma_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; +IF_DESKTOP(long long) int unpack_xz_stream(transformer_aux_data_t *aux, int src_fd, int dst_fd) FAST_FUNC; + +char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; +int bbunpack(char **argv, + IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(transformer_aux_data_t *aux), + char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), + const char *expected_ext +) FAST_FUNC; + +void check_errors_in_children(int signo); +#if BB_MMU +void open_transformer(int fd, + int check_signature, + IF_DESKTOP(long long) int FAST_FUNC (*transformer)(transformer_aux_data_t *aux, int src_fd, int dst_fd) +) FAST_FUNC; +#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), 1, (transformer)) +#define open_transformer_with_no_sig(fd, transformer) open_transformer((fd), 0, (transformer)) +#else +void open_transformer(int fd, const char *transform_prog) FAST_FUNC; +#define open_transformer_with_sig(fd, transformer, transform_prog) open_transformer((fd), (transform_prog)) +/* open_transformer_with_no_sig() does not exist on NOMMU */ +#endif + + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/e2fsprogs/e2fs_defs.h b/include/bb_e2fs_defs.h similarity index 87% rename from e2fsprogs/e2fs_defs.h rename to include/bb_e2fs_defs.h index 379640e..3f5e3c4 100644 --- a/e2fsprogs/e2fs_defs.h +++ b/include/bb_e2fs_defs.h @@ -406,25 +406,43 @@ struct ext2_super_block { * Performance hints. Directory preallocation should only * happen if the EXT2_FEATURE_COMPAT_DIR_PREALLOC flag is on. */ - uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ - uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ + uint8_t s_prealloc_blocks; /* Nr of blocks to try to preallocate*/ + uint8_t s_prealloc_dir_blocks; /* Nr to preallocate for dirs */ uint16_t s_reserved_gdt_blocks; /* Per group table for online growth */ /* * Journaling support valid if EXT2_FEATURE_COMPAT_HAS_JOURNAL set. */ - uint8_t s_journal_uuid[16]; /* uuid of journal superblock */ - uint32_t s_journal_inum; /* inode number of journal file */ +/*D0*/ uint8_t s_journal_uuid[16]; /* uuid of journal superblock */ +/*E0*/ uint32_t s_journal_inum; /* inode number of journal file */ uint32_t s_journal_dev; /* device number of journal file */ uint32_t s_last_orphan; /* start of list of inodes to delete */ uint32_t s_hash_seed[4]; /* HTREE hash seed */ uint8_t s_def_hash_version; /* Default hash version to use */ uint8_t s_jnl_backup_type; /* Default type of journal backup */ uint16_t s_reserved_word_pad; - uint32_t s_default_mount_opts; +/*100*/ uint32_t s_default_mount_opts; uint32_t s_first_meta_bg; /* First metablock group */ + /* ext3 additions */ uint32_t s_mkfs_time; /* When the filesystem was created */ uint32_t s_jnl_blocks[17]; /* Backup of the journal inode */ - uint32_t s_reserved[172]; /* Padding to the end of the block */ + /* 64bit support valid if EXT4_FEATURE_COMPAT_64BIT */ +/*150*/ uint32_t s_blocks_count_hi; /* Blocks count */ + uint32_t s_r_blocks_count_hi; /* Reserved blocks count */ + uint32_t s_free_blocks_count_hi; /* Free blocks count */ + uint16_t s_min_extra_isize; /* All inodes have at least # bytes */ + uint16_t s_want_extra_isize; /* New inodes should reserve # bytes */ + uint32_t s_flags; /* Miscellaneous flags */ + uint16_t s_raid_stride; /* RAID stride */ + uint16_t s_mmp_interval; /* # seconds to wait in MMP checking */ + uint64_t s_mmp_block; /* Block for multi-mount protection */ + uint32_t s_raid_stripe_width; /* blocks on all data disks (N*stride)*/ + uint8_t s_log_groups_per_flex; /* FLEX_BG group size */ + uint8_t s_reserved_char_pad2; + uint16_t s_reserved_pad; + uint32_t s_reserved[162]; /* Padding to the end of the block */ +}; +struct BUG_ext2_super_block { + char bug[sizeof(struct ext2_super_block) == 1024 ? 1 : -1]; }; /* @@ -463,30 +481,53 @@ struct ext2_super_block { #define EXT2_HAS_INCOMPAT_FEATURE(sb,mask) \ ( EXT2_SB(sb)->s_feature_incompat & (mask) ) +/* for s_feature_compat */ #define EXT2_FEATURE_COMPAT_DIR_PREALLOC 0x0001 #define EXT2_FEATURE_COMPAT_IMAGIC_INODES 0x0002 #define EXT3_FEATURE_COMPAT_HAS_JOURNAL 0x0004 #define EXT2_FEATURE_COMPAT_EXT_ATTR 0x0008 -#define EXT2_FEATURE_COMPAT_RESIZE_INODE 0x0010 +#define EXT2_FEATURE_COMPAT_RESIZE_INO 0x0010 #define EXT2_FEATURE_COMPAT_DIR_INDEX 0x0020 +/* for s_feature_ro_compat */ #define EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER 0x0001 #define EXT2_FEATURE_RO_COMPAT_LARGE_FILE 0x0002 -/* #define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 not used */ +#define EXT2_FEATURE_RO_COMPAT_BTREE_DIR 0x0004 /* not used */ +#define EXT4_FEATURE_RO_COMPAT_HUGE_FILE 0x0008 +#define EXT4_FEATURE_RO_COMPAT_GDT_CSUM 0x0010 +#define EXT4_FEATURE_RO_COMPAT_DIR_NLINK 0x0020 +#define EXT4_FEATURE_RO_COMPAT_EXTRA_ISIZE 0x0040 +/* for s_feature_incompat */ #define EXT2_FEATURE_INCOMPAT_COMPRESSION 0x0001 #define EXT2_FEATURE_INCOMPAT_FILETYPE 0x0002 -#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ -#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ +#define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 +#define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 #define EXT2_FEATURE_INCOMPAT_META_BG 0x0010 -#define EXT3_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_EXTENTS 0x0040 +#define EXT4_FEATURE_INCOMPAT_64BIT 0x0080 +#define EXT4_FEATURE_INCOMPAT_MMP 0x0100 +#define EXT4_FEATURE_INCOMPAT_FLEX_BG 0x0200 #define EXT2_FEATURE_COMPAT_SUPP 0 -#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE) #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT2_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT2_FEATURE_INCOMPAT_UNSUPPORTED (~EXT2_FEATURE_INCOMPAT_SUPP) +#define EXT2_FEATURE_RO_COMPAT_UNSUPPORTED (~EXT2_FEATURE_RO_COMPAT_SUPP) + +#define EXT3_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ + EXT2_FEATURE_RO_COMPAT_BTREE_DIR) +#define EXT3_FEATURE_INCOMPAT_SUPP (EXT2_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER| \ + EXT2_FEATURE_INCOMPAT_META_BG) +#define EXT3_FEATURE_INCOMPAT_UNSUPPORTED (~EXT3_FEATURE_INCOMPAT_SUPP) +#define EXT3_FEATURE_RO_COMPAT_UNSUPPORTED (~EXT3_FEATURE_RO_COMPAT_SUPP) + /* * Default values for user and/or group using reserved blocks diff --git a/include/busybox.h b/include/busybox.h index 48ce856..b1e31e5 100644 --- a/include/busybox.h +++ b/include/busybox.h @@ -1,52 +1,39 @@ /* vi: set sw=4 ts=4: */ /* - * Busybox main internal header file - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef BUSYBOX_H #define BUSYBOX_H 1 #include "libbb.h" +/* BB_DIR_foo and BB_SUID_bar constants: */ +#include "applet_metadata.h" PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -/* order matters: used as index into "install_dir[]" in appletlib.c */ -typedef enum bb_install_loc_t { - _BB_DIR_ROOT = 0, - _BB_DIR_BIN, - _BB_DIR_SBIN, - _BB_DIR_USR_BIN, - _BB_DIR_USR_SBIN -} bb_install_loc_t; - -typedef enum bb_suid_t { - _BB_SUID_DROP = 0, - _BB_SUID_MAYBE, - _BB_SUID_REQUIRE -} bb_suid_t; - - /* Defined in appletlib.c (by including generated applet_tables.h) */ /* Keep in sync with applets/applet_tables.c! */ -extern const char applet_names[]; +extern const char applet_names[] ALIGN1; extern int (*const applet_main[])(int argc, char **argv); extern const uint16_t applet_nameofs[]; -extern const uint8_t applet_install_loc[]; +extern const uint8_t applet_install_loc[] ALIGN1; #if ENABLE_FEATURE_SUID || ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) +# define APPLET_NAME(i) (applet_names + (applet_nameofs[i] & 0x0fff)) #else -#define APPLET_NAME(i) (applet_names + applet_nameofs[i]) +# define APPLET_NAME(i) (applet_names + applet_nameofs[i]) #endif #if ENABLE_FEATURE_PREFER_APPLETS -#define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) -#define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +# define APPLET_IS_NOFORK(i) (applet_nameofs[i] & (1 << 12)) +# define APPLET_IS_NOEXEC(i) (applet_nameofs[i] & (1 << 13)) +#else +# define APPLET_IS_NOFORK(i) 0 +# define APPLET_IS_NOEXEC(i) 0 #endif #if ENABLE_FEATURE_SUID -#define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) +# define APPLET_SUID(i) ((applet_nameofs[i] >> 14) & 0x3) #endif #if ENABLE_FEATURE_INSTALLER diff --git a/include/dump.h b/include/dump.h index 925270d..4c237ef 100644 --- a/include/dump.h +++ b/include/dump.h @@ -45,7 +45,7 @@ typedef struct FS { /* format strings */ typedef struct dumper_t { off_t dump_skip; /* bytes to skip */ int dump_length; /* max bytes to read */ - smallint dump_vflag; /*enum dump_vflag_t*/ + smallint dump_vflag; /*enum dump_vflag_t*/ FS *fshead; } dumper_t; diff --git a/include/fix_u32.h b/include/fix_u32.h index c26e5d1..a2ba6d0 100644 --- a/include/fix_u32.h +++ b/include/fix_u32.h @@ -3,7 +3,7 @@ * This header makes it easier to include kernel headers * which use u32 and such. * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #ifndef FIX_U32_H #define FIX_U32_H 1 diff --git a/include/grp_.h b/include/grp_.h index 7a95f88..e5075e5 100644 --- a/include/grp_.h +++ b/include/grp_.h @@ -18,7 +18,7 @@ 02111-1307 USA. */ /* - * POSIX Standard: 9.2.1 Group Database Access + * POSIX Standard: 9.2.1 Group Database Access */ #ifndef BB_GRP_H #define BB_GRP_H 1 @@ -29,7 +29,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endgrent #define setgrent bb_internal_setgrent #define endgrent bb_internal_endgrent #define getgrent bb_internal_getgrent @@ -64,7 +64,7 @@ extern struct group *fgetgrent(FILE *__stream); /* Write the given entry onto the given stream. */ extern int putgrent(const struct group *__restrict __p, - FILE *__restrict __f); + FILE *__restrict __f); #endif /* Search for an entry with a matching group ID. */ @@ -82,32 +82,32 @@ extern struct group *getgrnam(const char *__name); POSIX people would choose. */ extern int getgrent_r(struct group *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct group **__restrict __result); + char *__restrict __buffer, size_t __buflen, + struct group **__restrict __result); /* Search for an entry with a matching group ID. */ extern int getgrgid_r(gid_t __gid, struct group *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct group **__restrict __result); + char *__restrict __buffer, size_t __buflen, + struct group **__restrict __result); /* Search for an entry with a matching group name. */ extern int getgrnam_r(const char *__restrict __name, - struct group *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct group **__restrict __result); + struct group *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct group **__restrict __result); /* Read a group entry from STREAM. This function is not standardized an probably never will. */ extern int fgetgrent_r(FILE *__restrict __stream, - struct group *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct group **__restrict __result); + struct group *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct group **__restrict __result); /* Store at most *NGROUPS members of the group set for USER into *GROUPS. Also include GROUP. The actual number of groups found is returned in *NGROUPS. Return -1 if the if *NGROUPS is too small. */ extern int getgrouplist(const char *__user, gid_t __group, - gid_t *__groups, int *__ngroups); + gid_t *__groups, int *__ngroups); /* Initialize the group set for the current user by reading the group database and using all groups diff --git a/include/libbb.h b/include/libbb.h index e2a8322..64167bb 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -3,9 +3,9 @@ * Busybox main internal header file * * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. + * Permission has been granted to redistribute this code under GPL. * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #ifndef LIBBB_H #define LIBBB_H 1 @@ -20,37 +20,71 @@ #include #include #include +#if defined __UCLIBC__ /* TODO: and glibc? */ +/* use inlined versions of these: */ +# define sigfillset(s) __sigfillset(s) +# define sigemptyset(s) __sigemptyset(s) +# define sigisemptyset(s) __sigisemptyset(s) +#endif #include #include #include #include #include #include -#include +/* There are two incompatible basename's, let's not use them! */ +/* See the dirname/basename man page for details */ +#include /* dirname,basename */ +#undef basename +#define basename dont_use_basename +#include #include #include #include #include #include #include +#ifndef major +# include +#endif #include #include #include -#include -/* Try to pull in PATH_MAX */ -#include #include +#include +#include +#if ENABLE_FEATURE_SHADOWPASSWDS +# if !ENABLE_USE_BB_SHADOW +/* If using busybox's shadow implementation, do not include the shadow.h + * header as the toolchain may not provide it at all. + */ +# include +# endif +#endif +#if defined(ANDROID) || defined(__ANDROID__) +# define endpwent() ((void)0) +# define endgrent() ((void)0) +#endif #ifdef HAVE_MNTENT_H -#include +# include #endif #ifdef HAVE_SYS_STATFS_H -#include +# include #endif +/* Don't do this here: + * #include + * Some linux/ includes pull in conflicting definition + * of struct sysinfo (only in some toolchanins), which breaks build. + * Include sys/sysinfo.h only in those files which need it. + */ #if ENABLE_SELINUX -#include -#include -#include -#include +# include +# include +# include +# include +#endif +#if ENABLE_FEATURE_UTMP +# include #endif #if ENABLE_LOCALE_SUPPORT # include @@ -60,17 +94,20 @@ #ifdef DMALLOC # include #endif -#include -#include -#if ENABLE_FEATURE_SHADOWPASSWDS -# if !ENABLE_USE_BB_SHADOW -/* If using busybox's shadow implementation, do not include the shadow.h - * header as the toolchain may not provide it at all. - */ -# include -# endif +/* Just in case libc doesn't define some of these... */ +#ifndef _PATH_PASSWD +#define _PATH_PASSWD "/etc/passwd" +#endif +#ifndef _PATH_GROUP +#define _PATH_GROUP "/etc/group" +#endif +#ifndef _PATH_SHADOW +#define _PATH_SHADOW "/etc/shadow" #endif -#if defined __FreeBSD__ +#ifndef _PATH_GSHADOW +#define _PATH_GSHADOW "/etc/gshadow" +#endif +#if defined __FreeBSD__ || defined __OpenBSD__ # include # include #elif defined __APPLE__ @@ -86,6 +123,15 @@ typedef unsigned socklen_t; # endif #endif +#ifndef HAVE_CLEARENV +# define clearenv() do { if (environ) environ[0] = NULL; } while (0) +#endif +#ifndef HAVE_FDATASYNC +# define fdatasync fsync +#endif +#ifndef HAVE_XTABS +# define XTABS TAB3 +#endif /* Some libc's forget to declare these, do it ourself */ @@ -96,31 +142,6 @@ int vdprintf(int d, const char *format, va_list ap); #endif /* klogctl is in libc's klog.h, but we cheat and not #include that */ int klogctl(int type, char *b, int len); -/* This is declared here rather than #including in order to avoid - * confusing the two versions of basename. See the dirname/basename man page - * for details. */ -#if !defined __FreeBSD__ -char *dirname(char *path); -#endif -/* Include our own copy of struct sysinfo to avoid binary compatibility - * problems with Linux 2.4, which changed things. Grumble, grumble. */ -struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ - unsigned long totalram; /* Total usable main memory size */ - unsigned long freeram; /* Available memory size */ - unsigned long sharedram; /* Amount of shared memory */ - unsigned long bufferram; /* Memory used by buffers */ - unsigned long totalswap; /* Total swap space size */ - unsigned long freeswap; /* swap space still available */ - unsigned short procs; /* Number of current processes */ - unsigned short pad; /* Padding needed for m68k */ - unsigned long totalhigh; /* Total high memory size */ - unsigned long freehigh; /* Available high memory size */ - unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20 - 2 * sizeof(long) - sizeof(int)]; /* Padding: libc5 uses this.. */ -}; -int sysinfo(struct sysinfo* info); #ifndef PATH_MAX # define PATH_MAX 256 #endif @@ -129,6 +150,30 @@ int sysinfo(struct sysinfo* info); #endif +/* Busybox does not use threads, we can speed up stdio. */ +#ifdef HAVE_UNLOCKED_STDIO +# undef getc +# define getc(stream) getc_unlocked(stream) +# undef getchar +# define getchar() getchar_unlocked() +# undef putc +# define putc(c, stream) putc_unlocked(c, stream) +# undef putchar +# define putchar(c) putchar_unlocked(c) +# undef fgetc +# define fgetc(stream) getc_unlocked(stream) +# undef fputc +# define fputc(c, stream) putc_unlocked(c, stream) +#endif +/* Above functions are required by POSIX.1-2008, below ones are extensions */ +#ifdef HAVE_UNLOCKED_LINE_OPS +# undef fgets +# define fgets(s, n, stream) fgets_unlocked(s, n, stream) +# undef fputs +# define fputs(s, stream) fputs_unlocked(s, stream) +#endif + + /* Make all declarations hidden (-fvisibility flag only affects definitions) */ /* (don't include system headers after this until corresponding pop!) */ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN @@ -170,7 +215,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN # if ULONG_MAX > 0xffffffff /* "long" is long enough on this system */ typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX) /* usage: sz = BB_STRTOOFF(s, NULL, 10); if (errno || sz < 0) die(); */ # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtoul @@ -179,7 +224,7 @@ typedef unsigned long uoff_t; # else /* "long" is too short, need "long long" */ typedef unsigned long long uoff_t; -# define XATOOFF(a) xatoull_range(a, 0, LLONG_MAX) +# define XATOOFF(a) xatoull_range((a), 0, LLONG_MAX) # define BB_STRTOOFF bb_strtoull # define STRTOOFF strtoull # define OFF_FMT "ll" @@ -190,13 +235,13 @@ typedef unsigned long long uoff_t; /* While sizeof(off_t) == sizeof(int), off_t is typedef'ed to long anyway. * gcc will throw warnings on printf("%d", off_t). Crap... */ typedef unsigned long uoff_t; -# define XATOOFF(a) xatoi_u(a) +# define XATOOFF(a) xatoi_positive(a) # define BB_STRTOOFF bb_strtou # define STRTOOFF strtol # define OFF_FMT "l" # else typedef unsigned long uoff_t; -# define XATOOFF(a) xatoul_range(a, 0, LONG_MAX) +# define XATOOFF(a) xatoul_range((a), 0, LONG_MAX) # define BB_STRTOOFF bb_strtoul # define STRTOOFF strtol # define OFF_FMT "l" @@ -204,6 +249,12 @@ typedef unsigned long uoff_t; #endif /* scary. better ideas? (but do *test* them first!) */ #define OFF_T_MAX ((off_t)~((off_t)1 << (sizeof(off_t)*8-1))) +/* Users report bionic to use 32-bit off_t even if LARGEFILE support is requested. + * We misdetected that. Don't let it build: + */ +struct BUG_off_t_size_is_misdetected { + char BUG_off_t_size_is_misdetected[sizeof(off_t) == sizeof(uoff_t) ? 1 : -1]; +}; /* Some useful definitions */ #undef FALSE @@ -213,20 +264,13 @@ typedef unsigned long uoff_t; #undef SKIP #define SKIP ((int) 2) -/* for mtab.c */ -#define MTAB_GETMOUNTPT '1' -#define MTAB_GETDEVICE '2' - -#define BUF_SIZE 8192 -#define EXPAND_ALLOC 1024 - /* Macros for min/max. */ #ifndef MIN -#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MIN(a,b) (((a)<(b))?(a):(b)) #endif #ifndef MAX -#define MAX(a,b) (((a)>(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) #endif /* buffer allocation schemes */ @@ -254,6 +298,11 @@ extern int *const bb_errno; #define errno (*bb_errno) #endif +#if !(ULONG_MAX > 0xffffffff) +/* Only 32-bit CPUs need this, 64-bit ones use inlined version */ +uint64_t bb_bswap_64(uint64_t x) FAST_FUNC; +#endif + unsigned long long monotonic_ns(void) FAST_FUNC; unsigned long long monotonic_us(void) FAST_FUNC; unsigned long long monotonic_ms(void) FAST_FUNC; @@ -269,7 +318,7 @@ extern char *strrstr(const char *haystack, const char *needle) FAST_FUNC; //TODO: supply a pointer to char[11] buffer (avoid statics)? extern const char *bb_mode_string(mode_t mode) FAST_FUNC; -extern int is_directory(const char *name, int followLinks, struct stat *statBuf) FAST_FUNC; +extern int is_directory(const char *name, int followLinks) FAST_FUNC; enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ FILEUTILS_PRESERVE_STATUS = 1 << 0, /* -p */ FILEUTILS_DEREFERENCE = 1 << 1, /* !-d */ @@ -284,6 +333,7 @@ enum { /* DO NOT CHANGE THESE VALUES! cp.c, mv.c, install.c depend on them. */ FILEUTILS_PRESERVE_SECURITY_CONTEXT = 1 << 9, /* -c */ FILEUTILS_SET_SECURITY_CONTEXT = 1 << 10, #endif + FILEUTILS_IGNORE_CHMOD_ERR = 1 << 11, }; #define FILEUTILS_CP_OPTSTR "pdRfilsLH" IF_SELINUX("c") extern int remove_file(const char *path, int flags) FAST_FUNC; @@ -320,20 +370,27 @@ extern void bb_copyfd_exact_size(int fd1, int fd2, off_t size) FAST_FUNC; /* "short" copy can be detected by return value < size */ /* this helper yells "short read!" if param is not -1 */ extern void complain_copyfd_and_die(off_t sz) NORETURN FAST_FUNC; + extern char bb_process_escape_sequence(const char **ptr) FAST_FUNC; +char* strcpy_and_process_escape_sequences(char *dst, const char *src) FAST_FUNC; /* xxxx_strip version can modify its parameter: * "/" -> "/" * "abc" -> "abc" * "abc/def" -> "def" * "abc/def/" -> "def" !! */ -extern char *bb_get_last_path_component_strip(char *path) FAST_FUNC; +char *bb_get_last_path_component_strip(char *path) FAST_FUNC; /* "abc/def/" -> "" and it never modifies 'path' */ -extern char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; +char *bb_get_last_path_component_nostrip(const char *path) FAST_FUNC; +/* Simpler version: does not special case "/" string */ +const char *bb_basename(const char *name) FAST_FUNC; +/* NB: can violate const-ness (similarly to strchr) */ +char *last_char_is(const char *s, int c) FAST_FUNC; +const char* endofname(const char *name) FAST_FUNC; -int ndelay_on(int fd) FAST_FUNC; -int ndelay_off(int fd) FAST_FUNC; -int close_on_exec_on(int fd) FAST_FUNC; +void ndelay_on(int fd) FAST_FUNC; +void ndelay_off(int fd) FAST_FUNC; +void close_on_exec_on(int fd) FAST_FUNC; void xdup2(int, int) FAST_FUNC; void xmove_fd(int, int) FAST_FUNC; @@ -404,6 +461,8 @@ void record_signo(int signo); /* not FAST_FUNC! */ void xsetgid(gid_t gid) FAST_FUNC; void xsetuid(uid_t uid) FAST_FUNC; +void xsetegid(gid_t egid) FAST_FUNC; +void xseteuid(uid_t euid) FAST_FUNC; void xchdir(const char *path) FAST_FUNC; void xchroot(const char *path) FAST_FUNC; void xsetenv(const char *key, const char *value) FAST_FUNC; @@ -411,21 +470,25 @@ void bb_unsetenv(const char *key) FAST_FUNC; void bb_unsetenv_and_free(char *key) FAST_FUNC; void xunlink(const char *pathname) FAST_FUNC; void xstat(const char *pathname, struct stat *buf) FAST_FUNC; +void xfstat(int fd, struct stat *buf, const char *errmsg) FAST_FUNC; +int open3_or_warn(const char *pathname, int flags, int mode) FAST_FUNC; +int open_or_warn(const char *pathname, int flags) FAST_FUNC; +int xopen3(const char *pathname, int flags, int mode) FAST_FUNC; int xopen(const char *pathname, int flags) FAST_FUNC; int xopen_nonblocking(const char *pathname) FAST_FUNC; -int xopen3(const char *pathname, int flags, int mode) FAST_FUNC; -int open_or_warn(const char *pathname, int flags) FAST_FUNC; -int open3_or_warn(const char *pathname, int flags, int mode) FAST_FUNC; +int xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g) FAST_FUNC; int open_or_warn_stdin(const char *pathname) FAST_FUNC; +int xopen_stdin(const char *pathname) FAST_FUNC; void xrename(const char *oldpath, const char *newpath) FAST_FUNC; int rename_or_warn(const char *oldpath, const char *newpath) FAST_FUNC; off_t xlseek(int fd, off_t offset, int whence) FAST_FUNC; +int xmkstemp(char *template) FAST_FUNC; off_t fdlength(int fd) FAST_FUNC; uoff_t FAST_FUNC get_volume_size_in_bytes(int fd, - const char *override, - unsigned override_units, - int extend); + const char *override, + unsigned override_units, + int extend); void xpipe(int filedes[2]) FAST_FUNC; /* In this form code with pipes is much more readable */ @@ -463,7 +526,8 @@ struct BUG_too_small { void parse_datestr(const char *date_str, struct tm *ptm) FAST_FUNC; time_t validate_tm_time(const char *date_str, struct tm *ptm) FAST_FUNC; - +char *strftime_HHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; +char *strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) FAST_FUNC; int xsocket(int domain, int type, int protocol) FAST_FUNC; void xbind(int sockfd, struct sockaddr *my_addr, socklen_t addrlen) FAST_FUNC; @@ -510,12 +574,7 @@ enum { * and if kernel doesn't support it, fall back to IPv4. * This is useful if you plan to bind to resulting local lsa. */ -#if ENABLE_FEATURE_IPV6 int xsocket_type(len_and_sockaddr **lsap, int af, int sock_type) FAST_FUNC; -#else -int xsocket_type(len_and_sockaddr **lsap, int sock_type) FAST_FUNC; -#define xsocket_type(lsap, af, sock_type) xsocket_type((lsap), (sock_type)) -#endif int xsocket_stream(len_and_sockaddr **lsap) FAST_FUNC; /* Create server socket bound to bindaddr:port. bindaddr can be NULL, * numeric IP ("N.N.N.N") or numeric IPv6 address, @@ -555,7 +614,7 @@ len_and_sockaddr* xhost_and_af2sockaddr(const char *host, int port, sa_family_t /* Assign sin[6]_port member if the socket is an AF_INET[6] one, * otherwise no-op. Useful for ftp. * NB: does NOT do htons() internally, just direct assignment. */ -void set_nport(len_and_sockaddr *lsa, unsigned port) FAST_FUNC; +void set_nport(struct sockaddr *sa, unsigned port) FAST_FUNC; /* Retrieve sin[6]_port or return -1 for non-INET[6] lsa's */ int get_nport(const struct sockaddr *sa) FAST_FUNC; /* Reverse DNS. Returns NULL on failure. */ @@ -584,6 +643,7 @@ ssize_t recv_from_to(int fd, void *buf, size_t len, int flags, struct sockaddr *to, socklen_t sa_size) FAST_FUNC; +uint16_t inet_cksum(uint16_t *addr, int len) FAST_FUNC; char *xstrdup(const char *s) FAST_FUNC RETURNS_MALLOC; char *xstrndup(const char *s, int n) FAST_FUNC RETURNS_MALLOC; @@ -621,6 +681,13 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str); * else it is printed as-is (except for ch = 0x9b) */ enum { PRINTABLE_META = 0x100 }; void fputc_printable(int ch, FILE *file) FAST_FUNC; +/* Return a string that is the printable representation of character ch. + * Buffer must hold at least four characters. */ +enum { + VISIBLE_ENDLINE = 1 << 0, + VISIBLE_SHOW_TABS = 1 << 1, +}; +void visible(unsigned ch, char *buf, int flags) FAST_FUNC; /* dmalloc will redefine these to it's own implementation. It is safe * to have the prototypes here unconditionally. */ @@ -628,17 +695,20 @@ void *malloc_or_warn(size_t size) FAST_FUNC RETURNS_MALLOC; void *xmalloc(size_t size) FAST_FUNC RETURNS_MALLOC; void *xzalloc(size_t size) FAST_FUNC RETURNS_MALLOC; void *xrealloc(void *old, size_t size) FAST_FUNC; -/* After xrealloc_vector(v, 4, idx) it's ok to use +/* After v = xrealloc_vector(v, SHIFT, idx) it's ok to use * at least v[idx] and v[idx+1], for all idx values. - * shift specifies how many new elements are added (1: 2, 2: 4... 8: 256...) - * when all elements are used up. New elements are zeroed out. */ + * SHIFT specifies how many new elements are added (1:2, 2:4, ..., 8:256...) + * when all elements are used up. New elements are zeroed out. + * xrealloc_vector(v, SHIFT, idx) *MUST* be called with consecutive IDXs - + * skipping an index is a bad bug - it may miss a realloc! + */ #define xrealloc_vector(vector, shift, idx) \ xrealloc_vector_helper((vector), (sizeof((vector)[0]) << 8) + (shift), (idx)) void* xrealloc_vector_helper(void *vector, unsigned sizeof_and_shift, int idx) FAST_FUNC; extern ssize_t safe_read(int fd, void *buf, size_t count) FAST_FUNC; -extern ssize_t nonblock_safe_read(int fd, void *buf, size_t count) FAST_FUNC; +extern ssize_t nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) FAST_FUNC; // NB: will return short read on error, not -1, // if some data was read before error occurred extern ssize_t full_read(int fd, void *buf, size_t count) FAST_FUNC; @@ -649,25 +719,31 @@ extern ssize_t open_read_close(const char *filename, void *buf, size_t maxsz) FA // Reads one line a-la fgets (but doesn't save terminating '\n'). // Reads byte-by-byte. Useful when it is important to not read ahead. // Bytes are appended to pfx (which must be malloced, or NULL). -extern char *xmalloc_reads(int fd, char *pfx, size_t *maxsz_p) FAST_FUNC; +extern char *xmalloc_reads(int fd, size_t *maxsz_p) FAST_FUNC; /* Reads block up to *maxsz_p (default: INT_MAX - 4095) */ extern void *xmalloc_read(int fd, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; /* Returns NULL if file can't be opened (default max size: INT_MAX - 4095) */ extern void *xmalloc_open_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; -/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ -#if ENABLE_FEATURE_SEAMLESS_LZMA \ +/* Never returns NULL */ +extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; + +#define SEAMLESS_COMPRESSION (0 \ + || ENABLE_FEATURE_SEAMLESS_XZ \ + || ENABLE_FEATURE_SEAMLESS_LZMA \ || ENABLE_FEATURE_SEAMLESS_BZ2 \ || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ -extern void setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) FAST_FUNC; -#else -# define setup_unzip_on_fd(...) ((void)0) -#endif + || ENABLE_FEATURE_SEAMLESS_Z) + +#if SEAMLESS_COMPRESSION +/* Autodetects gzip/bzip2 formats. fd may be in the middle of the file! */ +extern int setup_unzip_on_fd(int fd, int fail_if_not_detected) FAST_FUNC; /* Autodetects .gz etc */ extern int open_zipped(const char *fname) FAST_FUNC; +#else +# define setup_unzip_on_fd(...) (0) +# define open_zipped(fname) open((fname), O_RDONLY); +#endif extern void *xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; -/* Never returns NULL */ -extern void *xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) FAST_FUNC RETURNS_MALLOC; extern ssize_t safe_write(int fd, const void *buf, size_t count) FAST_FUNC; // NB: will return short write on error, not -1, @@ -685,8 +761,12 @@ extern void xclose(int fd) FAST_FUNC; /* Reads and prints to stdout till eof, then closes FILE. Exits on error: */ extern void xprint_and_close_file(FILE *file) FAST_FUNC; +/* Reads a line from a text file, up to a newline or NUL byte, inclusive. + * Returns malloc'ed char*. If end is NULL '\n' isn't considered + * end of line. If end isn't NULL, length of the chunk is stored in it. + * Returns NULL if EOF/error. + */ extern char *bb_get_chunk_from_file(FILE *file, int *end) FAST_FUNC; -extern char *bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) FAST_FUNC; /* Reads up to (and including) TERMINATING_STRING: */ extern char *xmalloc_fgets_str(FILE *file, const char *terminating_string) FAST_FUNC RETURNS_MALLOC; /* Same, with limited max size, and returns the length (excluding NUL): */ @@ -728,7 +808,6 @@ void qsort_string_vector(char **sv, unsigned count) FAST_FUNC; int safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout_ms) FAST_FUNC; char *safe_gethostname(void) FAST_FUNC; -char *safe_getdomainname(void) FAST_FUNC; /* Convert each alpha char in str to lower-case */ char* str_tolower(char *str) FAST_FUNC; @@ -739,8 +818,8 @@ char *itoa(int n) FAST_FUNC; char *utoa_to_buf(unsigned n, char *buf, unsigned buflen) FAST_FUNC; char *itoa_to_buf(int n, char *buf, unsigned buflen) FAST_FUNC; /* Intelligent formatters of bignums */ -void smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; -void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; +char *smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) FAST_FUNC; +char *smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_FUNC; /* If block_size == 0, display size without fractional part, * else display (size * block_size) with one decimal digit. * If display_unit == 0, show value no bigger than 1024 with suffix (K,M,G...), @@ -751,9 +830,9 @@ void smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) FAST_F const char *make_human_readable_str(unsigned long long size, unsigned long block_size, unsigned long display_unit) FAST_FUNC; /* Put a string of hex bytes ("1b2e66fe"...), return advanced pointer */ -char *bin2hex(char *buf, const char *cp, int count) FAST_FUNC; +char *bin2hex(char *dst, const char *src, int count) FAST_FUNC; /* Reverse */ -char* hex2bin(char *dst, const char *str, int count) FAST_FUNC; +char* hex2bin(char *dst, const char *src, int count) FAST_FUNC; /* Generate a UUID */ void generate_uuid(uint8_t *buf) FAST_FUNC; @@ -763,13 +842,21 @@ struct suffix_mult { char suffix[4]; unsigned mult; }; +extern const struct suffix_mult bkm_suffixes[]; +#define km_suffixes (bkm_suffixes + 1) + #include "xatonum.h" /* Specialized: */ + /* Using xatoi() instead of naive atoi() is not always convenient - * in many places people want *non-negative* values, but store them * in signed int. Therefore we need this one: - * dies if input is not in [0, INT_MAX] range. Also will reject '-0' etc */ -int xatoi_u(const char *numstr) FAST_FUNC; + * dies if input is not in [0, INT_MAX] range. Also will reject '-0' etc. + * It should really be named xatoi_nonnegative (since it allows 0), + * but that would be too long. + */ +int xatoi_positive(const char *numstr) FAST_FUNC; + /* Useful for reading port numbers */ uint16_t xatou16(const char *numstr) FAST_FUNC; @@ -800,14 +887,14 @@ char* xuid2uname(uid_t uid) FAST_FUNC; char* xgid2group(gid_t gid) FAST_FUNC; char* uid2uname(uid_t uid) FAST_FUNC; char* gid2group(gid_t gid) FAST_FUNC; -char* uid2uname_utoa(long uid) FAST_FUNC; -char* gid2group_utoa(long gid) FAST_FUNC; +char* uid2uname_utoa(uid_t uid) FAST_FUNC; +char* gid2group_utoa(gid_t gid) FAST_FUNC; /* versions which cache results (useful for ps, ls etc) */ const char* get_cached_username(uid_t uid) FAST_FUNC; const char* get_cached_groupname(gid_t gid) FAST_FUNC; void clear_username_cache(void) FAST_FUNC; /* internally usernames are saved in fixed-sized char[] buffers */ -enum { USERNAME_MAX_SIZE = 16 - sizeof(int) }; +enum { USERNAME_MAX_SIZE = 32 - sizeof(uid_t) }; #if ENABLE_FEATURE_CHECK_NAMES void die_if_bad_username(const char* name) FAST_FUNC; #else @@ -822,6 +909,7 @@ void FAST_FUNC update_utmp(pid_t pid, int new_type, const char *tty_name, const # define update_utmp(pid, new_type, tty_name, username, hostname) ((void)0) #endif + int execable_file(const char *name) FAST_FUNC; char *find_execable(const char *filename, char **PATHp) FAST_FUNC; int exists_execable(const char *filename) FAST_FUNC; @@ -830,14 +918,16 @@ int exists_execable(const char *filename) FAST_FUNC; * but it may exec busybox and call applet instead of searching PATH. */ #if ENABLE_FEATURE_PREFER_APPLETS -int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; -#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) +int BB_EXECVP(const char *file, char *const argv[]) FAST_FUNC; #define BB_EXECLP(prog,cmd,...) \ - execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \ - cmd, __VA_ARGS__) + do { \ + if (find_applet_by_name(prog) >= 0) \ + execlp(bb_busybox_exec_path, cmd, __VA_ARGS__); \ + execlp(prog, cmd, __VA_ARGS__); \ + } while (0) #else #define BB_EXECVP(prog,cmd) execvp(prog,cmd) -#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) +#define BB_EXECLP(prog,cmd,...) execlp(prog,cmd,__VA_ARGS__) #endif int BB_EXECVP_or_die(char **argv) NORETURN FAST_FUNC; @@ -871,19 +961,8 @@ pid_t wait_any_nohang(int *wstat) FAST_FUNC; int wait4pid(pid_t pid) FAST_FUNC; /* Same as wait4pid(spawn(argv)), but with NOFORK/NOEXEC if configured: */ int spawn_and_wait(char **argv) FAST_FUNC; -struct nofork_save_area { - jmp_buf die_jmp; - const char *applet_name; - int xfunc_error_retval; - uint32_t option_mask32; - int die_sleep; - smallint saved; -}; -void save_nofork_data(struct nofork_save_area *save) FAST_FUNC; -void restore_nofork_data(struct nofork_save_area *save) FAST_FUNC; /* Does NOT check that applet is NOFORK, just blindly runs it */ int run_nofork_applet(int applet_no, char **argv) FAST_FUNC; -int run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) FAST_FUNC; /* Helpers for daemonization. * @@ -913,6 +992,7 @@ enum { DAEMON_DEVNULL_STDIO = 2, DAEMON_CLOSE_EXTRA_FDS = 4, DAEMON_ONLY_SANITIZE = 8, /* internal use */ + DAEMON_DOUBLE_FORK = 16, /* double fork to avoid controlling tty */ }; #if BB_MMU enum { re_execed = 0 }; @@ -921,6 +1001,9 @@ enum { # define bb_daemonize(flags) bb_daemonize_or_rexec(flags, bogus) #else extern bool re_execed; + /* Note: re_exec() and fork_or_rexec() do argv[0][0] |= 0x80 on NOMMU! + * _Parent_ needs to undo it if it doesn't want to have argv[0] mangled. + */ void re_exec(char **argv) NORETURN FAST_FUNC; pid_t fork_or_rexec(char **argv) FAST_FUNC; int BUG_fork_is_unavailable_on_nommu(void) FAST_FUNC; @@ -950,9 +1033,13 @@ extern uint32_t option_mask32; extern uint32_t getopt32(char **argv, const char *applet_opts, ...) FAST_FUNC; +/* Having next pointer as a first member allows easy creation + * of "llist-compatible" structs, and using llist_FOO functions + * on them. + */ typedef struct llist_t { - char *data; struct llist_t *link; + char *data; } llist_t; void llist_add_to(llist_t **old_head, void *data) FAST_FUNC; void llist_add_to_end(llist_t **list_head, void *data) FAST_FUNC; @@ -987,7 +1074,7 @@ enum { extern const char *msg_eol; extern smallint logmode; extern int die_sleep; -extern int xfunc_error_retval; +extern uint8_t xfunc_error_retval; extern jmp_buf die_jmp; extern void xfunc_die(void) NORETURN FAST_FUNC; extern void bb_show_usage(void) NORETURN FAST_FUNC; @@ -1035,9 +1122,6 @@ void bb_displayroutes(int noresolve, int netstatfmt) FAST_FUNC; /* Networking */ -int create_icmp_socket(void) FAST_FUNC; -int create_icmp6_socket(void) FAST_FUNC; -/* interface.c */ /* This structure defines protocol families and their handlers. */ struct aftype { const char *name; @@ -1066,6 +1150,7 @@ struct hwtype { }; extern smallint interface_opt_a; int display_interfaces(char *ifname) FAST_FUNC; +int in_ether(const char *bufp, struct sockaddr *sap) FAST_FUNC; #if ENABLE_FEATURE_HWIB int in_ib(const char *bufp, struct sockaddr *sap) FAST_FUNC; #else @@ -1103,7 +1188,7 @@ extern int del_loop(const char *device) FAST_FUNC; /* If *devname is not NULL, use that name, otherwise try to find free one, * malloc and return it in *devname. * return value: 1: read-only loopdev was setup, 0: rw, < 0: error */ -extern int set_loop(char **devname, const char *file, unsigned long long offset) FAST_FUNC; +extern int set_loop(char **devname, const char *file, unsigned long long offset, int ro) FAST_FUNC; /* Like bb_ask below, but asks on stdin with no timeout. */ char *bb_ask_stdin(const char * prompt) FAST_FUNC; @@ -1124,18 +1209,20 @@ enum { PARSE_MIN_DIE = 0x00100000, // die if < min tokens found // keep a copy of current line PARSE_KEEP_COPY = 0x00200000 * ENABLE_FEATURE_CROND_D, -// PARSE_ESCAPE = 0x00400000, // process escape sequences in tokens + PARSE_EOL_COMMENTS = 0x00400000, // comments are recognized even if they aren't the first char // NORMAL is: // * remove leading and trailing delimiters and collapse // multiple delimiters into one // * warn and continue if less than mintokens delimiters found // * grab everything into last token - PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY, + // * comments are recognized even if they aren't the first char + PARSE_NORMAL = PARSE_COLLAPSE | PARSE_TRIM | PARSE_GREEDY | PARSE_EOL_COMMENTS, }; typedef struct parser_t { FILE *fp; - char *line; char *data; + char *line, *nline; + size_t line_alloc, nline_alloc; int lineno; } parser_t; parser_t* config_open(const char *filename) FAST_FUNC; @@ -1151,10 +1238,8 @@ void config_close(parser_t *parser) FAST_FUNC; * If path is NULL, it is assumed to be "/". * filename should not be NULL. */ char *concat_path_file(const char *path, const char *filename) FAST_FUNC; +/* Returns NULL on . and .. */ char *concat_subpath_file(const char *path, const char *filename) FAST_FUNC; -const char *bb_basename(const char *name) FAST_FUNC; -/* NB: can violate const-ness (similarly to strchr) */ -char *last_char_is(const char *s, int c) FAST_FUNC; int bb_make_directory(char *path, long mode, int flags) FAST_FUNC; @@ -1167,10 +1252,17 @@ char *bb_simplify_path(const char *path) FAST_FUNC; /* Returns ptr to NUL */ char *bb_simplify_abs_path_inplace(char *path) FAST_FUNC; -#define FAIL_DELAY 3 +#define LOGIN_FAIL_DELAY 3 extern void bb_do_delay(int seconds) FAST_FUNC; extern void change_identity(const struct passwd *pw) FAST_FUNC; extern void run_shell(const char *shell, int loginshell, const char *command, const char **additional_args) NORETURN FAST_FUNC; + +/* Returns $SHELL, getpwuid(getuid())->pw_shell, or DEFAULT_SHELL. + * Note that getpwuid result might need xstrdup'ing + * if there is a possibility of intervening getpwxxx() calls. + */ +const char *get_shell_name(void) FAST_FUNC; + #if ENABLE_SELINUX extern void renew_current_security_context(void) FAST_FUNC; extern void set_current_security_context(security_context_t sid) FAST_FUNC; @@ -1183,6 +1275,12 @@ extern void selinux_preserve_fcontext(int fdesc) FAST_FUNC; #endif extern void selinux_or_die(void) FAST_FUNC; + +/* systemd support */ +#define SD_LISTEN_FDS_START 3 +int sd_listen_fds(void); + + /* setup_environment: * if chdir pw->pw_dir: ok: else if to_tmp == 1: goto /tmp else: goto / or die * if clear_env = 1: cd(pw->pw_dir), clear environment, then set @@ -1201,22 +1299,30 @@ extern void selinux_or_die(void) FAST_FUNC; #define SETUP_ENV_CHANGEENV (1 << 0) #define SETUP_ENV_CLEARENV (1 << 1) #define SETUP_ENV_TO_TMP (1 << 2) -extern void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; -extern int correct_password(const struct passwd *pw) FAST_FUNC; +#define SETUP_ENV_NO_CHDIR (1 << 4) +void setup_environment(const char *shell, int flags, const struct passwd *pw) FAST_FUNC; +void nuke_str(char *str) FAST_FUNC; +int ask_and_check_password_extended(const struct passwd *pw, int timeout, const char *prompt) FAST_FUNC; +int ask_and_check_password(const struct passwd *pw) FAST_FUNC; /* Returns a malloced string */ #if !ENABLE_USE_BB_CRYPT #define pw_encrypt(clear, salt, cleanup) pw_encrypt(clear, salt) #endif extern char *pw_encrypt(const char *clear, const char *salt, int cleanup) FAST_FUNC; extern int obscure(const char *old, const char *newval, const struct passwd *pwdp) FAST_FUNC; -/* rnd is additional random input. New one is returned. +/* + * rnd is additional random input. New one is returned. * Useful if you call crypt_make_salt many times in a row: * rnd = crypt_make_salt(buf1, 4, 0); * rnd = crypt_make_salt(buf2, 4, rnd); * rnd = crypt_make_salt(buf3, 4, rnd); * (otherwise we risk having same salt generated) */ -extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; +extern int crypt_make_salt(char *p, int cnt /*, int rnd*/) FAST_FUNC; +/* "$N$" + sha_salt_16_bytes + NUL */ +#define MAX_PW_SALT_LEN (3 + 16 + 1) +extern char* crypt_make_pw_salt(char p[MAX_PW_SALT_LEN], const char *algo) FAST_FUNC; + /* Returns number of lines changed, or -1 on error */ #if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) @@ -1263,7 +1369,7 @@ void add_to_ino_dev_hashtable(const struct stat *statbuf, const char *name) FAST void reset_ino_dev_hashtable(void) FAST_FUNC; #ifdef __GLIBC__ /* At least glibc has horrendously large inline for this, so wrap it */ -unsigned long long bb_makedev(unsigned int major, unsigned int minor) FAST_FUNC; +unsigned long long bb_makedev(unsigned major, unsigned minor) FAST_FUNC; #undef makedev #define makedev(a,b) bb_makedev(a,b) #endif @@ -1284,25 +1390,37 @@ enum { KEYCODE_DELETE = -9, KEYCODE_PAGEUP = -10, KEYCODE_PAGEDOWN = -11, - - KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40, - KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40, - KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40, - KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40, + // -12 is reserved for Alt/Ctrl/Shift-TAB #if 0 - KEYCODE_FUN1 = -12, - KEYCODE_FUN2 = -13, - KEYCODE_FUN3 = -14, - KEYCODE_FUN4 = -15, - KEYCODE_FUN5 = -16, - KEYCODE_FUN6 = -17, - KEYCODE_FUN7 = -18, - KEYCODE_FUN8 = -19, - KEYCODE_FUN9 = -20, - KEYCODE_FUN10 = -21, - KEYCODE_FUN11 = -22, - KEYCODE_FUN12 = -23, + KEYCODE_FUN1 = -13, + KEYCODE_FUN2 = -14, + KEYCODE_FUN3 = -15, + KEYCODE_FUN4 = -16, + KEYCODE_FUN5 = -17, + KEYCODE_FUN6 = -18, + KEYCODE_FUN7 = -19, + KEYCODE_FUN8 = -20, + KEYCODE_FUN9 = -21, + KEYCODE_FUN10 = -22, + KEYCODE_FUN11 = -23, + KEYCODE_FUN12 = -24, #endif + /* Be sure that last defined value is small enough + * to not interfere with Alt/Ctrl/Shift bits. + * So far we do not exceed -31 (0xfff..fffe1), + * which gives us three upper bits in LSB to play with. + */ + //KEYCODE_SHIFT_TAB = (-12) & ~0x80, + //KEYCODE_SHIFT_... = KEYCODE_... & ~0x80, + //KEYCODE_CTRL_UP = KEYCODE_UP & ~0x40, + //KEYCODE_CTRL_DOWN = KEYCODE_DOWN & ~0x40, + KEYCODE_CTRL_RIGHT = KEYCODE_RIGHT & ~0x40, + KEYCODE_CTRL_LEFT = KEYCODE_LEFT & ~0x40, + //KEYCODE_ALT_UP = KEYCODE_UP & ~0x20, + //KEYCODE_ALT_DOWN = KEYCODE_DOWN & ~0x20, + KEYCODE_ALT_RIGHT = KEYCODE_RIGHT & ~0x20, + KEYCODE_ALT_LEFT = KEYCODE_LEFT & ~0x20, + KEYCODE_CURSOR_POS = -0x100, /* 0xfff..fff00 */ /* How long is the longest ESC sequence we know? * We want it big enough to be able to contain @@ -1329,8 +1447,9 @@ void read_key_ungets(char *buffer, const char *str, unsigned len) FAST_FUNC; #if ENABLE_FEATURE_EDITING /* It's NOT just ENABLEd or disabled. It's a number: */ -# ifdef CONFIG_FEATURE_EDITING_HISTORY +# if defined CONFIG_FEATURE_EDITING_HISTORY && CONFIG_FEATURE_EDITING_HISTORY > 0 # define MAX_HISTORY (CONFIG_FEATURE_EDITING_HISTORY + 0) +unsigned size_from_HISTFILESIZE(const char *hp) FAST_FUNC; # else # define MAX_HISTORY 0 # endif @@ -1340,7 +1459,14 @@ typedef struct line_input_t { # if MAX_HISTORY int cnt_history; int cur_history; + int max_history; /* must never be <= 0 */ # if ENABLE_FEATURE_EDITING_SAVEHISTORY + /* meaning of this field depends on FEATURE_EDITING_SAVE_ON_EXIT: + * if !FEATURE_EDITING_SAVE_ON_EXIT: "how many lines are + * in on-disk history" + * if FEATURE_EDITING_SAVE_ON_EXIT: "how many in-memory lines are + * also in on-disk history (and thus need to be skipped on save)" + */ unsigned cnt_history_in_file; const char *hist_file; # endif @@ -1348,27 +1474,31 @@ typedef struct line_input_t { # endif } line_input_t; enum { - DO_HISTORY = 1 * (MAX_HISTORY > 0), - SAVE_HISTORY = 2 * (MAX_HISTORY > 0) * ENABLE_FEATURE_EDITING_SAVEHISTORY, - TAB_COMPLETION = 4 * ENABLE_FEATURE_TAB_COMPLETION, - USERNAME_COMPLETION = 8 * ENABLE_FEATURE_USERNAME_COMPLETION, - VI_MODE = 0x10 * ENABLE_FEATURE_EDITING_VI, - WITH_PATH_LOOKUP = 0x20, - FOR_SHELL = DO_HISTORY | SAVE_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION, + DO_HISTORY = 1 * (MAX_HISTORY > 0), + TAB_COMPLETION = 2 * ENABLE_FEATURE_TAB_COMPLETION, + USERNAME_COMPLETION = 4 * ENABLE_FEATURE_USERNAME_COMPLETION, + VI_MODE = 8 * ENABLE_FEATURE_EDITING_VI, + WITH_PATH_LOOKUP = 0x10, + FOR_SHELL = DO_HISTORY | TAB_COMPLETION | USERNAME_COMPLETION, }; line_input_t *new_line_input_t(int flags) FAST_FUNC; /* So far static: void free_line_input_t(line_input_t *n) FAST_FUNC; */ -/* maxsize must be >= 2. +/* + * maxsize must be >= 2. * Returns: * -1 on read errors or EOF, or on bare Ctrl-D, * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -int read_line_input(const char* prompt, char* command, int maxsize, line_input_t *state) FAST_FUNC; +int read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) FAST_FUNC; +void show_history(const line_input_t *st) FAST_FUNC; +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +void save_history(line_input_t *st); +# endif #else #define MAX_HISTORY 0 int read_line_input(const char* prompt, char* command, int maxsize) FAST_FUNC; -#define read_line_input(prompt, command, maxsize, state) \ +#define read_line_input(state, prompt, command, maxsize, timeout) \ read_line_input(prompt, command, maxsize) #endif @@ -1381,6 +1511,29 @@ enum { COMM_LEN = TASK_COMM_LEN }; enum { COMM_LEN = 16 }; # endif #endif + +struct smaprec { + unsigned long mapped_rw; + unsigned long mapped_ro; + unsigned long shared_clean; + unsigned long shared_dirty; + unsigned long private_clean; + unsigned long private_dirty; + unsigned long stack; + unsigned long smap_pss, smap_swap; + unsigned long smap_size; + unsigned long smap_start; + char smap_mode[5]; + char *smap_name; +}; + +#if !ENABLE_PMAP +#define procps_read_smaps(pid, total, cb, data) \ + procps_read_smaps(pid, total) +#endif +int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, + void (*cb)(struct smaprec *, void *), void *data); + typedef struct procps_status_t { DIR *dir; IF_FEATURE_SHOW_THREADS(DIR *task_dir;) @@ -1391,6 +1544,7 @@ typedef struct procps_status_t { char *argv0; char *exe; IF_SELINUX(char *context;) + IF_FEATURE_SHOW_THREADS(unsigned main_thread_pid;) /* Everything below must contain no ptrs to malloc'ed data: * it is memset(0) for each process in procps_scan() */ unsigned long vsz, rss; /* we round it to kbytes */ @@ -1409,13 +1563,7 @@ typedef struct procps_status_t { #endif unsigned tty_major,tty_minor; #if ENABLE_FEATURE_TOPMEM - unsigned long mapped_rw; - unsigned long mapped_ro; - unsigned long shared_clean; - unsigned long shared_dirty; - unsigned long private_clean; - unsigned long private_dirty; - unsigned long stack; + struct smaprec smaps; #endif char state[4]; /* basename of executable in exec(2), read from /proc/N/stat @@ -1458,13 +1606,6 @@ enum { PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, PSSCAN_RUIDGID = (1 << 21) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, PSSCAN_TASKS = (1 << 22) * ENABLE_FEATURE_SHOW_THREADS, - /* These are all retrieved from proc/NN/stat in one go: */ - PSSCAN_STAT = PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID - /**/ | PSSCAN_COMM | PSSCAN_STATE - /**/ | PSSCAN_VSZ | PSSCAN_RSS - /**/ | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME - /**/ | PSSCAN_TTY | PSSCAN_NICE - /**/ | PSSCAN_CPU }; //procps_status_t* alloc_procps_scan(void) FAST_FUNC; void free_procps_scan(procps_status_t* sp) FAST_FUNC; @@ -1474,57 +1615,67 @@ procps_status_t* procps_scan(procps_status_t* sp, int flags) FAST_FUNC; void read_cmdline(char *buf, int size, unsigned pid, const char *comm) FAST_FUNC; pid_t *find_pid_by_name(const char* procName) FAST_FUNC; pid_t *pidlist_reverse(pid_t *pidList) FAST_FUNC; +int starts_with_cpu(const char *str) FAST_FUNC; +unsigned get_cpu_count(void) FAST_FUNC; -extern const char bb_uuenc_tbl_base64[]; -extern const char bb_uuenc_tbl_std[]; +/* Use strict=1 if you process input from untrusted source: + * it will return NULL on invalid %xx (bad hex chars) + * and str + 1 if decoded char is / or NUL. + * In non-strict mode, it always succeeds (returns str), + * and also it additionally decoded '+' to space. + */ +char *percent_decode_in_place(char *str, int strict) FAST_FUNC; + + +extern const char bb_uuenc_tbl_base64[] ALIGN1; +extern const char bb_uuenc_tbl_std[] ALIGN1; void bb_uuencode(char *store, const void *s, int length, const char *tbl) FAST_FUNC; +enum { + BASE64_FLAG_UU_STOP = 0x100, + /* Sign-extends to a value which never matches fgetc result: */ + BASE64_FLAG_NO_STOP_CHAR = 0x80, +}; +const char *decode_base64(char **pp_dst, const char *src) FAST_FUNC; +void read_base64(FILE *src_stream, FILE *dst_stream, int flags) FAST_FUNC; -typedef struct sha1_ctx_t { - uint32_t hash[8]; /* 5, +3 elements for sha256 */ - uint64_t total64; - uint8_t wbuffer[64]; /* NB: always correctly aligned for uint64_t */ - void (*process_block)(struct sha1_ctx_t*) FAST_FUNC; -} sha1_ctx_t; -void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC; -void sha1_hash(const void *data, size_t length, sha1_ctx_t *ctx) FAST_FUNC; -void sha1_end(void *resbuf, sha1_ctx_t *ctx) FAST_FUNC; -typedef struct sha1_ctx_t sha256_ctx_t; -void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; -#define sha256_hash sha1_hash -#define sha256_end sha1_end +typedef struct md5_ctx_t { + uint8_t wbuffer[64]; /* always correctly aligned for uint64_t */ + void (*process_block)(struct md5_ctx_t*) FAST_FUNC; + uint64_t total64; /* must be directly before hash[] */ + uint32_t hash[8]; /* 4 elements for md5, 5 for sha1, 8 for sha256 */ +} md5_ctx_t; +typedef struct md5_ctx_t sha1_ctx_t; +typedef struct md5_ctx_t sha256_ctx_t; typedef struct sha512_ctx_t { + uint64_t total64[2]; /* must be directly before hash[] */ uint64_t hash[8]; - uint64_t total64[2]; - uint8_t wbuffer[128]; /* NB: always correctly aligned for uint64_t */ + uint8_t wbuffer[128]; /* always correctly aligned for uint64_t */ } sha512_ctx_t; -void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; -void sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) FAST_FUNC; -void sha512_end(void *resbuf, sha512_ctx_t *ctx) FAST_FUNC; -#if 1 -typedef struct md5_ctx_t { - uint32_t A; - uint32_t B; - uint32_t C; - uint32_t D; - uint64_t total; - uint32_t buflen; - char buffer[128]; -} md5_ctx_t; -#else -/* libbb/md5prime.c uses a bit different one: */ -typedef struct md5_ctx_t { - uint32_t state[4]; /* state (ABCD) */ - uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ - unsigned char buffer[64]; /* input buffer */ -} md5_ctx_t; -#endif +typedef struct sha3_ctx_t { + uint64_t state[25]; + unsigned bytes_queued; +} sha3_ctx_t; void md5_begin(md5_ctx_t *ctx) FAST_FUNC; -void md5_hash(const void *data, size_t length, md5_ctx_t *ctx) FAST_FUNC; -void md5_end(void *resbuf, md5_ctx_t *ctx) FAST_FUNC; - +void md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; +void md5_end(md5_ctx_t *ctx, void *resbuf) FAST_FUNC; +void sha1_begin(sha1_ctx_t *ctx) FAST_FUNC; +#define sha1_hash md5_hash +void sha1_end(sha1_ctx_t *ctx, void *resbuf) FAST_FUNC; +void sha256_begin(sha256_ctx_t *ctx) FAST_FUNC; +#define sha256_hash md5_hash +#define sha256_end sha1_end +void sha512_begin(sha512_ctx_t *ctx) FAST_FUNC; +void sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; +void sha512_end(sha512_ctx_t *ctx, void *resbuf) FAST_FUNC; +void sha3_begin(sha3_ctx_t *ctx) FAST_FUNC; +void sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) FAST_FUNC; +void sha3_end(sha3_ctx_t *ctx, void *resbuf) FAST_FUNC; +extern uint32_t *global_crc32_table; uint32_t *crc32_filltable(uint32_t *tbl256, int endian) FAST_FUNC; +uint32_t crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; +uint32_t crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) FAST_FUNC; typedef struct masks_labels_t { const char *labels; @@ -1535,49 +1686,72 @@ int print_flags_separated(const int *masks, const char *labels, int print_flags(const masks_labels_t *ml, int flags) FAST_FUNC; typedef struct bb_progress_t { - off_t lastsize; - unsigned lastupdate_sec; + unsigned last_size; + unsigned last_update_sec; + unsigned last_change_sec; unsigned start_sec; - smallint inited; + const char *curfile; } bb_progress_t; -void bb_progress_init(bb_progress_t *p) FAST_FUNC; -void bb_progress_update(bb_progress_t *p, const char *curfile, - off_t beg_range, off_t transferred, - off_t totalsize) FAST_FUNC; +#define is_bb_progress_inited(p) ((p)->curfile != NULL) +#define bb_progress_free(p) do { \ + if (ENABLE_UNICODE_SUPPORT) free((char*)((p)->curfile)); \ + (p)->curfile = NULL; \ +} while (0) +void bb_progress_init(bb_progress_t *p, const char *curfile) FAST_FUNC; +void bb_progress_update(bb_progress_t *p, + uoff_t beg_range, + uoff_t transferred, + uoff_t totalsize) FAST_FUNC; + extern const char *applet_name; + +/* Some older linkers don't perform string merging, we used to have common strings + * as global arrays to do it by hand. But: + * (1) newer linkers do it themselves, + * (2) however, they DONT merge string constants with global arrays, + * even if the value is the same (!). Thus global arrays actually + * increased size a bit: for example, "/etc/passwd" string from libc + * wasn't merged with bb_path_passwd_file[] array! + * Therefore now we use #defines. + */ /* "BusyBox vN.N.N (timestamp or extra_version)" */ -extern const char bb_banner[]; -extern const char bb_msg_memory_exhausted[]; -extern const char bb_msg_invalid_date[]; -extern const char bb_msg_read_error[]; -extern const char bb_msg_write_error[]; -extern const char bb_msg_unknown[]; -extern const char bb_msg_can_not_create_raw_socket[]; -extern const char bb_msg_perm_denied_are_you_root[]; -extern const char bb_msg_you_must_be_root[]; -extern const char bb_msg_requires_arg[]; -extern const char bb_msg_invalid_arg[]; -extern const char bb_msg_standard_input[]; -extern const char bb_msg_standard_output[]; - -extern const char bb_str_default[]; +extern const char bb_banner[] ALIGN1; +extern const char bb_msg_memory_exhausted[] ALIGN1; +extern const char bb_msg_invalid_date[] ALIGN1; +#define bb_msg_read_error "read error" +#define bb_msg_write_error "write error" +extern const char bb_msg_unknown[] ALIGN1; +extern const char bb_msg_can_not_create_raw_socket[] ALIGN1; +extern const char bb_msg_perm_denied_are_you_root[] ALIGN1; +extern const char bb_msg_you_must_be_root[] ALIGN1; +extern const char bb_msg_requires_arg[] ALIGN1; +extern const char bb_msg_invalid_arg[] ALIGN1; +extern const char bb_msg_standard_input[] ALIGN1; +extern const char bb_msg_standard_output[] ALIGN1; + /* NB: (bb_hexdigits_upcase[i] | 0x20) -> lowercase hex digit */ -extern const char bb_hexdigits_upcase[]; - -extern const char bb_path_mtab_file[]; -extern const char bb_path_passwd_file[]; -extern const char bb_path_shadow_file[]; -extern const char bb_path_gshadow_file[]; -extern const char bb_path_group_file[]; -extern const char bb_path_motd_file[]; -extern const char bb_path_wtmp_file[]; -extern const char bb_dev_null[]; -extern const char bb_busybox_exec_path[]; +extern const char bb_hexdigits_upcase[] ALIGN1; + +extern const char bb_path_wtmp_file[] ALIGN1; + +/* Busybox mount uses either /proc/mounts or /etc/mtab to + * get the list of currently mounted filesystems */ +#define bb_path_mtab_file IF_FEATURE_MTAB_SUPPORT("/etc/mtab")IF_NOT_FEATURE_MTAB_SUPPORT("/proc/mounts") + +#define bb_path_passwd_file _PATH_PASSWD +#define bb_path_group_file _PATH_GROUP +#define bb_path_shadow_file _PATH_SHADOW +#define bb_path_gshadow_file _PATH_GSHADOW + +#define bb_path_motd_file "/etc/motd" + +#define bb_dev_null "/dev/null" +extern const char bb_busybox_exec_path[] ALIGN1; /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, * but I want to save a few bytes here */ -extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ +extern const char bb_PATH_root_path[] ALIGN1; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ #define bb_default_root_path (bb_PATH_root_path + sizeof("PATH")) #define bb_default_path (bb_PATH_root_path + sizeof("PATH=/sbin:/usr/sbin")) @@ -1601,69 +1775,71 @@ extern struct globals *const ptr_to_globals; (*(struct globals**)&ptr_to_globals) = (void*)(x); \ barrier(); \ } while (0) +#define FREE_PTR_TO_GLOBALS() do { \ + if (ENABLE_FEATURE_CLEAN_UP) { \ + free(ptr_to_globals); \ + } \ +} while (0) /* You can change LIBBB_DEFAULT_LOGIN_SHELL, but don't use it, * use bb_default_login_shell and following defines. * If you change LIBBB_DEFAULT_LOGIN_SHELL, * don't forget to change increment constant. */ #define LIBBB_DEFAULT_LOGIN_SHELL "-/bin/sh" -extern const char bb_default_login_shell[]; +extern const char bb_default_login_shell[] ALIGN1; /* "/bin/sh" */ #define DEFAULT_SHELL (bb_default_login_shell+1) /* "sh" */ #define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) -#if ENABLE_FEATURE_DEVFS +/* The following devices are the same on all systems. */ +#define CURRENT_TTY "/dev/tty" +#define DEV_CONSOLE "/dev/console" + +#if defined(__FreeBSD_kernel__) +# define CURRENT_VC CURRENT_TTY +# define VC_1 "/dev/ttyv0" +# define VC_2 "/dev/ttyv1" +# define VC_3 "/dev/ttyv2" +# define VC_4 "/dev/ttyv3" +# define VC_5 "/dev/ttyv4" +# define VC_FORMAT "/dev/ttyv%d" +#elif defined(__GNU__) +# define CURRENT_VC CURRENT_TTY +# define VC_1 "/dev/tty1" +# define VC_2 "/dev/tty2" +# define VC_3 "/dev/tty3" +# define VC_4 "/dev/tty4" +# define VC_5 "/dev/tty5" +# define VC_FORMAT "/dev/tty%d" +#elif ENABLE_FEATURE_DEVFS +/*Linux, obsolete devfs names */ # define CURRENT_VC "/dev/vc/0" # define VC_1 "/dev/vc/1" # define VC_2 "/dev/vc/2" # define VC_3 "/dev/vc/3" # define VC_4 "/dev/vc/4" # define VC_5 "/dev/vc/5" -# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) -/* Yes, this sucks, but both SH (including sh64) and H8 have a SCI(F) for their - respective serial ports .. as such, we can't use the common device paths for - these. -- PFM */ -# define SC_0 "/dev/ttsc/0" -# define SC_1 "/dev/ttsc/1" -# define SC_FORMAT "/dev/ttsc/%d" -# else -# define SC_0 "/dev/tts/0" -# define SC_1 "/dev/tts/1" -# define SC_FORMAT "/dev/tts/%d" -# endif # define VC_FORMAT "/dev/vc/%d" -# define LOOP_FORMAT "/dev/loop/%d" +# define LOOP_FORMAT "/dev/loop/%u" # define LOOP_NAMESIZE (sizeof("/dev/loop/") + sizeof(int)*3 + 1) # define LOOP_NAME "/dev/loop/" # define FB_0 "/dev/fb/0" #else +/*Linux, normal names */ # define CURRENT_VC "/dev/tty0" # define VC_1 "/dev/tty1" # define VC_2 "/dev/tty2" # define VC_3 "/dev/tty3" # define VC_4 "/dev/tty4" # define VC_5 "/dev/tty5" -# if defined(__sh__) || defined(__H8300H__) || defined(__H8300S__) -# define SC_0 "/dev/ttySC0" -# define SC_1 "/dev/ttySC1" -# define SC_FORMAT "/dev/ttySC%d" -# else -# define SC_0 "/dev/ttyS0" -# define SC_1 "/dev/ttyS1" -# define SC_FORMAT "/dev/ttyS%d" -# endif # define VC_FORMAT "/dev/tty%d" -# define LOOP_FORMAT "/dev/loop%d" +# define LOOP_FORMAT "/dev/loop%u" # define LOOP_NAMESIZE (sizeof("/dev/loop") + sizeof(int)*3 + 1) # define LOOP_NAME "/dev/loop" # define FB_0 "/dev/fb0" #endif -/* The following devices are the same on devfs and non-devfs systems. */ -#define CURRENT_TTY "/dev/tty" -#define DEV_CONSOLE "/dev/console" - #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) diff --git a/archival/liblzo_interface.h b/include/liblzo_interface.h similarity index 97% rename from archival/liblzo_interface.h rename to include/liblzo_interface.h index 9a84c0b..b7f1b63 100644 --- a/archival/liblzo_interface.h +++ b/include/liblzo_interface.h @@ -30,7 +30,7 @@ /* static void die_at(int line) { - bb_error_msg_and_die("internal error at %d", line); + bb_error_msg_and_die("internal error at %d", line); } #define assert(v) if (!(v)) die_at(__LINE__) */ diff --git a/include/platform.h b/include/platform.h index 0dadf42..cfc8029 100644 --- a/include/platform.h +++ b/include/platform.h @@ -1,24 +1,12 @@ /* vi: set sw=4 ts=4: */ /* - Copyright 2006, Bernhard Reutner-Fischer - - Licensed under the GPL v2 or later, see the file LICENSE in this tarball. -*/ -#ifndef BB_PLATFORM_H + * Copyright 2006, Bernhard Reutner-Fischer + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +#ifndef BB_PLATFORM_H #define BB_PLATFORM_H 1 -/* Assume all these functions exist by default. Platforms where it is not - * true will #undef them below. - */ -#define HAVE_FDPRINTF 1 -#define HAVE_MEMRCHR 1 -#define HAVE_MKDTEMP 1 -#define HAVE_SETBIT 1 -#define HAVE_STRCASESTR 1 -#define HAVE_STRCHRNUL 1 -#define HAVE_STRSEP 1 -#define HAVE_STRSIGNAL 1 -#define HAVE_VASPRINTF 1 /* Convenience macros to test the version of gcc. */ #undef __GNUC_PREREQ @@ -36,10 +24,6 @@ # endif #endif -/* Define macros for some gcc attributes. This permits us to use the - macros freely, and know that they will come into play for the - version of gcc in which they are supported. */ - #if !__GNUC_PREREQ(2,7) # ifndef __attribute__ # define __attribute__(x) @@ -93,7 +77,7 @@ #endif /* -fwhole-program makes all symbols local. The attribute externally_visible - forces a symbol global. */ + * forces a symbol global. */ #if __GNUC_PREREQ(4,1) # define EXTERNALLY_VISIBLE __attribute__(( visibility("default") )) //__attribute__ ((__externally_visible__)) @@ -109,22 +93,14 @@ #endif /* We use __extension__ in some places to suppress -pedantic warnings - about GCC extensions. This feature didn't work properly before - gcc 2.8. */ + * about GCC extensions. This feature didn't work properly before + * gcc 2.8. */ #if !__GNUC_PREREQ(2,8) # ifndef __extension__ # define __extension__ # endif #endif -/* gcc-2.95 had no va_copy but only __va_copy. */ -#if !__GNUC_PREREQ(3,0) -# include -# if !defined va_copy && defined __va_copy -# define va_copy(d,s) __va_copy((d),(s)) -# endif -#endif - /* FAST_FUNC is a qualifier which (possibly) makes function call faster * and/or smaller by using modified ABI. It is usually only needed * on non-static, busybox internal functions. Recent versions of gcc @@ -140,7 +116,7 @@ /* Make all declarations hidden (-fvisibility flag only affects definitions) */ /* (don't include system headers after this until corresponding pop!) */ -#if __GNUC_PREREQ(4,1) +#if __GNUC_PREREQ(4,1) && !defined(__CYGWIN__) # define PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN _Pragma("GCC visibility push(hidden)") # define POP_SAVED_FUNCTION_VISIBILITY _Pragma("GCC visibility pop") #else @@ -148,37 +124,61 @@ # define POP_SAVED_FUNCTION_VISIBILITY #endif +/* gcc-2.95 had no va_copy but only __va_copy. */ +#if !__GNUC_PREREQ(3,0) +# include +# if !defined va_copy && defined __va_copy +# define va_copy(d,s) __va_copy((d),(s)) +# endif +#endif + + /* ---- Endian Detection ------------------------------------ */ +#include #if defined(__digital__) && defined(__unix__) # include -# define __BIG_ENDIAN__ (BYTE_ORDER == BIG_ENDIAN) -# define __BYTE_ORDER BYTE_ORDER -#elif defined __FreeBSD__ -# include /* rlimit */ +#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) +# include /* rlimit */ # include # define bswap_64 __bswap64 # define bswap_32 __bswap32 # define bswap_16 __bswap16 -# define __BIG_ENDIAN__ (_BYTE_ORDER == _BIG_ENDIAN) -#elif !defined __APPLE__ +#else # include # include #endif -#if defined(__BIG_ENDIAN__) && __BIG_ENDIAN__ +#if defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN # define BB_BIG_ENDIAN 1 # define BB_LITTLE_ENDIAN 0 -#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN +#elif defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN +# define BB_BIG_ENDIAN 0 +# define BB_LITTLE_ENDIAN 1 +#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _BIG_ENDIAN # define BB_BIG_ENDIAN 1 # define BB_LITTLE_ENDIAN 0 -#elif (defined(__BYTE_ORDER) && __BYTE_ORDER == __LITTLE_ENDIAN) || defined(__386__) +#elif defined(_BYTE_ORDER) && _BYTE_ORDER == _LITTLE_ENDIAN +# define BB_BIG_ENDIAN 0 +# define BB_LITTLE_ENDIAN 1 +#elif defined(BYTE_ORDER) && BYTE_ORDER == BIG_ENDIAN +# define BB_BIG_ENDIAN 1 +# define BB_LITTLE_ENDIAN 0 +#elif defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN +# define BB_BIG_ENDIAN 0 +# define BB_LITTLE_ENDIAN 1 +#elif defined(__386__) # define BB_BIG_ENDIAN 0 # define BB_LITTLE_ENDIAN 1 #else # error "Can't determine endianness" #endif +#if ULONG_MAX > 0xffffffff +# define bb_bswap_64(x) bswap_64(x) +#endif + /* SWAP_LEnn means "convert CPU<->little_endian by swapping bytes" */ #if BB_BIG_ENDIAN # define SWAP_BE16(x) (x) @@ -186,27 +186,36 @@ # define SWAP_BE64(x) (x) # define SWAP_LE16(x) bswap_16(x) # define SWAP_LE32(x) bswap_32(x) -# define SWAP_LE64(x) bswap_64(x) +# define SWAP_LE64(x) bb_bswap_64(x) +# define IF_BIG_ENDIAN(...) __VA_ARGS__ +# define IF_LITTLE_ENDIAN(...) #else # define SWAP_BE16(x) bswap_16(x) # define SWAP_BE32(x) bswap_32(x) -# define SWAP_BE64(x) bswap_64(x) +# define SWAP_BE64(x) bb_bswap_64(x) # define SWAP_LE16(x) (x) # define SWAP_LE32(x) (x) # define SWAP_LE64(x) (x) +# define IF_BIG_ENDIAN(...) +# define IF_LITTLE_ENDIAN(...) __VA_ARGS__ #endif + /* ---- Unaligned access ------------------------------------ */ +#include +typedef int bb__aliased_int FIX_ALIASING; +typedef long bb__aliased_long FIX_ALIASING; +typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; +typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; +typedef uint64_t bb__aliased_uint64_t FIX_ALIASING; + /* NB: unaligned parameter should be a pointer, aligned one - * a lvalue. This makes it more likely to not swap them by mistake */ #if defined(i386) || defined(__x86_64__) || defined(__powerpc__) -# include -typedef int bb__aliased_int FIX_ALIASING; -typedef uint16_t bb__aliased_uint16_t FIX_ALIASING; -typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; -# define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp)) +# define move_from_unaligned_int(v, intp) ((v) = *(bb__aliased_int*)(intp)) +# define move_from_unaligned_long(v, longp) ((v) = *(bb__aliased_long*)(longp)) # define move_from_unaligned16(v, u16p) ((v) = *(bb__aliased_uint16_t*)(u16p)) # define move_from_unaligned32(v, u32p) ((v) = *(bb__aliased_uint32_t*)(u32p)) # define move_to_unaligned16(u16p, v) (*(bb__aliased_uint16_t*)(u16p) = (v)) @@ -215,11 +224,12 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; #else /* performs reasonably well (gcc usually inlines memcpy here) */ # define move_from_unaligned_int(v, intp) (memcpy(&(v), (intp), sizeof(int))) +# define move_from_unaligned_long(v, longp) (memcpy(&(v), (longp), sizeof(long))) # define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2)) # define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4)) # define move_to_unaligned16(u16p, v) do { \ uint16_t __t = (v); \ - memcpy((u16p), &__t, 4); \ + memcpy((u16p), &__t, 2); \ } while (0) # define move_to_unaligned32(u32p, v) do { \ uint32_t __t = (v); \ @@ -227,38 +237,9 @@ typedef uint32_t bb__aliased_uint32_t FIX_ALIASING; } while (0) #endif -/* ---- Compiler dependent settings ------------------------- */ -#if (defined __digital__ && defined __unix__) \ - || defined __APPLE__ || defined __FreeBSD__ -# undef HAVE_MNTENT_H -# undef HAVE_SYS_STATFS_H -#else -# define HAVE_MNTENT_H 1 -# define HAVE_SYS_STATFS_H 1 -#endif - -/*----- Kernel versioning ------------------------------------*/ - -#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) - -/* ---- Miscellaneous --------------------------------------- */ - -#if defined(__GNU_LIBRARY__) && __GNU_LIBRARY__ < 5 && \ - !defined(__dietlibc__) && \ - !defined(_NEWLIB_VERSION) && \ - !(defined __digital__ && defined __unix__) -# error "Sorry, this libc version is not supported :(" -#endif - -/* Don't perpetuate e2fsck crap into the headers. Clean up e2fsck instead. */ +/* ---- Size-saving "small" ints (arch-dependent) ----------- */ -#if defined __GLIBC__ || defined __UCLIBC__ \ - || defined __dietlibc__ || defined _NEWLIB_VERSION -# include -#endif - -/* Size-saving "small" ints (arch-dependent) */ #if defined(i386) || defined(__x86_64__) || defined(__mips__) || defined(__cris__) /* add other arches which benefit from this... */ typedef signed char smallint; @@ -278,8 +259,43 @@ typedef unsigned smalluint; # include #endif -/* Try to defeat gcc's alignment of "char message[]"-like data */ -#if 1 /* if needed: !defined(arch1) && !defined(arch2) */ + +/*----- Kernel versioning ------------------------------------*/ + +#define KERNEL_VERSION(a,b,c) (((a) << 16) + ((b) << 8) + (c)) + +#ifdef __UCLIBC__ +# define UCLIBC_VERSION KERNEL_VERSION(__UCLIBC_MAJOR__, __UCLIBC_MINOR__, __UCLIBC_SUBLEVEL__) +#else +# define UCLIBC_VERSION 0 +#endif + + +/* ---- Miscellaneous --------------------------------------- */ + +#if defined __GLIBC__ \ + || defined __UCLIBC__ \ + || defined __dietlibc__ \ + || defined __BIONIC__ \ + || defined _NEWLIB_VERSION +# include +#endif + +/* Define bb_setpgrp */ +#if defined(__digital__) && defined(__unix__) +/* use legacy setpgrp(pid_t, pid_t) for now. move to platform.c */ +# define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me, __me); } while (0) +#else +# define bb_setpgrp() setpgrp() +#endif + +/* fdprintf is more readable, we used it before dprintf was standardized */ +#include +#define fdprintf dprintf + +/* Useful for defeating gcc's alignment of "char message[]"-like data */ +#if !defined(__s390__) + /* on s390[x], non-word-aligned data accesses require larger code */ # define ALIGN1 __attribute__((aligned(1))) # define ALIGN2 __attribute__((aligned(2))) # define ALIGN4 __attribute__((aligned(4))) @@ -290,15 +306,15 @@ typedef unsigned smalluint; # define ALIGN4 #endif - -/* uclibc does not implement daemon() for no-mmu systems. +/* * For 0.9.29 and svn, __ARCH_USE_MMU__ indicates no-mmu reliably. * For earlier versions there is no reliable way to check if we are building * for a mmu-less system. */ #if ENABLE_NOMMU || \ - (defined __UCLIBC__ && __UCLIBC_MAJOR__ >= 0 && __UCLIBC_MINOR__ >= 9 && \ - __UCLIBC_SUBLEVEL__ > 28 && !defined __ARCH_USE_MMU__) + (defined __UCLIBC__ && \ + UCLIBC_VERSION > KERNEL_VERSION(0, 9, 28) && \ + !defined __ARCH_USE_MMU__) # define BB_MMU 0 # define USE_FOR_NOMMU(...) __VA_ARGS__ # define USE_FOR_MMU(...) @@ -308,18 +324,10 @@ typedef unsigned smalluint; # define USE_FOR_MMU(...) __VA_ARGS__ #endif -/* Don't use lchown with glibc older than 2.1.x */ -#if defined(__GLIBC__) && __GLIBC__ <= 2 && __GLIBC_MINOR__ < 1 -# define lchown chown -#endif - #if defined(__digital__) && defined(__unix__) - # include # include # define PRIu32 "u" -/* use legacy setpgrp(pid_t,pid_t) for now. move to platform.c */ -# define bb_setpgrp() do { pid_t __me = getpid(); setpgrp(__me, __me); } while (0) # if !defined ADJ_OFFSET_SINGLESHOT && defined MOD_CLKA && defined MOD_OFFSET # define ADJ_OFFSET_SINGLESHOT (MOD_CLKA | MOD_OFFSET) # endif @@ -332,15 +340,49 @@ typedef unsigned smalluint; # if !defined ADJ_TICK && defined MOD_CLKB # define ADJ_TICK MOD_CLKB # endif +#endif -#else - -# define bb_setpgrp() setpgrp() +#if defined(__CYGWIN__) +# define MAXSYMLINKS SYMLOOP_MAX +#endif +#if defined(ANDROID) || defined(__ANDROID__) +# define BB_ADDITIONAL_PATH ":/system/sbin:/system/bin:/system/xbin" +# define SYS_ioprio_set __NR_ioprio_set +# define SYS_ioprio_get __NR_ioprio_get #endif -#if defined(__GLIBC__) -# define fdprintf dprintf + +/* ---- Who misses what? ------------------------------------ */ + +/* Assume all these functions and header files exist by default. + * Platforms where it is not true will #undef them below. + */ +#define HAVE_CLEARENV 1 +#define HAVE_FDATASYNC 1 +#define HAVE_DPRINTF 1 +#define HAVE_MEMRCHR 1 +#define HAVE_MKDTEMP 1 +#define HAVE_PTSNAME_R 1 +#define HAVE_SETBIT 1 +#define HAVE_SIGHANDLER_T 1 +#define HAVE_STPCPY 1 +#define HAVE_STRCASESTR 1 +#define HAVE_STRCHRNUL 1 +#define HAVE_STRSEP 1 +#define HAVE_STRSIGNAL 1 +#define HAVE_STRVERSCMP 1 +#define HAVE_VASPRINTF 1 +#define HAVE_UNLOCKED_STDIO 1 +#define HAVE_UNLOCKED_LINE_OPS 1 +#define HAVE_GETLINE 1 +#define HAVE_XTABS 1 +#define HAVE_MNTENT_H 1 +#define HAVE_NET_ETHERNET_H 1 +#define HAVE_SYS_STATFS_H 1 + +#if defined(__UCLIBC__) && UCLIBC_VERSION < KERNEL_VERSION(0, 9, 32) +# undef HAVE_STRVERSCMP #endif #if defined(__dietlibc__) @@ -348,19 +390,70 @@ typedef unsigned smalluint; #endif #if defined(__WATCOMC__) -# undef HAVE_FDPRINTF +# undef HAVE_DPRINTF +# undef HAVE_GETLINE # undef HAVE_MEMRCHR # undef HAVE_MKDTEMP # undef HAVE_SETBIT +# undef HAVE_STPCPY # undef HAVE_STRCASESTR # undef HAVE_STRCHRNUL # undef HAVE_STRSEP # undef HAVE_STRSIGNAL +# undef HAVE_STRVERSCMP # undef HAVE_VASPRINTF +# undef HAVE_UNLOCKED_STDIO +# undef HAVE_UNLOCKED_LINE_OPS +# undef HAVE_NET_ETHERNET_H +#endif + +#if defined(__CYGWIN__) +# undef HAVE_CLEARENV +# undef HAVE_FDPRINTF +# undef HAVE_MEMRCHR +# undef HAVE_PTSNAME_R +# undef HAVE_STRVERSCMP +# undef HAVE_UNLOCKED_LINE_OPS #endif -#if defined(__FreeBSD__) +/* These BSD-derived OSes share many similarities */ +#if (defined __digital__ && defined __unix__) \ + || defined __APPLE__ \ + || defined __FreeBSD__ || defined __OpenBSD__ || defined __NetBSD__ +# undef HAVE_CLEARENV +# undef HAVE_FDATASYNC +# undef HAVE_GETLINE +# undef HAVE_MNTENT_H +# undef HAVE_PTSNAME_R +# undef HAVE_SYS_STATFS_H +# undef HAVE_SIGHANDLER_T +# undef HAVE_STRVERSCMP +# undef HAVE_XTABS +# undef HAVE_DPRINTF +# undef HAVE_UNLOCKED_STDIO +# undef HAVE_UNLOCKED_LINE_OPS +#endif + +#if defined(__FreeBSD__) || defined(__APPLE__) +# undef HAVE_STRCHRNUL +#endif + +#if defined(__NetBSD__) +# define HAVE_GETLINE 1 /* Recent NetBSD versions have getline() */ +#endif + +#if defined(__digital__) && defined(__unix__) +# undef HAVE_STPCPY +#endif + +#if defined(ANDROID) || defined(__ANDROID__) +# undef HAVE_DPRINTF +# undef HAVE_GETLINE +# undef HAVE_STPCPY # undef HAVE_STRCHRNUL +# undef HAVE_STRVERSCMP +# undef HAVE_UNLOCKED_LINE_OPS +# undef HAVE_NET_ETHERNET_H #endif /* @@ -368,8 +461,8 @@ typedef unsigned smalluint; * These must come after all the HAVE_* macros are defined (or not) */ -#ifndef HAVE_FDPRINTF -extern int fdprintf(int fd, const char *format, ...); +#ifndef HAVE_DPRINTF +extern int dprintf(int fd, const char *format, ...); #endif #ifndef HAVE_MEMRCHR @@ -385,6 +478,14 @@ extern char *mkdtemp(char *template) FAST_FUNC; # define clrbit(a, b) ((a)[(b) >> 3] &= ~(1 << ((b) & 7))) #endif +#ifndef HAVE_SIGHANDLER_T +typedef void (*sighandler_t)(int); +#endif + +#ifndef HAVE_STPCPY +extern char *stpcpy(char *p, const char *to_add) FAST_FUNC; +#endif + #ifndef HAVE_STRCASESTR extern char *strcasestr(const char *s, const char *pattern) FAST_FUNC; #endif @@ -406,4 +507,10 @@ extern char *strsep(char **stringp, const char *delim) FAST_FUNC; extern int vasprintf(char **string_ptr, const char *format, va_list p) FAST_FUNC; #endif +#ifndef HAVE_GETLINE +# include /* for FILE */ +# include /* size_t */ +extern ssize_t getline(char **lineptr, size_t *n, FILE *stream) FAST_FUNC; +#endif + #endif diff --git a/include/pwd_.h b/include/pwd_.h index aa63ac9..625b6f5 100644 --- a/include/pwd_.h +++ b/include/pwd_.h @@ -18,7 +18,7 @@ 02111-1307 USA. */ /* - * POSIX Standard: 9.2.2 User Database Access + * POSIX Standard: 9.2.2 User Database Access */ #ifndef BB_PWD_H @@ -30,7 +30,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN * We will use libc-defined structures, but will #define function names * so that function calls are directed to bb_internal_XXX replacements */ - +#undef endpwent #define setpwent bb_internal_setpwent #define endpwent bb_internal_endpwent #define getpwent bb_internal_getpwent @@ -63,7 +63,7 @@ extern struct passwd *fgetpwent(FILE *__stream); /* Write the given entry onto the given stream. */ extern int putpwent(const struct passwd *__restrict __p, - FILE *__restrict __f); + FILE *__restrict __f); #endif /* Search for an entry with a matching user ID. */ @@ -81,25 +81,25 @@ extern struct passwd *getpwnam(const char *__name); POSIX people would choose. */ extern int getpwent_r(struct passwd *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct passwd **__restrict __result); + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result); extern int getpwuid_r(uid_t __uid, - struct passwd *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct passwd **__restrict __result); + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result); extern int getpwnam_r(const char *__restrict __name, - struct passwd *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct passwd **__restrict __result); + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result); /* Read an entry from STREAM. This function is not standardized and probably never will. */ extern int fgetpwent_r(FILE *__restrict __stream, - struct passwd *__restrict __resultbuf, - char *__restrict __buffer, size_t __buflen, - struct passwd **__restrict __result); + struct passwd *__restrict __resultbuf, + char *__restrict __buffer, size_t __buflen, + struct passwd **__restrict __result); POP_SAVED_FUNCTION_VISIBILITY diff --git a/include/rtc_.h b/include/rtc_.h index b5fe8ec..750fc20 100644 --- a/include/rtc_.h +++ b/include/rtc_.h @@ -1,7 +1,7 @@ /* * Common defines/structures/etc... for applets that need to work with the RTC. * - * Licensed under the GPL-2 or later. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef BB_RTC_H @@ -35,9 +35,9 @@ struct linux_rtc_time { }; struct linux_rtc_wkalrm { - unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ + unsigned char enabled; /* 0 = alarm disabled, 1 = alarm enabled */ unsigned char pending; /* 0 = alarm not pending, 1 = alarm pending */ - struct linux_rtc_time time; /* time the alarm is set to */ + struct linux_rtc_time time; /* time the alarm is set to */ }; /* diff --git a/include/shadow_.h b/include/shadow_.h index de126dd..7babe4f 100644 --- a/include/shadow_.h +++ b/include/shadow_.h @@ -37,11 +37,6 @@ struct spwd { unsigned long sp_flag; /* Reserved */ }; -/* Paths to the user database files */ -#ifndef _PATH_SHADOW -#define _PATH_SHADOW "/etc/shadow" -#endif - #define setspent bb_internal_setspent #define endspent bb_internal_endspent #define getspent bb_internal_getspent @@ -84,21 +79,21 @@ extern int putspent(const struct spwd *__p, FILE *__stream); /* Reentrant versions of some of the functions above */ extern int getspent_r(struct spwd *__result_buf, char *__buffer, - size_t __buflen, struct spwd **__result); + size_t __buflen, struct spwd **__result); #endif extern int getspnam_r(const char *__name, struct spwd *__result_buf, - char *__buffer, size_t __buflen, - struct spwd **__result); + char *__buffer, size_t __buflen, + struct spwd **__result); #ifdef UNUSED_FOR_NOW extern int sgetspent_r(const char *__string, struct spwd *__result_buf, - char *__buffer, size_t __buflen, - struct spwd **__result); + char *__buffer, size_t __buflen, + struct spwd **__result); extern int fgetspent_r(FILE *__stream, struct spwd *__result_buf, - char *__buffer, size_t __buflen, - struct spwd **__result); + char *__buffer, size_t __buflen, + struct spwd **__result); /* Protect password file against multi writers */ extern int lckpwdf(void); diff --git a/include/unarchive.h b/include/unarchive.h deleted file mode 100644 index b55af6d..0000000 --- a/include/unarchive.h +++ /dev/null @@ -1,236 +0,0 @@ -/* vi: set sw=4 ts=4: */ -#ifndef UNARCHIVE_H -#define UNARCHIVE_H 1 - -PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN - -enum { -#if BB_BIG_ENDIAN - COMPRESS_MAGIC = 0x1f9d, - GZIP_MAGIC = 0x1f8b, - BZIP2_MAGIC = 'B' * 256 + 'Z', - /* .xz signature: 0xfd, '7', 'z', 'X', 'Z', 0x00 */ - /* More info at: http://tukaani.org/xz/xz-file-format.txt */ - XZ_MAGIC1 = 0xfd * 256 + '7', - XZ_MAGIC2 = (('z' * 256 + 'X') * 256 + 'Z') * 256 + 0, - /* Different form: 32 bits, then 16 bits: */ - XZ_MAGIC1a = ((0xfd * 256 + '7') * 256 + 'z') * 256 + 'X', - XZ_MAGIC2a = 'Z' * 256 + 0, -#else - COMPRESS_MAGIC = 0x9d1f, - GZIP_MAGIC = 0x8b1f, - BZIP2_MAGIC = 'Z' * 256 + 'B', - XZ_MAGIC1 = '7' * 256 + 0xfd, - XZ_MAGIC2 = ((0 * 256 + 'Z') * 256 + 'X') * 256 + 'z', - XZ_MAGIC1a = (('X' * 256 + 'z') * 256 + '7') * 256 + 0xfd, - XZ_MAGIC2a = 0 * 256 + 'Z', -#endif -}; - -typedef struct file_header_t { - char *name; - char *link_target; -#if ENABLE_FEATURE_TAR_UNAME_GNAME - char *tar__uname; - char *tar__gname; -#endif - off_t size; - uid_t uid; - gid_t gid; - mode_t mode; - time_t mtime; - dev_t device; -} file_header_t; - -struct hardlinks_t; - -typedef struct archive_handle_t { - /* Flags. 1st since it is most used member */ - unsigned ah_flags; - - /* The raw stream as read from disk or stdin */ - int src_fd; - - /* Define if the header and data component should be processed */ - char FAST_FUNC (*filter)(struct archive_handle_t *); - /* List of files that have been accepted */ - llist_t *accept; - /* List of files that have been rejected */ - llist_t *reject; - /* List of files that have successfully been worked on */ - llist_t *passed; - - /* Currently processed file's header */ - file_header_t *file_header; - - /* Process the header component, e.g. tar -t */ - void FAST_FUNC (*action_header)(const file_header_t *); - - /* Process the data component, e.g. extract to filesystem */ - void FAST_FUNC (*action_data)(struct archive_handle_t *); - - /* Function that skips data */ - void FAST_FUNC (*seek)(int fd, off_t amount); - - /* Count processed bytes */ - off_t offset; - - /* Archiver specific. Can make it a union if it ever gets big */ -#if ENABLE_TAR || ENABLE_DPKG || ENABLE_DPKG_DEB - smallint tar__end; -# if ENABLE_FEATURE_TAR_GNU_EXTENSIONS - char* tar__longname; - char* tar__linkname; -# endif -#if ENABLE_FEATURE_TAR_TO_COMMAND - char* tar__to_command; -#endif -# if ENABLE_FEATURE_TAR_SELINUX - char* tar__global_sctx; - char* tar__next_file_sctx; -# endif -#endif -#if ENABLE_CPIO || ENABLE_RPM2CPIO || ENABLE_RPM - uoff_t cpio__blocks; - struct hardlinks_t *cpio__hardlinks_to_create; - struct hardlinks_t *cpio__created_hardlinks; -#endif -#if ENABLE_DPKG || ENABLE_DPKG_DEB - /* Temporary storage */ - char *dpkg__buffer; - /* How to process any sub archive, e.g. get_header_tar_gz */ - char FAST_FUNC (*dpkg__action_data_subarchive)(struct archive_handle_t *); - /* Contains the handle to a sub archive */ - struct archive_handle_t *dpkg__sub_archive; -#endif -#if ENABLE_FEATURE_AR_CREATE - const char *ar__name; - struct archive_handle_t *ar__out; -#endif -} archive_handle_t; -/* bits in ah_flags */ -#define ARCHIVE_RESTORE_DATE (1 << 0) -#define ARCHIVE_CREATE_LEADING_DIRS (1 << 1) -#define ARCHIVE_UNLINK_OLD (1 << 2) -#define ARCHIVE_EXTRACT_QUIET (1 << 3) -#define ARCHIVE_EXTRACT_NEWER (1 << 4) -#define ARCHIVE_DONT_RESTORE_OWNER (1 << 5) -#define ARCHIVE_DONT_RESTORE_PERM (1 << 6) -#define ARCHIVE_NUMERIC_OWNER (1 << 7) -#define ARCHIVE_O_TRUNC (1 << 8) - - -/* POSIX tar Header Block, from POSIX 1003.1-1990 */ -#define TAR_BLOCK_SIZE 512 -#define NAME_SIZE 100 -#define NAME_SIZE_STR "100" -typedef struct tar_header_t { /* byte offset */ - char name[NAME_SIZE]; /* 0-99 */ - char mode[8]; /* 100-107 */ - char uid[8]; /* 108-115 */ - char gid[8]; /* 116-123 */ - char size[12]; /* 124-135 */ - char mtime[12]; /* 136-147 */ - char chksum[8]; /* 148-155 */ - char typeflag; /* 156-156 */ - char linkname[NAME_SIZE]; /* 157-256 */ - /* POSIX: "ustar" NUL "00" */ - /* GNU tar: "ustar " NUL */ - /* Normally it's defined as magic[6] followed by - * version[2], but we put them together to save code. - */ - char magic[8]; /* 257-264 */ - char uname[32]; /* 265-296 */ - char gname[32]; /* 297-328 */ - char devmajor[8]; /* 329-336 */ - char devminor[8]; /* 337-344 */ - char prefix[155]; /* 345-499 */ - char padding[12]; /* 500-512 (pad to exactly TAR_BLOCK_SIZE) */ -} tar_header_t; -struct BUG_tar_header { - char c[sizeof(tar_header_t) == TAR_BLOCK_SIZE ? 1 : -1]; -}; - - - -/* Info struct unpackers can fill out to inform users of thing like - * timestamps of unpacked files */ -typedef struct unpack_info_t { - time_t mtime; -} unpack_info_t; - -extern archive_handle_t *init_handle(void) FAST_FUNC; - -extern char filter_accept_all(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_list(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_list_reassign(archive_handle_t *archive_handle) FAST_FUNC; -extern char filter_accept_reject_list(archive_handle_t *archive_handle) FAST_FUNC; - -extern void unpack_ar_archive(archive_handle_t *ar_archive) FAST_FUNC; - -extern void data_skip(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_all(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_to_stdout(archive_handle_t *archive_handle) FAST_FUNC; -extern void data_extract_to_command(archive_handle_t *archive_handle) FAST_FUNC; - -extern void header_skip(const file_header_t *file_header) FAST_FUNC; -extern void header_list(const file_header_t *file_header) FAST_FUNC; -extern void header_verbose_list(const file_header_t *file_header) FAST_FUNC; - -extern char get_header_ar(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_cpio(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_gz(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_bz2(archive_handle_t *archive_handle) FAST_FUNC; -extern char get_header_tar_lzma(archive_handle_t *archive_handle) FAST_FUNC; - -extern void seek_by_jump(int fd, off_t amount) FAST_FUNC; -extern void seek_by_read(int fd, off_t amount) FAST_FUNC; - -extern void data_align(archive_handle_t *archive_handle, unsigned boundary) FAST_FUNC; -extern const llist_t *find_list_entry(const llist_t *list, const char *filename) FAST_FUNC; -extern const llist_t *find_list_entry2(const llist_t *list, const char *filename) FAST_FUNC; - -/* A bit of bunzip2 internals are exposed for compressed help support: */ -typedef struct bunzip_data bunzip_data; -int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, int len) FAST_FUNC; -int read_bunzip(bunzip_data *bd, char *outbuf, int len) FAST_FUNC; -void dealloc_bunzip(bunzip_data *bd) FAST_FUNC; - -typedef struct inflate_unzip_result { - off_t bytes_out; - uint32_t crc; -} inflate_unzip_result; - -IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC; -/* xz unpacker takes .xz stream from offset 6 */ -IF_DESKTOP(long long) int unpack_xz_stream(int src_fd, int dst_fd) FAST_FUNC; -/* lzma unpacker takes .lzma stream from offset 0 */ -IF_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC; -/* the rest wants 2 first bytes already skipped by the caller */ -IF_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC; -IF_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC; -IF_DESKTOP(long long) int unpack_Z_stream(int src_fd, int dst_fd) FAST_FUNC; -/* wrapper which checks first two bytes to be "BZ" */ -IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC; - -char* append_ext(char *filename, const char *expected_ext) FAST_FUNC; -int bbunpack(char **argv, - IF_DESKTOP(long long) int FAST_FUNC (*unpacker)(unpack_info_t *info), - char* FAST_FUNC (*make_new_name)(char *filename, const char *expected_ext), - const char *expected_ext -) FAST_FUNC; - -#if BB_MMU -void open_transformer(int fd, - IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transformer) -#else -void open_transformer(int src_fd, const char *transform_prog) FAST_FUNC; -#define open_transformer(fd, transformer, transform_prog) open_transformer(fd, transform_prog) -#endif - -POP_SAVED_FUNCTION_VISIBILITY - -#endif diff --git a/include/unicode.h b/include/unicode.h index e9e2bd1..0317a21 100644 --- a/include/unicode.h +++ b/include/unicode.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #ifndef UNICODE_H #define UNICODE_H 1 @@ -27,6 +27,7 @@ enum { # define unicode_strwidth(string) strlen(string) # define unicode_status UNICODE_OFF # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) #else @@ -60,13 +61,14 @@ enum { //UNUSED: unsigned FAST_FUNC unicode_padding_to_width(unsigned width, const char *src); //UNUSED: char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char *src, unsigned width, int flags); char* FAST_FUNC unicode_conv_to_printable(uni_stat_t *stats, const char *src); -char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth); -char* FAST_FUNC unicode_conv_to_printable_fixedwidth(uni_stat_t *stats, const char *src, unsigned width); +//UNUSED: char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth); +char* FAST_FUNC unicode_conv_to_printable_fixedwidth(/*uni_stat_t *stats,*/ const char *src, unsigned width); # if ENABLE_UNICODE_USING_LOCALE extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # else @@ -75,9 +77,11 @@ void init_unicode(void) FAST_FUNC; # if !ENABLE_FEATURE_CHECK_UNICODE_IN_ENV # define unicode_status UNICODE_ON # define init_unicode() ((void)0) +# define reinit_unicode(LANG) ((void)0) # else extern uint8_t unicode_status; void init_unicode(void) FAST_FUNC; +void reinit_unicode(const char *LANG) FAST_FUNC; # endif # undef MB_CUR_MAX diff --git a/include/usage.src.h b/include/usage.src.h index df5b2f8..78beccf 100644 --- a/include/usage.src.h +++ b/include/usage.src.h @@ -12,4861 +12,11 @@ #ifndef BB_USAGE_H #define BB_USAGE_H 1 - #define NOUSAGE_STR "\b" INSERT -#define acpid_trivial_usage \ - "[-d] [-c CONFDIR] [-l LOGFILE] [-e PROC_EVENT_FILE] [EVDEV_EVENT_FILE]..." -#define acpid_full_usage "\n\n" \ - "Listen to ACPI events and spawn specific helpers on event arrival\n" \ - "\nOptions:" \ - "\n -d Don't daemonize, log to stderr" \ - "\n -c DIR Config directory [/etc/acpi]" \ - "\n -e FILE /proc event file [/proc/acpi/event]" \ - "\n -l FILE Log file [/var/log/acpid]" \ - IF_FEATURE_ACPID_COMPAT( \ - "\n\nAccept and ignore compatibility options -g -m -s -S -v" \ - ) - -#define acpid_example_usage \ - "# acpid -l /var/log/my-acpi-log\n" \ - "# acpid -d /dev/input/event*\n" - -#define addgroup_trivial_usage \ - "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP" -#define addgroup_full_usage "\n\n" \ - "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \ - "\nOptions:" \ - "\n -g GID Group id" \ - "\n -S Create a system group" \ - -#define adduser_trivial_usage \ - "[OPTIONS] USER" -#define adduser_full_usage "\n\n" \ - "Add a user\n" \ - "\nOptions:" \ - "\n -h DIR Home directory" \ - "\n -g GECOS GECOS field" \ - "\n -s SHELL Login shell" \ - "\n -G GRP Add user to existing group" \ - "\n -S Create a system user" \ - "\n -D Don't assign a password" \ - "\n -H Don't create home directory" \ - "\n -u UID User id" \ - -#define adjtimex_trivial_usage \ - "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]" -#define adjtimex_full_usage "\n\n" \ - "Read and optionally set system timebase parameters. See adjtimex(2)\n" \ - "\nOptions:" \ - "\n -q Quiet" \ - "\n -o OFF Time offset, microseconds" \ - "\n -f FREQ Frequency adjust, integer kernel units (65536 is 1ppm)" \ - "\n (positive values make clock run faster)" \ - "\n -t TICK Microseconds per tick, usually 10000" \ - "\n -p TCONST" \ - -#define ar_trivial_usage \ - "[-o] [-v] [-p] [-t] [-x] ARCHIVE FILES" -#define ar_full_usage "\n\n" \ - "Extract or list FILES from an ar archive\n" \ - "\nOptions:" \ - "\n -o Preserve original dates" \ - "\n -p Extract to stdout" \ - "\n -t List" \ - "\n -x Extract" \ - "\n -v Verbose" \ - -#define arp_trivial_usage \ - "\n[-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]" \ - "\n[-v] [-i IF] -d HOSTNAME [pub]" \ - "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]" \ - "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub" \ - "\n[-v] [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub" -#define arp_full_usage "\n\n" \ - "Manipulate ARP cache\n" \ - "\nOptions:" \ - "\n -a Display (all) hosts" \ - "\n -s Set new ARP entry" \ - "\n -d Delete a specified entry" \ - "\n -v Verbose" \ - "\n -n Don't resolve names" \ - "\n -i IF Network interface" \ - "\n -D Read from given device" \ - "\n -A, -p AF Protocol family" \ - "\n -H HWTYPE Hardware address type" \ - -#define arping_trivial_usage \ - "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP" -#define arping_full_usage "\n\n" \ - "Send ARP requests/replies\n" \ - "\nOptions:" \ - "\n -f Quit on first ARP reply" \ - "\n -q Quiet" \ - "\n -b Keep broadcasting, don't go unicast" \ - "\n -D Duplicated address detection mode" \ - "\n -U Unsolicited ARP mode, update your neighbors" \ - "\n -A ARP answer mode, update your neighbors" \ - "\n -c N Stop after sending N ARP requests" \ - "\n -w TIMEOUT Time to wait for ARP reply, seconds" \ - "\n -I IFACE Interface to use (default eth0)" \ - "\n -s SRC_IP Sender IP address" \ - "\n DST_IP Target IP address" \ - -#define sh_trivial_usage NOUSAGE_STR -#define sh_full_usage "" -#define ash_trivial_usage NOUSAGE_STR -#define ash_full_usage "" -#define hush_trivial_usage NOUSAGE_STR -#define hush_full_usage "" -#define lash_trivial_usage NOUSAGE_STR -#define lash_full_usage "" -#define msh_trivial_usage NOUSAGE_STR -#define msh_full_usage "" -#define bash_trivial_usage NOUSAGE_STR -#define bash_full_usage "" - -#define awk_trivial_usage \ - "[OPTIONS] [AWK_PROGRAM] [FILE]..." -#define awk_full_usage "\n\n" \ - "Options:" \ - "\n -v VAR=VAL Set variable" \ - "\n -F SEP Use SEP as field separator" \ - "\n -f FILE Read program from FILE" \ - -#define basename_trivial_usage \ - "FILE [SUFFIX]" -#define basename_full_usage "\n\n" \ - "Strip directory path and .SUFFIX from FILE\n" -#define basename_example_usage \ - "$ basename /usr/local/bin/foo\n" \ - "foo\n" \ - "$ basename /usr/local/bin/\n" \ - "bin\n" \ - "$ basename /foo/bar.txt .txt\n" \ - "bar" - -#define beep_trivial_usage \ - "-f FREQ -l LEN -d DELAY -r COUNT -n" -#define beep_full_usage "\n\n" \ - "Options:" \ - "\n -f Frequency in Hz" \ - "\n -l Length in ms" \ - "\n -d Delay in ms" \ - "\n -r Repetitions" \ - "\n -n Start new tone" \ - -#define blkid_trivial_usage \ - "" -#define blkid_full_usage "\n\n" \ - "Print UUIDs of all filesystems" - -#define brctl_trivial_usage \ - "COMMAND [BRIDGE [INTERFACE]]" -#define brctl_full_usage "\n\n" \ - "Manage ethernet bridges\n" \ - "\nCommands:" \ - IF_FEATURE_BRCTL_SHOW( \ - "\n show Show a list of bridges" \ - ) \ - "\n addbr BRIDGE Create BRIDGE" \ - "\n delbr BRIDGE Delete BRIDGE" \ - "\n addif BRIDGE IFACE Add IFACE to BRIDGE" \ - "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" \ - IF_FEATURE_BRCTL_FANCY( \ - "\n setageing BRIDGE TIME Set ageing time" \ - "\n setfd BRIDGE TIME Set bridge forward delay" \ - "\n sethello BRIDGE TIME Set hello time" \ - "\n setmaxage BRIDGE TIME Set max message age" \ - "\n setpathcost BRIDGE COST Set path cost" \ - "\n setportprio BRIDGE PRIO Set port priority" \ - "\n setbridgeprio BRIDGE PRIO Set bridge priority" \ - "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" \ - ) \ - -#define bzip2_trivial_usage \ - "[OPTIONS] [FILE]..." -#define bzip2_full_usage "\n\n" \ - "Compress FILEs (or stdin) with bzip2 algorithm\n" \ - "\nOptions:" \ - "\n -1..9 Compression level" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - #define busybox_notes_usage \ "Hello world!\n" -#define lzop_trivial_usage \ - "[-cfvd123456789CF] [FILE]..." -#define lzop_full_usage "\n\n" \ - "Options:" \ - "\n -1..9 Compression level" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - "\n -v Verbose" \ - "\n -F Don't store or verify checksum" \ - "\n -C Also write checksum of compressed block" \ - -#define lzopcat_trivial_usage \ - "[-vCF] [FILE]..." -#define lzopcat_full_usage "\n\n" \ - " -v Verbose" \ - "\n -F Don't store or verify checksum" \ - -#define unlzop_trivial_usage \ - "[-cfvCF] [FILE]..." -#define unlzop_full_usage "\n\n" \ - "Options:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - "\n -v Verbose" \ - "\n -F Don't store or verify checksum" \ - -#define unlzma_trivial_usage \ - "[OPTIONS] [FILE]..." -#define unlzma_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define lzma_trivial_usage \ - "-d [OPTIONS] [FILE]..." -#define lzma_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define lzcat_trivial_usage \ - "FILE" -#define lzcat_full_usage "\n\n" \ - "Decompress to stdout" - -#define unxz_trivial_usage \ - "[OPTIONS] [FILE]..." -#define unxz_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define xz_trivial_usage \ - "-d [OPTIONS] [FILE]..." -#define xz_full_usage "\n\n" \ - "Decompress FILE (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define xzcat_trivial_usage \ - "FILE" -#define xzcat_full_usage "\n\n" \ - "Decompress to stdout" - -#define cal_trivial_usage \ - "[-jy] [[MONTH] YEAR]" -#define cal_full_usage "\n\n" \ - "Display a calendar\n" \ - "\nOptions:" \ - "\n -j Use julian dates" \ - "\n -y Display the entire year" \ - -#define cat_trivial_usage \ - "[FILE]..." -#define cat_full_usage "\n\n" \ - "Concatenate FILEs and print them to stdout" \ - -#define cat_example_usage \ - "$ cat /proc/uptime\n" \ - "110716.72 17.67" - -#define catv_trivial_usage \ - "[-etv] [FILE]..." -#define catv_full_usage "\n\n" \ - "Display nonprinting characters as ^x or M-x\n" \ - "\nOptions:" \ - "\n -e End each line with $" \ - "\n -t Show tabs as ^I" \ - "\n -v Don't use ^x or M-x escapes" \ - -#define chat_trivial_usage \ - "EXPECT [SEND [EXPECT [SEND...]]]" -#define chat_full_usage "\n\n" \ - "Useful for interacting with a modem connected to stdin/stdout.\n" \ - "A script consists of one or more \"expect-send\" pairs of strings,\n" \ - "each pair is a pair of arguments. Example:\n" \ - "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" \ - -#define chattr_trivial_usage \ - "[-R] [-+=AacDdijsStTu] [-v VERSION] [FILE]..." -#define chattr_full_usage "\n\n" \ - "Change file attributes on an ext2 fs\n" \ - "\nModifiers:" \ - "\n - Remove attributes" \ - "\n + Add attributes" \ - "\n = Set attributes" \ - "\nAttributes:" \ - "\n A Don't track atime" \ - "\n a Append mode only" \ - "\n c Enable compress" \ - "\n D Write dir contents synchronously" \ - "\n d Don't backup with dump" \ - "\n i Cannot be modified (immutable)" \ - "\n j Write all data to journal first" \ - "\n s Zero disk storage when deleted" \ - "\n S Write file contents synchronously" \ - "\n t Disable tail-merging of partial blocks with other files" \ - "\n u Allow file to be undeleted" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\n -v Set the file's version/generation number" \ - -#define chcon_trivial_usage \ - "[OPTIONS] CONTEXT FILE..." \ - "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." \ - IF_FEATURE_CHCON_LONG_OPTIONS( \ - "\n chcon [OPTIONS] --reference=RFILE FILE..." \ - ) -#define chcon_full_usage "\n\n" \ - "Change the security context of each FILE to CONTEXT\n" \ - IF_FEATURE_CHCON_LONG_OPTIONS( \ - "\n -v,--verbose Verbose" \ - "\n -c,--changes Report changes made" \ - "\n -h,--no-dereference Affect symlinks instead of their targets" \ - "\n -f,--silent,--quiet Suppress most error messages" \ - "\n --reference=RFILE Use RFILE's group instead of using a CONTEXT value" \ - "\n -u,--user=USER Set user/role/type/range in the target" \ - "\n -r,--role=ROLE security context" \ - "\n -t,--type=TYPE" \ - "\n -l,--range=RANGE" \ - "\n -R,--recursive Recurse" \ - ) \ - IF_NOT_FEATURE_CHCON_LONG_OPTIONS( \ - "\n -v Verbose" \ - "\n -c Report changes made" \ - "\n -h Affect symlinks instead of their targets" \ - "\n -f Suppress most error messages" \ - "\n -u USER Set user/role/type/range in the target security context" \ - "\n -r ROLE" \ - "\n -t TYPE" \ - "\n -l RNG" \ - "\n -R Recurse" \ - ) - -#define chmod_trivial_usage \ - "[-R"IF_DESKTOP("cvf")"] MODE[,MODE]... FILE..." -#define chmod_full_usage "\n\n" \ - "Each MODE is one or more of the letters ugoa, one of the\n" \ - "symbols +-= and one or more of the letters rwxst\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - IF_DESKTOP( \ - "\n -c List changed files" \ - "\n -v List all files" \ - "\n -f Hide errors" \ - ) -#define chmod_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chmod u+x /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rwxrw-r-- 1 root root 0 Apr 12 18:25 /tmp/foo*\n" \ - "$ chmod 444 /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chgrp_trivial_usage \ - "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..." -#define chgrp_full_usage "\n\n" \ - "Change the group membership of each FILE to GROUP\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\n -h Affect symlinks instead of symlink targets" \ - "\n -L Traverse all symlinks to directories" \ - "\n -H Traverse symlinks on command line only" \ - "\n -P Don't traverse symlinks (default)" \ - IF_DESKTOP( \ - "\n -c List changed files" \ - "\n -v Verbose" \ - "\n -f Hide errors" \ - ) -#define chgrp_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chgrp root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen root 0 Apr 12 18:25 /tmp/foo\n" - -#define chown_trivial_usage \ - "[-RhLHP"IF_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..." -#define chown_full_usage "\n\n" \ - "Change the owner and/or group of each FILE to OWNER and/or GROUP\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\n -h Affect symlinks instead of symlink targets" \ - "\n -L Traverse all symlinks to directories" \ - "\n -H Traverse symlinks on command line only" \ - "\n -P Don't traverse symlinks (default)" \ - IF_DESKTOP( \ - "\n -c List changed files" \ - "\n -v List all files" \ - "\n -f Hide errors" \ - ) -#define chown_example_usage \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 andersen andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root andersen 0 Apr 12 18:25 /tmp/foo\n" \ - "$ chown root.root /tmp/foo\n" \ - "ls -l /tmp/foo\n" \ - "-r--r--r-- 1 root root 0 Apr 12 18:25 /tmp/foo\n" - -#define chpst_trivial_usage \ - "[-vP012] [-u USER[:GRP]] [-U USER[:GRP]] [-e DIR]\n" \ - " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" \ - " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" -#define chpst_full_usage "\n\n" \ - "Change the process state, run PROG\n" \ - "\nOptions:" \ - "\n -u USER[:GRP] Set uid and gid" \ - "\n -U USER[:GRP] Set $UID and $GID in environment" \ - "\n -e DIR Set environment variables as specified by files" \ - "\n in DIR: file=1st_line_of_file" \ - "\n -/ DIR Chroot to DIR" \ - "\n -n NICE Add NICE to nice value" \ - "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES" \ - "\n -d BYTES Limit data segment" \ - "\n -o N Limit number of open files per process" \ - "\n -p N Limit number of processes per uid" \ - "\n -f BYTES Limit output file sizes" \ - "\n -c BYTES Limit core file size" \ - "\n -v Verbose" \ - "\n -P Create new process group" \ - "\n -0 Close stdin" \ - "\n -1 Close stdout" \ - "\n -2 Close stderr" \ - -#define setuidgid_trivial_usage \ - "USER PROG ARGS" -#define setuidgid_full_usage "\n\n" \ - "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" \ - "run PROG" -#define envuidgid_trivial_usage \ - "USER PROG ARGS" -#define envuidgid_full_usage "\n\n" \ - "Set $UID to USER's uid and $GID to USER's gid, run PROG" -#define envdir_trivial_usage \ - "DIR PROG ARGS" -#define envdir_full_usage "\n\n" \ - "Set various environment variables as specified by files\n" \ - "in the directory DIR, run PROG" -#define softlimit_trivial_usage \ - "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" \ - " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" \ - " PROG ARGS" -#define softlimit_full_usage "\n\n" \ - "Set soft resource limits, then run PROG\n" \ - "\nOptions:" \ - "\n -a BYTES Limit total size of all segments" \ - "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES -a BYTES" \ - "\n -d BYTES Limit data segment" \ - "\n -s BYTES Limit stack segment" \ - "\n -l BYTES Limit locked memory size" \ - "\n -o N Limit number of open files per process" \ - "\n -p N Limit number of processes per uid" \ - "\nOptions controlling file sizes:" \ - "\n -f BYTES Limit output file sizes" \ - "\n -c BYTES Limit core file size" \ - "\nEfficiency opts:" \ - "\n -r BYTES Limit resident set size" \ - "\n -t N Limit CPU time, process receives" \ - "\n a SIGXCPU after N seconds" \ - -#define chroot_trivial_usage \ - "NEWROOT [PROG ARGS]" -#define chroot_full_usage "\n\n" \ - "Run PROG with root directory set to NEWROOT" -#define chroot_example_usage \ - "$ ls -l /bin/ls\n" \ - "lrwxrwxrwx 1 root root 12 Apr 13 00:46 /bin/ls -> /BusyBox\n" \ - "# mount /dev/hdc1 /mnt -t minix\n" \ - "# chroot /mnt\n" \ - "# ls -l /bin/ls\n" \ - "-rwxr-xr-x 1 root root 40816 Feb 5 07:45 /bin/ls*\n" - -#define chvt_trivial_usage \ - "N" -#define chvt_full_usage "\n\n" \ - "Change the foreground virtual terminal to /dev/ttyN" - -#define cksum_trivial_usage \ - "FILES..." -#define cksum_full_usage "\n\n" \ - "Calculate the CRC32 checksums of FILES" - -#define clear_trivial_usage \ - "" -#define clear_full_usage "\n\n" \ - "Clear screen" - -#define cmp_trivial_usage \ - "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]]") "]" -#define cmp_full_usage "\n\n" \ - "Compare FILE1 with FILE2 (or stdin)\n" \ - "\nOptions:" \ - "\n -l Write the byte numbers (decimal) and values (octal)" \ - "\n for all differing bytes" \ - "\n -s Quiet" \ - -#define comm_trivial_usage \ - "[-123] FILE1 FILE2" -#define comm_full_usage "\n\n" \ - "Compare FILE1 with FILE2\n" \ - "\nOptions:" \ - "\n -1 Suppress lines unique to FILE1" \ - "\n -2 Suppress lines unique to FILE2" \ - "\n -3 Suppress lines common to both files" \ - -#define bbconfig_trivial_usage \ - "" -#define bbconfig_full_usage "\n\n" \ - "Print the config file used by busybox build" - -#define chrt_trivial_usage \ - "[OPTIONS] [PRIO] [PID | PROG ARGS]" -#define chrt_full_usage "\n\n" \ - "Change scheduling priority and class for a process\n" \ - "\nOptions:" \ - "\n -p Operate on PID" \ - "\n -r Set SCHED_RR class" \ - "\n -f Set SCHED_FIFO class" \ - "\n -o Set SCHED_OTHER class" \ - "\n -m Show min/max priorities" \ - -#define chrt_example_usage \ - "$ chrt -r 4 sleep 900; x=$!\n" \ - "$ chrt -f -p 3 $x\n" \ - "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" - -#define nice_trivial_usage \ - "[-n ADJUST] [PROG ARGS]" -#define nice_full_usage "\n\n" \ - "Change scheduling priority, run PROG\n" \ - "\nOptions:" \ - "\n -n ADJUST Adjust priority by ADJUST" \ - -#define renice_trivial_usage \ - "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" -#define renice_full_usage "\n\n" \ - "Change scheduling priority for a running process\n" \ - "\nOptions:" \ - "\n -n Adjust current nice value (smaller is faster)" \ - "\n -p Process id(s) (default)" \ - "\n -g Process group id(s)" \ - "\n -u Process user name(s) and/or id(s)" \ - -#define ionice_trivial_usage \ - "[-c 1-3] [-n 0-7] [-p PID] [PROG]" -#define ionice_full_usage "\n\n" \ - "Change I/O priority and class\n" \ - "\nOptions:" \ - "\n -c Class. 1:realtime 2:best-effort 3:idle" \ - "\n -n Priority" \ - -#define cp_trivial_usage \ - "[OPTIONS] SOURCE DEST" -#define cp_full_usage "\n\n" \ - "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY\n" \ - "\nOptions:" \ - "\n -a Same as -dpR" \ - IF_SELINUX( \ - "\n -c Preserve security context" \ - ) \ - "\n -R,-r Recurse" \ - "\n -d,-P Preserve symlinks (default if -R)" \ - "\n -L Follow all symlinks" \ - "\n -H Follow symlinks on command line" \ - "\n -p Preserve file attributes if possible" \ - "\n -f Overwrite" \ - "\n -i Prompt before overwrite" \ - "\n -l,-s Create (sym)links" \ - -#define cpio_trivial_usage \ - "[-dmvu] [-F FILE]" IF_FEATURE_CPIO_O(" [-H newc]") \ - " [-ti"IF_FEATURE_CPIO_O("o")"]" IF_FEATURE_CPIO_P(" [-p DIR]") -#define cpio_full_usage "\n\n" \ - "Extract or list files from a cpio archive" \ - IF_FEATURE_CPIO_O(", or" \ - "\ncreate an archive" IF_FEATURE_CPIO_P(" (-o) or copy files (-p)") \ - " using file list on stdin" \ - ) \ - "\n" \ - "\nMain operation mode:" \ - "\n -t List" \ - "\n -i Extract" \ - IF_FEATURE_CPIO_O( \ - "\n -o Create (requires -H newc)" \ - ) \ - IF_FEATURE_CPIO_P( \ - "\n -p DIR Copy files to DIR" \ - ) \ - "\nOptions:" \ - "\n -d Make leading directories" \ - "\n -m Preserve mtime" \ - "\n -v Verbose" \ - "\n -u Overwrite" \ - "\n -F FILE Input (-t,-i,-p) or output (-o) file" \ - IF_FEATURE_CPIO_O( \ - "\n -H newc Archive format" \ - ) \ - -#define crond_trivial_usage \ - "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" -#define crond_full_usage "\n\n" \ - " -f Foreground" \ - "\n -b Background (default)" \ - "\n -S Log to syslog (default)" \ - "\n -l Set log level. 0 is the most verbose, default 8" \ - IF_FEATURE_CROND_D( \ - "\n -d Set log level, log to stderr" \ - ) \ - "\n -L Log to file" \ - "\n -c Working dir" \ - -#define crontab_trivial_usage \ - "[-c DIR] [-u USER] [-ler]|[FILE]" -#define crontab_full_usage "\n\n" \ - " -c Crontab directory" \ - "\n -u User" \ - "\n -l List crontab" \ - "\n -e Edit crontab" \ - "\n -r Delete crontab" \ - "\n FILE Replace crontab by FILE ('-': stdin)" \ - -#define cryptpw_trivial_usage \ - "[OPTIONS] [PASSWORD] [SALT]" -/* We do support -s, we just don't mention it */ -#define cryptpw_full_usage "\n\n" \ - "Crypt the PASSWORD using crypt(3)\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -P,--password-fd=N Read password from fd N" \ -/* "\n -s,--stdin Use stdin; like -P0" */ \ - "\n -m,--method=TYPE Encryption method TYPE" \ - "\n -S,--salt=SALT" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -P N Read password from fd N" \ -/* "\n -s Use stdin; like -P0" */ \ - "\n -m TYPE Encryption method TYPE" \ - "\n -S SALT" \ - ) \ - -/* mkpasswd is an alias to cryptpw */ - -#define mkpasswd_trivial_usage \ - "[OPTIONS] [PASSWORD] [SALT]" -/* We do support -s, we just don't mention it */ -#define mkpasswd_full_usage "\n\n" \ - "Crypt the PASSWORD using crypt(3)\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -P,--password-fd=N Read password from fd N" \ -/* "\n -s,--stdin Use stdin; like -P0" */ \ - "\n -m,--method=TYPE Encryption method TYPE" \ - "\n -S,--salt=SALT" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -P N Read password from fd N" \ -/* "\n -s Use stdin; like -P0" */ \ - "\n -m TYPE Encryption method TYPE" \ - "\n -S SALT" \ - ) \ - -#define cttyhack_trivial_usage \ - "PROG ARGS" -#define cttyhack_full_usage "\n\n" \ - "Give PROG a controlling tty if possible." \ - "\nExample for /etc/inittab (for busybox init):" \ - "\n ::respawn:/bin/cttyhack /bin/sh" \ - "\nGiving controlling tty to shell running with PID 1:" \ - "\n $ exec cttyhack sh" \ - "\nStarting interactive shell from boot shell script:" \ - "\n setsid cttyhack sh" \ - -#define cut_trivial_usage \ - "[OPTIONS] [FILE]..." -#define cut_full_usage "\n\n" \ - "Print selected fields from each input FILE to stdout\n" \ - "\nOptions:" \ - "\n -b LIST Output only bytes from LIST" \ - "\n -c LIST Output only characters from LIST" \ - "\n -d CHAR Use CHAR instead of tab as the field delimiter" \ - "\n -s Output only the lines containing delimiter" \ - "\n -f N Print only these fields" \ - "\n -n Ignored" \ - -#define cut_example_usage \ - "$ echo \"Hello world\" | cut -f 1 -d ' '\n" \ - "Hello\n" \ - "$ echo \"Hello world\" | cut -f 2 -d ' '\n" \ - "world\n" - -#define date_trivial_usage \ - "[OPTIONS] [+FMT] [TIME]" -#define date_full_usage "\n\n" \ - "Display time (using +FMT), or set time\n" \ - "\nOptions:" \ - IF_NOT_LONG_OPTS( \ - "\n [-s] TIME Set time to TIME" \ - "\n -u Work in UTC (don't convert to local time)" \ - "\n -R Output RFC-2822 compliant date string" \ - ) IF_LONG_OPTS( \ - "\n [-s,--set] TIME Set time to TIME" \ - "\n -u,--utc Work in UTC (don't convert to local time)" \ - "\n -R,--rfc-2822 Output RFC-2822 compliant date string" \ - ) \ - IF_FEATURE_DATE_ISOFMT( \ - "\n -I[SPEC] Output ISO-8601 compliant date string" \ - "\n SPEC='date' (default) for date only," \ - "\n 'hours', 'minutes', or 'seconds' for date and" \ - "\n time to the indicated precision" \ - ) IF_NOT_LONG_OPTS( \ - "\n -r FILE Display last modification time of FILE" \ - "\n -d TIME Display TIME, not 'now'" \ - ) IF_LONG_OPTS( \ - "\n -r,--reference FILE Display last modification time of FILE" \ - "\n -d,--date TIME Display TIME, not 'now'" \ - ) \ - IF_FEATURE_DATE_ISOFMT( \ - "\n -D FMT Use FMT for -d TIME conversion" \ - ) \ - "\n" \ - "\nRecognized TIME formats:" \ - "\n hh:mm[:ss]" \ - "\n [YYYY.]MM.DD-hh:mm[:ss]" \ - "\n YYYY-MM-DD hh:mm[:ss]" \ - "\n [[[[[YY]YY]MM]DD]hh]mm[.ss]" \ - -#define date_example_usage \ - "$ date\n" \ - "Wed Apr 12 18:52:41 MDT 2000\n" - -#define dc_trivial_usage \ - "expression..." -#define dc_full_usage "\n\n" \ - "Tiny RPN calculator. Operations:\n" \ - "+, add, -, sub, *, mul, /, div, %, mod, **, exp, and, or, not, eor,\n" \ - "p - print top of the stack (without altering the stack),\n" \ - "f - print entire stack, o - pop the value and set output radix\n" \ - "(value must be 10 or 16).\n" \ - "Examples: 'dc 2 2 add' -> 4, 'dc 8 8 * 2 2 + /' -> 16\n" \ - -#define dc_example_usage \ - "$ dc 2 2 + p\n" \ - "4\n" \ - "$ dc 8 8 \\* 2 2 + / p\n" \ - "16\n" \ - "$ dc 0 1 and p\n" \ - "0\n" \ - "$ dc 0 1 or p\n" \ - "1\n" \ - "$ echo 72 9 div 8 mul p | dc\n" \ - "64\n" - -#define dd_trivial_usage \ - "[if=FILE] [of=FILE] " IF_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \ - " [seek=N]" IF_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]") -#define dd_full_usage "\n\n" \ - "Copy a file with converting and formatting\n" \ - "\nOptions:" \ - "\n if=FILE Read from FILE instead of stdin" \ - "\n of=FILE Write to FILE instead of stdout" \ - "\n bs=N Read and write N bytes at a time" \ - IF_FEATURE_DD_IBS_OBS( \ - "\n ibs=N Read N bytes at a time" \ - ) \ - IF_FEATURE_DD_IBS_OBS( \ - "\n obs=N Write N bytes at a time" \ - ) \ - "\n count=N Copy only N input blocks" \ - "\n skip=N Skip N input blocks" \ - "\n seek=N Skip N output blocks" \ - IF_FEATURE_DD_IBS_OBS( \ - "\n conv=notrunc Don't truncate output file" \ - "\n conv=noerror Continue after read errors" \ - "\n conv=sync Pad blocks with zeros" \ - "\n conv=fsync Physically write data out before finishing" \ - ) \ - "\n" \ - "\nNumbers may be suffixed by c (x1), w (x2), b (x512), kD (x1000), k (x1024)," \ - "\nMD (x1000000), M (x1048576), GD (x1000000000) or G (x1073741824)" \ - -#define dd_example_usage \ - "$ dd if=/dev/zero of=/dev/ram1 bs=1M count=4\n" \ - "4+0 records in\n" \ - "4+0 records out\n" - -#define deallocvt_trivial_usage \ - "[N]" -#define deallocvt_full_usage "\n\n" \ - "Deallocate unused virtual terminal /dev/ttyN" - -#define delgroup_trivial_usage \ - IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" -#define delgroup_full_usage "\n\n" \ - "Delete group GROUP from the system" \ - IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") - -#define deluser_trivial_usage \ - "USER" -#define deluser_full_usage "\n\n" \ - "Delete USER from the system" - -#define depmod_trivial_usage NOUSAGE_STR -#define depmod_full_usage "" - -#define devmem_trivial_usage \ - "ADDRESS [WIDTH [VALUE]]" - -#define devmem_full_usage "\n\n" \ - "Read/write from physical address\n" \ - "\n ADDRESS Address to act upon" \ - "\n WIDTH Width (8/16/...)" \ - "\n VALUE Data to be written" \ - -#define devfsd_trivial_usage \ - "mntpnt [-v]" IF_DEVFSD_FG_NP("[-fg][-np]") -#define devfsd_full_usage "\n\n" \ - "Manage devfs permissions and old device name symlinks\n" \ - "\nOptions:" \ - "\n mntpnt The mount point where devfs is mounted" \ - "\n -v Print the protocol version numbers for devfsd" \ - "\n and the kernel-side protocol version and exit" \ - IF_DEVFSD_FG_NP( \ - "\n -fg Run in foreground" \ - "\n -np Exit after parsing the configuration file" \ - "\n and processing synthetic REGISTER events," \ - "\n don't poll for events" \ - ) - -#define df_trivial_usage \ - "[-Pk" \ - IF_FEATURE_HUMAN_READABLE("mh") \ - IF_FEATURE_DF_FANCY("ai] [-B SIZE") \ - "] [FILESYSTEM]..." -#define df_full_usage "\n\n" \ - "Print filesystem usage statistics\n" \ - "\nOptions:" \ - "\n -P POSIX output format" \ - "\n -k 1024-byte blocks (default)" \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -m 1M-byte blocks" \ - "\n -h Human readable (e.g. 1K 243M 2G)" \ - ) \ - IF_FEATURE_DF_FANCY( \ - "\n -a Show all filesystems" \ - "\n -i Inodes" \ - "\n -B SIZE Blocksize" \ - ) \ - -#define df_example_usage \ - "$ df\n" \ - "Filesystem 1K-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" \ - "/dev/sda1 64216 36364 27852 57% /boot\n" \ - "$ df /dev/sda3\n" \ - "Filesystem 1K-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 8690864 8553540 137324 98% /\n" \ - "$ POSIXLY_CORRECT=sure df /dev/sda3\n" \ - "Filesystem 512B-blocks Used Available Use% Mounted on\n" \ - "/dev/sda3 17381728 17107080 274648 98% /\n" \ - "$ POSIXLY_CORRECT=yep df -P /dev/sda3\n" \ - "Filesystem 512-blocks Used Available Capacity Mounted on\n" \ - "/dev/sda3 17381728 17107080 274648 98% /\n" - -#define dhcprelay_trivial_usage \ - "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" -#define dhcprelay_full_usage "\n\n" \ - "Relay DHCP requests between clients and server" \ - -#define diff_trivial_usage \ - "[-abBdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" -#define diff_full_usage "\n\n" \ - "Compare files line by line and output the differences between them.\n" \ - "This implementation supports unified diffs only.\n" \ - "\nOptions:" \ - "\n -a Treat all files as text" \ - "\n -b Ignore changes in the amount of whitespace" \ - "\n -B Ignore changes whose lines are all blank" \ - "\n -d Try hard to find a smaller set of changes" \ - "\n -i Ignore case differences" \ - "\n -L Use LABEL instead of the filename in the unified header" \ - "\n -N Treat absent files as empty" \ - "\n -q Output only whether files differ" \ - "\n -r Recurse" \ - "\n -S Start with FILE when comparing directories" \ - "\n -T Make tabs line up by prefixing a tab when necessary" \ - "\n -s Report when two files are the same" \ - "\n -t Expand tabs to spaces in output" \ - "\n -U Output LINES lines of context" \ - "\n -w Ignore all whitespace" \ - -#define dirname_trivial_usage \ - "FILENAME" -#define dirname_full_usage "\n\n" \ - "Strip non-directory suffix from FILENAME" -#define dirname_example_usage \ - "$ dirname /tmp/foo\n" \ - "/tmp\n" \ - "$ dirname /tmp/foo/\n" \ - "/tmp\n" - -#define dmesg_trivial_usage \ - "[-c] [-n LEVEL] [-s SIZE]" -#define dmesg_full_usage "\n\n" \ - "Print or control the kernel ring buffer\n" \ - "\nOptions:" \ - "\n -c Clear ring buffer after printing" \ - "\n -n LEVEL Set console logging level" \ - "\n -s SIZE Buffer size" \ - -#define dnsd_trivial_usage \ - "[-dvs] [-c CONFFILE] [-t TTL_SEC] [-p PORT] [-i ADDR]" -#define dnsd_full_usage "\n\n" \ - "Small static DNS server daemon\n" \ - "\nOptions:" \ - "\n -c FILE Config file" \ - "\n -t SEC TTL" \ - "\n -p PORT Listen on PORT" \ - "\n -i ADDR Listen on ADDR" \ - "\n -d Daemonize" \ - "\n -v Verbose" \ - "\n -s Send successful replies only. Use this if you want" \ - "\n to use /etc/resolv.conf with two nameserver lines:" \ - "\n nameserver DNSD_SERVER" \ - "\n nameserver NORNAL_DNS_SERVER" \ - -#define dos2unix_trivial_usage \ - "[OPTIONS] [FILE]" -#define dos2unix_full_usage "\n\n" \ - "Convert FILE in-place from DOS to Unix format.\n" \ - "When no file is given, use stdin/stdout.\n" \ - "\nOptions:" \ - "\n -u dos2unix" \ - "\n -d unix2dos" \ - -#define unix2dos_trivial_usage \ - "[OPTIONS] [FILE]" -#define unix2dos_full_usage "\n\n" \ - "Convert FILE in-place from Unix to DOS format.\n" \ - "When no file is given, use stdin/stdout.\n" \ - "\nOptions:" \ - "\n -u dos2unix" \ - "\n -d unix2dos" \ - -#define dpkg_trivial_usage \ - "[-ilCPru] [-F OPT] PACKAGE" -#define dpkg_full_usage "\n\n" \ - "Install, remove and manage Debian packages\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -i,--install Install the package" \ - "\n -l,--list List of installed packages" \ - "\n --configure Configure an unpackaged package" \ - "\n -P,--purge Purge all files of a package" \ - "\n -r,--remove Remove all but the configuration files for a package" \ - "\n --unpack Unpack a package, but don't configure it" \ - "\n --force-depends Ignore dependency problems" \ - "\n --force-confnew Overwrite existing config files when installing" \ - "\n --force-confold Keep old config files when installing" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -i Install the package" \ - "\n -l List of installed packages" \ - "\n -C Configure an unpackaged package" \ - "\n -P Purge all files of a package" \ - "\n -r Remove all but the configuration files for a package" \ - "\n -u Unpack a package, but don't configure it" \ - "\n -F depends Ignore dependency problems" \ - "\n -F confnew Overwrite existing config files when installing" \ - "\n -F confold Keep old config files when installing" \ - ) - -#define dpkg_deb_trivial_usage \ - "[-cefxX] FILE [argument]" -#define dpkg_deb_full_usage "\n\n" \ - "Perform actions on Debian packages (.debs)\n" \ - "\nOptions:" \ - "\n -c List contents of filesystem tree" \ - "\n -e Extract control files to [argument] directory" \ - "\n -f Display control field name starting with [argument]" \ - "\n -x Extract packages filesystem tree to directory" \ - "\n -X Verbose extract" \ - -#define dpkg_deb_example_usage \ - "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n" - -#define du_trivial_usage \ - "[-aHLdclsx" IF_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..." -#define du_full_usage "\n\n" \ - "Summarize disk space used for each FILE and/or directory.\n" \ - "Disk space is printed in units of " \ - IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") \ - IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") \ - " bytes.\n" \ - "\nOptions:" \ - "\n -a Show file sizes too" \ - "\n -L Follow all symlinks" \ - "\n -H Follow symlinks on command line" \ - "\n -d N Limit output to directories (and files with -a) of depth < N" \ - "\n -c Show grand total" \ - "\n -l Count sizes many times if hard linked" \ - "\n -s Display only a total for each argument" \ - "\n -x Skip directories on different filesystems" \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -h Sizes in human readable format (e.g., 1K 243M 2G )" \ - "\n -m Sizes in megabytes" \ - ) \ - "\n -k Sizes in kilobytes" \ - IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") \ - -#define du_example_usage \ - "$ du\n" \ - "16 ./CVS\n" \ - "12 ./kernel-patches/CVS\n" \ - "80 ./kernel-patches\n" \ - "12 ./tests/CVS\n" \ - "36 ./tests\n" \ - "12 ./scripts/CVS\n" \ - "16 ./scripts\n" \ - "12 ./docs/CVS\n" \ - "104 ./docs\n" \ - "2417 .\n" - -#define dumpkmap_trivial_usage \ - "> keymap" -#define dumpkmap_full_usage "\n\n" \ - "Print a binary keyboard translation table to stdout" -#define dumpkmap_example_usage \ - "$ dumpkmap > keymap\n" - -#define dumpleases_trivial_usage \ - "[-r|-a] [-f LEASEFILE]" -#define dumpleases_full_usage "\n\n" \ - "Display DHCP leases granted by udhcpd\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -f,--file=FILE Lease file" \ - "\n -r,--remaining Show remaining time" \ - "\n -a,--absolute Show expiration time" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -f FILE Lease file" \ - "\n -r Show remaining time" \ - "\n -a Show expiration time" \ - ) - -/* -#define e2fsck_trivial_usage \ - "[-panyrcdfvstDFSV] [-b superblock] [-B blocksize] " \ - "[-I inode_buffer_blocks] [-P process_inode_size] " \ - "[-l|-L bad_blocks_file] [-C fd] [-j external_journal] " \ - "[-E extended-options] device" -#define e2fsck_full_usage "\n\n" \ - "Check ext2/ext3 file system\n" \ - "\nOptions:" \ - "\n -p Automatic repair (no questions)" \ - "\n -n Make no changes to the filesystem" \ - "\n -y Assume 'yes' to all questions" \ - "\n -c Check for bad blocks and add them to the badblock list" \ - "\n -f Force checking even if filesystem is marked clean" \ - "\n -v Verbose" \ - "\n -b superblock Use alternative superblock" \ - "\n -B blocksize Force blocksize when looking for superblock" \ - "\n -j journal Set location of the external journal" \ - "\n -l file Add to badblocks list" \ - "\n -L file Set badblocks list" \ -*/ - -#define echo_trivial_usage \ - IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG]..." -#define echo_full_usage "\n\n" \ - "Print the specified ARGs to stdout" \ - IF_FEATURE_FANCY_ECHO( "\n" \ - "\nOptions:" \ - "\n -n Suppress trailing newline" \ - "\n -e Interpret backslash escapes (i.e., \\t=tab)" \ - "\n -E Don't interpret backslash escapes (default)" \ - ) -#define echo_example_usage \ - "$ echo \"Erik is cool\"\n" \ - "Erik is cool\n" \ - IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" \ - "Erik\n" \ - "is\n" \ - "cool\n" \ - "$ echo \"Erik\\nis\\ncool\"\n" \ - "Erik\\nis\\ncool\n") - -#define eject_trivial_usage \ - "[-t] [-T] [DEVICE]" -#define eject_full_usage "\n\n" \ - "Eject DEVICE or default /dev/cdrom\n" \ - "\nOptions:" \ - IF_FEATURE_EJECT_SCSI( \ - "\n -s SCSI device" \ - ) \ - "\n -t Close tray" \ - "\n -T Open/close tray (toggle)" \ - -#define ed_trivial_usage "" -#define ed_full_usage "" - -#define env_trivial_usage \ - "[-iu] [-] [name=value]... [PROG ARGS]" -#define env_full_usage "\n\n" \ - "Print the current environment or run PROG after setting up\n" \ - "the specified environment\n" \ - "\nOptions:" \ - "\n -, -i Start with an empty environment" \ - "\n -u Remove variable from the environment" \ - -#define ether_wake_trivial_usage \ - "[-b] [-i iface] [-p aa:bb:cc:dd[:ee:ff]] MAC" -#define ether_wake_full_usage "\n\n" \ - "Send a magic packet to wake up sleeping machines.\n" \ - "MAC must be a station address (00:11:22:33:44:55) or\n" \ - "a hostname with a known 'ethers' entry.\n" \ - "\nOptions:" \ - "\n -b Send wake-up packet to the broadcast address" \ - "\n -i iface Interface to use (default eth0)" \ - "\n -p pass Append four or six byte password PW to the packet" \ - -#define expand_trivial_usage \ - "[-i] [-t N] [FILE]..." -#define expand_full_usage "\n\n" \ - "Convert tabs to spaces, writing to stdout\n" \ - "\nOptions:" \ - IF_FEATURE_EXPAND_LONG_OPTIONS( \ - "\n -i,--initial Don't convert tabs after non blanks" \ - "\n -t,--tabs=N Tabstops every N chars" \ - ) \ - IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( \ - "\n -i Don't convert tabs after non blanks" \ - "\n -t Tabstops every N chars" \ - ) - -#define expr_trivial_usage \ - "EXPRESSION" -#define expr_full_usage "\n\n" \ - "Print the value of EXPRESSION to stdout\n" \ - "\n" \ - "EXPRESSION may be:\n" \ - " ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n" \ - " ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n" \ - " ARG1 < ARG2 1 if ARG1 is less than ARG2, else 0. Similarly:\n" \ - " ARG1 <= ARG2\n" \ - " ARG1 = ARG2\n" \ - " ARG1 != ARG2\n" \ - " ARG1 >= ARG2\n" \ - " ARG1 > ARG2\n" \ - " ARG1 + ARG2 Sum of ARG1 and ARG2. Similarly:\n" \ - " ARG1 - ARG2\n" \ - " ARG1 * ARG2\n" \ - " ARG1 / ARG2\n" \ - " ARG1 % ARG2\n" \ - " STRING : REGEXP Anchored pattern match of REGEXP in STRING\n" \ - " match STRING REGEXP Same as STRING : REGEXP\n" \ - " substr STRING POS LENGTH Substring of STRING, POS counted from 1\n" \ - " index STRING CHARS Index in STRING where any CHARS is found, or 0\n" \ - " length STRING Length of STRING\n" \ - " quote TOKEN Interpret TOKEN as a string, even if\n" \ - " it is a keyword like 'match' or an\n" \ - " operator like '/'\n" \ - " (EXPRESSION) Value of EXPRESSION\n" \ - "\n" \ - "Beware that many operators need to be escaped or quoted for shells.\n" \ - "Comparisons are arithmetic if both ARGs are numbers, else\n" \ - "lexicographical. Pattern matches return the string matched between\n" \ - "\\( and \\) or null; if \\( and \\) are not used, they return the number\n" \ - "of characters matched or 0." - -#define fakeidentd_trivial_usage \ - "[-fiw] [-b ADDR] [STRING]" -#define fakeidentd_full_usage "\n\n" \ - "Provide fake ident (auth) service\n" \ - "\nOptions:" \ - "\n -f Run in foreground" \ - "\n -i Inetd mode" \ - "\n -w Inetd 'wait' mode" \ - "\n -b ADDR Bind to specified address" \ - "\n STRING Ident answer string (default: nobody)" \ - -#define false_trivial_usage \ - "" -#define false_full_usage "\n\n" \ - "Return an exit code of FALSE (1)" - -#define false_example_usage \ - "$ false\n" \ - "$ echo $?\n" \ - "1\n" - -#define fbsplash_trivial_usage \ - "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" -#define fbsplash_full_usage "\n\n" \ - "Options:" \ - "\n -s Image" \ - "\n -c Hide cursor" \ - "\n -d Framebuffer device (default /dev/fb0)" \ - "\n -i Config file (var=value):" \ - "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" \ - "\n BAR_R,BAR_G,BAR_B" \ - "\n -f Control pipe (else exit after drawing image)" \ - "\n commands: 'NN' (% for progress bar) or 'exit'" \ - -#define fbset_trivial_usage \ - "[OPTIONS] [MODE]" -#define fbset_full_usage "\n\n" \ - "Show and modify frame buffer settings" - -#define fbset_example_usage \ - "$ fbset\n" \ - "mode \"1024x768-76\"\n" \ - " # D: 78.653 MHz, H: 59.949 kHz, V: 75.694 Hz\n" \ - " geometry 1024 768 1024 768 16\n" \ - " timings 12714 128 32 16 4 128 4\n" \ - " accel false\n" \ - " rgba 5/11,6/5,5/0,0/0\n" \ - "endmode\n" - -#define fdflush_trivial_usage \ - "DEVICE" -#define fdflush_full_usage "\n\n" \ - "Force floppy disk drive to detect disk change" - -#define fdformat_trivial_usage \ - "[-n] DEVICE" -#define fdformat_full_usage "\n\n" \ - "Format floppy disk\n" \ - "\nOptions:" \ - "\n -n Don't verify after format" \ - -/* Looks like someone forgot to add this to config system */ -#ifndef ENABLE_FEATURE_FDISK_BLKSIZE -# define ENABLE_FEATURE_FDISK_BLKSIZE 0 -# define IF_FEATURE_FDISK_BLKSIZE(a) -#endif - -#define fdisk_trivial_usage \ - "[-ul" IF_FEATURE_FDISK_BLKSIZE("s") "] " \ - "[-C CYLINDERS] [-H HEADS] [-S SECTORS] [-b SSZ] DISK" -#define fdisk_full_usage "\n\n" \ - "Change partition table\n" \ - "\nOptions:" \ - "\n -u Start and End are in sectors (instead of cylinders)" \ - "\n -l Show partition table for each DISK, then exit" \ - IF_FEATURE_FDISK_BLKSIZE( \ - "\n -s Show partition sizes in kb for each DISK, then exit" \ - ) \ - "\n -b 2048 (for certain MO disks) use 2048-byte sectors" \ - "\n -C CYLINDERS Set number of cylinders/heads/sectors" \ - "\n -H HEADS" \ - "\n -S SECTORS" \ - -#define fgconsole_trivial_usage \ - "" -#define fgconsole_full_usage "\n\n" \ - "Get active console" - -#define findfs_trivial_usage \ - "LABEL=label or UUID=uuid" -#define findfs_full_usage "\n\n" \ - "Find a filesystem device based on a label or UUID" -#define findfs_example_usage \ - "$ findfs LABEL=MyDevice" - -#define flash_lock_trivial_usage \ - "MTD_DEVICE OFFSET SECTORS" -#define flash_lock_full_usage "\n\n" \ - "Lock part or all of an MTD device. If SECTORS is -1, then all sectors\n" \ - "will be locked, regardless of the value of OFFSET" - -#define flash_unlock_trivial_usage \ - "MTD_DEVICE" -#define flash_unlock_full_usage "\n\n" \ - "Unlock an MTD device" - -#define flash_eraseall_trivial_usage \ - "[-jq] MTD_DEVICE" -#define flash_eraseall_full_usage "\n\n" \ - "Erase an MTD device\n" \ - "\nOptions:" \ - "\n -j Format the device for jffs2" \ - "\n -q Don't display progress messages" \ - -#define flashcp_trivial_usage \ - "-v FILE MTD_DEVICE" -#define flashcp_full_usage "\n\n" \ - "Copy an image to MTD device\n" \ - "\nOptions:" \ - "\n -v Verbose" \ - -#define flock_trivial_usage \ - "[-sxun] FD|{FILE [-c] PROG ARGS}" -#define flock_full_usage "\n\n" \ - "[Un]lock file descriptor, or lock FILE, run PROG\n" \ - "\nOptions:" \ - "\n -s Shared lock" \ - "\n -x Exclusive lock (default)" \ - "\n -u Unlock FD" \ - "\n -n Fail rather than wait" \ - -#define fold_trivial_usage \ - "[-bs] [-w WIDTH] [FILE]..." -#define fold_full_usage "\n\n" \ - "Wrap input lines in each FILE (or stdin), writing to stdout\n" \ - "\nOptions:" \ - "\n -b Count bytes rather than columns" \ - "\n -s Break at spaces" \ - "\n -w Use WIDTH columns instead of 80" \ - -#define free_trivial_usage \ - "" -#define free_full_usage "\n\n" \ - "Display the amount of free and used system memory" -#define free_example_usage \ - "$ free\n" \ - " total used free shared buffers\n" \ - " Mem: 257628 248724 8904 59644 93124\n" \ - " Swap: 128516 8404 120112\n" \ - "Total: 386144 257128 129016\n" \ - -#define freeramdisk_trivial_usage \ - "DEVICE" -#define freeramdisk_full_usage "\n\n" \ - "Free all memory used by the specified ramdisk" -#define freeramdisk_example_usage \ - "$ freeramdisk /dev/ram2\n" - -#define fsck_trivial_usage \ - "[-ANPRTV] [-C FD] [-t FSTYPE] [FS_OPTS] [BLOCKDEV]..." -#define fsck_full_usage "\n\n" \ - "Check and repair filesystems\n" \ - "\nOptions:" \ - "\n -A Walk /etc/fstab and check all filesystems" \ - "\n -N Don't execute, just show what would be done" \ - "\n -P With -A, check filesystems in parallel" \ - "\n -R With -A, skip the root filesystem" \ - "\n -T Don't show title on startup" \ - "\n -V Verbose" \ - "\n -C n Write status information to specified filedescriptor" \ - "\n -t TYPE List of filesystem types to check" \ - -#define fsck_minix_trivial_usage \ - "[-larvsmf] BLOCKDEV" -#define fsck_minix_full_usage "\n\n" \ - "Check MINIX filesystem\n" \ - "\nOptions:" \ - "\n -l List all filenames" \ - "\n -r Perform interactive repairs" \ - "\n -a Perform automatic repairs" \ - "\n -v Verbose" \ - "\n -s Output superblock information" \ - "\n -m Show \"mode not cleared\" warnings" \ - "\n -f Force file system check" \ - -#define ftpd_trivial_usage \ - "[-wvS] [-t N] [-T N] [DIR]" -#define ftpd_full_usage "\n\n" \ - "Anonymous FTP server\n" \ - "\n" \ - "ftpd should be used as an inetd service.\n" \ - "ftpd's line for inetd.conf:\n" \ - " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" \ - "It also can be ran from tcpsvd:\n" \ - " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve\n" \ - "\nOptions:" \ - "\n -w Allow upload" \ - "\n -v Log to stderr" \ - "\n -S Log to syslog" \ - "\n -t,-T Idle and absolute timeouts" \ - "\n DIR Change root to this directory" \ - -#define ftpget_trivial_usage \ - "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" -#define ftpget_full_usage "\n\n" \ - "Retrieve a remote file via FTP\n" \ - "\nOptions:" \ - IF_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -c,--continue Continue previous transfer" \ - "\n -v,--verbose Verbose" \ - "\n -u,--username Username" \ - "\n -p,--password Password" \ - "\n -P,--port Port number" \ - ) \ - IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -c Continue previous transfer" \ - "\n -v Verbose" \ - "\n -u Username" \ - "\n -p Password" \ - "\n -P Port number" \ - ) - -#define ftpput_trivial_usage \ - "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" -#define ftpput_full_usage "\n\n" \ - "Store a local file on a remote machine via FTP\n" \ - "\nOptions:" \ - IF_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -v,--verbose Verbose" \ - "\n -u,--username Username" \ - "\n -p,--password Password" \ - "\n -P,--port Port number" \ - ) \ - IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \ - "\n -v Verbose" \ - "\n -u Username" \ - "\n -p Password" \ - "\n -P Port number" \ - ) - -#define fuser_trivial_usage \ - "[OPTIONS] FILE or PORT/PROTO" -#define fuser_full_usage "\n\n" \ - "Find processes which use FILEs or PORTs\n" \ - "\nOptions:" \ - "\n -m Find processes which use same fs as FILEs" \ - "\n -4 Search only IPv4 space" \ - "\n -6 Search only IPv6 space" \ - "\n -s Don't display PIDs" \ - "\n -k Kill found processes" \ - "\n -SIGNAL Signal to send (default: KILL)" \ - -#define getenforce_trivial_usage NOUSAGE_STR -#define getenforce_full_usage "" - -#define getopt_trivial_usage \ - "[OPTIONS]" -#define getopt_full_usage "\n\n" \ - "Options:" \ - IF_LONG_OPTS( \ - "\n -a,--alternative Allow long options starting with single -" \ - "\n -l,--longoptions=longopts Long options to be recognized" \ - "\n -n,--name=progname The name under which errors are reported" \ - "\n -o,--options=optstring Short options to be recognized" \ - "\n -q,--quiet Disable error reporting by getopt(3)" \ - "\n -Q,--quiet-output No normal output" \ - "\n -s,--shell=shell Set shell quoting conventions" \ - "\n -T,--test Test for getopt(1) version" \ - "\n -u,--unquoted Don't quote the output" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -a Allow long options starting with single -" \ - "\n -l longopts Long options to be recognized" \ - "\n -n progname The name under which errors are reported" \ - "\n -o optstring Short options to be recognized" \ - "\n -q Disable error reporting by getopt(3)" \ - "\n -Q No normal output" \ - "\n -s shell Set shell quoting conventions" \ - "\n -T Test for getopt(1) version" \ - "\n -u Don't quote the output" \ - ) -#define getopt_example_usage \ - "$ cat getopt.test\n" \ - "#!/bin/sh\n" \ - "GETOPT=`getopt -o ab:c:: --long a-long,b-long:,c-long:: \\\n" \ - " -n 'example.busybox' -- \"$@\"`\n" \ - "if [ $? != 0 ]; then exit 1; fi\n" \ - "eval set -- \"$GETOPT\"\n" \ - "while true; do\n" \ - " case $1 in\n" \ - " -a|--a-long) echo \"Option a\"; shift;;\n" \ - " -b|--b-long) echo \"Option b, argument '$2'\"; shift 2;;\n" \ - " -c|--c-long)\n" \ - " case \"$2\" in\n" \ - " \"\") echo \"Option c, no argument\"; shift 2;;\n" \ - " *) echo \"Option c, argument '$2'\"; shift 2;;\n" \ - " esac;;\n" \ - " --) shift; break;;\n" \ - " *) echo \"Internal error!\"; exit 1;;\n" \ - " esac\n" \ - "done\n" - -#define getsebool_trivial_usage \ - "-a or getsebool boolean..." -#define getsebool_full_usage "\n\n" \ - " -a Show all selinux booleans" - -#define getty_trivial_usage \ - "[OPTIONS] BAUD_RATE TTY [TERMTYPE]" -#define getty_full_usage "\n\n" \ - "Open a tty, prompt for a login name, then invoke /bin/login\n" \ - "\nOptions:" \ - "\n -h Enable hardware (RTS/CTS) flow control" \ - "\n -i Don't display /etc/issue before running login" \ - "\n -L Local line, don't do carrier detect" \ - "\n -m Get baud rate from modem's CONNECT status message" \ - "\n -w Wait for a CR or LF before sending /etc/issue" \ - "\n -n Don't prompt the user for a login name" \ - "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \ - "\n -l LOGIN Invoke LOGIN instead of /bin/login" \ - "\n -t SEC Terminate after SEC if no username is read" \ - "\n -I INITSTR Send INITSTR before anything else" \ - "\n -H HOST Log HOST into the utmp file as the hostname" \ - -#define gunzip_trivial_usage \ - "[OPTIONS] [FILE]..." -#define gunzip_full_usage "\n\n" \ - "Decompress FILEs (or stdin)\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - "\n -t Test file integrity" \ - -#define gunzip_example_usage \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 557009 Apr 11 10:55 /tmp/BusyBox-0.43.tar.gz\n" \ - "$ gunzip /tmp/BusyBox-0.43.tar.gz\n" \ - "$ ls -la /tmp/BusyBox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/BusyBox-0.43.tar\n" - -#define gzip_trivial_usage \ - "[OPTIONS] [FILE]..." -#define gzip_full_usage "\n\n" \ - "Compress FILEs (or stdin)\n" \ - "\nOptions:" \ - "\n -d Decompress" \ - "\n -c Write to stdout" \ - "\n -f Force" \ - -#define gzip_example_usage \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 1761280 Apr 14 17:47 /tmp/busybox.tar\n" \ - "$ gzip /tmp/busybox.tar\n" \ - "$ ls -la /tmp/busybox*\n" \ - "-rw-rw-r-- 1 andersen andersen 554058 Apr 14 17:49 /tmp/busybox.tar.gz\n" - -#define halt_trivial_usage \ - "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]") -#define halt_full_usage "\n\n" \ - "Halt the system\n" \ - "\nOptions:" \ - "\n -d Delay interval for halting" \ - "\n -n No call to sync()" \ - "\n -f Force halt (don't go through init)" \ - IF_FEATURE_WTMP( \ - "\n -w Only write a wtmp record" \ - ) - -#define hdparm_trivial_usage \ - "[OPTIONS] [DEVICE]" -#define hdparm_full_usage "\n\n" \ - "Options:" \ - "\n -a Get/set fs readahead" \ - "\n -A Set drive read-lookahead flag (0/1)" \ - "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)" \ - "\n -B Set Advanced Power Management setting (1-255)" \ - "\n -c Get/set IDE 32-bit IO setting" \ - "\n -C Check IDE power mode status" \ - IF_FEATURE_HDPARM_HDIO_GETSET_DMA( \ - "\n -d Get/set using_dma flag") \ - "\n -D Enable/disable drive defect-mgmt" \ - "\n -f Flush buffer cache for device on exit" \ - "\n -g Display drive geometry" \ - "\n -h Display terse usage information" \ - IF_FEATURE_HDPARM_GET_IDENTITY( \ - "\n -i Display drive identification") \ - IF_FEATURE_HDPARM_GET_IDENTITY( \ - "\n -I Detailed/current information directly from drive") \ - "\n -k Get/set keep_settings_over_reset flag (0/1)" \ - "\n -K Set drive keep_features_over_reset flag (0/1)" \ - "\n -L Set drive doorlock (0/1) (removable harddisks only)" \ - "\n -m Get/set multiple sector count" \ - "\n -n Get/set ignore-write-errors flag (0/1)" \ - "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)" \ - "\n -P Set drive prefetch count" \ -/* "\n -q Change next setting quietly" - not supported ib bbox */ \ - "\n -Q Get/set DMA tagged-queuing depth (if supported)" \ - "\n -r Get/set readonly flag (DANGEROUS to set)" \ - IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( \ - "\n -R Register an IDE interface (DANGEROUS)") \ - "\n -S Set standby (spindown) timeout" \ - "\n -t Perform device read timings" \ - "\n -T Perform cache read timings" \ - "\n -u Get/set unmaskirq flag (0/1)" \ - IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( \ - "\n -U Unregister an IDE interface (DANGEROUS)") \ - "\n -v Defaults; same as -mcudkrag for IDE drives" \ - "\n -V Display program version and exit immediately" \ - IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( \ - "\n -w Perform device reset (DANGEROUS)") \ - "\n -W Set drive write-caching flag (0/1) (DANGEROUS)" \ - IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( \ - "\n -x Tristate device for hotswap (0/1) (DANGEROUS)") \ - "\n -X Set IDE xfer mode (DANGEROUS)" \ - "\n -y Put IDE drive in standby mode" \ - "\n -Y Put IDE drive to sleep" \ - "\n -Z Disable Seagate auto-powersaving mode" \ - "\n -z Reread partition table" \ - -#define head_trivial_usage \ - "[OPTIONS] [FILE]..." -#define head_full_usage "\n\n" \ - "Print first 10 lines of each FILE (or stdin) to stdout.\n" \ - "With more than one FILE, precede each with a filename header.\n" \ - "\nOptions:" \ - "\n -n N[kbm] Print first N lines" \ - IF_FEATURE_FANCY_HEAD( \ - "\n -c N[kbm] Print first N bytes" \ - "\n -q Never print headers" \ - "\n -v Always print headers" \ - ) \ - "\n" \ - "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." \ - -#define head_example_usage \ - "$ head -n 2 /etc/passwd\n" \ - "root:x:0:0:root:/root:/bin/bash\n" \ - "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" - -#define tail_trivial_usage \ - "[OPTIONS] [FILE]..." -#define tail_full_usage "\n\n" \ - "Print last 10 lines of each FILE (or stdin) to stdout.\n" \ - "With more than one FILE, precede each with a filename header.\n" \ - "\nOptions:" \ - "\n -f Print data as file grows" \ - IF_FEATURE_FANCY_TAIL( \ - "\n -s SECONDS Wait SECONDS between reads with -f" \ - ) \ - "\n -n N[kbm] Print last N lines" \ - IF_FEATURE_FANCY_TAIL( \ - "\n -c N[kbm] Print last N bytes" \ - "\n -q Never print headers" \ - "\n -v Always print headers" \ - "\n" \ - "\nN may be suffixed by k (x1024), b (x512), or m (x1024^2)." \ - "\nIf N starts with a '+', output begins with the Nth item from the start" \ - "\nof each file, not from the end." \ - ) \ - -#define tail_example_usage \ - "$ tail -n 1 /etc/resolv.conf\n" \ - "nameserver 10.0.0.1\n" - -#define hexdump_trivial_usage \ - "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] [FILE]..." -#define hexdump_full_usage "\n\n" \ - "Display FILEs (or stdin) in a user specified format\n" \ - "\nOptions:" \ - "\n -b One-byte octal display" \ - "\n -c One-byte character display" \ - "\n -C Canonical hex+ASCII, 16 bytes per line" \ - "\n -d Two-byte decimal display" \ - "\n -e FORMAT STRING" \ - "\n -f FORMAT FILE" \ - "\n -n LENGTH Interpret only LENGTH bytes of input" \ - "\n -o Two-byte octal display" \ - "\n -s OFFSET Skip OFFSET bytes" \ - "\n -v Display all input data" \ - "\n -x Two-byte hexadecimal display" \ - IF_FEATURE_HEXDUMP_REVERSE( \ - "\n -R Reverse of 'hexdump -Cv'") \ - -#define hd_trivial_usage \ - "FILE..." -#define hd_full_usage "\n\n" \ - "hd is an alias for hexdump -C" - -#define hostid_trivial_usage \ - "" -#define hostid_full_usage "\n\n" \ - "Print out a unique 32-bit identifier for the machine" - -#define hostname_trivial_usage \ - "[OPTIONS] [HOSTNAME | -F FILE]" -#define hostname_full_usage "\n\n" \ - "Get or set hostname or DNS domain name\n" \ - "\nOptions:" \ - "\n -s Short" \ - "\n -i Addresses for the hostname" \ - "\n -d DNS domain name" \ - "\n -f Fully qualified domain name" \ - "\n -F FILE Use FILE's content as hostname" \ - -#define hostname_example_usage \ - "$ hostname\n" \ - "sage\n" - -#define dnsdomainname_trivial_usage NOUSAGE_STR -#define dnsdomainname_full_usage "" - -#define httpd_trivial_usage \ - "[-ifv[v]]" \ - " [-c CONFFILE]" \ - " [-p [IP:]PORT]" \ - IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") \ - IF_FEATURE_HTTPD_BASIC_AUTH(" [-r REALM]") \ - " [-h HOME]\n" \ - "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" -#define httpd_full_usage "\n\n" \ - "Listen for incoming HTTP requests\n" \ - "\nOptions:" \ - "\n -i Inetd mode" \ - "\n -f Don't daemonize" \ - "\n -v[v] Verbose" \ - "\n -p [IP:]PORT Bind to ip:port (default *:80)" \ - IF_FEATURE_HTTPD_SETUID( \ - "\n -u USER[:GRP] Set uid/gid after binding to port") \ - IF_FEATURE_HTTPD_BASIC_AUTH( \ - "\n -r REALM Authentication Realm for Basic Authentication") \ - "\n -h HOME Home directory (default .)" \ - "\n -c FILE Configuration file (default {/etc,HOME}/httpd.conf)" \ - IF_FEATURE_HTTPD_AUTH_MD5( \ - "\n -m STRING MD5 crypt STRING") \ - "\n -e STRING HTML encode STRING" \ - "\n -d STRING URL decode STRING" \ - -#define hwclock_trivial_usage \ - IF_FEATURE_HWCLOCK_LONG_OPTIONS( \ - "[-r|--show] [-s|--hctosys] [-w|--systohc]" \ - " [-l|--localtime] [-u|--utc]" \ - " [-f FILE]" \ - ) \ - IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS( \ - "[-r] [-s] [-w] [-l] [-u] [-f FILE]" \ - ) -#define hwclock_full_usage "\n\n" \ - "Query and set hardware clock (RTC)\n" \ - "\nOptions:" \ - "\n -r Show hardware clock time" \ - "\n -s Set system time from hardware clock" \ - "\n -w Set hardware clock to system time" \ - "\n -u Hardware clock is in UTC" \ - "\n -l Hardware clock is in local time" \ - "\n -f FILE Use specified device (e.g. /dev/rtc2)" \ - -#define id_trivial_usage \ - "[OPTIONS] [USER]" -#define id_full_usage "\n\n" \ - "Print information about USER or the current user\n" \ - "\nOptions:" \ - IF_SELINUX( \ - "\n -Z Print the security context" \ - ) \ - "\n -u Print user ID" \ - "\n -g Print group ID" \ - "\n -G Print supplementary group IDs" \ - "\n -n Print name instead of a number" \ - "\n -r Print real user ID instead of effective ID" \ - -#define id_example_usage \ - "$ id\n" \ - "uid=1000(andersen) gid=1000(andersen)\n" - -#define ifconfig_trivial_usage \ - IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]" -#define ifconfig_full_usage "\n\n" \ - "Configure a network interface\n" \ - "\nOptions:" \ - "\n" \ - IF_FEATURE_IPV6( \ - " [add ADDRESS[/PREFIXLEN]]\n") \ - IF_FEATURE_IPV6( \ - " [del ADDRESS[/PREFIXLEN]]\n") \ - " [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" \ - " [netmask ADDRESS] [dstaddr ADDRESS]\n" \ - IF_FEATURE_IFCONFIG_SLIP( \ - " [outfill NN] [keepalive NN]\n") \ - " " IF_FEATURE_IFCONFIG_HW("[hw ether" IF_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu NN]\n" \ - " [[-]trailers] [[-]arp] [[-]allmulti]\n" \ - " [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic]\n" \ - IF_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( \ - " [mem_start NN] [io_addr NN] [irq NN]\n") \ - " [up|down] ..." - -#define ifenslave_trivial_usage \ - "[-cdf] MASTER_IFACE SLAVE_IFACE..." -#define ifenslave_full_usage "\n\n" \ - "Configure network interfaces for parallel routing\n" \ - "\nOptions:" \ - "\n -c, --change-active Change active slave" \ - "\n -d, --detach Remove slave interface from bonding device" \ - "\n -f, --force Force, even if interface is not Ethernet" \ -/* "\n -r, --receive-slave Create a receive-only slave" */ - -#define ifenslave_example_usage \ - "To create a bond device, simply follow these three steps:\n" \ - "- ensure that the required drivers are properly loaded:\n" \ - " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" \ - "- assign an IP address to the bond device:\n" \ - " # ifconfig bond0 netmask broadcast \n" \ - "- attach all the interfaces you need to the bond device:\n" \ - " # ifenslave bond0 eth0 eth1 eth2\n" \ - " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" \ - " interfaces attached AFTER this assignment will get the same MAC addr.\n\n" \ - " To detach a dead interface without setting the bond device down:\n" \ - " # ifenslave -d bond0 eth1\n\n" \ - " To set the bond device down and automatically release all the slaves:\n" \ - " # ifconfig bond0 down\n\n" \ - " To change active slave:\n" \ - " # ifenslave -c bond0 eth0\n" \ - -#define ifplugd_trivial_usage \ - "[OPTIONS]" -#define ifplugd_full_usage "\n\n" \ - "Network interface plug detection daemon\n" \ - "\nOptions:" \ - "\n -n Don't daemonize" \ - "\n -s Don't log to syslog" \ - "\n -i IFACE Interface" \ - "\n -f/-F Treat link detection error as link down/link up" \ - "\n (otherwise exit on error)" \ - "\n -a Don't up interface at each link probe" \ - "\n -M Monitor creation/destruction of interface" \ - "\n (otherwise it must exist)" \ - "\n -r PROG Script to run" \ - "\n -x ARG Extra argument for script" \ - "\n -I Don't exit on nonzero exit code from script" \ - "\n -p Don't run script on daemon startup" \ - "\n -q Don't run script on daemon quit" \ - "\n -l Run script on startup even if no cable is detected" \ - "\n -t SECS Poll time in seconds" \ - "\n -u SECS Delay before running script after link up" \ - "\n -d SECS Delay after link down" \ - "\n -m MODE API mode (mii, priv, ethtool, wlan, iff, auto)" \ - "\n -k Kill running daemon" \ - -#define ifup_trivial_usage \ - "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] IFACE..." -#define ifup_full_usage "\n\n" \ - "Options:" \ - "\n -a De/configure all interfaces automatically" \ - "\n -i FILE Use FILE for interface definitions" \ - "\n -n Print out what would happen, but don't do it" \ - IF_FEATURE_IFUPDOWN_MAPPING( \ - "\n (note: doesn't disable mappings)" \ - "\n -m Don't run any mappings" \ - ) \ - "\n -v Print out what would happen before doing it" \ - "\n -f Force de/configuration" \ - -#define ifdown_trivial_usage \ - "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..." -#define ifdown_full_usage "\n\n" \ - "Options:" \ - "\n -a De/configure all interfaces automatically" \ - "\n -i FILE Use FILE for interface definitions" \ - "\n -n Print out what would happen, but don't do it" \ - IF_FEATURE_IFUPDOWN_MAPPING( \ - "\n (note: doesn't disable mappings)" \ - "\n -m Don't run any mappings" \ - ) \ - "\n -v Print out what would happen before doing it" \ - "\n -f Force de/configuration" \ - -#define inetd_trivial_usage \ - "[-fe] [-q N] [-R N] [CONFFILE]" -#define inetd_full_usage "\n\n" \ - "Listen for network connections and launch programs\n" \ - "\nOptions:" \ - "\n -f Run in foreground" \ - "\n -e Log to stderr" \ - "\n -q N Socket listen queue (default: 128)" \ - "\n -R N Pause services after N connects/min" \ - "\n (default: 0 - disabled)" \ - -#define init_trivial_usage \ - "" -#define init_full_usage "\n\n" \ - "Init is the parent of all processes" - -#define init_notes_usage \ -"This version of init is designed to be run only by the kernel.\n" \ -"\n" \ -"BusyBox init doesn't support multiple runlevels. The runlevels field of\n" \ -"the /etc/inittab file is completely ignored by BusyBox init. If you want\n" \ -"runlevels, use sysvinit.\n" \ -"\n" \ -"BusyBox init works just fine without an inittab. If no inittab is found,\n" \ -"it has the following default behavior:\n" \ -"\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" ::askfirst:/bin/sh\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/sbin/swapoff -a\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -" ::restart:/sbin/init\n" \ -"\n" \ -"if it detects that /dev/console is _not_ a serial console, it will also run:\n" \ -"\n" \ -" tty2::askfirst:/bin/sh\n" \ -" tty3::askfirst:/bin/sh\n" \ -" tty4::askfirst:/bin/sh\n" \ -"\n" \ -"If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" \ -"\n" \ -" :::\n" \ -"\n" \ -" :\n" \ -"\n" \ -" WARNING: This field has a non-traditional meaning for BusyBox init!\n" \ -" The id field is used by BusyBox init to specify the controlling tty for\n" \ -" the specified process to run on. The contents of this field are\n" \ -" appended to \"/dev/\" and used as-is. There is no need for this field to\n" \ -" be unique, although if it isn't you may have strange results. If this\n" \ -" field is left blank, the controlling tty is set to the console. Also\n" \ -" note that if BusyBox detects that a serial console is in use, then only\n" \ -" entries whose controlling tty is either the serial console or /dev/null\n" \ -" will be run. BusyBox init does nothing with utmp. We don't need no\n" \ -" stinkin' utmp.\n" \ -"\n" \ -" :\n" \ -"\n" \ -" The runlevels field is completely ignored.\n" \ -"\n" \ -" :\n" \ -"\n" \ -" Valid actions include: sysinit, respawn, askfirst, wait,\n" \ -" once, restart, ctrlaltdel, and shutdown.\n" \ -"\n" \ -" The available actions can be classified into two groups: actions\n" \ -" that are run only once, and actions that are re-run when the specified\n" \ -" process exits.\n" \ -"\n" \ -" Run only-once actions:\n" \ -"\n" \ -" 'sysinit' is the first item run on boot. init waits until all\n" \ -" sysinit actions are completed before continuing. Following the\n" \ -" completion of all sysinit actions, all 'wait' actions are run.\n" \ -" 'wait' actions, like 'sysinit' actions, cause init to wait until\n" \ -" the specified task completes. 'once' actions are asynchronous,\n" \ -" therefore, init does not wait for them to complete. 'restart' is\n" \ -" the action taken to restart the init process. By default this should\n" \ -" simply run /sbin/init, but can be a script which runs pivot_root or it\n" \ -" can do all sorts of other interesting things. The 'ctrlaltdel' init\n" \ -" actions are run when the system detects that someone on the system\n" \ -" console has pressed the CTRL-ALT-DEL key combination. Typically one\n" \ -" wants to run 'reboot' at this point to cause the system to reboot.\n" \ -" Finally the 'shutdown' action specifies the actions to taken when\n" \ -" init is told to reboot. Unmounting filesystems and disabling swap\n" \ -" is a very good here.\n" \ -"\n" \ -" Run repeatedly actions:\n" \ -"\n" \ -" 'respawn' actions are run after the 'once' actions. When a process\n" \ -" started with a 'respawn' action exits, init automatically restarts\n" \ -" it. Unlike sysvinit, BusyBox init does not stop processes from\n" \ -" respawning out of control. The 'askfirst' actions acts just like\n" \ -" respawn, except that before running the specified process it\n" \ -" displays the line \"Please press Enter to activate this console.\"\n" \ -" and then waits for the user to press enter before starting the\n" \ -" specified process.\n" \ -"\n" \ -" Unrecognized actions (like initdefault) will cause init to emit an\n" \ -" error message, and then go along with its business. All actions are\n" \ -" run in the order they appear in /etc/inittab.\n" \ -"\n" \ -" :\n" \ -"\n" \ -" Specifies the process to be executed and its command line.\n" \ -"\n" \ -"Example /etc/inittab file:\n" \ -"\n" \ -" # This is run first except when booting in single-user mode\n" \ -" #\n" \ -" ::sysinit:/etc/init.d/rcS\n" \ -" \n" \ -" # /bin/sh invocations on selected ttys\n" \ -" #\n" \ -" # Start an \"askfirst\" shell on the console (whatever that may be)\n" \ -" ::askfirst:-/bin/sh\n" \ -" # Start an \"askfirst\" shell on /dev/tty2-4\n" \ -" tty2::askfirst:-/bin/sh\n" \ -" tty3::askfirst:-/bin/sh\n" \ -" tty4::askfirst:-/bin/sh\n" \ -" \n" \ -" # /sbin/getty invocations for selected ttys\n" \ -" #\n" \ -" tty4::respawn:/sbin/getty 38400 tty4\n" \ -" tty5::respawn:/sbin/getty 38400 tty5\n" \ -" \n" \ -" \n" \ -" # Example of how to put a getty on a serial line (for a terminal)\n" \ -" #\n" \ -" #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" \ -" #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" \ -" #\n" \ -" # Example how to put a getty on a modem line\n" \ -" #::respawn:/sbin/getty 57600 ttyS2\n" \ -" \n" \ -" # Stuff to do when restarting the init process\n" \ -" ::restart:/sbin/init\n" \ -" \n" \ -" # Stuff to do before rebooting\n" \ -" ::ctrlaltdel:/sbin/reboot\n" \ -" ::shutdown:/bin/umount -a -r\n" \ -" ::shutdown:/sbin/swapoff -a\n" - -#define inotifyd_trivial_usage \ - "PROG FILE1[:MASK]..." -#define inotifyd_full_usage "\n\n" \ - "Run PROG on filesystem changes." \ - "\nWhen a filesystem event matching MASK occurs on FILEn," \ - "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." \ - "\nEvents:" \ - "\n a File is accessed" \ - "\n c File is modified" \ - "\n e Metadata changed" \ - "\n w Writable file is closed" \ - "\n 0 Unwritable file is closed" \ - "\n r File is opened" \ - "\n D File is deleted" \ - "\n M File is moved" \ - "\n u Backing fs is unmounted" \ - "\n o Event queue overflowed" \ - "\n x File can't be watched anymore" \ - "\nIf watching a directory:" \ - "\n m Subfile is moved into dir" \ - "\n y Subfile is moved out of dir" \ - "\n n Subfile is created" \ - "\n d Subfile is deleted" \ - "\n" \ - "\ninotifyd waits for PROG to exit." \ - "\nWhen x event happens for all FILEs, inotifyd exits." \ - -/* -v, -b, -c are ignored */ -#define install_trivial_usage \ - "[-cdDsp] [-o USER] [-g GRP] [-m MODE] [SOURCE]... DEST" -#define install_full_usage "\n\n" \ - "Copy files and set attributes\n" \ - "\nOptions:" \ - "\n -c Just copy (default)" \ - "\n -d Create directories" \ - "\n -D Create leading target directories" \ - "\n -s Strip symbol table" \ - "\n -p Preserve date" \ - "\n -o USER Set ownership" \ - "\n -g GRP Set group ownership" \ - "\n -m MODE Set permissions" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -/* would need to make the " | " optional depending on more than one selected: */ -#define ip_trivial_usage \ - "[OPTIONS] {" \ - IF_FEATURE_IP_ADDRESS("address | ") \ - IF_FEATURE_IP_ROUTE("route | ") \ - IF_FEATURE_IP_LINK("link | ") \ - IF_FEATURE_IP_TUNNEL("tunnel | ") \ - IF_FEATURE_IP_RULE("rule") \ - "} {COMMAND}" -#define ip_full_usage "\n\n" \ - "ip [OPTIONS] OBJECT {COMMAND}\n" \ - "where OBJECT := {" \ - IF_FEATURE_IP_ADDRESS("address | ") \ - IF_FEATURE_IP_ROUTE("route | ") \ - IF_FEATURE_IP_LINK("link | ") \ - IF_FEATURE_IP_TUNNEL("tunnel | ") \ - IF_FEATURE_IP_RULE("rule") \ - "}\n" \ - "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" \ - -#define ipaddr_trivial_usage \ - "{ {add|del} IFADDR dev STRING | {show|flush}\n" \ - " [dev STRING] [to PREFIX] }" -#define ipaddr_full_usage "\n\n" \ - "ipaddr {add|delete} IFADDR dev STRING\n" \ - "ipaddr {show|flush} [dev STRING] [scope SCOPE-ID]\n" \ - " [to PREFIX] [label PATTERN]\n" \ - " IFADDR := PREFIX | ADDR peer PREFIX\n" \ - " [broadcast ADDR] [anycast ADDR]\n" \ - " [label STRING] [scope SCOPE-ID]\n" \ - " SCOPE-ID := [host | link | global | NUMBER]" \ - -#define ipcalc_trivial_usage \ - "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" -#define ipcalc_full_usage "\n\n" \ - "Calculate IP network settings from a IP address\n" \ - "\nOptions:" \ - IF_FEATURE_IPCALC_LONG_OPTIONS( \ - "\n -b,--broadcast Display calculated broadcast address" \ - "\n -n,--network Display calculated network address" \ - "\n -m,--netmask Display default netmask for IP" \ - IF_FEATURE_IPCALC_FANCY( \ - "\n -p,--prefix Display the prefix for IP/NETMASK" \ - "\n -h,--hostname Display first resolved host name" \ - "\n -s,--silent Don't ever display error messages" \ - ) \ - ) \ - IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( \ - "\n -b Display calculated broadcast address" \ - "\n -n Display calculated network address" \ - "\n -m Display default netmask for IP" \ - IF_FEATURE_IPCALC_FANCY( \ - "\n -p Display the prefix for IP/NETMASK" \ - "\n -h Display first resolved host name" \ - "\n -s Don't ever display error messages" \ - ) \ - ) - -#define ipcrm_trivial_usage \ - "[-MQS key] [-mqs id]" -#define ipcrm_full_usage "\n\n" \ - "Upper-case options MQS remove an object by shmkey value.\n" \ - "Lower-case options remove an object by shmid value.\n" \ - "\nOptions:" \ - "\n -mM Remove memory segment after last detach" \ - "\n -qQ Remove message queue" \ - "\n -sS Remove semaphore" \ - -#define ipcs_trivial_usage \ - "[[-smq] -i shmid] | [[-asmq] [-tcplu]]" -#define ipcs_full_usage "\n\n" \ - " -i Show specific resource" \ - "\nResource specification:" \ - "\n -m Shared memory segments" \ - "\n -q Message queues" \ - "\n -s Semaphore arrays" \ - "\n -a All (default)" \ - "\nOutput format:" \ - "\n -t Time" \ - "\n -c Creator" \ - "\n -p Pid" \ - "\n -l Limits" \ - "\n -u Summary" \ - -#define iplink_trivial_usage \ - "{ set DEVICE { up | down | arp { on | off } | show [DEVICE] }" -#define iplink_full_usage "\n\n" \ - "iplink set DEVICE { up | down | arp | multicast { on | off } |\n" \ - " dynamic { on | off } |\n" \ - " mtu MTU }\n" \ - "iplink show [DEVICE]" \ - -#define iproute_trivial_usage \ - "{ list | flush | { add | del | change | append |\n" \ - " replace | monitor } ROUTE }" -#define iproute_full_usage "\n\n" \ - "iproute { list | flush } SELECTOR\n" \ - "iproute get ADDRESS [from ADDRESS iif STRING]\n" \ - " [oif STRING] [tos TOS]\n" \ - "iproute { add | del | change | append | replace | monitor } ROUTE\n" \ - " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" \ - " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO]\n" \ - " [metric METRIC]" \ - -#define iprule_trivial_usage \ - "{[list | add | del] RULE}" -#define iprule_full_usage "\n\n" \ - "iprule [list | add | del] SELECTOR ACTION\n" \ - " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n" \ - " [dev STRING] [pref NUMBER]\n" \ - " ACTION := [table TABLE_ID] [nat ADDRESS]\n" \ - " [prohibit | reject | unreachable]\n" \ - " [realms [SRCREALM/]DSTREALM]\n" \ - " TABLE_ID := [local | main | default | NUMBER]" \ - -#define iptunnel_trivial_usage \ - "{ add | change | del | show } [NAME]\n" \ - " [mode { ipip | gre | sit }]\n" \ - " [remote ADDR] [local ADDR] [ttl TTL]" -#define iptunnel_full_usage "\n\n" \ - "iptunnel { add | change | del | show } [NAME]\n" \ - " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" \ - " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" \ - " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" \ - -#define kbd_mode_trivial_usage \ - "[-a|k|s|u] [-C TTY]" -#define kbd_mode_full_usage "\n\n" \ - "Report or set the keyboard mode\n" \ - "\nOptions:" \ - "\n -a Default (ASCII)" \ - "\n -k Medium-raw (keyboard)" \ - "\n -s Raw (scancode)" \ - "\n -u Unicode (utf-8)" \ - "\n -C TTY Affect TTY instead of /dev/tty" \ - -#define kill_trivial_usage \ - "[-l] [-SIG] PID..." -#define kill_full_usage "\n\n" \ - "Send a signal (default: TERM) to given PIDs\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - -#define kill_example_usage \ - "$ ps | grep apache\n" \ - "252 root root S [apache]\n" \ - "263 www-data www-data S [apache]\n" \ - "264 www-data www-data S [apache]\n" \ - "265 www-data www-data S [apache]\n" \ - "266 www-data www-data S [apache]\n" \ - "267 www-data www-data S [apache]\n" \ - "$ kill 252\n" - -#define killall_trivial_usage \ - "[-l] [-q] [-SIG] PROCESS_NAME..." -#define killall_full_usage "\n\n" \ - "Send a signal (default: TERM) to given processes\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - "\n -q Don't complain if no processes were killed" \ - -#define killall_example_usage \ - "$ killall apache\n" - -#define killall5_trivial_usage \ - "[-l] [-SIG] [-o PID]..." -#define killall5_full_usage "\n\n" \ - "Send a signal (default: TERM) to all processes outside current session\n" \ - "\nOptions:" \ - "\n -l List all signal names and numbers" \ - "\n -o PID Don't signal this PID" \ -/* "\n -s SIG Yet another way of specifying SIG" */ \ - -#define klogd_trivial_usage \ - "[-c N] [-n]" -#define klogd_full_usage "\n\n" \ - "Kernel logger\n" \ - "\nOptions:" \ - "\n -c N Only messages with level < N are printed to console" \ - "\n -n Run in foreground" \ - -#define length_trivial_usage \ - "STRING" -#define length_full_usage "\n\n" \ - "Print STRING's length" - -#define length_example_usage \ - "$ length Hello\n" \ - "5\n" - -#define less_trivial_usage \ - "[-EMNmh~I?] [FILE]..." -#define less_full_usage "\n\n" \ - "View FILE (or stdin) one screenful at a time\n" \ - "\nOptions:" \ - "\n -E Quit once the end of a file is reached" \ - "\n -M,-m Display status line with line numbers" \ - "\n and percentage through the file" \ - "\n -N Prefix line number to each line" \ - "\n -I Ignore case in all searches" \ - "\n -~ Suppress ~s displayed past the end of the file" \ - -#define linux32_trivial_usage NOUSAGE_STR -#define linux32_full_usage "" -#define linux64_trivial_usage NOUSAGE_STR -#define linux64_full_usage "" - -#define linuxrc_trivial_usage NOUSAGE_STR -#define linuxrc_full_usage "" - -#define setarch_trivial_usage \ - "personality PROG ARGS" -#define setarch_full_usage "\n\n" \ - "Personality may be:\n" \ - " linux32 Set 32bit uname emulation\n" \ - " linux64 Set 64bit uname emulation" \ - -#define ln_trivial_usage \ - "[OPTIONS] TARGET... LINK|DIR" -#define ln_full_usage "\n\n" \ - "Create a link LINK or DIR/TARGET to the specified TARGET(s)\n" \ - "\nOptions:" \ - "\n -s Make symlinks instead of hardlinks" \ - "\n -f Remove existing destinations" \ - "\n -n Don't dereference symlinks - treat like normal file" \ - "\n -b Make a backup of the target (if exists) before link operation" \ - "\n -S suf Use suffix instead of ~ when making backup files" \ - -#define ln_example_usage \ - "$ ln -s BusyBox /tmp/ls\n" \ - "$ ls -l /tmp/ls\n" \ - "lrwxrwxrwx 1 root root 7 Apr 12 18:39 ls -> BusyBox*\n" - -#define load_policy_trivial_usage NOUSAGE_STR -#define load_policy_full_usage "" - -#define loadfont_trivial_usage \ - "< font" -#define loadfont_full_usage "\n\n" \ - "Load a console font from stdin" \ -/* "\n -C TTY Affect TTY instead of /dev/tty" */ \ - -#define loadfont_example_usage \ - "$ loadfont < /etc/i18n/fontname\n" - -#define loadkmap_trivial_usage \ - "< keymap" -#define loadkmap_full_usage "\n\n" \ - "Load a binary keyboard translation table from stdin\n" \ -/* "\n -C TTY Affect TTY instead of /dev/tty" */ \ - -#define loadkmap_example_usage \ - "$ loadkmap < /etc/i18n/lang-keymap\n" - -#define logger_trivial_usage \ - "[OPTIONS] [MESSAGE]" -#define logger_full_usage "\n\n" \ - "Write MESSAGE (or stdin) to syslog\n" \ - "\nOptions:" \ - "\n -s Log to stderr as well as the system log" \ - "\n -t TAG Log using the specified tag (defaults to user name)" \ - "\n -p PRIO Priority (numeric or facility.level pair)" \ - -#define logger_example_usage \ - "$ logger \"hello\"\n" - -#define login_trivial_usage \ - "[-p] [-h HOST] [[-f] USER]" -#define login_full_usage "\n\n" \ - "Begin a new session on the system\n" \ - "\nOptions:" \ - "\n -f Don't authenticate (user already authenticated)" \ - "\n -h Name of the remote host" \ - "\n -p Preserve environment" \ - -#define logname_trivial_usage \ - "" -#define logname_full_usage "\n\n" \ - "Print the name of the current user" -#define logname_example_usage \ - "$ logname\n" \ - "root\n" - -#define logread_trivial_usage \ - "[OPTIONS]" -#define logread_full_usage "\n\n" \ - "Show messages in syslogd's circular buffer\n" \ - "\nOptions:" \ - "\n -f Output data as log grows" \ - -#define losetup_trivial_usage \ - "[-o OFS] LOOPDEV FILE - associate loop devices\n" \ - " losetup -d LOOPDEV - disassociate\n" \ - " losetup [-f] - show" -#define losetup_full_usage "\n\n" \ - "Options:" \ - "\n -o OFS Start OFS bytes into FILE" \ - "\n -f Show first free loop device" \ - -#define losetup_notes_usage \ - "No arguments will display all current associations.\n" \ - "One argument (losetup /dev/loop1) will display the current association\n" \ - "(if any), or disassociate it (with -d). The display shows the offset\n" \ - "and filename of the file the loop device is currently bound to.\n\n" \ - "Two arguments (losetup /dev/loop1 file.img) create a new association,\n" \ - "with an optional offset (-o 12345). Encryption is not yet supported.\n" \ - "losetup -f will show the first loop free loop device\n\n" - -#define lpd_trivial_usage \ - "SPOOLDIR [HELPER [ARGS]]" -#define lpd_full_usage "\n\n" \ - "SPOOLDIR must contain (symlinks to) device nodes or directories" \ - "\nwith names matching print queue names. In the first case, jobs are" \ - "\nsent directly to the device. Otherwise each job is stored in queue" \ - "\ndirectory and HELPER program is called. Name of file to print" \ - "\nis passed in $DATAFILE variable." \ - "\nExample:" \ - "\n tcpsvd -E 0 515 softlimit -m 999999 lpd /var/spool ./print" \ - -#define lpq_trivial_usage \ - "[-P queue[@host[:port]]] [-U USERNAME] [-d JOBID]... [-fs]" -#define lpq_full_usage "\n\n" \ - "Options:" \ - "\n -P lp service to connect to (else uses $PRINTER)" \ - "\n -d Delete jobs" \ - "\n -f Force any waiting job to be printed" \ - "\n -s Short display" \ - -#define lpr_trivial_usage \ - "-P queue[@host[:port]] -U USERNAME -J TITLE -Vmh [FILE]..." -/* -C CLASS exists too, not shown. - * CLASS is supposed to be printed on banner page, if one is requested */ -#define lpr_full_usage "\n\n" \ - "Options:" \ - "\n -P lp service to connect to (else uses $PRINTER)"\ - "\n -m Send mail on completion" \ - "\n -h Print banner page too" \ - "\n -V Verbose" \ - -#define ls_trivial_usage \ - "[-1Aa" IF_FEATURE_LS_TIMESTAMPS("c") "Cd" \ - IF_FEATURE_LS_TIMESTAMPS("e") IF_FEATURE_LS_FILETYPES("F") "iln" \ - IF_FEATURE_LS_FILETYPES("p") IF_FEATURE_LS_FOLLOWLINKS("L") \ - IF_FEATURE_LS_RECURSIVE("R") IF_FEATURE_LS_SORTFILES("rS") "s" \ - IF_FEATURE_AUTOWIDTH("T") IF_FEATURE_LS_TIMESTAMPS("tu") \ - IF_FEATURE_LS_SORTFILES("v") IF_FEATURE_AUTOWIDTH("w") "x" \ - IF_FEATURE_LS_SORTFILES("X") IF_FEATURE_HUMAN_READABLE("h") "k" \ - IF_SELINUX("K") "] [FILE]..." -#define ls_full_usage "\n\n" \ - "List directory contents\n" \ - "\nOptions:" \ - "\n -1 List in a single column" \ - "\n -A Don't list . and .." \ - "\n -a Don't hide entries starting with ." \ - "\n -C List by columns" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -c With -l: sort by ctime") \ - IF_FEATURE_LS_COLOR( \ - "\n --color[={always,never,auto}] Control coloring") \ - "\n -d List directory entries instead of contents" \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -e List full date and time") \ - IF_FEATURE_LS_FILETYPES( \ - "\n -F Append indicator (one of */=@|) to entries") \ - "\n -i List inode numbers" \ - "\n -l Long listing format" \ - "\n -n List numeric UIDs and GIDs instead of names" \ - IF_FEATURE_LS_FILETYPES( \ - "\n -p Append indicator (one of /=@|) to entries") \ - IF_FEATURE_LS_FOLLOWLINKS( \ - "\n -L List entries pointed to by symlinks") \ - IF_FEATURE_LS_RECURSIVE( \ - "\n -R Recurse") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -r Sort in reverse order") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -S Sort by file size") \ - "\n -s List the size of each file, in blocks" \ - IF_FEATURE_AUTOWIDTH( \ - "\n -T N Assume tabstop every N columns") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -t With -l: sort by modification time") \ - IF_FEATURE_LS_TIMESTAMPS( \ - "\n -u With -l: sort by access time") \ - IF_FEATURE_LS_SORTFILES( \ - "\n -v Sort by version") \ - IF_FEATURE_AUTOWIDTH( \ - "\n -w N Assume the terminal is N columns wide") \ - "\n -x List by lines" \ - IF_FEATURE_LS_SORTFILES( \ - "\n -X Sort by extension") \ - IF_FEATURE_HUMAN_READABLE( \ - "\n -h List sizes in human readable format (1K 243M 2G)") \ - IF_SELINUX( \ - "\n -k List security context") \ - IF_SELINUX( \ - "\n -K List security context in long format") \ - IF_SELINUX( \ - "\n -Z List security context and permission") \ - -#define lsattr_trivial_usage \ - "[-Radlv] [FILE]..." -#define lsattr_full_usage "\n\n" \ - "List file attributes on an ext2 fs\n" \ - "\nOptions:" \ - "\n -R Recurse" \ - "\n -a Don't hide entries starting with ." \ - "\n -d List directory entries instead of contents" \ - "\n -l List long flag names" \ - "\n -v List the file's version/generation number" \ - -#define lsmod_trivial_usage \ - "" -#define lsmod_full_usage "\n\n" \ - "List the currently loaded kernel modules" - -#define lspci_trivial_usage \ - "[-mk]" -#define lspci_full_usage "\n\n" \ - "List all PCI devices" \ - "\n" \ - "\n -m Parseable output" \ - "\n -k Show driver" \ - -#define lsusb_trivial_usage NOUSAGE_STR -#define lsusb_full_usage "" - -#if ENABLE_FEATURE_MAKEDEVS_LEAF -#define makedevs_trivial_usage \ - "NAME TYPE MAJOR MINOR FIRST LAST [s]" -#define makedevs_full_usage "\n\n" \ - "Create a range of block or character special files" \ - "\n" \ - "\nTYPE is:" \ - "\n b Block device" \ - "\n c Character device" \ - "\n f FIFO, MAJOR and MINOR are ignored" \ - "\n" \ - "\nFIRST..LAST specify numbers appended to NAME." \ - "\nIf 's' is the last argument, the base device is created as well." \ - "\n" \ - "\nExamples:" \ - "\n makedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63" \ - "\n makedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" -#define makedevs_example_usage \ - "# makedevs /dev/ttyS c 4 66 2 63\n" \ - "[creates ttyS2-ttyS63]\n" \ - "# makedevs /dev/hda b 3 0 0 8 s\n" \ - "[creates hda,hda1-hda8]\n" -#endif - -#if ENABLE_FEATURE_MAKEDEVS_TABLE -#define makedevs_trivial_usage \ - "[-d device_table] rootdir" -#define makedevs_full_usage "\n\n" \ - "Create a range of special files as specified in a device table.\n" \ - "Device table entries take the form of:\n" \ - " \n" \ - "Where name is the file name, type can be one of:\n" \ - " f Regular file\n" \ - " d Directory\n" \ - " c Character device\n" \ - " b Block device\n" \ - " p Fifo (named pipe)\n" \ - "uid is the user id for the target file, gid is the group id for the\n" \ - "target file. The rest of the entries (major, minor, etc) apply to\n" \ - "to device special files. A '-' may be used for blank entries." -#define makedevs_example_usage \ - "For example:\n" \ - " \n" \ - "/dev d 755 0 0 - - - - -\n" \ - "/dev/console c 666 0 0 5 1 - - -\n" \ - "/dev/null c 666 0 0 1 3 0 0 -\n" \ - "/dev/zero c 666 0 0 1 5 0 0 -\n" \ - "/dev/hda b 640 0 0 3 0 0 0 -\n" \ - "/dev/hda b 640 0 0 3 1 1 1 15\n\n" \ - "Will Produce:\n" \ - "/dev\n" \ - "/dev/console\n" \ - "/dev/null\n" \ - "/dev/zero\n" \ - "/dev/hda\n" \ - "/dev/hda[0-15]\n" -#endif - -#define makemime_trivial_usage \ - "[OPTIONS] [FILE]..." -#define makemime_full_usage "\n\n" \ - "Create multipart MIME-encoded message from FILEs\n" \ -/* "Transfer encoding is base64, disposition is inline (not attachment)\n" */ \ - "\nOptions:" \ - "\n -o FILE Output. Default: stdout" \ - "\n -a HDR Add header. Examples:" \ - "\n \"From: user@host.org\", \"Date: `date -R`\"" \ - "\n -c CT Content type. Default: text/plain" \ - "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET \ -/* "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ \ - "\n" \ - "\nOther options are silently ignored" \ - -#define man_trivial_usage \ - "[OPTIONS] [MANPAGE]..." -#define man_full_usage "\n\n" \ - "Format and display manual page\n" \ - "\nOptions:" \ - "\n -a Display all pages" \ - "\n -w Show page locations" \ - -#define matchpathcon_trivial_usage \ - "[-n] [-N] [-f file_contexts_file] [-p prefix] [-V]" -#define matchpathcon_full_usage "\n\n" \ - " -n Don't display path" \ - "\n -N Don't use translations" \ - "\n -f Use alternate file_context file" \ - "\n -p Use prefix to speed translations" \ - "\n -V Verify file context on disk matches defaults" \ - -#define md5sum_trivial_usage \ - "[OPTIONS] [FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: md5sum [OPTIONS] -c [FILE]") -#define md5sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define md5sum_example_usage \ - "$ md5sum < busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003\n" \ - "$ md5sum busybox\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "$ md5sum -c -\n" \ - "6fd11e98b98a58f64ff3398d7b324003 busybox\n" \ - "busybox: OK\n" \ - "^D\n" - -#define sha1sum_trivial_usage \ - "[OPTIONS] [FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha1sum [OPTIONS] -c [FILE]") -#define sha1sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define sha256sum_trivial_usage \ - "[OPTIONS] [FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha256sum [OPTIONS] -c [FILE]") -#define sha256sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA256 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define sha512sum_trivial_usage \ - "[OPTIONS] [FILE]..." \ - IF_FEATURE_MD5_SHA1_SUM_CHECK("\n or: sha512sum [OPTIONS] -c [FILE]") -#define sha512sum_full_usage "\n\n" \ - "Print" IF_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA512 checksums" \ - IF_FEATURE_MD5_SHA1_SUM_CHECK( "\n" \ - "\nOptions:" \ - "\n -c Check sums against given list" \ - "\n -s Don't output anything, status code shows success" \ - "\n -w Warn about improperly formatted checksum lines" \ - ) - -#define mdev_trivial_usage \ - "[-s]" -#define mdev_full_usage "\n\n" \ - " -s Scan /sys and populate /dev during system boot\n" \ - "\n" \ - "It can be run by kernel as a hotplug helper. To activate it:\n" \ - " echo /sbin/mdev > /proc/sys/kernel/hotplug\n" \ - IF_FEATURE_MDEV_CONF( \ - "It uses /etc/mdev.conf with lines\n" \ - "[-]DEVNAME UID:GID PERM" \ - IF_FEATURE_MDEV_RENAME(" [>|=PATH]") \ - IF_FEATURE_MDEV_EXEC(" [@|$|*PROG]") \ - ) \ - -#define mdev_notes_usage "" \ - IF_FEATURE_MDEV_CONFIG( \ - "The mdev config file contains lines that look like:\n" \ - " hd[a-z][0-9]* 0:3 660\n\n" \ - "That's device name (with regex match), uid:gid, and permissions.\n\n" \ - IF_FEATURE_MDEV_EXEC( \ - "Optionally, that can be followed (on the same line) by a special character\n" \ - "and a command line to run after creating/before deleting the corresponding\n" \ - "device(s). The environment variable $MDEV indicates the active device node\n" \ - "(which is useful if it's a regex match). For example:\n\n" \ - " hdc root:cdrom 660 *ln -s $MDEV cdrom\n\n" \ - "The special characters are @ (run after creating), $ (run before deleting),\n" \ - "and * (run both after creating and before deleting). The commands run in\n" \ - "the /dev directory, and use system() which calls /bin/sh.\n\n" \ - ) \ - "Config file parsing stops on the first matching line. If no config\n" \ - "entry is matched, devices are created with default 0:0 660. (Make\n" \ - "the last line match .* to override this.)\n\n" \ - ) - -#define mesg_trivial_usage \ - "[y|n]" -#define mesg_full_usage "\n\n" \ - "Control write access to your terminal\n" \ - " y Allow write access to your terminal\n" \ - " n Disallow write access to your terminal" - -#define microcom_trivial_usage \ - "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY" -#define microcom_full_usage "\n\n" \ - "Copy bytes for stdin to TTY and from TTY to stdout\n" \ - "\nOptions:" \ - "\n -d Wait up to DELAY ms for TTY output before sending every" \ - "\n next byte to it" \ - "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms" \ - "\n -s Set serial line to SPEED" \ - "\n -X Disable special meaning of NUL and Ctrl-X from stdin" \ - -#define mkdir_trivial_usage \ - "[OPTIONS] DIRECTORY..." -#define mkdir_full_usage "\n\n" \ - "Create DIRECTORY\n" \ - "\nOptions:" \ - "\n -m Mode" \ - "\n -p No error if exists; make parent directories as needed" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -#define mkdir_example_usage \ - "$ mkdir /tmp/foo\n" \ - "$ mkdir /tmp/foo\n" \ - "/tmp/foo: File exists\n" \ - "$ mkdir /tmp/foo/bar/baz\n" \ - "/tmp/foo/bar/baz: No such file or directory\n" \ - "$ mkdir -p /tmp/foo/bar/baz\n" - -#define mkfifo_trivial_usage \ - "[OPTIONS] name" -#define mkfifo_full_usage "\n\n" \ - "Create named pipe (identical to 'mknod name p')\n" \ - "\nOptions:" \ - "\n -m MODE Mode (default a=rw)" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -#define mkfs_ext2_trivial_usage \ - "[-Fn] " \ - /* "[-c|-l filename] " */ \ - "[-b BLK_SIZE] " \ - /* "[-f fragment-size] [-g blocks-per-group] " */ \ - "[-i INODE_RATIO] [-I INODE_SIZE] " \ - /* "[-j] [-J journal-options] [-N number-of-inodes] " */ \ - "[-m RESERVED_PERCENT] " \ - /* "[-o creator-os] [-O feature[,...]] [-q] " */ \ - /* "[r fs-revision-level] [-E extended-options] [-v] [-F] " */ \ - "[-L LABEL] " \ - /* "[-M last-mounted-directory] [-S] [-T filesystem-type] " */ \ - "BLOCKDEV [KBYTES]" -#define mkfs_ext2_full_usage "\n\n" \ - " -b BLK_SIZE Block size, bytes" \ -/* "\n -c Check device for bad blocks" */ \ -/* "\n -E opts Set extended options" */ \ -/* "\n -f size Fragment size in bytes" */ \ - "\n -F Force" \ -/* "\n -g N Number of blocks in a block group" */ \ - "\n -i RATIO Max number of files is filesystem_size / RATIO" \ - "\n -I BYTES Inode size (min 128)" \ -/* "\n -j Create a journal (ext3)" */ \ -/* "\n -J opts Set journal options (size/device)" */ \ -/* "\n -l file Read bad blocks list from file" */ \ - "\n -L LBL Volume label" \ - "\n -m PERCENT Percent of blocks to reserve for admin" \ -/* "\n -M dir Set last mounted directory" */ \ - "\n -n Dry run" \ -/* "\n -N N Number of inodes to create" */ \ -/* "\n -o os Set the 'creator os' field" */ \ -/* "\n -O features Dir_index/filetype/has_journal/journal_dev/sparse_super" */ \ -/* "\n -q Quiet" */ \ -/* "\n -r rev Set filesystem revision" */ \ -/* "\n -S Write superblock and group descriptors only" */ \ -/* "\n -T fs-type Set usage type (news/largefile/largefile4)" */ \ -/* "\n -v Verbose" */ \ - -#define mkfs_minix_trivial_usage \ - "[-c | -l FILE] [-nXX] [-iXX] BLOCKDEV [KBYTES]" -#define mkfs_minix_full_usage "\n\n" \ - "Make a MINIX filesystem\n" \ - "\nOptions:" \ - "\n -c Check device for bad blocks" \ - "\n -n [14|30] Maximum length of filenames" \ - "\n -i INODES Number of inodes for the filesystem" \ - "\n -l FILE Read bad blocks list from FILE" \ - "\n -v Make version 2 filesystem" \ - -#define mkfs_reiser_trivial_usage \ - "[-f] [-l LABEL] BLOCKDEV [4K-BLOCKS]" - -#define mkfs_reiser_full_usage "\n\n" \ - "Make a ReiserFS V3 filesystem\n" \ - "\nOptions:" \ - "\n -f Force" \ - "\n -l LBL Volume label" \ - -#define mkfs_vfat_trivial_usage \ - "[-v] [-n LABEL] BLOCKDEV [KBYTES]" -/* Accepted but ignored: - "[-c] [-C] [-I] [-l bad-block-file] [-b backup-boot-sector] " - "[-m boot-msg-file] [-i volume-id] " - "[-s sectors-per-cluster] [-S logical-sector-size] [-f number-of-FATs] " - "[-h hidden-sectors] [-F fat-size] [-r root-dir-entries] [-R reserved-sectors] " -*/ -#define mkfs_vfat_full_usage "\n\n" \ - "Make a FAT32 filesystem\n" \ - "\nOptions:" \ -/* "\n -c Check device for bad blocks" */ \ - "\n -v Verbose" \ -/* "\n -I Allow to use entire disk device (e.g. /dev/hda)" */ \ - "\n -n LBL Volume label" \ - -#define mknod_trivial_usage \ - "[OPTIONS] NAME TYPE MAJOR MINOR" -#define mknod_full_usage "\n\n" \ - "Create a special file (block, character, or pipe)\n" \ - "\nOptions:" \ - "\n -m Create the special file using the specified mode (default a=rw)" \ - "\nTYPEs include:" \ - "\n b: Make a block device" \ - "\n c or u: Make a character device" \ - "\n p: Make a named pipe (MAJOR and MINOR are ignored)" \ - IF_SELINUX( \ - "\n -Z Set security context" \ - ) - -#define mknod_example_usage \ - "$ mknod /dev/fd0 b 2 0\n" \ - "$ mknod -m 644 /tmp/pipe p\n" - -#define mkswap_trivial_usage \ - "[OPTIONS] BLOCKDEV [KBYTES]" -#define mkswap_full_usage "\n\n" \ - "Prepare BLOCKDEV to be used as swap partition\n" \ - "\nOptions:" \ - "\n -L LBL Label" \ - -#define mktemp_trivial_usage \ - "[-dt] [-p DIR] [TEMPLATE]" -#define mktemp_full_usage "\n\n" \ - "Create a temporary file with name based on TEMPLATE and print its name.\n" \ - "TEMPLATE must end with XXXXXX (e.g. [/dir/]nameXXXXXX).\n" \ - "\nOptions:" \ - "\n -d Make a directory instead of a file" \ -/* "\n -q Fail silently if an error occurs" - we ignore it */ \ - "\n -t Generate a path rooted in temporary directory" \ - "\n -p DIR Use DIR as a temporary directory (implies -t)" \ - "\n" \ - "\nFor -t or -p, directory is chosen as follows:" \ - "\n$TMPDIR if set, else -p DIR, else /tmp" \ - -#define mktemp_example_usage \ - "$ mktemp /tmp/temp.XXXXXX\n" \ - "/tmp/temp.mWiLjM\n" \ - "$ ls -la /tmp/temp.mWiLjM\n" \ - "-rw------- 1 andersen andersen 0 Apr 25 17:10 /tmp/temp.mWiLjM\n" - -#define more_trivial_usage \ - "[FILE]..." -#define more_full_usage "\n\n" \ - "View FILE (or stdin) one screenful at a time" - -#define more_example_usage \ - "$ dmesg | more\n" - -#define mount_trivial_usage \ - "[OPTIONS] [-o OPTS] DEVICE NODE" -#define mount_full_usage "\n\n" \ - "Mount a filesystem. Filesystem autodetection requires /proc.\n" \ - "\nOptions:" \ - "\n -a Mount all filesystems in fstab" \ - IF_FEATURE_MOUNT_FAKE( \ - IF_FEATURE_MTAB_SUPPORT( \ - "\n -f Update /etc/mtab, but don't mount" \ - ) \ - IF_NOT_FEATURE_MTAB_SUPPORT( \ - "\n -f Dry run" \ - ) \ - ) \ - IF_FEATURE_MOUNT_HELPERS( \ - "\n -i Don't run mount helper" \ - ) \ - IF_FEATURE_MTAB_SUPPORT( \ - "\n -n Don't update /etc/mtab" \ - ) \ - "\n -r Read-only mount" \ - "\n -w Read-write mount (default)" \ - "\n -t FSTYPE Filesystem type (supports comma-separated list of types)" \ - "\n -O OPT Mount only filesystems with option OPT (-a only)" \ - "\n-o OPT:" \ - IF_FEATURE_MOUNT_LOOP( \ - "\n loop Ignored (loop devices are autodetected)" \ - ) \ - IF_FEATURE_MOUNT_FLAGS( \ - "\n [a]sync Writes are [a]synchronous" \ - "\n [no]atime Disable/enable updates to inode access times" \ - "\n [no]diratime Disable/enable atime updates to directories" \ - "\n [no]relatime Disable/enable atime updates relative to modification time" \ - "\n [no]dev (Dis)allow use of special device files" \ - "\n [no]exec (Dis)allow use of executable files" \ - "\n [no]suid (Dis)allow set-user-id-root programs" \ - "\n [r]shared Convert [recursively] to a shared subtree" \ - "\n [r]slave Convert [recursively] to a slave subtree" \ - "\n [r]private Convert [recursively] to a private subtree" \ - "\n [un]bindable Make mount point [un]able to be bind mounted" \ - "\n bind Bind a file or directory to another location" \ - "\n move Relocate an existing mount point" \ - ) \ - "\n remount Remount a mounted filesystem, changing flags" \ - "\n ro/rw Same as -r/-w" \ - "\n" \ - "\nThere are filesystem-specific -o flags." \ - -#define mount_example_usage \ - "$ mount\n" \ - "/dev/hda3 on / type minix (rw)\n" \ - "proc on /proc type proc (rw)\n" \ - "devpts on /dev/pts type devpts (rw)\n" \ - "$ mount /dev/fd0 /mnt -t msdos -o ro\n" \ - "$ mount /tmp/diskimage /opt -t ext2 -o loop\n" \ - "$ mount cd_image.iso mydir\n" -#define mount_notes_usage \ - "Returns 0 for success, number of failed mounts for -a, or errno for one mount." - -#define mountpoint_trivial_usage \ - "[-q] <[-dn] DIR | -x DEVICE>" -#define mountpoint_full_usage "\n\n" \ - "Check if the directory is a mountpoint\n" \ - "\nOptions:" \ - "\n -q Quiet" \ - "\n -d Print major/minor device number of the filesystem" \ - "\n -n Print device name of the filesystem" \ - "\n -x Print major/minor device number of the blockdevice" \ - -#define mountpoint_example_usage \ - "$ mountpoint /proc\n" \ - "/proc is not a mountpoint\n" \ - "$ mountpoint /sys\n" \ - "/sys is a mountpoint\n" - -#define mt_trivial_usage \ - "[-f device] opcode value" -#define mt_full_usage "\n\n" \ - "Control magnetic tape drive operation\n" \ - "\n" \ - "Available Opcodes:\n" \ - "\n" \ - "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" \ - "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" \ - "ras3 reset retension rewind rewoffline seek setblk setdensity\n" \ - "setpart tell unload unlock weof wset" \ - -#define mv_trivial_usage \ - "[OPTIONS] SOURCE DEST\n" \ - "or: mv [OPTIONS] SOURCE... DIRECTORY" -#define mv_full_usage "\n\n" \ - "Rename SOURCE to DEST, or move SOURCE(s) to DIRECTORY\n" \ - "\nOptions:" \ - "\n -f Don't prompt before overwriting" \ - "\n -i Interactive, prompt before overwrite" \ - -#define mv_example_usage \ - "$ mv /tmp/foo /bin/bar\n" - -#define nameif_trivial_usage \ - "[-s] [-c FILE] [{IFNAME MACADDR}]" -#define nameif_full_usage "\n\n" \ - "Rename network interface while it in the down state\n" \ - "\nOptions:" \ - "\n -c FILE Use configuration file (default: /etc/mactab)" \ - "\n -s Use syslog (LOCAL0 facility)" \ - "\n IFNAME MACADDR new_interface_name interface_mac_address" \ - -#define nameif_example_usage \ - "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n" \ - " or\n" \ - "$ nameif -c /etc/my_mactab_file\n" \ - -#define netstat_trivial_usage \ - "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" -#define netstat_full_usage "\n\n" \ - "Display networking information\n" \ - "\nOptions:" \ - "\n -l Display listening server sockets" \ - "\n -a Display all sockets (default: connected)" \ - "\n -e Display other/more information" \ - "\n -n Don't resolve names" \ - "\n -t Tcp sockets" \ - "\n -u Udp sockets" \ - "\n -w Raw sockets" \ - "\n -x Unix sockets" \ - "\n -r Display routing table" \ - IF_FEATURE_NETSTAT_WIDE( \ - "\n -W Display with no column truncation" \ - ) \ - IF_FEATURE_NETSTAT_PRG( \ - "\n -p Display PID/Program name for sockets" \ - ) - -#define nmeter_trivial_usage \ - "format_string" -#define nmeter_full_usage "\n\n" \ - "Monitor system in real time\n\n" \ - "Format specifiers:\n" \ - " %Nc or %[cN] Monitor CPU. N - bar size, default 10\n" \ - " (displays: S:system U:user N:niced D:iowait I:irq i:softirq)\n" \ - " %[niface] Monitor network interface 'iface'\n" \ - " %m Monitor allocated memory\n" \ - " %[mf] Monitor free memory\n" \ - " %[mt] Monitor total memory\n" \ - " %s Monitor allocated swap\n" \ - " %f Monitor number of used file descriptors\n" \ - " %Ni Monitor total/specific IRQ rate\n" \ - " %x Monitor context switch rate\n" \ - " %p Monitor forks\n" \ - " %[pn] Monitor # of processes\n" \ - " %b Monitor block io\n" \ - " %Nt Show time (with N decimal points)\n" \ - " %Nd Milliseconds between updates (default:1000)\n" \ - " %r Print instead of at EOL" \ - -#define nmeter_example_usage \ - "nmeter '%250d%t %20c int %i bio %b mem %m forks%p'" - -#define nohup_trivial_usage \ - "PROG ARGS" -#define nohup_full_usage "\n\n" \ - "Run PROG immune to hangups, with output to a non-tty" -#define nohup_example_usage \ - "$ nohup make &" - -#define nslookup_trivial_usage \ - "[HOST] [SERVER]" -#define nslookup_full_usage "\n\n" \ - "Query the nameserver for the IP address of the given HOST\n" \ - "optionally using a specified DNS server" -#define nslookup_example_usage \ - "$ nslookup localhost\n" \ - "Server: default\n" \ - "Address: default\n" \ - "\n" \ - "Name: debian\n" \ - "Address: 127.0.0.1\n" - -#define ntpd_trivial_usage \ - "[-dnqwl] [-S PROG] [-p PEER]..." -#define ntpd_full_usage "\n\n" \ - "NTP client/server\n" \ - "\nOptions:" \ - "\n -d Verbose" \ - "\n -n Do not daemonize" \ - "\n -q Quit after clock is set" \ -/* -N exists for mostly compat reasons, thus not essential to inform */ \ -/* the user that it exists: user may use nice as well */ \ -/* "\n -N Run at high priority" */ \ - "\n -w Do not set time (only query peers), implies -n" \ - "\n -l Run as server on port 123" \ - "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" \ - "\n -p PEER Obtain time from PEER (may be repeated)" \ - -#define od_trivial_usage \ - "[-aBbcDdeFfHhIiLlOovXx] " IF_DESKTOP("[-t TYPE] ") "[FILE]" -#define od_full_usage "\n\n" \ - "Write an unambiguous representation, octal bytes by default, of FILE\n" \ - "(or stdin) to stdout" - -#define openvt_trivial_usage \ - "[-c N] [-sw] [PROG ARGS]" -#define openvt_full_usage "\n\n" \ - "Start PROG on a new virtual terminal\n" \ - "\nOptions:" \ - "\n -c N Use specified VT" \ - "\n -s Switch to the VT" \ -/* "\n -l Run PROG as login shell (by prepending '-')" */ \ - "\n -w Wait for PROG to exit" \ - -#define openvt_example_usage \ - "openvt 2 /bin/ash\n" - -/* -#define parse_trivial_usage \ - "[-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..." -#define parse_full_usage "" -*/ - -#define passwd_trivial_usage \ - "[OPTIONS] [USER]" -#define passwd_full_usage "\n\n" \ - "Change USER's password. If no USER is specified,\n" \ - "changes the password for the current user.\n" \ - "\nOptions:" \ - "\n -a Algorithm to use for password (des, md5)" /* ", sha1)" */ \ - "\n -d Delete password for the account" \ - "\n -l Lock (disable) account" \ - "\n -u Unlock (re-enable) account" \ - -#define chpasswd_trivial_usage \ - IF_LONG_OPTS("[--md5|--encrypted]") IF_NOT_LONG_OPTS("[-m|-e]") -#define chpasswd_full_usage "\n\n" \ - "Read user:password from stdin and update /etc/passwd\n" \ - "\nOptions:" \ - IF_LONG_OPTS( \ - "\n -e,--encrypted Supplied passwords are in encrypted form" \ - "\n -m,--md5 Use MD5 encryption instead of DES" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -e Supplied passwords are in encrypted form" \ - "\n -m Use MD5 encryption instead of DES" \ - ) - -#define patch_trivial_usage \ - "[OPTIONS] [ORIGFILE [PATCHFILE]]" -#define patch_full_usage "\n\n" \ - IF_LONG_OPTS( \ - " -p,--strip N Strip N leading components from file names" \ - "\n -i,--input DIFF Read DIFF instead of stdin" \ - "\n -R,--reverse Reverse patch" \ - "\n -N,--forward Ignore already applied patches" \ - "\n --dry-run Don't actually change files" \ - ) \ - IF_NOT_LONG_OPTS( \ - " -p N Strip N leading components from file names" \ - "\n -i DIFF Read DIFF instead of stdin" \ - "\n -R Reverse patch" \ - "\n -N Ignore already applied patches" \ - ) - -#define patch_example_usage \ - "$ patch -p1 < example.diff\n" \ - "$ patch -p0 -i example.diff" - -#define pgrep_trivial_usage \ - "[-flnovx] [-s SID|-P PPID|PATTERN]" -#define pgrep_full_usage "\n\n" \ - "Display process(es) selected by regex PATTERN\n" \ - "\nOptions:" \ - "\n -l Show command name too" \ - "\n -f Match against entire command line" \ - "\n -n Show the newest process only" \ - "\n -o Show the oldest process only" \ - "\n -v Negate the match" \ - "\n -x Match whole name (not substring)" \ - "\n -s Match session ID (0 for current)" \ - "\n -P Match parent process ID" \ - -#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) -#define pidof_trivial_usage \ - "[OPTIONS] [NAME]..." -#define USAGE_PIDOF "\n\nOptions:" -#else -#define pidof_trivial_usage \ - "[NAME]..." -#define USAGE_PIDOF /* none */ -#endif -#define pidof_full_usage "\n\n" \ - "List PIDs of all processes with names that match NAMEs" \ - USAGE_PIDOF \ - IF_FEATURE_PIDOF_SINGLE( \ - "\n -s Show only one PID") \ - IF_FEATURE_PIDOF_OMIT( \ - "\n -o PID Omit given pid" \ - "\n Use %PPID to omit pid of pidof's parent") \ - -#define pidof_example_usage \ - "$ pidof init\n" \ - "1\n" \ - IF_FEATURE_PIDOF_OMIT( \ - "$ pidof /bin/sh\n20351 5973 5950\n") \ - IF_FEATURE_PIDOF_OMIT( \ - "$ pidof /bin/sh -o %PPID\n20351 5950") - -#if !ENABLE_FEATURE_FANCY_PING -#define ping_trivial_usage \ - "host" -#define ping_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts" -#define ping6_trivial_usage \ - "host" -#define ping6_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts" -#else -#define ping_trivial_usage \ - "[OPTIONS] HOST" -#define ping_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts\n" \ - "\nOptions:" \ - "\n -4, -6 Force IP or IPv6 name resolution" \ - "\n -c CNT Send only CNT pings" \ - "\n -s SIZE Send SIZE data bytes in packets (default:56)" \ - "\n -I IFACE/IP Use interface or IP address as source" \ - "\n -W SEC Seconds to wait for the first response (default:10)" \ - "\n (after all -c CNT packets are sent)" \ - "\n -w SEC Seconds until ping exits (default:infinite)" \ - "\n (can exit earlier with -c CNT)" \ - "\n -q Quiet, only displays output at start" \ - "\n and when finished" \ - -#define ping6_trivial_usage \ - "[OPTIONS] HOST" -#define ping6_full_usage "\n\n" \ - "Send ICMP ECHO_REQUEST packets to network hosts\n" \ - "\nOptions:" \ - "\n -c CNT Send only CNT pings" \ - "\n -s SIZE Send SIZE data bytes in packets (default:56)" \ - "\n -I IFACE/IP Use interface or IP address as source" \ - "\n -q Quiet, only displays output at start" \ - "\n and when finished" \ - -#endif -#define ping_example_usage \ - "$ ping localhost\n" \ - "PING slag (127.0.0.1): 56 data bytes\n" \ - "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" \ - "\n" \ - "--- debian ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" -#define ping6_example_usage \ - "$ ping6 ip6-localhost\n" \ - "PING ip6-localhost (::1): 56 data bytes\n" \ - "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" \ - "\n" \ - "--- ip6-localhost ping statistics ---\n" \ - "1 packets transmitted, 1 packets received, 0% packet loss\n" \ - "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" - -#define pipe_progress_trivial_usage NOUSAGE_STR -#define pipe_progress_full_usage "" - -#define pivot_root_trivial_usage \ - "NEW_ROOT PUT_OLD" -#define pivot_root_full_usage "\n\n" \ - "Move the current root file system to PUT_OLD and make NEW_ROOT\n" \ - "the new root file system" - -#define pkill_trivial_usage \ - "[-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]" -#define pkill_full_usage "\n\n" \ - "Send a signal to process(es) selected by regex PATTERN\n" \ - "\nOptions:" \ - "\n -l List all signals" \ - "\n -f Match against entire command line" \ - "\n -n Signal the newest process only" \ - "\n -o Signal the oldest process only" \ - "\n -v Negate the match" \ - "\n -x Match whole name (not substring)" \ - "\n -s Match session ID (0 for current)" \ - "\n -P Match parent process ID" \ - -#define popmaildir_trivial_usage \ - "[OPTIONS] MAILDIR [CONN_HELPER ARGS]" -#define popmaildir_full_usage "\n\n" \ - "Fetch content of remote mailbox to local maildir\n" \ - "\nOptions:" \ -/* "\n -b Binary mode. Ignored" */ \ -/* "\n -d Debug. Ignored" */ \ -/* "\n -m Show used memory. Ignored" */ \ -/* "\n -V Show version. Ignored" */ \ -/* "\n -c Use tcpclient. Ignored" */ \ -/* "\n -a Use APOP protocol. Implied. If server supports APOP -> use it" */ \ - "\n -s Skip authorization" \ - "\n -T Get messages with TOP instead of RETR" \ - "\n -k Keep retrieved messages on the server" \ - "\n -t SEC Network timeout" \ - IF_FEATURE_POPMAILDIR_DELIVERY( \ - "\n -F \"PROG ARGS\" Filter program (may be repeated)" \ - "\n -M \"PROG ARGS\" Delivery program" \ - ) \ - "\n" \ - "\nFetch from plain POP3 server:" \ - "\npopmaildir -k DIR nc pop3.server.com 110 = BYTES. Ignored" */ -/* "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" */ -/* "\n -L BYTES Don't retrieve new messages >= BYTES. Ignored" */ -/* "\n -H LINES Type first LINES of a message. Ignored" */ -#define popmaildir_example_usage \ - "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [ after signal is processed" \ - -#define rx_trivial_usage \ - "FILE" -#define rx_full_usage "\n\n" \ - "Receive a file using the xmodem protocol" -#define rx_example_usage \ - "$ rx /tmp/foo\n" - -#define script_trivial_usage \ - "[-afq" IF_SCRIPTREPLAY("t") "] [-c PROG] [OUTFILE]" -#define script_full_usage "\n\n" \ - "Options:" \ - "\n -a Append output" \ - "\n -c PROG Run PROG, not shell" \ - "\n -f Flush output after each write" \ - "\n -q Quiet" \ - IF_SCRIPTREPLAY( \ - "\n -t Send timing to stderr" \ - ) - -#define sed_trivial_usage \ - "[-efinr] SED_CMD [FILE]..." -#define sed_full_usage "\n\n" \ - "Options:" \ - "\n -e CMD Add CMD to sed commands to be executed" \ - "\n -f FILE Add FILE contents to sed commands to be executed" \ - "\n -i Edit files in-place (else sends result to stdout)" \ - "\n -n Suppress automatic printing of pattern space" \ - "\n -r Use extended regex syntax" \ - "\n" \ - "\nIf no -e or -f, the first non-option argument is the sed command string." \ - "\nRemaining arguments are input files (stdin if none)." - -#define sed_example_usage \ - "$ echo \"foo\" | sed -e 's/f[a-zA-Z]o/bar/g'\n" \ - "bar\n" - -#define selinuxenabled_trivial_usage NOUSAGE_STR -#define selinuxenabled_full_usage "" - -#define sendmail_trivial_usage \ - "[OPTIONS] [RECIPIENT_EMAIL]..." -#define sendmail_full_usage "\n\n" \ - "Read email from stdin and send it\n" \ - "\nStandard options:" \ - "\n -t Read additional recipients from message body" \ - "\n -f sender Sender (required)" \ - "\n -o options Various options. -oi implied, others are ignored" \ - "\n -i -oi synonym. implied and ignored" \ - "\n" \ - "\nBusybox specific options:" \ - "\n -w seconds Network timeout" \ - "\n -H 'PROG ARGS' Run connection helper" \ - "\n Examples:" \ - "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" \ - "\n -connect smtp.gmail.com:25' -ap]" \ - "\n -H 'exec openssl s_client -quiet -tls1" \ - "\n -connect smtp.gmail.com:465' -ap]" \ - "\n -S server[:port] Server" \ - "\n -au Username for AUTH LOGIN" \ - "\n -ap Password for AUTH LOGIN" \ - "\n -am Authentication method. Ignored. LOGIN is implied" \ - "\n" \ - "\nOther options are silently ignored; -oi -t is implied" \ - IF_MAKEMIME( \ - "\nUse makemime applet to create message with attachments" \ - ) - -#define seq_trivial_usage \ - "[-w] [-s SEP] [FIRST [INC]] LAST" -#define seq_full_usage "\n\n" \ - "Print numbers from FIRST to LAST, in steps of INC.\n" \ - "FIRST, INC default to 1.\n" \ - "\nOptions:" \ - "\n -w Pad to last with leading zeros" \ - "\n -s SEP String separator" \ - -#define sestatus_trivial_usage \ - "[-vb]" -#define sestatus_full_usage "\n\n" \ - " -v Verbose" \ - "\n -b Display current state of booleans" \ - -#define setconsole_trivial_usage \ - "[-r" IF_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]" -#define setconsole_full_usage "\n\n" \ - "Redirect system console output to DEVICE (default: /dev/tty)\n" \ - "\nOptions:" \ - "\n -r Reset output to /dev/console" \ - -#define setenforce_trivial_usage \ - "[Enforcing | Permissive | 1 | 0]" -#define setenforce_full_usage "" - -#define setfiles_trivial_usage \ - "[-dnpqsvW] [-e DIR]... [-o FILE] [-r alt_root_path]" \ - IF_FEATURE_SETFILES_CHECK_OPTION( \ - " [-c policyfile] spec_file" \ - ) \ - " pathname" -#define setfiles_full_usage "\n\n" \ - "Reset file contexts under pathname according to spec_file\n" \ - IF_FEATURE_SETFILES_CHECK_OPTION( \ - "\n -c FILE Check the validity of the contexts against the specified binary policy" \ - ) \ - "\n -d Show which specification matched each file" \ - "\n -l Log changes in file labels to syslog" \ - "\n -n Don't change any file labels" \ - "\n -q Suppress warnings" \ - "\n -r DIR Use an alternate root path" \ - "\n -e DIR Exclude DIR" \ - "\n -F Force reset of context to match file_context for customizable files" \ - "\n -o FILE Save list of files with incorrect context" \ - "\n -s Take a list of files from stdin (instead of command line)" \ - "\n -v Show changes in file labels, if type or role are changing" \ - "\n -vv Show changes in file labels, if type, role, or user are changing" \ - "\n -W Display warnings about entries that had no matching files" \ - -#define setfont_trivial_usage \ - "FONT [-m MAPFILE] [-C TTY]" -#define setfont_full_usage "\n\n" \ - "Load a console font\n" \ - "\nOptions:" \ - "\n -m MAPFILE Load console screen map" \ - "\n -C TTY Affect TTY instead of /dev/tty" \ - -#define setfont_example_usage \ - "$ setfont -m koi8-r /etc/i18n/fontname\n" - -#define setkeycodes_trivial_usage \ - "SCANCODE KEYCODE..." -#define setkeycodes_full_usage "\n\n" \ - "Set entries into the kernel's scancode-to-keycode map,\n" \ - "allowing unusual keyboards to generate usable keycodes.\n\n" \ - "SCANCODE may be either xx or e0xx (hexadecimal),\n" \ - "and KEYCODE is given in decimal." \ - -#define setkeycodes_example_usage \ - "$ setkeycodes e030 127\n" - -#define setlogcons_trivial_usage \ - "N" -#define setlogcons_full_usage "\n\n" \ - "Redirect the kernel output to console N (0 for current)" - -#define setsebool_trivial_usage \ - "boolean value" - -#define setsebool_full_usage "\n\n" \ - "Change boolean setting" - -#define setsid_trivial_usage \ - "PROG ARGS" -#define setsid_full_usage "\n\n" \ - "Run PROG in a new session. PROG will have no controlling terminal\n" \ - "and will not be affected by keyboard signals (Ctrl-C etc).\n" \ - "See setsid(2) for details." \ - -#define last_trivial_usage \ - ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]") -#define last_full_usage "\n\n" \ - "Show listing of the last users that logged into the system" \ - IF_FEATURE_LAST_FANCY( "\n" \ - "\nOptions:" \ -/* "\n -H Show header line" */ \ - "\n -W Display with no host column truncation" \ - "\n -f FILE Read from FILE instead of /var/log/wtmp" \ - ) - -#define showkey_trivial_usage \ - "[-a | -k | -s]" -#define showkey_full_usage "\n\n" \ - "Show keys pressed\n" \ - "\nOptions:" \ - "\n -a Display decimal/octal/hex values of the keys" \ - "\n -k Display interpreted keycodes (default)" \ - "\n -s Display raw scan-codes" \ - -#define slattach_trivial_usage \ - "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" -#define slattach_full_usage "\n\n" \ - "Attach network interface(s) to serial line(s)\n" \ - "\nOptions:" \ - "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" \ - "\n -s SPD Set line speed" \ - "\n -e Exit after initializing device" \ - "\n -h Exit when the carrier is lost" \ - "\n -c PROG Run PROG when the line is hung up" \ - "\n -m Do NOT initialize the line in raw 8 bits mode" \ - "\n -L Enable 3-wire operation" \ - "\n -F Disable RTS/CTS flow control" \ - -#define sleep_trivial_usage \ - IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...") -#define sleep_full_usage "\n\n" \ - IF_NOT_FEATURE_FANCY_SLEEP("Pause for N seconds") \ - IF_FEATURE_FANCY_SLEEP( \ - "Pause for a time equal to the total of the args given, where each arg can\n" \ - "have an optional suffix of (s)econds, (m)inutes, (h)ours, or (d)ays") -#define sleep_example_usage \ - "$ sleep 2\n" \ - "[2 second delay results]\n" \ - IF_FEATURE_FANCY_SLEEP( \ - "$ sleep 1d 3h 22m 8s\n" \ - "[98528 second delay results]\n") - -#define sort_trivial_usage \ - "[-nru" \ - IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") \ - "] [FILE]..." -#define sort_full_usage "\n\n" \ - "Sort lines of text\n" \ - "\nOptions:" \ - IF_FEATURE_SORT_BIG( \ - "\n -b Ignore leading blanks" \ - "\n -c Check whether input is sorted" \ - "\n -d Dictionary order (blank or alphanumeric only)" \ - "\n -f Ignore case" \ - "\n -g General numerical sort" \ - "\n -i Ignore unprintable characters" \ - "\n -k Sort key" \ - "\n -M Sort month" \ - ) \ - "\n -n Sort numbers" \ - IF_FEATURE_SORT_BIG( \ - "\n -o Output to file" \ - "\n -k Sort by key" \ - "\n -t CHAR Key separator" \ - ) \ - "\n -r Reverse sort order" \ - IF_FEATURE_SORT_BIG( \ - "\n -s Stable (don't sort ties alphabetically)" \ - ) \ - "\n -u Suppress duplicate lines" \ - IF_FEATURE_SORT_BIG( \ - "\n -z Lines are terminated by NUL, not newline" \ - "\n -mST Ignored for GNU compatibility") \ - -#define sort_example_usage \ - "$ echo -e \"e\\nf\\nb\\nd\\nc\\na\" | sort\n" \ - "a\n" \ - "b\n" \ - "c\n" \ - "d\n" \ - "e\n" \ - "f\n" \ - IF_FEATURE_SORT_BIG( \ - "$ echo -e \"c 3\\nb 2\\nd 2\" | $SORT -k 2,2n -k 1,1r\n" \ - "d 2\n" \ - "b 2\n" \ - "c 3\n" \ - ) \ - "" - -#define split_trivial_usage \ - "[OPTIONS] [INPUT [PREFIX]]" -#define split_full_usage "\n\n" \ - "Options:" \ - "\n -b n[k|m] Split by bytes" \ - "\n -l n Split by lines" \ - "\n -a n Use n letters as suffix" \ - -#define split_example_usage \ - "$ split TODO foo\n" \ - "$ cat TODO | split -a 2 -l 2 TODO_\n" - -#define start_stop_daemon_trivial_usage \ - "[OPTIONS] [-S|-K] ... [-- ARGS...]" -#define start_stop_daemon_full_usage "\n\n" \ - "Search for matching processes, and then\n" \ - "-K: stop all matching processes.\n" \ - "-S: start a process unless a matching process is found.\n" \ - IF_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \ - "\nProcess matching:" \ - "\n -u,--user USERNAME|UID Match only this user's processes" \ - "\n -n,--name NAME Match processes with NAME" \ - "\n in comm field in /proc/PID/stat" \ - "\n -x,--exec EXECUTABLE Match processes with this command" \ - "\n in /proc/PID/cmdline" \ - "\n -p,--pidfile FILE Match a process with PID from the file" \ - "\n All specified conditions must match" \ - "\n-S only:" \ - "\n -x,--exec EXECUTABLE Program to run" \ - "\n -a,--startas NAME Zeroth argument" \ - "\n -b,--background Background" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -N,--nicelevel N Change nice level" \ - ) \ - "\n -c,--chuid USER[:[GRP]] Change to user/group" \ - "\n -m,--make-pidfile Write PID to the pidfile specified by -p" \ - "\n-K only:" \ - "\n -s,--signal SIG Signal to send" \ - "\n -t,--test Match only, exit with 0 if a process is found" \ - "\nOther:" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -o,--oknodo Exit with status 0 if nothing is done" \ - "\n -v,--verbose Verbose" \ - ) \ - "\n -q,--quiet Quiet" \ - ) \ - IF_NOT_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \ - "\nProcess matching:" \ - "\n -u USERNAME|UID Match only this user's processes" \ - "\n -n NAME Match processes with NAME" \ - "\n in comm field in /proc/PID/stat" \ - "\n -x EXECUTABLE Match processes with this command" \ - "\n command in /proc/PID/cmdline" \ - "\n -p FILE Match a process with PID from the file" \ - "\n All specified conditions must match" \ - "\n-S only:" \ - "\n -x EXECUTABLE Program to run" \ - "\n -a NAME Zeroth argument" \ - "\n -b Background" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -N N Change nice level" \ - ) \ - "\n -c USER[:[GRP]] Change to user/group" \ - "\n -m Write PID to the pidfile specified by -p" \ - "\n-K only:" \ - "\n -s SIG Signal to send" \ - "\n -t Match only, exit with 0 if a process is found" \ - "\nOther:" \ - IF_FEATURE_START_STOP_DAEMON_FANCY( \ - "\n -o Exit with status 0 if nothing is done" \ - "\n -v Verbose" \ - ) \ - "\n -q Quiet" \ - ) \ - -#define stat_trivial_usage \ - "[OPTIONS] FILE..." -#define stat_full_usage "\n\n" \ - "Display file (default) or filesystem status\n" \ - "\nOptions:" \ - IF_FEATURE_STAT_FORMAT( \ - "\n -c fmt Use the specified format" \ - ) \ - "\n -f Display filesystem status" \ - "\n -L Follow links" \ - "\n -t Display info in terse form" \ - IF_SELINUX( \ - "\n -Z Print security context" \ - ) \ - IF_FEATURE_STAT_FORMAT( \ - "\n\nValid format sequences for files:\n" \ - " %a Access rights in octal\n" \ - " %A Access rights in human readable form\n" \ - " %b Number of blocks allocated (see %B)\n" \ - " %B The size in bytes of each block reported by %b\n" \ - " %d Device number in decimal\n" \ - " %D Device number in hex\n" \ - " %f Raw mode in hex\n" \ - " %F File type\n" \ - " %g Group ID of owner\n" \ - " %G Group name of owner\n" \ - " %h Number of hard links\n" \ - " %i Inode number\n" \ - " %n File name\n" \ - " %N File name, with -> TARGET if symlink\n" \ - " %o I/O block size\n" \ - " %s Total size, in bytes\n" \ - " %t Major device type in hex\n" \ - " %T Minor device type in hex\n" \ - " %u User ID of owner\n" \ - " %U User name of owner\n" \ - " %x Time of last access\n" \ - " %X Time of last access as seconds since Epoch\n" \ - " %y Time of last modification\n" \ - " %Y Time of last modification as seconds since Epoch\n" \ - " %z Time of last change\n" \ - " %Z Time of last change as seconds since Epoch\n" \ - "\nValid format sequences for file systems:\n" \ - " %a Free blocks available to non-superuser\n" \ - " %b Total data blocks in file system\n" \ - " %c Total file nodes in file system\n" \ - " %d Free file nodes in file system\n" \ - " %f Free blocks in file system\n" \ - IF_SELINUX( \ - " %C Security context in selinux\n" \ - ) \ - " %i File System ID in hex\n" \ - " %l Maximum length of filenames\n" \ - " %n File name\n" \ - " %s Block size (for faster transfer)\n" \ - " %S Fundamental block size (for block counts)\n" \ - " %t Type in hex\n" \ - " %T Type in human readable form" \ - ) \ - -#define strings_trivial_usage \ - "[-afo] [-n LEN] [FILE]..." -#define strings_full_usage "\n\n" \ - "Display printable strings in a binary file\n" \ - "\nOptions:" \ - "\n -a Scan whole file (default)" \ - "\n -f Precede strings with filenames" \ - "\n -n LEN At least LEN characters form a string (default 4)" \ - "\n -o Precede strings with decimal offsets" \ - -#define stty_trivial_usage \ - "[-a|g] [-F DEVICE] [SETTING]..." -#define stty_full_usage "\n\n" \ - "Without arguments, prints baud rate, line discipline,\n" \ - "and deviations from stty sane\n" \ - "\nOptions:" \ - "\n -F DEVICE Open device instead of stdin" \ - "\n -a Print all current settings in human-readable form" \ - "\n -g Print in stty-readable form" \ - "\n [SETTING] See manpage" \ - -#define su_trivial_usage \ - "[OPTIONS] [-] [USERNAME]" -#define su_full_usage "\n\n" \ - "Change user id or become root\n" \ - "\nOptions:" \ - "\n -p,-m Preserve environment" \ - "\n -c CMD Command to pass to 'sh -c'" \ - "\n -s SH Shell to use instead of default shell" \ - -#define sulogin_trivial_usage \ - "[-t N] [TTY]" -#define sulogin_full_usage "\n\n" \ - "Single user login\n" \ - "\nOptions:" \ - "\n -t N Timeout" \ - -#define sum_trivial_usage \ - "[-rs] [FILE]..." -#define sum_full_usage "\n\n" \ - "Checksum and count the blocks in a file\n" \ - "\nOptions:" \ - "\n -r Use BSD sum algorithm (1K blocks)" \ - "\n -s Use System V sum algorithm (512byte blocks)" \ - -#define sv_trivial_usage \ - "[-v] [-w SEC] CMD SERVICE_DIR..." -#define sv_full_usage "\n\n" \ - "Control services monitored by runsv supervisor.\n" \ - "Commands (only first character is enough):\n" \ - "\n" \ - "status: query service status\n" \ - "up: if service isn't running, start it. If service stops, restart it\n" \ - "once: like 'up', but if service stops, don't restart it\n" \ - "down: send TERM and CONT signals. If ./run exits, start ./finish\n" \ - " if it exists. After it stops, don't restart service\n" \ - "exit: send TERM and CONT signals to service and log service. If they exit,\n" \ - " runsv exits too\n" \ - "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n" \ - "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service" \ - -#define svlogd_trivial_usage \ - "[-ttv] [-r C] [-R CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..." -#define svlogd_full_usage "\n\n" \ - "Continuously read log data from stdin, optionally\n" \ - "filter log messages, and write the data to one or more automatically\n" \ - "rotated logs" \ - -#define swapoff_trivial_usage \ - "[-a] [DEVICE]" -#define swapoff_full_usage "\n\n" \ - "Stop swapping on DEVICE\n" \ - "\nOptions:" \ - "\n -a Stop swapping on all swap devices" \ - -#define swapon_trivial_usage \ - "[-a]" IF_FEATURE_SWAPON_PRI(" [-p PRI]") " [DEVICE]" -#define swapon_full_usage "\n\n" \ - "Start swapping on DEVICE\n" \ - "\nOptions:" \ - "\n -a Start swapping on all swap devices" \ - IF_FEATURE_SWAPON_PRI( \ - "\n -p PRI Set swap device priority" \ - ) \ - -#define switch_root_trivial_usage \ - "[-c /dev/console] NEW_ROOT NEW_INIT [ARGS]" -#define switch_root_full_usage "\n\n" \ - "Free initramfs and switch to another root fs:\n" \ - "chroot to NEW_ROOT, delete all in /, move NEW_ROOT to /,\n" \ - "execute NEW_INIT. PID must be 1. NEW_ROOT must be a mountpoint.\n" \ - "\nOptions:" \ - "\n -c DEV Reopen stdio to DEV after switch" \ - -#define sync_trivial_usage \ - "" -#define sync_full_usage "\n\n" \ - "Write all buffered blocks to disk" - -#define fsync_trivial_usage \ - "[OPTIONS] FILE..." -#define fsync_full_usage "\n\n" \ - "Write files' buffered blocks to disk\n" \ - "\nOptions:" \ - "\n -d Avoid syncing metadata" - -#define sysctl_trivial_usage \ - "[OPTIONS] [VALUE]..." -#define sysctl_full_usage "\n\n" \ - "Configure kernel parameters at runtime\n" \ - "\nOptions:" \ - "\n -n Don't print key names" \ - "\n -e Don't warn about unknown keys" \ - "\n -w Change sysctl setting" \ - "\n -p FILE Load sysctl settings from FILE (default /etc/sysctl.conf)" \ - "\n -a Display all values" \ - "\n -A Display all values in table form" \ - -#define sysctl_example_usage \ - "sysctl [-n] [-e] variable...\n" \ - "sysctl [-n] [-e] -w variable=value...\n" \ - "sysctl [-n] [-e] -a\n" \ - "sysctl [-n] [-e] -p file (default /etc/sysctl.conf)\n" \ - "sysctl [-n] [-e] -A\n" - -#define syslogd_trivial_usage \ - "[OPTIONS]" -#define syslogd_full_usage "\n\n" \ - "System logging utility.\n" \ - "This version of syslogd ignores /etc/syslog.conf\n" \ - "\nOptions:" \ - "\n -n Run in foreground" \ - "\n -O FILE Log to given file (default:/var/log/messages)" \ - "\n -l N Set local log level" \ - "\n -S Smaller logging output" \ - IF_FEATURE_ROTATE_LOGFILE( \ - "\n -s SIZE Max size (KB) before rotate (default:200KB, 0=off)" \ - "\n -b N N rotated logs to keep (default:1, max=99, 0=purge)") \ - IF_FEATURE_REMOTE_LOG( \ - "\n -R HOST[:PORT] Log to IP or hostname on PORT (default PORT=514/UDP)" \ - "\n -L Log locally and via network (default is network only if -R)") \ - IF_FEATURE_SYSLOGD_DUP( \ - "\n -D Drop duplicates") \ - IF_FEATURE_IPC_SYSLOG( \ - "\n -C[size(KiB)] Log to shared mem buffer (read it using logread)") \ - /* NB: -Csize shouldn't have space (because size is optional) */ -/* "\n -m MIN Minutes between MARK lines (default:20, 0=off)" */ - -#define syslogd_example_usage \ - "$ syslogd -R masterlog:514\n" \ - "$ syslogd -R 192.168.1.1:601\n" - -#define tac_trivial_usage \ - "[FILE]..." -#define tac_full_usage "\n\n" \ - "Concatenate FILEs and print them in reverse" - -#define taskset_trivial_usage \ - "[-p] [MASK] [PID | PROG ARGS]" -#define taskset_full_usage "\n\n" \ - "Set or get CPU affinity\n" \ - "\nOptions:" \ - "\n -p Operate on an existing PID" \ - -#define taskset_example_usage \ - "$ taskset 0x7 ./dgemm_test&\n" \ - "$ taskset -p 0x1 $!\n" \ - "pid 4790's current affinity mask: 7\n" \ - "pid 4790's new affinity mask: 1\n" \ - "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n" \ - "pid 6671's current affinity mask: 1\n" \ - "pid 6671's new affinity mask: 1\n" \ - "$ taskset -p 1\n" \ - "pid 1's current affinity mask: 3\n" - -#define tee_trivial_usage \ - "[OPTIONS] [FILE]..." -#define tee_full_usage "\n\n" \ - "Copy stdin to each FILE, and also to stdout\n" \ - "\nOptions:" \ - "\n -a Append to the given FILEs, don't overwrite" \ - "\n -i Ignore interrupt signals (SIGINT)" \ - -#define tee_example_usage \ - "$ echo \"Hello\" | tee /tmp/foo\n" \ - "$ cat /tmp/foo\n" \ - "Hello\n" - -#if ENABLE_FEATURE_TELNET_AUTOLOGIN -#define telnet_trivial_usage \ - "[-a] [-l USER] HOST [PORT]" -#define telnet_full_usage "\n\n" \ - "Connect to telnet server\n" \ - "\nOptions:" \ - "\n -a Automatic login with $USER variable" \ - "\n -l USER Automatic login as USER" \ - -#else -#define telnet_trivial_usage \ - "HOST [PORT]" -#define telnet_full_usage "\n\n" \ - "Connect to telnet server" -#endif - -#define telnetd_trivial_usage \ - "[OPTIONS]" -#define telnetd_full_usage "\n\n" \ - "Handle incoming telnet connections" \ - IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \ - "\nOptions:" \ - "\n -l LOGIN Exec LOGIN on connect" \ - "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" \ - "\n -K Close connection as soon as login exits" \ - "\n (normally wait until all programs close slave pty)" \ - IF_FEATURE_TELNETD_STANDALONE( \ - "\n -p PORT Port to listen on" \ - "\n -b ADDR[:PORT] Address to bind to" \ - "\n -F Run in foreground" \ - "\n -i Inetd mode" \ - IF_FEATURE_TELNETD_INETD_WAIT( \ - "\n -w SEC Inetd 'wait' mode, linger time SEC" \ - "\n -S Log to syslog (implied by -i or without -F and -w)" \ - ) \ - ) - -/* "test --help" does not print help (POSIX compat), only "[ --help" does. - * We display " EXPRESSION ]" here (not " EXPRESSION") - * Unfortunately, it screws up generated BusyBox.html. TODO. */ -#define test_trivial_usage \ - "EXPRESSION ]" -#define test_full_usage "\n\n" \ - "Check file types, compare values etc. Return a 0/1 exit code\n" \ - "depending on logical value of EXPRESSION" -#define test_example_usage \ - "$ test 1 -eq 2\n" \ - "$ echo $?\n" \ - "1\n" \ - "$ test 1 -eq 1\n" \ - "$ echo $?\n" \ - "0\n" \ - "$ [ -d /etc ]\n" \ - "$ echo $?\n" \ - "0\n" \ - "$ [ -d /junk ]\n" \ - "$ echo $?\n" \ - "1\n" - -#define tc_trivial_usage \ - /*"[OPTIONS] "*/"OBJECT CMD [dev STRING]" -#define tc_full_usage "\n\n" \ - "OBJECT: {qdisc|class|filter}\n" \ - "CMD: {add|del|change|replace|show}\n" \ - "\n" \ - "qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \ - /* "[ estimator INTERVAL TIME_CONSTANT ]\n" */ \ - " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \ - " QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" \ - "qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n" \ - "class [ classid CLASSID ] [ root | parent CLASSID ]\n" \ - " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \ - "class show [ dev STRING ] [ root | parent CLASSID ]\n" \ - "filter [ pref PRIO ] [ protocol PROTO ]\n" \ - /* "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ \ - " [ root | classid CLASSID ] [ handle FILTERID ]\n" \ - " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" \ - "filter show [ dev STRING ] [ root | parent CLASSID ]" - -#define tcpsvd_trivial_usage \ - "[-hEv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] IP PORT PROG" -/* with not-implemented options: */ -/* "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */ -#define tcpsvd_full_usage "\n\n" \ - "Create TCP socket, bind to IP:PORT and listen\n" \ - "for incoming connection. Run PROG for each connection.\n" \ - "\n IP IP to listen on. '0' = all" \ - "\n PORT Port to listen on" \ - "\n PROG ARGS Program to run" \ - "\n -l NAME Local hostname (else looks up local hostname in DNS)" \ - "\n -u USER[:GRP] Change to user/group after bind" \ - "\n -c N Handle up to N connections simultaneously" \ - "\n -b N Allow a backlog of approximately N TCP SYNs" \ - "\n -C N[:MSG] Allow only up to N connections from the same IP" \ - "\n New connections from this IP address are closed" \ - "\n immediately. MSG is written to the peer before close" \ - "\n -h Look up peer's hostname" \ - "\n -E Don't set up environment variables" \ - "\n -v Verbose" \ - -#define udpsvd_trivial_usage \ - "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG" -#define udpsvd_full_usage "\n\n" \ - "Create UDP socket, bind to IP:PORT and wait\n" \ - "for incoming packets. Run PROG for each packet,\n" \ - "redirecting all further packets with same peer ip:port to it.\n" \ - "\n IP IP to listen on. '0' = all" \ - "\n PORT Port to listen on" \ - "\n PROG ARGS Program to run" \ - "\n -l NAME Local hostname (else looks up local hostname in DNS)" \ - "\n -u USER[:GRP] Change to user/group after bind" \ - "\n -c N Handle up to N connections simultaneously" \ - "\n -h Look up peer's hostname" \ - "\n -E Don't set up environment variables" \ - "\n -v Verbose" \ - -#define tftp_trivial_usage \ - "[OPTIONS] HOST [PORT]" -#define tftp_full_usage "\n\n" \ - "Transfer a file from/to tftp server\n" \ - "\nOptions:" \ - "\n -l FILE Local FILE" \ - "\n -r FILE Remote FILE" \ - IF_FEATURE_TFTP_GET( \ - "\n -g Get file" \ - ) \ - IF_FEATURE_TFTP_PUT( \ - "\n -p Put file" \ - ) \ - IF_FEATURE_TFTP_BLOCKSIZE( \ - "\n -b SIZE Transfer blocks of SIZE octets" \ - ) - -#define tftpd_trivial_usage \ - "[-cr] [-u USER] [DIR]" -#define tftpd_full_usage "\n\n" \ - "Transfer a file on tftp client's request\n" \ - "\n" \ - "tftpd should be used as an inetd service.\n" \ - "tftpd's line for inetd.conf:\n" \ - " 69 dgram udp nowait root tftpd tftpd /files/to/serve\n" \ - "It also can be ran from udpsvd:\n" \ - " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" \ - "\nOptions:" \ - "\n -r Prohibit upload" \ - "\n -c Allow file creation via upload" \ - "\n -u Access files as USER" \ - -#define time_trivial_usage \ - "[OPTIONS] PROG ARGS" -#define time_full_usage "\n\n" \ - "Run PROG, display resource usage when it exits\n" \ - "\nOptions:" \ - "\n -v Verbose" \ - -#define timeout_trivial_usage \ - "[-t SECS] [-s SIG] PROG ARGS" -#define timeout_full_usage "\n\n" \ - "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n" \ - "Defaults: SECS: 10, SIG: TERM." \ - -#define top_trivial_usage \ - "[-b] [-nCOUNT] [-dSECONDS]" IF_FEATURE_TOPMEM(" [-m]") -#define top_full_usage "\n\n" \ - "Provide a view of process activity in real time.\n" \ - "Read the status of all processes from /proc each SECONDS\n" \ - "and display a screenful of them." \ -//TODO: add options and keyboard commands - -#define touch_trivial_usage \ - "[-c] [-d DATE] FILE [FILE]..." -#define touch_full_usage "\n\n" \ - "Update the last-modified date on the given FILE[s]\n" \ - "\nOptions:" \ - "\n -c Don't create files" \ - "\n -d DT Date/time to use" \ - -#define touch_example_usage \ - "$ ls -l /tmp/foo\n" \ - "/bin/ls: /tmp/foo: No such file or directory\n" \ - "$ touch /tmp/foo\n" \ - "$ ls -l /tmp/foo\n" \ - "-rw-rw-r-- 1 andersen andersen 0 Apr 15 01:11 /tmp/foo\n" - -#define tr_trivial_usage \ - "[-cds] STRING1 [STRING2]" -#define tr_full_usage "\n\n" \ - "Translate, squeeze, or delete characters from stdin, writing to stdout\n" \ - "\nOptions:" \ - "\n -c Take complement of STRING1" \ - "\n -d Delete input characters coded STRING1" \ - "\n -s Squeeze multiple output characters of STRING2 into one character" \ - -#define tr_example_usage \ - "$ echo \"gdkkn vnqkc\" | tr [a-y] [b-z]\n" \ - "hello world\n" - -#define traceroute_trivial_usage \ - "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" \ - " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" \ - " [-z PAUSE_MSEC] HOST [BYTES]" -#define traceroute_full_usage "\n\n" \ - "Trace the route to HOST\n" \ - "\nOptions:" \ - IF_TRACEROUTE6( \ - "\n -4, -6 Force IP or IPv6 name resolution" \ - ) \ - "\n -F Set the don't fragment bit" \ - "\n -I Use ICMP ECHO instead of UDP datagrams" \ - "\n -l Display the TTL value of the returned packet" \ - "\n -d Set SO_DEBUG options to socket" \ - "\n -n Print numeric addresses" \ - "\n -r Bypass routing tables, send directly to HOST" \ - "\n -v Verbose" \ - "\n -m Max time-to-live (max number of hops)" \ - "\n -p Base UDP port number used in probes" \ - "\n (default 33434)" \ - "\n -q Number of probes per TTL (default 3)" \ - "\n -s IP address to use as the source address" \ - "\n -t Type-of-service in probe packets (default 0)" \ - "\n -w Time in seconds to wait for a response (default 3)" \ - "\n -g Loose source route gateway (8 max)" \ - -#define traceroute6_trivial_usage \ - "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" \ - " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" \ - " HOST [BYTES]" -#define traceroute6_full_usage "\n\n" \ - "Trace the route to HOST\n" \ - "\nOptions:" \ - "\n -d Set SO_DEBUG options to socket" \ - "\n -n Print numeric addresses" \ - "\n -r Bypass routing tables, send directly to HOST" \ - "\n -v Verbose" \ - "\n -m Max time-to-live (max number of hops)" \ - "\n -p Base UDP port number used in probes" \ - "\n (default is 33434)" \ - "\n -q Number of probes per TTL (default 3)" \ - "\n -s IP address to use as the source address" \ - "\n -t Type-of-service in probe packets (default 0)" \ - "\n -w Time in seconds to wait for a response (default 3)" \ - -#define true_trivial_usage \ - "" -#define true_full_usage "\n\n" \ - "Return an exit code of TRUE (0)" -#define true_example_usage \ - "$ true\n" \ - "$ echo $?\n" \ - "0\n" - -#define tty_trivial_usage \ - "" -#define tty_full_usage "\n\n" \ - "Print file name of stdin's terminal" \ - IF_INCLUDE_SUSv2( "\n" \ - "\nOptions:" \ - "\n -s Print nothing, only return exit status" \ - ) -#define tty_example_usage \ - "$ tty\n" \ - "/dev/tty2\n" - -#define ttysize_trivial_usage \ - "[w] [h]" -#define ttysize_full_usage "\n\n" \ - "Print dimension(s) of stdin's terminal, on error return 80x25" - -#define tunctl_trivial_usage \ - "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") -#define tunctl_full_usage "\n\n" \ - "Create or delete tun interfaces\n" \ - "\nOptions:" \ - "\n -f name tun device (/dev/net/tun)" \ - "\n -t name Create iface 'name'" \ - "\n -d name Delete iface 'name'" \ - IF_FEATURE_TUNCTL_UG( \ - "\n -u owner Set iface owner" \ - "\n -g group Set iface group" \ - "\n -b Brief output" \ - ) -#define tunctl_example_usage \ - "# tunctl\n" \ - "# tunctl -d tun0\n" - -#define tune2fs_trivial_usage \ -/* "[-c max-mounts-count] [-e errors-behavior] [-g group] " */ \ -/* "[-i interval[d|m|w]] [-j] [-J journal-options] [-l] [-s sparse-flag] " */ \ -/* "[-m reserved-blocks-percent] [-o [^]mount-options[,...]] " */ \ -/* "[-r reserved-blocks-count] [-u user] [-C mount-count] " */ \ - "[-L LABEL] " \ -/* "[-M last-mounted-dir] [-O [^]feature[,...]] " */ \ -/* "[-T last-check-time] [-U UUID] " */ \ - "BLOCKDEV" -#define tune2fs_full_usage "\n\n" \ - "Adjust filesystem options on ext[23] filesystems" - -#define udhcpc_trivial_usage \ - "[-fbnqvoCR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" \ - " [-H HOSTNAME] [-c CID] [-V VENDOR] [-O DHCP_OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") -#define udhcpc_full_usage "\n" \ - IF_LONG_OPTS( \ - "\n -i,--interface IFACE Interface to use (default eth0)" \ - "\n -p,--pidfile FILE Create pidfile" \ - "\n -r,--request IP IP address to request" \ - "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" \ - "\n -t,--retries N Send up to N discover packets" \ - "\n -T,--timeout N Pause between packets (default 3 seconds)" \ - "\n -A,--tryagain N Wait N seconds after failure (default 20)" \ - "\n -f,--foreground Run in foreground" \ - USE_FOR_MMU( \ - "\n -b,--background Background if lease is not obtained" \ - ) \ - "\n -S,--syslog Log to syslog too" \ - "\n -n,--now Exit if lease is not obtained" \ - "\n -q,--quit Exit after obtaining lease" \ - "\n -R,--release Release IP on exit" \ - IF_FEATURE_UDHCP_PORT( \ - "\n -P,--client-port N Use port N (default 68)" \ - ) \ - IF_FEATURE_UDHCPC_ARPING( \ - "\n -a,--arping Use arping to validate offered address" \ - ) \ - "\n -O,--request-option OPT Request DHCP option OPT (cumulative)" \ - "\n -o,--no-default-options Don't request any options (unless -O is given)" \ - "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" \ - "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" \ - "\n -H,-h,--hostname NAME Send NAME as client hostname (default none)" \ - "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" \ - "\n -c,--clientid CLIENTID Client identifier (default own MAC)" \ - "\n -C,--clientid-none Don't send client identifier" \ - ) \ - IF_NOT_LONG_OPTS( \ - "\n -i IFACE Interface to use (default eth0)" \ - "\n -p FILE Create pidfile" \ - "\n -r IP IP address to request" \ - "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" \ - "\n -t N Send up to N discover packets" \ - "\n -T N Pause between packets (default 3 seconds)" \ - "\n -A N Wait N seconds (default 20) after failure" \ - "\n -x OPT:VAL Include option OPT in sent packets" \ - "\n -O OPT Request DHCP option OPT (cumulative)" \ - "\n -o Don't request any options (unless -O is given)" \ - "\n -f Run in foreground" \ - USE_FOR_MMU( \ - "\n -b Background if lease is not obtained" \ - ) \ - "\n -S Log to syslog too" \ - "\n -n Exit if lease is not obtained" \ - "\n -q Exit after obtaining lease" \ - "\n -R Release IP on exit" \ - IF_FEATURE_UDHCP_PORT( \ - "\n -P N Use port N (default 68)" \ - ) \ - IF_FEATURE_UDHCPC_ARPING( \ - "\n -a Use arping to validate offered address" \ - ) \ - "\n -F NAME Ask server to update DNS mapping for NAME" \ - "\n -H,-h NAME Send NAME as client hostname (default none)" \ - "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" \ - "\n -c CLIENTID Client identifier (default own MAC)" \ - "\n -C Don't send client identifier" \ - ) - -#define udhcpd_trivial_usage \ - "[-fS]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [configfile]" \ - -#define udhcpd_full_usage "\n\n" \ - "DHCP server\n" \ - "\n -f Run in foreground" \ - "\n -S Log to syslog too" \ - IF_FEATURE_UDHCP_PORT( \ - "\n -P N Use port N (default 67)" \ - ) - -#define umount_trivial_usage \ - "[OPTIONS] FILESYSTEM|DIRECTORY" -#define umount_full_usage "\n\n" \ - "Unmount file systems\n" \ - "\nOptions:" \ - IF_FEATURE_UMOUNT_ALL( \ - "\n -a Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab") \ - ) \ - IF_FEATURE_MTAB_SUPPORT( \ - "\n -n Don't erase /etc/mtab entries" \ - ) \ - "\n -r Try to remount devices as read-only if mount is busy" \ - "\n -l Lazy umount (detach filesystem)" \ - "\n -f Force umount (i.e., unreachable NFS server)" \ - IF_FEATURE_MOUNT_LOOP( \ - "\n -d Free loop device if it has been used" \ - ) - -#define umount_example_usage \ - "$ umount /dev/hdc1\n" - -#define uname_trivial_usage \ - "[-amnrspv]" -#define uname_full_usage "\n\n" \ - "Print system information\n" \ - "\nOptions:" \ - "\n -a Print all" \ - "\n -m The machine (hardware) type" \ - "\n -n Hostname" \ - "\n -r OS release" \ - "\n -s OS name (default)" \ - "\n -p Processor type" \ - "\n -v OS version" \ - -#define uname_example_usage \ - "$ uname -a\n" \ - "Linux debian 2.4.23 #2 Tue Dec 23 17:09:10 MST 2003 i686 GNU/Linux\n" - -#define uncompress_trivial_usage \ - "[-cf] [FILE]..." -#define uncompress_full_usage "\n\n" \ - "Decompress .Z file[s]\n" \ - "\nOptions:" \ - "\n -c Write to stdout" \ - "\n -f Overwrite" \ - -#define unexpand_trivial_usage \ - "[-fa][-t N] [FILE]..." -#define unexpand_full_usage "\n\n" \ - "Convert spaces to tabs, writing to stdout\n" \ - "\nOptions:" \ - IF_FEATURE_UNEXPAND_LONG_OPTIONS( \ - "\n -a,--all Convert all blanks" \ - "\n -f,--first-only Convert only leading blanks" \ - "\n -t,--tabs=N Tabstops every N chars" \ - ) \ - IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( \ - "\n -a Convert all blanks" \ - "\n -f Convert only leading blanks" \ - "\n -t N Tabstops every N chars" \ - ) - -#define uniq_trivial_usage \ - "[-cdu][-f,s,w N] [INPUT [OUTPUT]]" -#define uniq_full_usage "\n\n" \ - "Discard duplicate lines\n" \ - "\nOptions:" \ - "\n -c Prefix lines by the number of occurrences" \ - "\n -d Only print duplicate lines" \ - "\n -u Only print unique lines" \ - "\n -f N Skip first N fields" \ - "\n -s N Skip first N chars (after any skipped fields)" \ - "\n -w N Compare N characters in line" \ - -#define uniq_example_usage \ - "$ echo -e \"a\\na\\nb\\nc\\nc\\na\" | sort | uniq\n" \ - "a\n" \ - "b\n" \ - "c\n" - -#define unzip_trivial_usage \ - "[-opts[modifiers]] FILE[.zip] [LIST] [-x XLIST] [-d DIR]" -#define unzip_full_usage "\n\n" \ - "Extract files from ZIP archives\n" \ - "\nOptions:" \ - "\n -l List archive contents (with -q for short form)" \ - "\n -n Never overwrite files (default)" \ - "\n -o Overwrite" \ - "\n -p Send output to stdout" \ - "\n -q Quiet" \ - "\n -x XLST Exclude these files" \ - "\n -d DIR Extract files into DIR" \ - -#define uptime_trivial_usage \ - "" -#define uptime_full_usage "\n\n" \ - "Display the time since the last boot" - -#define uptime_example_usage \ - "$ uptime\n" \ - " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" - -#define usleep_trivial_usage \ - "N" -#define usleep_full_usage "\n\n" \ - "Pause for N microseconds" - -#define usleep_example_usage \ - "$ usleep 1000000\n" \ - "[pauses for 1 second]\n" - -#define uudecode_trivial_usage \ - "[-o OUTFILE] [INFILE]" -#define uudecode_full_usage "\n\n" \ - "Uudecode a file\n" \ - "Finds outfile name in uuencoded source unless -o is given" - -#define uudecode_example_usage \ - "$ uudecode -o busybox busybox.uu\n" \ - "$ ls -l busybox\n" \ - "-rwxr-xr-x 1 ams ams 245264 Jun 7 21:35 busybox\n" - -#define uuencode_trivial_usage \ - "[-m] [INFILE] STORED_FILENAME" -#define uuencode_full_usage "\n\n" \ - "Uuencode a file to stdout\n" \ - "\nOptions:" \ - "\n -m Use base64 encoding per RFC1521" \ - -#define uuencode_example_usage \ - "$ uuencode busybox busybox\n" \ - "begin 755 busybox\n" \ - "\n" \ - "$ uudecode busybox busybox > busybox.uu\n" \ - "$\n" - -#define vconfig_trivial_usage \ - "COMMAND [OPTIONS]" -#define vconfig_full_usage "\n\n" \ - "Create and remove virtual ethernet devices\n" \ - "\nOptions:" \ - "\n add [interface-name] [vlan_id]" \ - "\n rem [vlan-name]" \ - "\n set_flag [interface-name] [flag-num] [0 | 1]" \ - "\n set_egress_map [vlan-name] [skb_priority] [vlan_qos]" \ - "\n set_ingress_map [vlan-name] [skb_priority] [vlan_qos]" \ - "\n set_name_type [name-type]" \ - -#define vi_trivial_usage \ - "[OPTIONS] [FILE]..." -#define vi_full_usage "\n\n" \ - "Edit FILE\n" \ - "\nOptions:" \ - IF_FEATURE_VI_COLON( \ - "\n -c Initial command to run ($EXINIT also available)") \ - IF_FEATURE_VI_READONLY( \ - "\n -R Read-only") \ - "\n -H Short help regarding available features" \ - -#define vlock_trivial_usage \ - "[OPTIONS]" -#define vlock_full_usage "\n\n" \ - "Lock a virtual terminal. A password is required to unlock.\n" \ - "\nOptions:" \ - "\n -a Lock all VTs" \ - -#define volname_trivial_usage \ - "[DEVICE]" -#define volname_full_usage "\n\n" \ - "Show CD volume name of the DEVICE (default /dev/cdrom)" - -#define wall_trivial_usage \ - "[FILE]" -#define wall_full_usage "\n\n" \ - "Write content of FILE or stdin to all logged-in users" -#define wall_sample_usage \ - "echo foo | wall\n" \ - "wall ./mymessage" - -#define watch_trivial_usage \ - "[-n SEC] [-t] PROG ARGS" -#define watch_full_usage "\n\n" \ - "Run PROG periodically\n" \ - "\nOptions:" \ - "\n -n Loop period in seconds (default 2)" \ - "\n -t Don't print header" \ - -#define watch_example_usage \ - "$ watch date\n" \ - "Mon Dec 17 10:31:40 GMT 2000\n" \ - "Mon Dec 17 10:31:42 GMT 2000\n" \ - "Mon Dec 17 10:31:44 GMT 2000" - -#define watchdog_trivial_usage \ - "[-t N[ms]] [-T N[ms]] [-F] DEV" -#define watchdog_full_usage "\n\n" \ - "Periodically write to watchdog device DEV\n" \ - "\nOptions:" \ - "\n -T N Reboot after N seconds if not reset (default 60)" \ - "\n -t N Reset every N seconds (default 30)" \ - "\n -F Run in foreground" \ - "\n" \ - "\nUse 500ms to specify period in milliseconds" \ - -#define wc_trivial_usage \ - "[OPTIONS] [FILE]..." -#define wc_full_usage "\n\n" \ - "Print line, word, and byte counts for each FILE (or stdin),\n" \ - "and a total line if more than one FILE is specified\n" \ - "\nOptions:" \ - "\n -c Print the byte counts" \ - "\n -l Print the newline counts" \ - "\n -L Print the length of the longest line" \ - "\n -w Print the word counts" \ - -#define wc_example_usage \ - "$ wc /etc/passwd\n" \ - " 31 46 1365 /etc/passwd\n" - -#define wget_trivial_usage \ - IF_FEATURE_WGET_LONG_OPTIONS( \ - "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" \ - " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" \ - " [--no-check-certificate] [-U|--user-agent AGENT] URL" \ - ) \ - IF_NOT_FEATURE_WGET_LONG_OPTIONS( \ - "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT] URL" \ - ) -#define wget_full_usage "\n\n" \ - "Retrieve files via HTTP or FTP\n" \ - "\nOptions:" \ - "\n -s Spider mode - only check file existence" \ - "\n -c Continue retrieval of aborted transfer" \ - "\n -q Quiet" \ - "\n -P Set directory prefix to DIR" \ - "\n -O FILE Save to FILE ('-' for stdout)" \ - "\n -U STR Use STR for User-Agent header" \ - "\n -Y Use proxy ('on' or 'off')" \ - -#define which_trivial_usage \ - "[COMMAND]..." -#define which_full_usage "\n\n" \ - "Locate a COMMAND" -#define which_example_usage \ - "$ which login\n" \ - "/bin/login\n" - -#define who_trivial_usage \ - "[-a]" -#define who_full_usage "\n\n" \ - "Show who is logged on\n" \ - "\nOptions:" \ - "\n -a Show all" \ - -#define whoami_trivial_usage \ - "" -#define whoami_full_usage "\n\n" \ - "Print the user name associated with the current effective user id" - -#define zcat_trivial_usage \ - "FILE" -#define zcat_full_usage "\n\n" \ - "Decompress to stdout" - -#define zcip_trivial_usage \ - "[OPTIONS] IFACE SCRIPT" -#define zcip_full_usage "\n\n" \ - "Manage a ZeroConf IPv4 link-local address\n" \ - "\nOptions:" \ - "\n -f Run in foreground" \ - "\n -q Quit after obtaining address" \ - "\n -r 169.254.x.x Request this address first" \ - "\n -v Verbose" \ - "\n" \ - "\nWith no -q, runs continuously monitoring for ARP conflicts," \ - "\nexits only on I/O errors (link down etc)" \ - - #endif diff --git a/include/volume_id.h b/include/volume_id.h index 77e874d..a83da89 100644 --- a/include/volume_id.h +++ b/include/volume_id.h @@ -20,7 +20,7 @@ char *get_devname_from_label(const char *spec); char *get_devname_from_uuid(const char *spec); -void display_uuid_cache(void); +void display_uuid_cache(int scan_devices); /* Returns: * 0: no UUID= or LABEL= prefix found @@ -28,3 +28,4 @@ void display_uuid_cache(void); * *fsname is replaced if device with such UUID or LABEL is found */ int resolve_mount_spec(char **fsname); +int add_to_uuid_cache(const char *device); diff --git a/include/xatonum.h b/include/xatonum.h index 978c502..45ebbfc 100644 --- a/include/xatonum.h +++ b/include/xatonum.h @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN @@ -168,6 +168,15 @@ uint32_t bb_strtou32(const char *arg, char **endp, int base) return bb_strtoul(arg, endp, base); return BUG_bb_strtou32_unimplemented(); } +static ALWAYS_INLINE +int32_t bb_strtoi32(const char *arg, char **endp, int base) +{ + if (sizeof(int32_t) == sizeof(int)) + return bb_strtoi(arg, endp, base); + if (sizeof(int32_t) == sizeof(long)) + return bb_strtol(arg, endp, base); + return BUG_bb_strtou32_unimplemented(); +} /* Floating point */ diff --git a/include/xregex.h b/include/xregex.h index 61658ed..5e5e6a2 100644 --- a/include/xregex.h +++ b/include/xregex.h @@ -4,9 +4,9 @@ * C library we're linking against may not support regex.h. * * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. + * Permission has been granted to redistribute this code under GPL. * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef BB_REGEX_H #define BB_REGEX_H 1 diff --git a/init/Config.src b/init/Config.src index 590e298..5767c93 100644 --- a/init/Config.src +++ b/init/Config.src @@ -7,119 +7,4 @@ menu "Init Utilities" INSERT -config INIT - bool "init" - default y - select FEATURE_SYSLOG - help - init is the first program run when the system boots. - -config FEATURE_USE_INITTAB - bool "Support reading an inittab file" - default y - depends on INIT - help - Allow init to read an inittab file when the system boot. - -config FEATURE_KILL_REMOVED - bool "Support killing processes that have been removed from inittab" - default n - depends on FEATURE_USE_INITTAB - help - When respawn entries are removed from inittab and a SIGHUP is - sent to init, this option will make init kill the processes - that have been removed. - -config FEATURE_KILL_DELAY - int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED - range 0 1024 - default 0 - depends on FEATURE_KILL_REMOVED - help - With nonzero setting, init sends TERM, forks, child waits N - seconds, sends KILL and exits. Setting it too high is unwise - (child will hang around for too long and could actually kill - the wrong process!) - -config FEATURE_INIT_SCTTY - bool "Run commands with leading dash with controlling tty" - default y - depends on INIT - help - If this option is enabled, init will try to give a controlling - tty to any command which has leading hyphen (often it's "-/bin/sh"). - More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)". - If device attached to STDIN_FILENO can be a ctty but is not yet - a ctty for other session, it will become this process' ctty. - This is not the traditional init behavour, but is often what you want - in an embedded system where the console is only accessed during - development or for maintenance. - NB: using cttyhack applet may work better. - -config FEATURE_INIT_SYSLOG - bool "Enable init to write to syslog" - default y - depends on INIT - -config FEATURE_EXTRA_QUIET - bool "Be _extra_ quiet on boot" - default y - depends on INIT - help - Prevent init from logging some messages to the console during boot. - -config FEATURE_INIT_COREDUMPS - bool "Support dumping core for child processes (debugging only)" - default y - depends on INIT - help - If this option is enabled and the file /.init_enable_core - exists, then init will call setrlimit() to allow unlimited - core file sizes. If this option is disabled, processes - will not generate any core files. - -config FEATURE_INITRD - bool "Support running init from within an initrd (not initramfs)" - default y - depends on INIT - help - Legacy support for running init under the old-style initrd. Allows - the name linuxrc to act as init, and it doesn't assume init is PID 1. - - This does not apply to initramfs, which runs /init as PID 1 and - requires no special support. - -config HALT - bool "poweroff, halt, and reboot" - default y - help - Stop all processes and either halt, reboot, or power off the system. - -config FEATURE_CALL_TELINIT - bool "Call telinit on shutdown and reboot" - default y - depends on HALT && !INIT - help - Call an external program (normally telinit) to facilitate - a switch to a proper runlevel. - - This option is only available if you selected halt and friends, - but did not select init. - -config TELINIT_PATH - string "Path to telinit executable" - default "/sbin/telinit" - depends on FEATURE_CALL_TELINIT - help - When busybox halt and friends have to call external telinit - to facilitate proper shutdown, this path is to be used when - locating telinit executable. - -config MESG - bool "mesg" - default y - help - Mesg controls access to your terminal by others. It is typically - used to allow or disallow other users to write to your terminal - endmenu diff --git a/init/Kbuild.src b/init/Kbuild.src index 6095a78..6b4fb74 100644 --- a/init/Kbuild.src +++ b/init/Kbuild.src @@ -2,12 +2,8 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= INSERT -lib-$(CONFIG_HALT) += halt.o -lib-$(CONFIG_INIT) += init.o -lib-$(CONFIG_MESG) += mesg.o -lib-$(CONFIG_BOOTCHARTD) += bootchartd.o diff --git a/init/bootchartd.c b/init/bootchartd.c index dae2fe6..c7388c9 100644 --- a/init/bootchartd.c +++ b/init/bootchartd.c @@ -1,8 +1,12 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//applet:IF_BOOTCHARTD(APPLET(bootchartd, BB_DIR_SBIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_BOOTCHARTD) += bootchartd.o + //config:config BOOTCHARTD //config: bool "bootchartd" //config: default y @@ -45,12 +49,21 @@ #include "libbb.h" /* After libbb.h, since it needs sys/types.h on some systems */ #include -#include -#ifndef MS_SILENT -# define MS_SILENT (1 << 15) + +#ifdef __linux__ +# include +# ifndef MS_SILENT +# define MS_SILENT (1 << 15) +# endif +# ifndef MNT_DETACH +# define MNT_DETACH 0x00000002 +# endif #endif -#ifndef MNT_DETACH -# define MNT_DETACH 0x00000002 + +#if !ENABLE_TAR && !ENABLE_WERROR +# warning Note: bootchartd requires tar command, but you did not select it. +#elif !ENABLE_FEATURE_SEAMLESS_GZ && !ENABLE_WERROR +# warning Note: bootchartd requires tar -z support, but you did not select it. #endif #define BC_VERSION_STR "0.8" @@ -174,6 +187,7 @@ static char *make_tempdir(void) char template[] = "/tmp/bootchart.XXXXXX"; char *tempdir = xstrdup(mkdtemp(template)); if (!tempdir) { +#ifdef __linux__ /* /tmp is not writable (happens when we are used as init). * Try to mount a tmpfs, them cd and lazily unmount it. * Since we unmount it at once, we can mount it anywhere. @@ -191,20 +205,17 @@ static char *make_tempdir(void) if (umount2(try_dir, MNT_DETACH) != 0) { bb_perror_msg_and_die("can't %smount tmpfs", "un"); } +#else + bb_perror_msg_and_die("can't create temporary directory"); +#endif } else { xchdir(tempdir); } return tempdir; } -static void do_logging(unsigned sample_period_us) +static void do_logging(unsigned sample_period_us, int process_accounting) { - //# Enable process accounting if configured - //if [ "$PROCESS_ACCOUNTING" = "yes" ]; then - // [ -e kernel_pacct ] || : > kernel_pacct - // accton kernel_pacct - //fi - FILE *proc_stat = xfopen("proc_stat.log", "w"); FILE *proc_diskstats = xfopen("proc_diskstats.log", "w"); //FILE *proc_netdev = xfopen("proc_netdev.log", "w"); @@ -212,6 +223,11 @@ static void do_logging(unsigned sample_period_us) int look_for_login_process = (getppid() == 1); unsigned count = 60*1000*1000 / sample_period_us; /* ~1 minute */ + if (process_accounting) { + close(xopen("kernel_pacct", O_WRONLY | O_CREAT | O_TRUNC)); + acct("kernel_pacct"); + } + while (--count && !bb_got_signal) { char *p; int len = open_read_close("/proc/uptime", G.jiffy_line, sizeof(G.jiffy_line)-2); @@ -242,11 +258,9 @@ static void do_logging(unsigned sample_period_us) wait_more: usleep(sample_period_us); } - - // [ -e kernel_pacct ] && accton off } -static void finalize(char *tempdir, const char *prog) +static void finalize(char *tempdir, const char *prog, int process_accounting) { //# Stop process accounting if configured //local pacct= @@ -254,6 +268,9 @@ static void finalize(char *tempdir, const char *prog) FILE *header_fp = xfopen("header", "w"); + if (process_accounting) + acct(NULL); + if (prog) fprintf(header_fp, "profile.process = %s\n", prog); @@ -296,7 +313,7 @@ static void finalize(char *tempdir, const char *prog) fclose(header_fp); /* Package log files */ - system("tar -zcf /var/log/bootchart.tgz header *.log"); // + $pacct + system(xasprintf("tar -zcf /var/log/bootlog.tgz header %s *.log", process_accounting ? "kernel_pacct" : "")); /* Clean up (if we are not in detached tmpfs) */ if (tempdir) { unlink("header"); @@ -304,6 +321,8 @@ static void finalize(char *tempdir, const char *prog) unlink("proc_diskstats.log"); //unlink("proc_netdev.log"); unlink("proc_ps.log"); + if (process_accounting) + unlink("kernel_pacct"); rmdir(tempdir); } @@ -316,7 +335,6 @@ static void finalize(char *tempdir, const char *prog) //usage: "start [PROG ARGS]|stop|init" //usage:#define bootchartd_full_usage "\n\n" //usage: "Create /var/log/bootchart.tgz with boot chart data\n" -//usage: "\nOptions:" //usage: "\nstart: start background logging; with PROG, run PROG, then kill logging with USR1" //usage: "\nstop: send USR1 to all bootchartd processes" //usage: "\ninit: start background logging; stop when getty/xdm is seen (for init scripts)" @@ -328,6 +346,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) unsigned sample_period_us; pid_t parent_pid, logger_pid; smallint cmd; + int process_accounting; enum { CMD_STOP = 0, CMD_START, @@ -361,6 +380,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) /* Read config file: */ sample_period_us = 200 * 1000; + process_accounting = 0; if (ENABLE_FEATURE_BOOTCHARTD_CONFIG_FILE) { char* token[2]; parser_t *parser = config_open2("/etc/bootchartd.conf" + 5, fopen_for_read); @@ -369,11 +389,16 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) while (config_read(parser, token, 2, 0, "#=", PARSE_NORMAL & ~PARSE_COLLAPSE)) { if (strcmp(token[0], "SAMPLE_PERIOD") == 0 && token[1]) sample_period_us = atof(token[1]) * 1000000; + if (strcmp(token[0], "PROCESS_ACCOUNTING") == 0 && token[1] + && (strcmp(token[1], "on") == 0 || strcmp(token[1], "yes") == 0) + ) { + process_accounting = 1; + } } config_close(parser); + if ((int)sample_period_us <= 0) + sample_period_us = 1; /* prevent division by 0 */ } - if ((int)sample_period_us <= 0) - sample_period_us = 1; /* prevent division by 0 */ /* Create logger child: */ logger_pid = fork_or_rexec(argv); @@ -401,13 +426,15 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) putenv((char*)bb_PATH_root_path); tempdir = make_tempdir(); - do_logging(sample_period_us); - finalize(tempdir, cmd == CMD_START ? argv[2] : NULL); + do_logging(sample_period_us, process_accounting); + finalize(tempdir, cmd == CMD_START ? argv[2] : NULL, process_accounting); return EXIT_SUCCESS; } /* parent */ + USE_FOR_NOMMU(argv[0][0] &= 0x7f); /* undo fork_or_rexec() damage */ + if (DO_SIGNAL_SYNC) { /* Wait for logger child to set handlers, then unpause it. * Otherwise with short-lived PROG (e.g. "bootchartd start true") @@ -430,8 +457,7 @@ int bootchartd_main(int argc UNUSED_PARAM, char **argv) pid_t pid = xvfork(); if (pid == 0) { /* child */ argv += 2; - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } /* parent */ waitpid(pid, NULL, 0); diff --git a/init/halt.c b/init/halt.c index f1bb2c4..7974adb 100644 --- a/init/halt.c +++ b/init/halt.c @@ -4,15 +4,73 @@ * * Copyright 2006 by Rob Landley * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//applet:IF_HALT(APPLET(halt, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_HALT(APPLET_ODDNAME(poweroff, halt, BB_DIR_SBIN, BB_SUID_DROP, poweroff)) +//applet:IF_HALT(APPLET_ODDNAME(reboot, halt, BB_DIR_SBIN, BB_SUID_DROP, reboot)) + +//kbuild:lib-$(CONFIG_HALT) += halt.o + +//config:config HALT +//config: bool "poweroff, halt, and reboot" +//config: default y +//config: help +//config: Stop all processes and either halt, reboot, or power off the system. +//config: +//config:config FEATURE_CALL_TELINIT +//config: bool "Call telinit on shutdown and reboot" +//config: default y +//config: depends on HALT && !INIT +//config: help +//config: Call an external program (normally telinit) to facilitate +//config: a switch to a proper runlevel. +//config: +//config: This option is only available if you selected halt and friends, +//config: but did not select init. +//config: +//config:config TELINIT_PATH +//config: string "Path to telinit executable" +//config: default "/sbin/telinit" +//config: depends on FEATURE_CALL_TELINIT +//config: help +//config: When busybox halt and friends have to call external telinit +//config: to facilitate proper shutdown, this path is to be used when +//config: locating telinit executable. + +//usage:#define halt_trivial_usage +//usage: "[-d DELAY] [-n] [-f]" IF_FEATURE_WTMP(" [-w]") +//usage:#define halt_full_usage "\n\n" +//usage: "Halt the system\n" +//usage: "\n -d SEC Delay interval" +//usage: "\n -n Do not sync" +//usage: "\n -f Force (don't go through init)" +//usage: IF_FEATURE_WTMP( +//usage: "\n -w Only write a wtmp record" +//usage: ) +//usage: +//usage:#define poweroff_trivial_usage +//usage: "[-d DELAY] [-n] [-f]" +//usage:#define poweroff_full_usage "\n\n" +//usage: "Halt and shut off power\n" +//usage: "\n -d SEC Delay interval" +//usage: "\n -n Do not sync" +//usage: "\n -f Force (don't go through init)" +//usage: +//usage:#define reboot_trivial_usage +//usage: "[-d DELAY] [-n] [-f]" +//usage:#define reboot_full_usage "\n\n" +//usage: "Reboot the system\n" +//usage: "\n -d SEC Delay interval" +//usage: "\n -n Do not sync" +//usage: "\n -f Force (don't go through init)" + #include "libbb.h" -#include +#include "reboot.h" #if ENABLE_FEATURE_WTMP #include -#include static void write_wtmp(void) { @@ -36,18 +94,6 @@ static void write_wtmp(void) #define write_wtmp() ((void)0) #endif -#ifndef RB_HALT_SYSTEM -#define RB_HALT_SYSTEM RB_HALT -#endif - -#ifndef RB_POWERDOWN -/* Stop system and switch power off if possible. */ -# define RB_POWERDOWN 0x4321fedc -#endif -#ifndef RB_POWER_OFF -# define RB_POWER_OFF RB_POWERDOWN -#endif - int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int halt_main(int argc UNUSED_PARAM, char **argv) @@ -108,11 +154,13 @@ int halt_main(int argc UNUSED_PARAM, char **argv) /* runlevels: * 0 == shutdown * 6 == reboot */ - rc = execlp(CONFIG_TELINIT_PATH, + execlp(CONFIG_TELINIT_PATH, CONFIG_TELINIT_PATH, which == 2 ? "6" : "0", (char *)NULL ); + bb_perror_msg_and_die("can't execute '%s'", + CONFIG_TELINIT_PATH); } } } else { diff --git a/init/init.c b/init/init.c index 2eb8f1a..d29328c 100644 --- a/init/init.c +++ b/init/init.c @@ -6,30 +6,145 @@ * Copyright (C) 1999-2004 by Erik Andersen * Adjusted by so many folks, it's impossible to keep track. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config INIT +//config: bool "init" +//config: default y +//config: select FEATURE_SYSLOG +//config: help +//config: init is the first program run when the system boots. +//config: +//config:config FEATURE_USE_INITTAB +//config: bool "Support reading an inittab file" +//config: default y +//config: depends on INIT +//config: help +//config: Allow init to read an inittab file when the system boot. +//config: +//config:config FEATURE_KILL_REMOVED +//config: bool "Support killing processes that have been removed from inittab" +//config: default n +//config: depends on FEATURE_USE_INITTAB +//config: help +//config: When respawn entries are removed from inittab and a SIGHUP is +//config: sent to init, this option will make init kill the processes +//config: that have been removed. +//config: +//config:config FEATURE_KILL_DELAY +//config: int "How long to wait between TERM and KILL (0 - send TERM only)" if FEATURE_KILL_REMOVED +//config: range 0 1024 +//config: default 0 +//config: depends on FEATURE_KILL_REMOVED +//config: help +//config: With nonzero setting, init sends TERM, forks, child waits N +//config: seconds, sends KILL and exits. Setting it too high is unwise +//config: (child will hang around for too long and could actually kill +//config: the wrong process!) +//config: +//config:config FEATURE_INIT_SCTTY +//config: bool "Run commands with leading dash with controlling tty" +//config: default y +//config: depends on INIT +//config: help +//config: If this option is enabled, init will try to give a controlling +//config: tty to any command which has leading hyphen (often it's "-/bin/sh"). +//config: More precisely, init will do "ioctl(STDIN_FILENO, TIOCSCTTY, 0)". +//config: If device attached to STDIN_FILENO can be a ctty but is not yet +//config: a ctty for other session, it will become this process' ctty. +//config: This is not the traditional init behavour, but is often what you want +//config: in an embedded system where the console is only accessed during +//config: development or for maintenance. +//config: NB: using cttyhack applet may work better. +//config: +//config:config FEATURE_INIT_SYSLOG +//config: bool "Enable init to write to syslog" +//config: default y +//config: depends on INIT +//config: +//config:config FEATURE_EXTRA_QUIET +//config: bool "Be _extra_ quiet on boot" +//config: default y +//config: depends on INIT +//config: help +//config: Prevent init from logging some messages to the console during boot. +//config: +//config:config FEATURE_INIT_COREDUMPS +//config: bool "Support dumping core for child processes (debugging only)" +//config: default y +//config: depends on INIT +//config: help +//config: If this option is enabled and the file /.init_enable_core +//config: exists, then init will call setrlimit() to allow unlimited +//config: core file sizes. If this option is disabled, processes +//config: will not generate any core files. +//config: +//config:config FEATURE_INITRD +//config: bool "Support running init from within an initrd (not initramfs)" +//config: default y +//config: depends on INIT +//config: help +//config: Legacy support for running init under the old-style initrd. Allows +//config: the name linuxrc to act as init, and it doesn't assume init is PID 1. +//config: +//config: This does not apply to initramfs, which runs /init as PID 1 and +//config: requires no special support. +//config: +//config:config INIT_TERMINAL_TYPE +//config: string "Initial terminal type" +//config: default "linux" +//config: depends on INIT +//config: help +//config: This is the initial value set by init for the TERM environment +//config: variable. This variable is used by programs which make use of +//config: extended terminal capabilities. +//config: +//config: Note that on Linux, init attempts to detect serial terminal and +//config: sets TERM to "vt102" if one is found. + +//applet:IF_INIT(APPLET(init, BB_DIR_SBIN, BB_SUID_DROP)) +//applet:IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, BB_DIR_ROOT, BB_SUID_DROP, linuxrc)) + +//kbuild:lib-$(CONFIG_INIT) += init.o + +#define DEBUG_SEGV_HANDLER 0 + #include "libbb.h" #include #include -#include #include -#include -#if ENABLE_FEATURE_UTMP -# include /* DEAD_PROCESS */ +#ifdef __linux__ +# include +# include +#endif +#include "reboot.h" /* reboot() constants */ + +#if DEBUG_SEGV_HANDLER +# undef _GNU_SOURCE +# define _GNU_SOURCE 1 +# undef __USE_GNU +# define __USE_GNU 1 +# include +# include #endif +/* Used only for sanitizing purposes in set_sane_term() below. On systems where + * the baud rate is stored in a separate field, we can safely disable them. */ +#ifndef CBAUD +# define CBAUD 0 +# define CBAUDEX 0 +#endif /* Was a CONFIG_xxx option. A lot of people were building * not fully functional init by switching it on! */ #define DEBUG_INIT 0 -#define COMMAND_SIZE 256 #define CONSOLE_NAME_SIZE 32 /* Default sysinit script. */ #ifndef INIT_SCRIPT -#define INIT_SCRIPT "/etc/init.d/rcS" +# define INIT_SCRIPT "/etc/init.d/rcS" #endif /* Each type of actions can appear many times. They will be @@ -79,7 +194,7 @@ struct init_action { pid_t pid; uint8_t action_type; char terminal[CONSOLE_NAME_SIZE]; - char command[COMMAND_SIZE]; + char command[1]; }; static struct init_action *init_action_list = NULL; @@ -89,13 +204,6 @@ static const char *log_console = VC_5; enum { L_LOG = 0x1, L_CONSOLE = 0x2, -#ifndef RB_HALT_SYSTEM - RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */ - RB_ENABLE_CAD = 0x89abcdef, - RB_DISABLE_CAD = 0, - RB_POWER_OFF = 0x4321fedc, - RB_AUTOBOOT = 0x01234567, -#endif }; /* Print a message to the specified device. @@ -114,8 +222,8 @@ static void message(int where, const char *fmt, ...) msg[0] = '\r'; va_start(arguments, fmt); l = 1 + vsnprintf(msg + 1, sizeof(msg) - 2, fmt, arguments); - if (l > sizeof(msg) - 1) - l = sizeof(msg) - 1; + if (l > sizeof(msg) - 2) + l = sizeof(msg) - 2; va_end(arguments); #if ENABLE_FEATURE_INIT_SYSLOG @@ -166,7 +274,9 @@ static void message(int where, const char *fmt, ...) static void console_init(void) { +#ifdef VT_OPENQRY int vtno; +#endif char *s; s = getenv("CONSOLE"); @@ -190,6 +300,7 @@ static void console_init(void) } s = getenv("TERM"); +#ifdef VT_OPENQRY if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) { /* Not a linux terminal, probably serial console. * Force the TERM setting to vt102 @@ -198,8 +309,10 @@ static void console_init(void) putenv((char*)"TERM=vt102"); if (!ENABLE_FEATURE_INIT_SYSLOG) log_console = NULL; - } else if (!s) - putenv((char*)"TERM=linux"); + } else +#endif + if (!s) + putenv((char*)"TERM=" CONFIG_INIT_TERMINAL_TYPE); } /* Set terminal settings to reasonable defaults. @@ -220,11 +333,17 @@ static void set_sane_term(void) tty.c_cc[VSTOP] = 19; /* C-s */ tty.c_cc[VSUSP] = 26; /* C-z */ +#ifdef __linux__ /* use line discipline 0 */ tty.c_line = 0; +#endif /* Make it be sane */ - tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; +#ifndef CRTSCTS +# define CRTSCTS 0 +#endif + /* added CRTSCTS to fix Debian bug 528560 */ + tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD | CRTSCTS; tty.c_cflag |= CREAD | HUPCL | CLOCAL; /* input modes */ @@ -234,8 +353,7 @@ static void set_sane_term(void) tty.c_oflag = OPOST | ONLCR; /* local modes */ - tty.c_lflag = - ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; + tty.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | ECHOCTL | ECHOKE | IEXTEN; tcsetattr_stdin_TCSANOW(&tty); } @@ -279,7 +397,7 @@ static void reset_sighandlers_and_unblock_sigs(void) } /* Wrapper around exec: - * Takes string (max COMMAND_SIZE chars). + * Takes string. * If chars like '>' detected, execs '[-]/bin/sh -c "exec ......."'. * Otherwise splits words on whitespace, deals with leading dash, * and uses plain exec(). @@ -287,24 +405,32 @@ static void reset_sighandlers_and_unblock_sigs(void) */ static void init_exec(const char *command) { - char *cmd[COMMAND_SIZE / 2]; - char buf[COMMAND_SIZE + 6]; /* COMMAND_SIZE+strlen("exec ")+1 */ - int dash = (command[0] == '-' /* maybe? && command[1] == '/' */); + /* +8 allows to write VLA sizes below more efficiently: */ + unsigned command_size = strlen(command) + 8; + /* strlen(command) + strlen("exec ")+1: */ + char buf[command_size]; + /* strlen(command) / 2 + 4: */ + char *cmd[command_size / 2]; + int dash; + + dash = (command[0] == '-' /* maybe? && command[1] == '/' */); + command += dash; /* See if any special /bin/sh requiring characters are present */ if (strpbrk(command, "~`!$^&*()=|\\{}[];\"'<>?") != NULL) { - strcpy(buf, "exec "); - strcpy(buf + 5, command + dash); /* excluding "-" */ + sprintf(buf, "exec %s", command); /* excluding "-" */ /* NB: LIBBB_DEFAULT_LOGIN_SHELL define has leading dash */ cmd[0] = (char*)(LIBBB_DEFAULT_LOGIN_SHELL + !dash); cmd[1] = (char*)"-c"; cmd[2] = buf; cmd[3] = NULL; + command = LIBBB_DEFAULT_LOGIN_SHELL + 1; } else { /* Convert command (char*) into cmd (char**, one word per string) */ char *word, *next; int i = 0; - next = strcpy(buf, command); /* including "-" */ + next = strcpy(buf, command - dash); /* command including "-" */ + command = next + dash; while ((word = strsep(&next, " \t")) != NULL) { if (*word != '\0') { /* not two spaces/tabs together? */ cmd[i] = word; @@ -315,14 +441,14 @@ static void init_exec(const char *command) } /* If we saw leading "-", it is interactive shell. * Try harder to give it a controlling tty. - * And skip "-" in actual exec call. */ - if (dash) { + */ + if (ENABLE_FEATURE_INIT_SCTTY && dash) { /* _Attempt_ to make stdin a controlling tty. */ - if (ENABLE_FEATURE_INIT_SCTTY) - ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); + ioctl(STDIN_FILENO, TIOCSCTTY, 0 /*only try, don't steal*/); } - BB_EXECVP(cmd[0] + dash, cmd); - message(L_LOG | L_CONSOLE, "can't run '%s': %s", cmd[0], strerror(errno)); + /* Here command never contains the dash, cmd[0] might */ + BB_EXECVP(command, cmd); + message(L_LOG | L_CONSOLE, "can't run '%s': %s", command, strerror(errno)); /* returns if execvp fails */ } @@ -398,7 +524,7 @@ static pid_t run(const struct init_action *a) /* Log the process name and args */ message(L_LOG, "starting pid %d, tty '%s': '%s'", - getpid(), a->terminal, a->command); + getpid(), a->terminal, a->command); /* Now run it. The new program will take over this PID, * so nothing further in init.c should be run. */ @@ -412,13 +538,17 @@ static struct init_action *mark_terminated(pid_t pid) struct init_action *a; if (pid > 0) { + update_utmp(pid, DEAD_PROCESS, + /*tty_name:*/ NULL, + /*username:*/ NULL, + /*hostname:*/ NULL + ); for (a = init_action_list; a; a = a->next) { if (a->pid == pid) { a->pid = 0; return a; } } - update_utmp(pid, DEAD_PROCESS, /*tty_name:*/ NULL, /*username:*/ NULL, /*hostname:*/ NULL); } return NULL; } @@ -483,7 +613,7 @@ static void new_init_action(uint8_t action_type, const char *command, const char */ nextp = &init_action_list; while ((a = *nextp) != NULL) { - /* Don't enter action if it's already in the list, + /* Don't enter action if it's already in the list. * This prevents losing running RESPAWNs. */ if (strcmp(a->command, command) == 0 @@ -495,25 +625,26 @@ static void new_init_action(uint8_t action_type, const char *command, const char while (*nextp != NULL) nextp = &(*nextp)->next; a->next = NULL; - break; + goto append; } nextp = &a->next; } - if (!a) - a = xzalloc(sizeof(*a)); + a = xzalloc(sizeof(*a) + strlen(command)); + /* Append to the end of the list */ + append: *nextp = a; a->action_type = action_type; - safe_strncpy(a->command, command, sizeof(a->command)); + strcpy(a->command, command); safe_strncpy(a->terminal, cons, sizeof(a->terminal)); - dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%d tty='%s'\n", + dbg_message(L_LOG | L_CONSOLE, "command='%s' action=%x tty='%s'\n", a->command, a->action_type, a->terminal); } /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default - * actions(i.e., runs INIT_SCRIPT and then starts a pair + * actions (i.e., runs INIT_SCRIPT and then starts a pair * of "askfirst" shells). If CONFIG_FEATURE_USE_INITTAB * _is_ defined, but /etc/inittab is missing, this * results in the same set of default behaviors. @@ -528,23 +659,22 @@ static void parse_inittab(void) #endif { /* No inittab file - set up some default behavior */ - /* Reboot on Ctrl-Alt-Del */ - new_init_action(CTRLALTDEL, "reboot", ""); - /* Umount all filesystems on halt/reboot */ - new_init_action(SHUTDOWN, "umount -a -r", ""); - /* Swapoff on halt/reboot */ - if (ENABLE_SWAPONOFF) - new_init_action(SHUTDOWN, "swapoff -a", ""); - /* Prepare to restart init when a QUIT is received */ - new_init_action(RESTART, "init", ""); + /* Sysinit */ + new_init_action(SYSINIT, INIT_SCRIPT, ""); /* Askfirst shell on tty1-4 */ new_init_action(ASKFIRST, bb_default_login_shell, ""); //TODO: VC_1 instead of ""? "" is console -> ctty problems -> angry users new_init_action(ASKFIRST, bb_default_login_shell, VC_2); new_init_action(ASKFIRST, bb_default_login_shell, VC_3); new_init_action(ASKFIRST, bb_default_login_shell, VC_4); - /* sysinit */ - new_init_action(SYSINIT, INIT_SCRIPT, ""); + /* Reboot on Ctrl-Alt-Del */ + new_init_action(CTRLALTDEL, "reboot", ""); + /* Umount all filesystems on halt/reboot */ + new_init_action(SHUTDOWN, "umount -a -r", ""); + /* Swapoff on halt/reboot */ + new_init_action(SHUTDOWN, "swapoff -a", ""); + /* Restart init when a QUIT is received */ + new_init_action(RESTART, "init", ""); return; } @@ -659,7 +789,7 @@ static void run_shutdown_and_kill_processes(void) * and only one will be remembered and acted upon. */ -/* The SIGUSR[12]/SIGTERM handler */ +/* The SIGPWR/SIGUSR[12]/SIGTERM handler */ static void halt_reboot_pwoff(int sig) NORETURN; static void halt_reboot_pwoff(int sig) { @@ -709,10 +839,12 @@ static void restart_handler(int sig UNUSED_PARAM) run_shutdown_and_kill_processes(); +#ifdef RB_ENABLE_CAD /* Allow Ctrl-Alt-Del to reboot the system. * This is how kernel sets it up for init, we follow suit. */ reboot(RB_ENABLE_CAD); /* misnomer */ +#endif if (open_stdio_to_tty(a->terminal)) { dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); @@ -802,10 +934,17 @@ static void reload_inittab(void) /* Remove stale entries and SYSINIT entries. * We never rerun SYSINIT entries anyway, - * removing them too saves a few bytes */ + * removing them too saves a few bytes + */ nextp = &init_action_list; while ((a = *nextp) != NULL) { - if ((a->action_type & ~SYSINIT) == 0) { + /* + * Why pid == 0 check? + * Process can be removed from inittab and added *later*. + * If we delete its entry but process still runs, + * duplicate is spawned when the entry is re-added. + */ + if ((a->action_type & ~SYSINIT) == 0 && a->pid == 0) { *nextp = a->next; free(a); } else { @@ -839,27 +978,76 @@ static int check_delayed_sigs(void) } } +#if DEBUG_SEGV_HANDLER +static +void handle_sigsegv(int sig, siginfo_t *info, void *ucontext) +{ + long ip; + ucontext_t *uc; + + uc = ucontext; + ip = uc->uc_mcontext.gregs[REG_EIP]; + fdprintf(2, "signal:%d address:0x%lx ip:0x%lx\n", + sig, + /* this is void*, but using %p would print "(null)" + * even for ptrs which are not exactly 0, but, say, 0x123: + */ + (long)info->si_addr, + ip); + { + /* glibc extension */ + void *array[50]; + int size; + size = backtrace(array, 50); + backtrace_symbols_fd(array, size, 2); + } + for (;;) sleep(9999); +} +#endif + int init_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int init_main(int argc UNUSED_PARAM, char **argv) { - die_sleep = 30 * 24*60*60; /* if xmalloc would ever die... */ - if (argv[1] && strcmp(argv[1], "-q") == 0) { return kill(1, SIGHUP); } +#if DEBUG_SEGV_HANDLER + { + struct sigaction sa; + memset(&sa, 0, sizeof(sa)); + sa.sa_sigaction = handle_sigsegv; + sa.sa_flags = SA_SIGINFO; + sigaction(SIGSEGV, &sa, NULL); + sigaction(SIGILL, &sa, NULL); + sigaction(SIGFPE, &sa, NULL); + sigaction(SIGBUS, &sa, NULL); + } +#endif + if (!DEBUG_INIT) { /* Expect to be invoked as init with PID=1 or be invoked as linuxrc */ if (getpid() != 1 - && (!ENABLE_FEATURE_INITRD || !strstr(applet_name, "linuxrc")) + && (!ENABLE_FEATURE_INITRD || applet_name[0] != 'l') /* not linuxrc? */ ) { - bb_show_usage(); + bb_error_msg_and_die("must be run as PID 1"); } +#ifdef RB_DISABLE_CAD /* Turn off rebooting via CTL-ALT-DEL - we get a * SIGINT on CAD so we can shut things down gracefully... */ reboot(RB_DISABLE_CAD); /* misnomer */ +#endif } + /* If, say, xmalloc would ever die, we don't want to oops kernel + * by exiting. + * NB: we set die_sleep *after* PID 1 check and bb_show_usage. + * Otherwise, for example, "init u" ("please rexec yourself" + * command for sysvinit) will show help text (which isn't too bad), + * *and sleep forever* (which is bad!) + */ + die_sleep = 30 * 24*60*60; + /* Figure out where the default console should be */ console_init(); set_sane_term(); @@ -880,8 +1068,13 @@ int init_main(int argc UNUSED_PARAM, char **argv) message(L_CONSOLE | L_LOG, "init started: %s", bb_banner); #endif +#if 0 +/* It's 2013, does anyone really still depend on this? */ +/* If you do, consider adding swapon to sysinot actions then! */ +/* struct sysinfo is linux-specific */ +# ifdef __linux__ /* Make sure there is enough memory to do something useful. */ - if (ENABLE_SWAPONOFF) { + /*if (ENABLE_SWAPONOFF) - WRONG: we may have non-bbox swapon*/ { struct sysinfo info; if (sysinfo(&info) == 0 @@ -895,6 +1088,8 @@ int init_main(int argc UNUSED_PARAM, char **argv) run_actions(SYSINIT); /* wait and removing */ } } +# endif +#endif /* Check if we are supposed to be in single user mode */ if (argv[1] @@ -908,8 +1103,8 @@ int init_main(int argc UNUSED_PARAM, char **argv) /* NOTE that if CONFIG_FEATURE_USE_INITTAB is NOT defined, * then parse_inittab() simply adds in some default - * actions(i.e., INIT_SCRIPT and a pair - * of "askfirst" shells */ + * actions (i.e., INIT_SCRIPT and a pair + * of "askfirst" shells) */ parse_inittab(); } @@ -924,7 +1119,7 @@ int init_main(int argc UNUSED_PARAM, char **argv) /* SELinux in enforcing mode but load_policy failed */ message(L_CONSOLE, "can't load SELinux Policy. " "Machine is in enforcing mode. Halting now."); - exit(EXIT_FAILURE); + return EXIT_FAILURE; } } #endif @@ -933,13 +1128,14 @@ int init_main(int argc UNUSED_PARAM, char **argv) strncpy(argv[0], "init", strlen(argv[0])); /* Wipe argv[1]-argv[N] so they don't clutter the ps listing */ while (*++argv) - memset(*argv, 0, strlen(*argv)); + nuke_str(*argv); /* Set up signal handlers */ if (!DEBUG_INIT) { struct sigaction sa; bb_signals(0 + + (1 << SIGPWR) /* halt */ + (1 << SIGUSR1) /* halt */ + (1 << SIGTERM) /* reboot */ + (1 << SIGUSR2) /* poweroff */ @@ -1028,3 +1224,138 @@ int init_main(int argc UNUSED_PARAM, char **argv) } } /* while (1) */ } + +//usage:#define linuxrc_trivial_usage NOUSAGE_STR +//usage:#define linuxrc_full_usage "" + +//usage:#define init_trivial_usage +//usage: "" +//usage:#define init_full_usage "\n\n" +//usage: "Init is the first process started during boot. It never exits." +//usage: IF_FEATURE_USE_INITTAB( +//usage: "\n""It (re)spawns children according to /etc/inittab." +//usage: ) +//usage: IF_NOT_FEATURE_USE_INITTAB( +//usage: "\n""This version of init doesn't use /etc/inittab," +//usage: "\n""has fixed set of processed to run." +//usage: ) +//usage: +//usage:#define init_notes_usage +//usage: "This version of init is designed to be run only by the kernel.\n" +//usage: "\n" +//usage: "BusyBox init doesn't support multiple runlevels. The runlevels field of\n" +//usage: "the /etc/inittab file is completely ignored by BusyBox init. If you want\n" +//usage: "runlevels, use sysvinit.\n" +//usage: "\n" +//usage: "BusyBox init works just fine without an inittab. If no inittab is found,\n" +//usage: "it has the following default behavior:\n" +//usage: "\n" +//usage: " ::sysinit:/etc/init.d/rcS\n" +//usage: " ::askfirst:/bin/sh\n" +//usage: " ::ctrlaltdel:/sbin/reboot\n" +//usage: " ::shutdown:/sbin/swapoff -a\n" +//usage: " ::shutdown:/bin/umount -a -r\n" +//usage: " ::restart:/sbin/init\n" +//usage: " tty2::askfirst:/bin/sh\n" +//usage: " tty3::askfirst:/bin/sh\n" +//usage: " tty4::askfirst:/bin/sh\n" +//usage: "\n" +//usage: "If you choose to use an /etc/inittab file, the inittab entry format is as follows:\n" +//usage: "\n" +//usage: " :::\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " WARNING: This field has a non-traditional meaning for BusyBox init!\n" +//usage: " The id field is used by BusyBox init to specify the controlling tty for\n" +//usage: " the specified process to run on. The contents of this field are\n" +//usage: " appended to \"/dev/\" and used as-is. There is no need for this field to\n" +//usage: " be unique, although if it isn't you may have strange results. If this\n" +//usage: " field is left blank, then the init's stdin/out will be used.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " The runlevels field is completely ignored.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " Valid actions include: sysinit, respawn, askfirst, wait,\n" +//usage: " once, restart, ctrlaltdel, and shutdown.\n" +//usage: "\n" +//usage: " The available actions can be classified into two groups: actions\n" +//usage: " that are run only once, and actions that are re-run when the specified\n" +//usage: " process exits.\n" +//usage: "\n" +//usage: " Run only-once actions:\n" +//usage: "\n" +//usage: " 'sysinit' is the first item run on boot. init waits until all\n" +//usage: " sysinit actions are completed before continuing. Following the\n" +//usage: " completion of all sysinit actions, all 'wait' actions are run.\n" +//usage: " 'wait' actions, like 'sysinit' actions, cause init to wait until\n" +//usage: " the specified task completes. 'once' actions are asynchronous,\n" +//usage: " therefore, init does not wait for them to complete. 'restart' is\n" +//usage: " the action taken to restart the init process. By default this should\n" +//usage: " simply run /sbin/init, but can be a script which runs pivot_root or it\n" +//usage: " can do all sorts of other interesting things. The 'ctrlaltdel' init\n" +//usage: " actions are run when the system detects that someone on the system\n" +//usage: " console has pressed the CTRL-ALT-DEL key combination. Typically one\n" +//usage: " wants to run 'reboot' at this point to cause the system to reboot.\n" +//usage: " Finally the 'shutdown' action specifies the actions to taken when\n" +//usage: " init is told to reboot. Unmounting filesystems and disabling swap\n" +//usage: " is a very good here.\n" +//usage: "\n" +//usage: " Run repeatedly actions:\n" +//usage: "\n" +//usage: " 'respawn' actions are run after the 'once' actions. When a process\n" +//usage: " started with a 'respawn' action exits, init automatically restarts\n" +//usage: " it. Unlike sysvinit, BusyBox init does not stop processes from\n" +//usage: " respawning out of control. The 'askfirst' actions acts just like\n" +//usage: " respawn, except that before running the specified process it\n" +//usage: " displays the line \"Please press Enter to activate this console.\"\n" +//usage: " and then waits for the user to press enter before starting the\n" +//usage: " specified process.\n" +//usage: "\n" +//usage: " Unrecognized actions (like initdefault) will cause init to emit an\n" +//usage: " error message, and then go along with its business. All actions are\n" +//usage: " run in the order they appear in /etc/inittab.\n" +//usage: "\n" +//usage: " :\n" +//usage: "\n" +//usage: " Specifies the process to be executed and its command line.\n" +//usage: "\n" +//usage: "Example /etc/inittab file:\n" +//usage: "\n" +//usage: " # This is run first except when booting in single-user mode\n" +//usage: " #\n" +//usage: " ::sysinit:/etc/init.d/rcS\n" +//usage: " \n" +//usage: " # /bin/sh invocations on selected ttys\n" +//usage: " #\n" +//usage: " # Start an \"askfirst\" shell on the console (whatever that may be)\n" +//usage: " ::askfirst:-/bin/sh\n" +//usage: " # Start an \"askfirst\" shell on /dev/tty2-4\n" +//usage: " tty2::askfirst:-/bin/sh\n" +//usage: " tty3::askfirst:-/bin/sh\n" +//usage: " tty4::askfirst:-/bin/sh\n" +//usage: " \n" +//usage: " # /sbin/getty invocations for selected ttys\n" +//usage: " #\n" +//usage: " tty4::respawn:/sbin/getty 38400 tty4\n" +//usage: " tty5::respawn:/sbin/getty 38400 tty5\n" +//usage: " \n" +//usage: " \n" +//usage: " # Example of how to put a getty on a serial line (for a terminal)\n" +//usage: " #\n" +//usage: " #::respawn:/sbin/getty -L ttyS0 9600 vt100\n" +//usage: " #::respawn:/sbin/getty -L ttyS1 9600 vt100\n" +//usage: " #\n" +//usage: " # Example how to put a getty on a modem line\n" +//usage: " #::respawn:/sbin/getty 57600 ttyS2\n" +//usage: " \n" +//usage: " # Stuff to do when restarting the init process\n" +//usage: " ::restart:/sbin/init\n" +//usage: " \n" +//usage: " # Stuff to do before rebooting\n" +//usage: " ::ctrlaltdel:/sbin/reboot\n" +//usage: " ::shutdown:/bin/umount -a -r\n" +//usage: " ::shutdown:/sbin/swapoff -a\n" diff --git a/init/mesg.c b/init/mesg.c index 2e8b16e..45c13b8 100644 --- a/init/mesg.c +++ b/init/mesg.c @@ -4,45 +4,73 @@ * * Copyright (c) 2002 Manuel Novoa III * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config MESG +//config: bool "mesg" +//config: default y +//config: help +//config: Mesg controls access to your terminal by others. It is typically +//config: used to allow or disallow other users to write to your terminal +//config: +//config:config FEATURE_MESG_ENABLE_ONLY_GROUP +//config: bool "Enable writing to tty only by group, not by everybody" +//config: default y +//config: depends on MESG +//config: help +//config: Usually, ttys are owned by group "tty", and "write" tool is +//config: setgid to this group. This way, "mesg y" only needs to enable +//config: "write by owning group" bit in tty mode. +//config: +//config: If you set this option to N, "mesg y" will enable writing +//config: by anybody at all. This is not recommended. + +//applet:IF_MESG(APPLET(mesg, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_MESG) += mesg.o + +//usage:#define mesg_trivial_usage +//usage: "[y|n]" +//usage:#define mesg_full_usage "\n\n" +//usage: "Control write access to your terminal\n" +//usage: " y Allow write access to your terminal\n" +//usage: " n Disallow write access to your terminal" + #include "libbb.h" -#ifdef USE_TTY_GROUP -#define S_IWGRP_OR_S_IWOTH S_IWGRP +#if ENABLE_FEATURE_MESG_ENABLE_ONLY_GROUP +#define S_IWGRP_OR_S_IWOTH S_IWGRP #else -#define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH) +#define S_IWGRP_OR_S_IWOTH (S_IWGRP | S_IWOTH) #endif int mesg_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int mesg_main(int argc UNUSED_PARAM, char **argv) { struct stat sb; - const char *tty; + mode_t m; char c = 0; argv++; - if (!argv[0] - || (!argv[1] && ((c = argv[0][0]) == 'y' || c == 'n')) + if (argv[0] + && (argv[1] || ((c = argv[0][0]) != 'y' && c != 'n')) ) { - tty = xmalloc_ttyname(STDERR_FILENO); - if (tty == NULL) { - tty = "ttyname"; - } else if (stat(tty, &sb) == 0) { - mode_t m; - if (c == 0) { - puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); - return EXIT_SUCCESS; - } - m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH - : sb.st_mode & ~(S_IWGRP|S_IWOTH); - if (chmod(tty, m) == 0) { - return EXIT_SUCCESS; - } - } - bb_simple_perror_msg_and_die(tty); + bb_show_usage(); + } + + if (!isatty(STDIN_FILENO)) + bb_error_msg_and_die("not a tty"); + + xfstat(STDIN_FILENO, &sb, "stderr"); + if (c == 0) { + puts((sb.st_mode & (S_IWGRP|S_IWOTH)) ? "is y" : "is n"); + return EXIT_SUCCESS; } - bb_show_usage(); + m = (c == 'y') ? sb.st_mode | S_IWGRP_OR_S_IWOTH + : sb.st_mode & ~(S_IWGRP|S_IWOTH); + if (fchmod(STDIN_FILENO, m) != 0) + bb_perror_nomsg_and_die(); + return EXIT_SUCCESS; } diff --git a/init/reboot.h b/init/reboot.h new file mode 100644 index 0000000..9497639 --- /dev/null +++ b/init/reboot.h @@ -0,0 +1,30 @@ +/* + * Definitions related to the reboot() system call, + * shared between init.c and halt.c. + */ + +#include + +#ifndef RB_HALT_SYSTEM +# if defined(__linux__) +# define RB_HALT_SYSTEM 0xcdef0123 +# define RB_ENABLE_CAD 0x89abcdef +# define RB_DISABLE_CAD 0 +# define RB_POWER_OFF 0x4321fedc +# define RB_AUTOBOOT 0x01234567 +# elif defined(RB_HALT) +# define RB_HALT_SYSTEM RB_HALT +# endif +#endif + +/* Stop system and switch power off if possible. */ +#ifndef RB_POWER_OFF +# if defined(RB_POWERDOWN) +# define RB_POWER_OFF RB_POWERDOWN +# elif defined(__linux__) +# define RB_POWER_OFF 0x4321fedc +# else +# warning "poweroff unsupported, using halt as fallback" +# define RB_POWER_OFF RB_HALT_SYSTEM +# endif +#endif diff --git a/libbb/Config.src b/libbb/Config.src index 09bf892..19021fe 100644 --- a/libbb/Config.src +++ b/libbb/Config.src @@ -14,9 +14,9 @@ config PASSWORD_MINLEN help Minimum allowable password length. -config MD5_SIZE_VS_SPEED +config MD5_SMALL int "MD5: Trade bytes for speed (0:fast, 3:slow)" - default 2 + default 1 range 0 3 help Trade binary size versus speed for the md5sum algorithm. @@ -28,6 +28,16 @@ config MD5_SIZE_VS_SPEED 2 3.0 5088 3 (smallest) 5.1 4912 +config SHA3_SMALL + int "SHA3: Trade bytes for speed (0:fast, 1:slow)" + default 1 + range 0 1 + help + Trade binary size versus speed for the sha3sum algorithm. + SHA3_SMALL=0 compared to SHA3_SMALL=1 (approximate): + 64-bit x86: +270 bytes of code, 45% faster + 32-bit x86: +450 bytes of code, 75% faster + config FEATURE_FAST_TOP bool "Faster /proc scanning code (+100 bytes)" default y @@ -43,6 +53,17 @@ config FEATURE_ETC_NETWORKS a rarely used feature which allows you to use names instead of IP/mask pairs in route command. +config FEATURE_USE_TERMIOS + bool "Use termios to manipulate the screen" + default y + depends on MORE || TOP || POWERTOP + help + This option allows utilities such as 'more' and 'top' to determine + the size of the screen. If you leave this disabled, your utilities + that display things on the screen will be especially primitive and + will be unable to determine the current screen size, and will be + unable to move the cursor. + config FEATURE_EDITING bool "Command line editing" default y @@ -69,18 +90,34 @@ config FEATURE_EDITING_VI config FEATURE_EDITING_HISTORY int "History size" - range 0 99999 + # Don't allow way too big values here, code uses fixed "char *history[N]" struct member + range 0 9999 default 255 depends on FEATURE_EDITING help - Specify command history size. + Specify command history size (0 - disable). config FEATURE_EDITING_SAVEHISTORY bool "History saving" default y - depends on ASH && FEATURE_EDITING + depends on FEATURE_EDITING + help + Enable history saving in shells. + +config FEATURE_EDITING_SAVE_ON_EXIT + bool "Save history on shell exit, not after every command" + default n + depends on FEATURE_EDITING_SAVEHISTORY + help + Save history on shell exit, not after every command. + +config FEATURE_REVERSE_SEARCH + bool "Reverse history search" + default y + depends on FEATURE_EDITING_SAVEHISTORY help - Enable history saving in ash shell. + Enable readline-like Ctrl-R combination for reverse history search. + Increases code by about 0.5k. config FEATURE_TAB_COMPLETION bool "Tab completion" @@ -124,7 +161,7 @@ config FEATURE_NON_POSIX_CP and create a regular file. This does not conform to POSIX, but prevents a symlink attack. Similarly, "cp file device" will not send file's data - to the device. + to the device. (To do that, use "cat file >device") config FEATURE_VERBOSE_CP_MESSAGE bool "Give more precise messages when copy fails (cp, mv etc)" @@ -145,14 +182,34 @@ config FEATURE_COPYBUF_KB range 1 1024 default 4 help - Size of buffer used by cp, mv, install etc. + Size of buffer used by cp, mv, install, wget etc. Buffers which are 4 kb or less will be allocated on stack. Bigger buffers will be allocated with mmap, with fallback to 4 kb stack buffer if mmap fails. +config FEATURE_SKIP_ROOTFS + bool "Skip rootfs in mount table" + default y + help + Ignore rootfs entry in mount table. + + In Linux, kernel has a special filesystem, rootfs, which is initially + mounted on /. It contains initramfs data, if kernel is configured + to have one. Usually, another file system is mounted over / early + in boot process, and therefore most tools which manipulate + mount table, such as df, will skip rootfs entry. + + However, some systems do not mount anything on /. + If you need to configure busybox for one of these systems, + you may find it useful to turn this option off to make df show + initramfs statistics. + + Otherwise, choose Y. + config MONOTONIC_SYSCALL bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" default n + select PLATFORM_LINUX help Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring time intervals (time, ping, traceroute etc need this). diff --git a/libbb/Kbuild.src b/libbb/Kbuild.src index 5c56700..a6468f1 100644 --- a/libbb/Kbuild.src +++ b/libbb/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. libbb/appletlib.o: include/usage_compressed.h @@ -13,7 +13,7 @@ INSERT lib-y += appletlib.o lib-y += ask_confirmation.o lib-y += bb_askpass.o -lib-y += bb_basename.o +lib-y += bb_bswap_64.o lib-y += bb_do_delay.o lib-y += bb_pwd.o lib-y += bb_qsort.o @@ -27,8 +27,6 @@ lib-y += concat_subpath_file.o lib-y += copy_file.o lib-y += copyfd.o lib-y += crc32.o -lib-y += create_icmp6_socket.o -lib-y += create_icmp_socket.o lib-y += default_error_retval.o lib-y += device_open.o lib-y += dump.o @@ -58,16 +56,12 @@ lib-y += llist.o lib-y += login.o lib-y += make_directory.o lib-y += makedev.o -lib-y += match_fstype.o -lib-y += md5.o -# Alternative (disabled) implementation -#lib-y += md5prime.o +lib-y += hash_md5_sha.o +# Alternative (disabled) MD5 implementation +#lib-y += hash_md5prime.o lib-y += messages.o lib-y += mode_string.o -lib-y += mtab_file.o -lib-y += obscure.o lib-y += parse_mode.o -lib-y += parse_config.o lib-y += perror_msg.o lib-y += perror_nomsg.o lib-y += perror_nomsg_and_die.o @@ -91,7 +85,6 @@ lib-y += safe_poll.o lib-y += safe_strncpy.o lib-y += safe_write.o lib-y += setup_environment.o -lib-y += sha1.o lib-y += signals.o lib-y += simplify_path.o lib-y += single_argv.o @@ -102,7 +95,6 @@ lib-y += strrstr.o lib-y += time.o lib-y += trim.o lib-y += u_signal_names.o -lib-y += udp_io.o lib-y += uuencode.o lib-y += vdprintf.o lib-y += verror_msg.o @@ -121,6 +113,8 @@ lib-y += xgethostbyname.o lib-y += xreadlink.o lib-y += xrealloc_vector.o +lib-$(CONFIG_PLATFORM_LINUX) += match_fstype.o + lib-$(CONFIG_FEATURE_UTMP) += utmp.o # A mix of optimizations (why build stuff we know won't be used) @@ -130,6 +124,15 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o +lib-$(CONFIG_NC) += udp_io.o +lib-$(CONFIG_DNSD) += udp_io.o +lib-$(CONFIG_NTPD) += udp_io.o +lib-$(CONFIG_TFTP) += udp_io.o +lib-$(CONFIG_TFTPD) += udp_io.o +lib-$(CONFIG_TCPSVD) += udp_io.o +lib-$(CONFIG_UDPSVD) += udp_io.o +lib-$(CONFIG_TRACEROUTE) += udp_io.o + lib-$(CONFIG_LOSETUP) += loop.o lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o @@ -138,10 +141,10 @@ lib-$(CONFIG_ADDUSER) += update_passwd.o lib-$(CONFIG_DELGROUP) += update_passwd.o lib-$(CONFIG_DELUSER) += update_passwd.o -lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o +lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o obscure.o lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o lib-$(CONFIG_CRYPTPW) += pw_encrypt.o -lib-$(CONFIG_SULOGIN) += pw_encrypt.o +lib-$(CONFIG_SULOGIN) += pw_encrypt.o correct_password.o lib-$(CONFIG_VLOCK) += pw_encrypt.o correct_password.o lib-$(CONFIG_SU) += pw_encrypt.o correct_password.o lib-$(CONFIG_LOGIN) += pw_encrypt.o correct_password.o @@ -157,6 +160,17 @@ lib-$(CONFIG_MOUNT) += find_mount_point.o lib-$(CONFIG_HWCLOCK) += rtc.o lib-$(CONFIG_RTCWAKE) += rtc.o +lib-$(CONFIG_IOSTAT) += get_cpu_count.o +lib-$(CONFIG_MPSTAT) += get_cpu_count.o +lib-$(CONFIG_POWERTOP) += get_cpu_count.o + +lib-$(CONFIG_PING) += inet_cksum.o +lib-$(CONFIG_TRACEROUTE) += inet_cksum.o +lib-$(CONFIG_TRACEROUTE6) += inet_cksum.o +lib-$(CONFIG_UDHCPC) += inet_cksum.o +lib-$(CONFIG_UDHCPC6) += inet_cksum.o +lib-$(CONFIG_UDHCPD) += inet_cksum.o + # We shouldn't build xregcomp.c if we don't need it - this ensures we don't # require regex.h to be in the include dir even if we don't need it thereby # allowing us to build busybox even if uclibc regex support is disabled. diff --git a/libbb/README b/libbb/README index 4f28f7e..6e63dc5 100644 --- a/libbb/README +++ b/libbb/README @@ -8,4 +8,3 @@ that you wrote that is mis-attributed, do let me know so we can fix that up. Erik Andersen - diff --git a/libbb/appletlib.c b/libbb/appletlib.c index 4924a97..8f3a8a1 100644 --- a/libbb/appletlib.c +++ b/libbb/appletlib.c @@ -7,9 +7,9 @@ * here, please feel free to acknowledge your work. * * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. + * Permission has been granted to redistribute this code under GPL. * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* We are trying to not use printf, this benefits the case when selected @@ -27,14 +27,11 @@ * FEATURE_INSTALLER or FEATURE_SUID will still link printf routines in. :( */ #include "busybox.h" -#include -#include -/* Try to pull in PAGE_SIZE */ -#ifdef __linux__ -# include -#endif -#ifdef __GNU__ /* Hurd */ -# include + +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for mallopt */ #endif @@ -43,7 +40,6 @@ #include "applets.h" #undef PROTOTYPES - /* Include generated applet names, pointers to _main, etc */ #include "applet_tables.h" /* ...and if applet_tables generator says we have only one applet... */ @@ -54,9 +50,9 @@ # define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__ #endif - #include "usage_compressed.h" + #if ENABLE_SHOW_USAGE && !ENABLE_FEATURE_COMPRESS_USAGE static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #else @@ -66,7 +62,7 @@ static const char usage_messages[] ALIGN1 = UNPACKED_USAGE; #if ENABLE_FEATURE_COMPRESS_USAGE static const char packed_usage[] ALIGN1 = { PACKED_USAGE }; -# include "unarchive.h" +# include "bb_archive.h" static const char *unpack_usage_messages(void) { char *outbuf = NULL; @@ -75,7 +71,7 @@ static const char *unpack_usage_messages(void) i = start_bunzip(&bd, /* src_fd: */ -1, - /* inbuf: */ (void *)packed_usage, + /* inbuf: */ packed_usage, /* len: */ sizeof(packed_usage)); /* read_bunzip can longjmp to start_bunzip, and ultimately * end up here with i != 0 on read data errors! Not trivial */ @@ -103,14 +99,13 @@ void FAST_FUNC bb_show_usage(void) if (ENABLE_SHOW_USAGE) { #ifdef SINGLE_APPLET_STR /* Imagine that this applet is "true". Dont suck in printf! */ - const char *p; - const char *usage_string = p = unpack_usage_messages(); + const char *usage_string = unpack_usage_messages(); - if (*p == '\b') { + if (*usage_string == '\b') { full_write2_str("No help available.\n\n"); } else { full_write2_str("Usage: "SINGLE_APPLET_STR" "); - full_write2_str(p); + full_write2_str(usage_string); full_write2_str("\n\n"); } if (ENABLE_FEATURE_CLEAN_UP) @@ -145,10 +140,9 @@ void FAST_FUNC bb_show_usage(void) } #if NUM_APPLETS > 8 -/* NB: any char pointer will work as well, not necessarily applet_names */ -static int applet_name_compare(const void *name, const void *v) +static int applet_name_compare(const void *name, const void *idx) { - int i = (const char *)v - applet_names; + int i = (int)(ptrdiff_t)idx - 1; return strcmp(name, APPLET_NAME(i)); } #endif @@ -157,10 +151,12 @@ int FAST_FUNC find_applet_by_name(const char *name) #if NUM_APPLETS > 8 /* Do a binary search to find the applet entry given the name. */ const char *p; - p = bsearch(name, applet_names, ARRAY_SIZE(applet_main), 1, applet_name_compare); - if (!p) - return -1; - return p - applet_names; + p = bsearch(name, (void*)(ptrdiff_t)1, ARRAY_SIZE(applet_main), 1, applet_name_compare); + /* + * if (!p) return -1; + * ^^^^^^^^^^^^^^^^^^ the code below will do this if p == NULL :) + */ + return (int)(ptrdiff_t)p - 1; #else /* A version which does not pull in bsearch */ int i = 0; @@ -228,15 +224,14 @@ bool re_execed; IF_FEATURE_SUID(static uid_t ruid;) /* real uid */ -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG -/* applets[] is const, so we have to define this "override" structure */ -static struct BB_suid_config { +static struct suid_config_t { + /* next ptr must be first: this struct needs to be llist-compatible */ + struct suid_config_t *m_next; + struct bb_uidgid_t m_ugid; int m_applet; - uid_t m_uid; - gid_t m_gid; mode_t m_mode; - struct BB_suid_config *m_next; } *suid_config; static bool suid_cfg_readable; @@ -245,13 +240,10 @@ static bool suid_cfg_readable; static int ingroup(uid_t u, gid_t g) { struct group *grp = getgrgid(g); - if (grp) { char **mem; - for (mem = grp->gr_mem; *mem; mem++) { struct passwd *pwd = getpwnam(*mem); - if (pwd && (pwd->pw_uid == u)) return 1; } @@ -259,9 +251,7 @@ static int ingroup(uid_t u, gid_t g) return 0; } -/* This should probably be a libbb routine. In that case, - * I'd probably rename it to something like bb_trimmed_slice. - */ +/* libbb candidate */ static char *get_trimmed_slice(char *s, char *e) { /* First, consider the value at e to be nul and back up until we @@ -279,38 +269,19 @@ static char *get_trimmed_slice(char *s, char *e) return skip_whitespace(s); } -/* Don't depend on the tools to combine strings. */ -static const char config_file[] ALIGN1 = "/etc/busybox.conf"; - -/* We don't supply a value for the nul, so an index adjustment is - * necessary below. Also, we use unsigned short here to save some - * space even though these are really mode_t values. */ -static const unsigned short mode_mask[] ALIGN2 = { - /* SST sst xxx --- */ - S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* user */ - S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* group */ - 0, S_IXOTH, S_IXOTH, 0 /* other */ -}; - -#define parse_error(x) do { errmsg = x; goto pe_label; } while (0) - static void parse_config_file(void) { - struct BB_suid_config *sct_head; - struct BB_suid_config *sct; + /* Don't depend on the tools to combine strings. */ + static const char config_file[] ALIGN1 = "/etc/busybox.conf"; + + struct suid_config_t *sct_head; int applet_no; FILE *f; const char *errmsg; - char *s; - char *e; - int i; unsigned lc; smallint section; - char buffer[256]; struct stat st; - assert(!suid_config); /* Should be set to NULL by bss init. */ - ruid = getuid(); if (ruid == 0) /* run by root - don't need to even read config file */ return; @@ -319,7 +290,7 @@ static void parse_config_file(void) || !S_ISREG(st.st_mode) /* Not a regular file? */ || (st.st_uid != 0) /* Not owned by root? */ || (st.st_mode & (S_IWGRP | S_IWOTH)) /* Writable by non-root? */ - || !(f = fopen_for_read(config_file)) /* Cannot open? */ + || !(f = fopen_for_read(config_file)) /* Cannot open? */ ) { return; } @@ -329,18 +300,21 @@ static void parse_config_file(void) section = lc = 0; while (1) { - s = buffer; - - if (!fgets(s, sizeof(buffer), f)) { /* Are we done? */ -// why? - if (ferror(f)) { /* Make sure it wasn't a read error. */ - parse_error("reading"); - } + char buffer[256]; + char *s; + + if (!fgets(buffer, sizeof(buffer), f)) { /* Are we done? */ + // Looks like bloat + //if (ferror(f)) { /* Make sure it wasn't a read error. */ + // errmsg = "reading"; + // goto pe_label; + //} fclose(f); suid_config = sct_head; /* Success, so set the pointer. */ return; } + s = buffer; lc++; /* Got a (partial) line. */ /* If a line is too long for our buffer, we consider it an error. @@ -352,7 +326,8 @@ static void parse_config_file(void) * we do err on the side of caution. Besides, the line would be * too long if it did end with a newline. */ if (!strchr(s, '\n') && !feof(f)) { - parse_error("line too long"); + errmsg = "line too long"; + goto pe_label; } /* Trim leading and trailing whitespace, ignoring comments, and @@ -368,12 +343,13 @@ static void parse_config_file(void) /* Unlike the old code, we ignore leading and trailing * whitespace for the section name. We also require that * there are no stray characters after the closing bracket. */ - e = strchr(s, ']'); + char *e = strchr(s, ']'); if (!e /* Missing right bracket? */ || e[1] /* Trailing characters? */ || !*(s = get_trimmed_slice(s+1, e)) /* Missing name? */ ) { - parse_error("section header"); + errmsg = "section header"; + goto pe_label; } /* Right now we only have one section so just check it. * If more sections are added in the future, please don't @@ -398,12 +374,13 @@ static void parse_config_file(void) * where both key and value could contain inner whitespace. */ /* First get the key (an applet name in our case). */ - e = strchr(s, '='); + char *e = strchr(s, '='); if (e) { s = get_trimmed_slice(s, e); } if (!e || !*s) { /* Missing '=' or empty key. */ - parse_error("keyword"); + errmsg = "keyword"; + goto pe_label; } /* Ok, we have an applet name. Process the rhs if this @@ -412,13 +389,16 @@ static void parse_config_file(void) * up when the busybox configuration is changed. */ applet_no = find_applet_by_name(s); if (applet_no >= 0) { + unsigned i; + struct suid_config_t *sct; + /* Note: We currently don't check for duplicates! * The last config line for each applet will be the * one used since we insert at the head of the list. * I suppose this could be considered a feature. */ - sct = xmalloc(sizeof(struct BB_suid_config)); + sct = xzalloc(sizeof(*sct)); sct->m_applet = applet_no; - sct->m_mode = 0; + /*sct->m_mode = 0;*/ sct->m_next = sct_head; sct_head = sct; @@ -427,48 +407,41 @@ static void parse_config_file(void) e = skip_whitespace(e+1); for (i = 0; i < 3; i++) { - /* There are 4 chars + 1 nul for each of user/group/other. */ - static const char mode_chars[] ALIGN1 = "Ssx-\0" "Ssx-\0" "Ttx-"; - - const char *q; - q = strchrnul(mode_chars + 5*i, *e++); - if (!*q) { - parse_error("mode"); + /* There are 4 chars for each of user/group/other. + * "x-xx" instead of "x-" are to make + * "idx > 3" check catch invalid chars. + */ + static const char mode_chars[] ALIGN1 = "Ssx-" "Ssx-" "x-xx"; + static const unsigned short mode_mask[] ALIGN2 = { + S_ISUID, S_ISUID|S_IXUSR, S_IXUSR, 0, /* Ssx- */ + S_ISGID, S_ISGID|S_IXGRP, S_IXGRP, 0, /* Ssx- */ + S_IXOTH, 0 /* x- */ + }; + const char *q = strchrnul(mode_chars + 4*i, *e); + unsigned idx = q - (mode_chars + 4*i); + if (idx > 3) { + errmsg = "mode"; + goto pe_label; } - /* Adjust by -i to account for nul. */ - sct->m_mode |= mode_mask[(q - mode_chars) - i]; + sct->m_mode |= mode_mask[q - mode_chars]; + e++; } - /* Now get the the user/group info. */ + /* Now get the user/group info. */ s = skip_whitespace(e); - - /* Note: we require whitespace between the mode and the - * user/group info. */ - if ((s == e) || !(e = strchr(s, '.'))) { - parse_error("."); - } - *e++ = '\0'; - - /* We can't use get_ug_id here since it would exit() - * if a uid or gid was not found. Oh well... */ - sct->m_uid = bb_strtoul(s, NULL, 10); - if (errno) { - struct passwd *pwd = getpwnam(s); - if (!pwd) { - parse_error("user"); + /* Default is 0.0, else parse USER.GROUP: */ + if (*s) { + /* We require whitespace between mode and USER.GROUP */ + if ((s == e) || !(e = strchr(s, '.'))) { + errmsg = "uid.gid"; + goto pe_label; } - sct->m_uid = pwd->pw_uid; - } - - sct->m_gid = bb_strtoul(e, NULL, 10); - if (errno) { - struct group *grp; - grp = getgrnam(e); - if (!grp) { - parse_error("group"); + *e = ':'; /* get_uidgid needs USER:GROUP syntax */ + if (get_uidgid(&sct->m_ugid, s, /*allow_numeric:*/ 1) == 0) { + errmsg = "unknown user/group"; + goto pe_label; } - sct->m_gid = grp->gr_gid; } } continue; @@ -482,32 +455,28 @@ static void parse_config_file(void) * We may want to simply ignore such lines in case they * are used in some future version of busybox. */ if (!section) { - parse_error("keyword outside section"); + errmsg = "keyword outside section"; + goto pe_label; } } /* while (1) */ pe_label: - fprintf(stderr, "Parse error in %s, line %d: %s\n", - config_file, lc, errmsg); - fclose(f); + bb_error_msg("parse error in %s, line %u: %s", config_file, lc, errmsg); + /* Release any allocated memory before returning. */ - while (sct_head) { - sct = sct_head->m_next; - free(sct_head); - sct_head = sct; - } + llist_free((llist_t*)sct_head, NULL); } -#else +# else static inline void parse_config_file(void) { IF_FEATURE_SUID(ruid = getuid();) } -#endif /* FEATURE_SUID_CONFIG */ +# endif /* FEATURE_SUID_CONFIG */ -#if ENABLE_FEATURE_SUID +# if ENABLE_FEATURE_SUID static void check_suid(int applet_no) { gid_t rgid; /* real gid */ @@ -516,10 +485,10 @@ static void check_suid(int applet_no) return; /* run by root - no need to check more */ rgid = getgid(); -#if ENABLE_FEATURE_SUID_CONFIG +# if ENABLE_FEATURE_SUID_CONFIG if (suid_cfg_readable) { uid_t uid; - struct BB_suid_config *sct; + struct suid_config_t *sct; mode_t m; for (sct = suid_config; sct; sct = sct->m_next) { @@ -528,76 +497,85 @@ static void check_suid(int applet_no) } goto check_need_suid; found: + /* Is this user allowed to run this applet? */ m = sct->m_mode; - if (sct->m_uid == ruid) + if (sct->m_ugid.uid == ruid) /* same uid */ m >>= 6; - else if ((sct->m_gid == rgid) || ingroup(ruid, sct->m_gid)) + else if ((sct->m_ugid.gid == rgid) || ingroup(ruid, sct->m_ugid.gid)) /* same group / in group */ m >>= 3; - - if (!(m & S_IXOTH)) /* is x bit not set ? */ - bb_error_msg_and_die("you have no permission to run this applet!"); - - /* _both_ sgid and group_exec have to be set for setegid */ - if ((sct->m_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) - rgid = sct->m_gid; - /* else (no setegid) we will set egid = rgid */ + if (!(m & S_IXOTH)) /* is x bit not set? */ + bb_error_msg_and_die("you have no permission to run this applet"); /* We set effective AND saved ids. If saved-id is not set - * like we do below, seteiud(0) can still later succeed! */ + * like we do below, seteuid(0) can still later succeed! */ + + /* Are we directed to change gid + * (APPLET = *s* USER.GROUP or APPLET = *S* USER.GROUP)? + */ + if (sct->m_mode & S_ISGID) + rgid = sct->m_ugid.gid; + /* else: we will set egid = rgid, thus dropping sgid effect */ if (setresgid(-1, rgid, rgid)) bb_perror_msg_and_die("setresgid"); - /* do we have to set effective uid? */ + /* Are we directed to change uid + * (APPLET = s** USER.GROUP or APPLET = S** USER.GROUP)? + */ uid = ruid; if (sct->m_mode & S_ISUID) - uid = sct->m_uid; - /* else (no seteuid) we will set euid = ruid */ - + uid = sct->m_ugid.uid; + /* else: we will set euid = ruid, thus dropping suid effect */ if (setresuid(-1, uid, uid)) bb_perror_msg_and_die("setresuid"); - return; + + goto ret; } -#if !ENABLE_FEATURE_SUID_CONFIG_QUIET +# if !ENABLE_FEATURE_SUID_CONFIG_QUIET { static bool onetime = 0; if (!onetime) { onetime = 1; - fprintf(stderr, "Using fallback suid method\n"); + bb_error_msg("using fallback suid method"); } } -#endif +# endif check_need_suid: -#endif - if (APPLET_SUID(applet_no) == _BB_SUID_REQUIRE) { +# endif + if (APPLET_SUID(applet_no) == BB_SUID_REQUIRE) { /* Real uid is not 0. If euid isn't 0 too, suid bit * is most probably not set on our executable */ if (geteuid()) bb_error_msg_and_die("must be suid to work properly"); - } else if (APPLET_SUID(applet_no) == _BB_SUID_DROP) { + } else if (APPLET_SUID(applet_no) == BB_SUID_DROP) { xsetgid(rgid); /* drop all privileges */ xsetuid(ruid); } +# if ENABLE_FEATURE_SUID_CONFIG + ret: ; + llist_free((llist_t*)suid_config, NULL); +# endif } -#else -#define check_suid(x) ((void)0) -#endif /* FEATURE_SUID */ +# else +# define check_suid(x) ((void)0) +# endif /* FEATURE_SUID */ -#if ENABLE_FEATURE_INSTALLER +# if ENABLE_FEATURE_INSTALLER static const char usr_bin [] ALIGN1 = "/usr/bin/"; static const char usr_sbin[] ALIGN1 = "/usr/sbin/"; static const char *const install_dir[] = { &usr_bin [8], /* "/" */ &usr_bin [4], /* "/bin/" */ - &usr_sbin[4], /* "/sbin/" */ - usr_bin, - usr_sbin + &usr_sbin[4] /* "/sbin/" */ +# if !ENABLE_INSTALL_NO_USR + ,usr_bin + ,usr_sbin +# endif }; - /* create (sym)links for each applet */ static void install_links(const char *busybox, int use_symbolic_links, char *custom_install_dir) @@ -627,9 +605,9 @@ static void install_links(const char *busybox, int use_symbolic_links, free(fpc); } } -#else -# define install_links(x,y,z) ((void)0) -#endif +# else +# define install_links(x,y,z) ((void)0) +# endif /* If we were called as "busybox..." */ static int busybox_main(char **argv) @@ -650,11 +628,15 @@ static int busybox_main(char **argv) full_write2_str(bb_banner); /* reuse const string */ full_write2_str(" multi-call binary.\n"); /* reuse */ full_write2_str( - "Copyright (C) 1998-2009 Erik Andersen, Rob Landley, Denys Vlasenko\n" - "and others. Licensed under GPLv2.\n" - "See source distribution for full notice.\n" + "BusyBox is copyrighted by many authors between 1998-2012.\n" + "Licensed under GPLv2. See source distribution for detailed\n" + "copyright notices.\n" "\n" - "Usage: busybox [function] [arguments]...\n" + "Usage: busybox [function [arguments]...]\n" + " or: busybox --list"IF_FEATURE_INSTALLER("[-full]")"\n" + IF_FEATURE_INSTALLER( + " or: busybox --install [-s] [DIR]\n" + ) " or: function [arguments]...\n" "\n" "\tBusyBox is a multi-call binary that combines many common Unix\n" @@ -693,10 +675,10 @@ static int busybox_main(char **argv) const char *a = applet_names; dup2(1, 2); while (*a) { -#if ENABLE_FEATURE_INSTALLER - if (argv[1][6]) /* --list-path? */ +# if ENABLE_FEATURE_INSTALLER + if (argv[1][6]) /* --list-full? */ full_write2_str(install_dir[APPLET_INSTALL_LOC(i)] + 1); -#endif +# endif full_write2_str(a); full_write2_str("\n"); i++; @@ -708,13 +690,23 @@ static int busybox_main(char **argv) if (ENABLE_FEATURE_INSTALLER && strcmp(argv[1], "--install") == 0) { int use_symbolic_links; const char *busybox; + busybox = xmalloc_readlink(bb_busybox_exec_path); - if (!busybox) - busybox = bb_busybox_exec_path; - /* busybox --install [-s] [DIR]: */ - /* -s: make symlinks */ - /* DIR: directory to install links to */ - use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && argv++); + if (!busybox) { + /* bb_busybox_exec_path is usually "/proc/self/exe". + * In chroot, readlink("/proc/self/exe") usually fails. + * In such case, better use argv[0] as symlink target + * if it is a full path name. + */ + if (argv[0][0] != '/') + bb_error_msg_and_die("'%s' is not an absolute path", argv[0]); + busybox = argv[0]; + } + /* busybox --install [-s] [DIR]: + * -s: make symlinks + * DIR: directory to install links to + */ + use_symbolic_links = (argv[2] && strcmp(argv[2], "-s") == 0 && ++argv); install_links(busybox, use_symbolic_links, argv[2]); return 0; } @@ -756,8 +748,11 @@ void FAST_FUNC run_applet_no_and_exit(int applet_no, char **argv) /* Special case. POSIX says "test --help" * should be no different from e.g. "test --foo". */ //TODO: just compare applet_no with APPLET_NO_test - if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) + if (!ENABLE_TEST || strcmp(applet_name, "test") != 0) { + /* If you want "foo --help" to return 0: */ + xfunc_error_retval = 0; bb_show_usage(); + } } if (ENABLE_FEATURE_SUID) check_suid(applet_no); @@ -769,7 +764,7 @@ void FAST_FUNC run_applet_and_exit(const char *name, char **argv) int applet = find_applet_by_name(name); if (applet >= 0) run_applet_no_and_exit(applet, argv); - if (!strncmp(name, "busybox", 7)) + if (strncmp(name, "busybox", 7) == 0) exit(busybox_main(argv)); } @@ -784,31 +779,20 @@ int main(int argc UNUSED_PARAM, char **argv) #endif { /* Tweak malloc for reduced memory consumption */ -#ifndef PAGE_SIZE -# define PAGE_SIZE (4*1024) /* guess */ -#endif #ifdef M_TRIM_THRESHOLD /* M_TRIM_THRESHOLD is the maximum amount of freed top-most memory * to keep before releasing to the OS * Default is way too big: 256k */ - mallopt(M_TRIM_THRESHOLD, 2 * PAGE_SIZE); + mallopt(M_TRIM_THRESHOLD, 8 * 1024); #endif #ifdef M_MMAP_THRESHOLD /* M_MMAP_THRESHOLD is the request size threshold for using mmap() * Default is too big: 256k */ - mallopt(M_MMAP_THRESHOLD, 8 * PAGE_SIZE - 256); + mallopt(M_MMAP_THRESHOLD, 32 * 1024 - 256); #endif -#if defined(SINGLE_APPLET_MAIN) - /* Only one applet is selected by the user! */ - /* applet_names in this case is just "applet\0\0" */ - lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); - return SINGLE_APPLET_MAIN(argc, argv); -#else - lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); - #if !BB_MMU /* NOMMU re-exec trick sets high-order bit in first byte of name */ if (argv[0][0] & 0x80) { @@ -816,6 +800,19 @@ int main(int argc UNUSED_PARAM, char **argv) argv[0][0] &= 0x7f; } #endif + +#if defined(SINGLE_APPLET_MAIN) + /* Only one applet is selected in .config */ + if (argv[1] && strncmp(argv[0], "busybox", 7) == 0) { + /* "busybox " should still work as expected */ + argv++; + } + /* applet_names in this case is just "applet\0\0" */ + lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv)); + return SINGLE_APPLET_MAIN(argc, argv); +#else + lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv)); + applet_name = argv[0]; if (applet_name[0] == '-') applet_name++; diff --git a/libbb/ask_confirmation.c b/libbb/ask_confirmation.c index e0e9419..d95729c 100644 --- a/libbb/ask_confirmation.c +++ b/libbb/ask_confirmation.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Read a line from stdin. If the first non-whitespace char is 'y' or 'Y', diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c index 12ebe17..77c1bcd 100644 --- a/libbb/bb_askpass.c +++ b/libbb/bb_askpass.c @@ -5,7 +5,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -30,14 +30,23 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) struct sigaction sa, oldsa; struct termios tio, oldtio; - tcgetattr(fd, &oldtio); + fputs(prompt, stdout); + fflush_all(); tcflush(fd, TCIFLUSH); + + tcgetattr(fd, &oldtio); tio = oldtio; -#ifndef IUCLC -# define IUCLC 0 -#endif +#if 0 + /* Switch off UPPERCASE->lowercase conversion (never used since 198x) + * and XON/XOFF (why we want to mess with this??) + */ +# ifndef IUCLC +# define IUCLC 0 +# endif tio.c_iflag &= ~(IUCLC|IXON|IXOFF|IXANY); - tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL|TOSTOP); +#endif + /* Switch off echo */ + tio.c_lflag &= ~(ECHO|ECHOE|ECHOK|ECHONL); tcsetattr(fd, TCSANOW, &tio); memset(&sa, 0, sizeof(sa)); @@ -50,16 +59,15 @@ char* FAST_FUNC bb_ask(const int fd, int timeout, const char *prompt) alarm(timeout); } - fputs(prompt, stdout); - fflush_all(); - if (!passwd) passwd = xmalloc(sizeof_passwd); ret = passwd; i = 0; while (1) { int r = read(fd, &ret[i], 1); - if (r < 0) { + if ((i == 0 && r == 0) /* EOF (^D) with no password */ + || r < 0 + ) { /* read is interrupted by timeout or ^C */ ret = NULL; break; diff --git a/libbb/bb_basename.c b/libbb/bb_basename.c deleted file mode 100644 index bab4166..0000000 --- a/libbb/bb_basename.c +++ /dev/null @@ -1,18 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 2007 Denys Vlasenko - * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -const char* FAST_FUNC bb_basename(const char *name) -{ - const char *cp = strrchr(name, '/'); - if (cp) - return cp + 1; - return name; -} diff --git a/libbb/bb_bswap_64.c b/libbb/bb_bswap_64.c new file mode 100644 index 0000000..ce9d53b --- /dev/null +++ b/libbb/bb_bswap_64.c @@ -0,0 +1,16 @@ +/* + * Utility routines. + * + * Copyright (C) 2010 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" + +#if !(ULONG_MAX > 0xffffffff) +uint64_t FAST_FUNC bb_bswap_64(uint64_t x) +{ + return bswap_64(x); +} +#endif diff --git a/libbb/bb_do_delay.c b/libbb/bb_do_delay.c index 139dc18..05c879f 100644 --- a/libbb/bb_do_delay.c +++ b/libbb/bb_do_delay.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005 by Tito Ragusa * - * Licensed under the GPL v2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/bb_pwd.c b/libbb/bb_pwd.c index d728577..8250cd4 100644 --- a/libbb/bb_pwd.c +++ b/libbb/bb_pwd.c @@ -5,7 +5,7 @@ * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2008 by Tito Ragusa * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -72,13 +72,13 @@ char* FAST_FUNC gid2group(gid_t gid) return (gr) ? gr->gr_name : NULL; } -char* FAST_FUNC uid2uname_utoa(long uid) +char* FAST_FUNC uid2uname_utoa(uid_t uid) { char *name = uid2uname(uid); return (name) ? name : utoa(uid); } -char* FAST_FUNC gid2group_utoa(long gid) +char* FAST_FUNC gid2group_utoa(gid_t gid) { char *name = gid2group(gid); return (name) ? name : utoa(gid); @@ -110,3 +110,51 @@ unsigned long FAST_FUNC get_ug_id(const char *s, return xname2id(s); return r; } + +/* Experimental "mallocing" API. + * The goal is nice: "we want to support a case when "guests" group is very large" + * but the code is butt-ugly. + */ +#if 0 +static char *find_latest(char last, char *cp) +{ + if (!cp) + return last; + cp += strlen(cp) + 1; + if (last < cp) + last = cp; + return last; +} + +struct group* FAST_FUNC xmalloc_getgrnam(const char *name) +{ + struct { + struct group gr; + // May still be not enough! + char buf[64*1024 - sizeof(struct group) - 16]; + } *s; + struct group *grp; + int r; + char *last; + char **gr_mem; + + s = xmalloc(sizeof(*s)); + r = getgrnam_r(name, &s->gr, s->buf, sizeof(s->buf), &grp); + if (!grp) { + free(s); + return grp; + } + last = find_latest(s->buf, grp->gr_name); + last = find_latest(last, grp->gr_passwd); + gr_mem = grp->gr_mem; + while (*gr_mem) + last = find_latest(last, *gr_mem++); + gr_mem++; /* points past NULL */ + if (last < (char*)gr_mem) + last = (char*)gr_mem; +//FIXME: what if we get not only truncated, but also moved here? +// grp->gr_name pointer and friends are invalid now!!! + s = xrealloc(s, last - (char*)s); + return grp; +} +#endif diff --git a/libbb/bb_qsort.c b/libbb/bb_qsort.c index 9773afa..a54e723 100644 --- a/libbb/bb_qsort.c +++ b/libbb/bb_qsort.c @@ -4,7 +4,7 @@ * * Copyright (c) 2008 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/bb_strtod.c b/libbb/bb_strtod.c index 1e96710..5dde784 100644 --- a/libbb/bb_strtod.c +++ b/libbb/bb_strtod.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/bb_strtonum.c b/libbb/bb_strtonum.c index 87cd744..949f26b 100644 --- a/libbb/bb_strtonum.c +++ b/libbb/bb_strtonum.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -36,14 +36,14 @@ static unsigned long long ret_ERANGE(void) return ULLONG_MAX; } -static unsigned long long handle_errors(unsigned long long v, char **endp, char *endptr) +static unsigned long long handle_errors(unsigned long long v, char **endp) { - if (endp) *endp = endptr; + char next_ch = **endp; /* errno is already set to ERANGE by strtoXXX if value overflowed */ - if (endptr[0]) { + if (next_ch) { /* "1234abcg" or out-of-range? */ - if (isalnum(endptr[0]) || errno) + if (isalnum(next_ch) || errno) return ret_ERANGE(); /* good number, just suspicious terminator */ errno = EINVAL; @@ -57,30 +57,37 @@ unsigned long long FAST_FUNC bb_strtoull(const char *arg, char **endp, int base) unsigned long long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + /* strtoul(" -4200000000") returns 94967296, errno 0 (!) */ /* I don't think that this is right. Preventing this... */ if (!isalnum(arg[0])) return ret_ERANGE(); /* not 100% correct for lib func, but convenient for the caller */ errno = 0; - v = strtoull(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoull(arg, endp, base); + return handle_errors(v, endp); } long long FAST_FUNC bb_strtoll(const char *arg, char **endp, int base) { unsigned long long v; char *endptr; + char first; + + if (!endp) endp = &endptr; + *endp = (char*) arg; /* Check for the weird "feature": * a "-" string is apparently a valid "number" for strto[u]l[l]! * It returns zero and errno is 0! :( */ - char first = (arg[0] != '-' ? arg[0] : arg[1]); + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtoll(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoll(arg, endp, base); + return handle_errors(v, endp); } #if ULONG_MAX != ULLONG_MAX @@ -89,23 +96,30 @@ unsigned long FAST_FUNC bb_strtoul(const char *arg, char **endp, int base) unsigned long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtoul(arg, endp, base); + return handle_errors(v, endp); } long FAST_FUNC bb_strtol(const char *arg, char **endp, int base) { long v; char *endptr; + char first; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + if (!endp) endp = &endptr; + *endp = (char*) arg; + + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); - return handle_errors(v, endp, endptr); + v = strtol(arg, endp, base); + return handle_errors(v, endp); } #endif @@ -115,25 +129,32 @@ unsigned FAST_FUNC bb_strtou(const char *arg, char **endp, int base) unsigned long v; char *endptr; + if (!endp) endp = &endptr; + *endp = (char*) arg; + if (!isalnum(arg[0])) return ret_ERANGE(); errno = 0; - v = strtoul(arg, &endptr, base); + v = strtoul(arg, endp, base); if (v > UINT_MAX) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } int FAST_FUNC bb_strtoi(const char *arg, char **endp, int base) { long v; char *endptr; + char first; + + if (!endp) endp = &endptr; + *endp = (char*) arg; - char first = (arg[0] != '-' ? arg[0] : arg[1]); + first = (arg[0] != '-' ? arg[0] : arg[1]); if (!isalnum(first)) return ret_ERANGE(); errno = 0; - v = strtol(arg, &endptr, base); + v = strtol(arg, endp, base); if (v > INT_MAX) return ret_ERANGE(); if (v < INT_MIN) return ret_ERANGE(); - return handle_errors(v, endp, endptr); + return handle_errors(v, endp); } #endif diff --git a/libbb/chomp.c b/libbb/chomp.c index ed4bf6b..cb92bef 100644 --- a/libbb/chomp.c +++ b/libbb/chomp.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/compare_string_array.c b/libbb/compare_string_array.c index 599449f..4b10cc1 100644 --- a/libbb/compare_string_array.c +++ b/libbb/compare_string_array.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/concat_path_file.c b/libbb/concat_path_file.c index fb53354..9ed2959 100644 --- a/libbb/concat_path_file.c +++ b/libbb/concat_path_file.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Concatenate path and filename to new allocated buffer. diff --git a/libbb/concat_subpath_file.c b/libbb/concat_subpath_file.c index 313fa63..c9167d4 100644 --- a/libbb/concat_subpath_file.c +++ b/libbb/concat_subpath_file.c @@ -4,7 +4,7 @@ * * Copyright (C) (C) 2003 Vladimir Oleynik * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* diff --git a/libbb/copy_file.c b/libbb/copy_file.c index ed765d8..9333a8d 100644 --- a/libbb/copy_file.c +++ b/libbb/copy_file.c @@ -5,7 +5,7 @@ * Copyright (C) 2001 by Matt Kraai * SELinux support by Yuichi Nakamura * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -78,9 +78,9 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* NB: each struct stat is ~100 bytes */ struct stat source_stat; struct stat dest_stat; - signed char retval = 0; - signed char dest_exists = 0; - signed char ovr; + smallint retval = 0; + smallint dest_exists = 0; + smallint ovr; /* Inverse of cp -d ("cp without -d") */ #define FLAGS_DEREF (flags & (FILEUTILS_DEREFERENCE + FILEUTILS_DEREFERENCE_L0)) @@ -147,7 +147,6 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) return -1; } - /* Create DEST */ if (dest_exists) { if (!S_ISDIR(dest_stat.st_mode)) { bb_error_msg("target '%s' is not a directory", dest); @@ -156,6 +155,7 @@ int FAST_FUNC copy_file(const char *source, const char *dest, int flags) /* race here: user can substitute a symlink between * this check and actual creation of files inside dest */ } else { + /* Create DEST */ mode_t mode; saved_umask = umask(0); diff --git a/libbb/copyfd.c b/libbb/copyfd.c index 82622c0..eda2747 100644 --- a/libbb/copyfd.c +++ b/libbb/copyfd.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2005 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/correct_password.c b/libbb/correct_password.c index 6301589..acadf39 100644 --- a/libbb/correct_password.c +++ b/libbb/correct_password.c @@ -31,22 +31,19 @@ #include "libbb.h" /* Ask the user for a password. + * Return 1 without asking if PW has an empty password. + * Return -1 on EOF, error while reading input, or timeout. * Return 1 if the user gives the correct password for entry PW, - * 0 if not. Return 1 without asking if PW has an empty password. + * 0 if not. * - * NULL pw means "just fake it for login with bad username" */ - -int FAST_FUNC correct_password(const struct passwd *pw) + * NULL pw means "just fake it for login with bad username" + */ +int FAST_FUNC ask_and_check_password_extended(const struct passwd *pw, + int timeout, const char *prompt) { char *unencrypted, *encrypted; const char *correct; int r; -#if ENABLE_FEATURE_SHADOWPASSWDS - /* Using _r function to avoid pulling in static buffers */ - struct spwd spw; - char buffer[256]; -#endif - /* fake salt. crypt() can choke otherwise. */ correct = "aa"; if (!pw) { @@ -55,7 +52,10 @@ int FAST_FUNC correct_password(const struct passwd *pw) } correct = pw->pw_passwd; #if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ if ((correct[0] == 'x' || correct[0] == '*') && !correct[1]) { + struct spwd spw; + char buffer[256]; /* getspnam_r may return 0 yet set result to NULL. * At least glibc 2.4 does this. Be extra paranoid here. */ struct spwd *result = NULL; @@ -68,13 +68,19 @@ int FAST_FUNC correct_password(const struct passwd *pw) return 1; fake_it: - unencrypted = bb_ask_stdin("Password: "); + unencrypted = bb_ask(STDIN_FILENO, timeout, prompt); if (!unencrypted) { - return 0; + /* EOF (such as ^D) or error (such as ^C) or timeout */ + return -1; } encrypted = pw_encrypt(unencrypted, correct, 1); r = (strcmp(encrypted, correct) == 0); free(encrypted); - memset(unencrypted, 0, strlen(unencrypted)); + nuke_str(unencrypted); return r; } + +int FAST_FUNC ask_and_check_password(const struct passwd *pw) +{ + return ask_and_check_password_extended(pw, 0, "Password: "); +} diff --git a/libbb/crc32.c b/libbb/crc32.c index 36ac860..ac9836c 100644 --- a/libbb/crc32.c +++ b/libbb/crc32.c @@ -13,11 +13,13 @@ * endian = 1: big-endian * endian = 0: little-endian * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" +uint32_t *global_crc32_table; + uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) { uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320; @@ -40,3 +42,25 @@ uint32_t* FAST_FUNC crc32_filltable(uint32_t *crc_table, int endian) return crc_table - 256; } + +uint32_t FAST_FUNC crc32_block_endian1(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = (val << 8) ^ crc_table[(val >> 24) ^ *(uint8_t*)buf]; + buf = (uint8_t*)buf + 1; + } + return val; +} + +uint32_t FAST_FUNC crc32_block_endian0(uint32_t val, const void *buf, unsigned len, uint32_t *crc_table) +{ + const void *end = (uint8_t*)buf + len; + + while (buf != end) { + val = crc_table[(uint8_t)val ^ *(uint8_t*)buf] ^ (val >> 8); + buf = (uint8_t*)buf + 1; + } + return val; +} diff --git a/libbb/create_icmp6_socket.c b/libbb/create_icmp6_socket.c deleted file mode 100644 index 91e478e..0000000 --- a/libbb/create_icmp6_socket.c +++ /dev/null @@ -1,38 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * create raw socket for icmp (IPv6 version) protocol - * and drop root privileges if running setuid - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -#if ENABLE_FEATURE_IPV6 -int FAST_FUNC create_icmp6_socket(void) -{ - int sock; -#if 0 - struct protoent *proto; - proto = getprotobyname("ipv6-icmp"); - /* if getprotobyname failed, just silently force - * proto->p_proto to have the correct value for "ipv6-icmp" */ - sock = socket(AF_INET6, SOCK_RAW, - (proto ? proto->p_proto : IPPROTO_ICMPV6)); -#else - sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); -#endif - if (sock < 0) { - if (errno == EPERM) - bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); - bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); - } - - /* drop root privs if running setuid */ - xsetuid(getuid()); - - return sock; -} -#endif diff --git a/libbb/create_icmp_socket.c b/libbb/create_icmp_socket.c deleted file mode 100644 index d75f845..0000000 --- a/libbb/create_icmp_socket.c +++ /dev/null @@ -1,36 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * create raw socket for icmp protocol - * and drop root privileges if running setuid - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -int FAST_FUNC create_icmp_socket(void) -{ - int sock; -#if 0 - struct protoent *proto; - proto = getprotobyname("icmp"); - /* if getprotobyname failed, just silently force - * proto->p_proto to have the correct value for "icmp" */ - sock = socket(AF_INET, SOCK_RAW, - (proto ? proto->p_proto : 1)); /* 1 == ICMP */ -#else - sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */ -#endif - if (sock < 0) { - if (errno == EPERM) - bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); - bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); - } - - /* drop root privs if running setuid */ - xsetuid(getuid()); - - return sock; -} diff --git a/libbb/default_error_retval.c b/libbb/default_error_retval.c index 0b19f21..4f6395f 100644 --- a/libbb/default_error_retval.c +++ b/libbb/default_error_retval.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Seems silly to copyright a global variable. ;-) Oh well. @@ -15,4 +15,4 @@ #include "libbb.h" -int xfunc_error_retval = EXIT_FAILURE; +uint8_t xfunc_error_retval = EXIT_FAILURE; diff --git a/libbb/device_open.c b/libbb/device_open.c index cf8bcf6..a8fe2fc 100644 --- a/libbb/device_open.c +++ b/libbb/device_open.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/die_if_bad_username.c b/libbb/die_if_bad_username.c index 8b4deec..cf1297b 100644 --- a/libbb/die_if_bad_username.c +++ b/libbb/die_if_bad_username.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 Tito Ragusa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -18,23 +18,45 @@ void FAST_FUNC die_if_bad_username(const char *name) { - /* 1st char being dash or dot isn't valid: */ - goto skip; - /* For example, name like ".." can make adduser - * chown "/home/.." recursively - NOT GOOD + const char *start = name; + + /* 1st char being dash or dot isn't valid: + * for example, name like ".." can make adduser + * chown "/home/.." recursively - NOT GOOD. + * Name of just a single "$" is also rejected. */ + goto skip; do { - if (*name == '-' || *name == '.') + unsigned char ch; + + /* These chars are valid unless they are at the 1st pos: */ + if (*name == '-' + || *name == '.' + /* $ is allowed if it's the last char: */ + || (*name == '$' && !name[1]) + ) { continue; + } skip: - if (isalnum(*name) - || *name == '_' - || *name == '@' - || (*name == '$' && !name[1]) + ch = *name; + if (ch == '_' + /* || ch == '@' -- we disallow this too. Think about "user@host" */ + /* open-coded isalnum: */ + || (ch >= '0' && ch <= '9') + || ((ch|0x20) >= 'a' && (ch|0x20) <= 'z') ) { continue; } - bb_error_msg_and_die("illegal character '%c'", *name); + bb_error_msg_and_die("illegal character with code %u at position %u", + (unsigned)ch, (unsigned)(name - start)); } while (*++name); + + /* The minimum size of the login name is one char or two if + * last char is the '$'. Violations of this are caught above. + * The maximum size of the login name is LOGIN_NAME_MAX + * including the terminating null byte. + */ + if (name - start >= LOGIN_NAME_MAX) + bb_error_msg_and_die("name is too long"); } diff --git a/libbb/dump.c b/libbb/dump.c index 7a87219..566881a 100644 --- a/libbb/dump.c +++ b/libbb/dump.c @@ -4,9 +4,9 @@ * based on code from util-linux v 2.11l * * Copyright (c) 1989 - * The Regents of the University of California. All rights reserved. + * The Regents of the University of California. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice is retained at the end of this file. */ @@ -71,7 +71,8 @@ static NOINLINE int bb_dump_size(FS *fs) * skip any special chars -- save precision in * case it's a %s format. */ - while (strchr(index_str + 1, *++fmt)); + while (strchr(index_str + 1, *++fmt)) + continue; if (*fmt == '.' && isdigit(*++fmt)) { prec = atoi(fmt); while (isdigit(*++fmt)) @@ -99,8 +100,8 @@ static NOINLINE int bb_dump_size(FS *fs) static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) { enum { NOTOKAY, USEBCNT, USEPREC } sokay; - PR *pr, **nextpr = NULL; FU *fu; + PR *pr; char *p1, *p2, *p3; char savech, *fmtp; const char *byte_count_str; @@ -111,15 +112,12 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * break each format unit into print units; each * conversion character gets its own. */ - for (nconv = 0, fmtp = fu->fmt; *fmtp; nextpr = &pr->nextpr) { + for (nconv = 0, fmtp = fu->fmt; *fmtp; ) { /* NOSTRICT */ /* DBU:[dvae@cray.com] zalloc so that forward ptrs start out NULL*/ pr = xzalloc(sizeof(PR)); if (!fu->nextpr) fu->nextpr = pr; - /* ignore nextpr -- its unused inside the loop and is - * uninitialized 1st time through. - */ /* skip preceding text and up to the next % sign */ for (p1 = fmtp; *p1 && *p1 != '%'; ++p1) @@ -208,7 +206,7 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) pr->bcnt = fu->bcnt; } else if (sokay == USEPREC) { pr->bcnt = prec; - } else { /* NOTOKAY */ + } else { /* NOTOKAY */ bb_error_msg_and_die("%%s requires a precision or a byte count"); } } else if (*p1 == '_') { @@ -295,16 +293,18 @@ static NOINLINE void rewrite(priv_dumper_t *dumper, FS *fs) * interprets any data at all, and has no iteration count, * repeat it as necessary. * - * if, rep count is greater than 1, no trailing whitespace + * if rep count is greater than 1, no trailing whitespace * gets output from the last iteration of the format unit. */ for (fu = fs->nextfu; fu; fu = fu->nextfu) { - if (!fu->nextfu && fs->bcnt < dumper->blocksize - && !(fu->flags & F_SETREP) && fu->bcnt + if (!fu->nextfu + && fs->bcnt < dumper->blocksize + && !(fu->flags & F_SETREP) + && fu->bcnt ) { fu->reps += (dumper->blocksize - fs->bcnt) / fu->bcnt; } - if (fu->reps > 1) { + if (fu->reps > 1 && fu->nextpr) { for (pr = fu->nextpr;; pr = pr->nextpr) if (!pr->nextpr) break; @@ -323,9 +323,7 @@ static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) struct stat sbuf; if (statok) { - if (fstat(STDIN_FILENO, &sbuf)) { - bb_simple_perror_msg_and_die(fname); - } + xfstat(STDIN_FILENO, &sbuf, fname); if (!(S_ISCHR(sbuf.st_mode) || S_ISBLK(sbuf.st_mode) || S_ISFIFO(sbuf.st_mode)) && dumper->pub.dump_skip >= sbuf.st_size ) { @@ -335,7 +333,7 @@ static void do_skip(priv_dumper_t *dumper, const char *fname, int statok) return; } } - if (fseek(stdin, dumper->pub.dump_skip, SEEK_SET)) { + if (fseeko(stdin, dumper->pub.dump_skip, SEEK_SET)) { bb_simple_perror_msg_and_die(fname); } dumper->address += dumper->pub.dump_skip; @@ -469,7 +467,7 @@ static void bpad(PR *pr) static const char conv_str[] ALIGN1 = "\0\\0\0" - "\007\\a\0" /* \a */ + "\007\\a\0" /* \a */ "\b\\b\0" "\f\\b\0" "\n\\n\0" @@ -726,7 +724,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) p = fmt; for (;;) { p = skip_whitespace(p); - if (!*p) { + if (*p == '\0') { break; } @@ -754,7 +752,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* skip slash and trailing white space */ if (*p == '/') { - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* byte count */ @@ -768,7 +766,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) } tfu->bcnt = atoi(savep); /* skip trailing white space */ - p = skip_whitespace(++p); + p = skip_whitespace(p + 1); } /* format */ @@ -776,7 +774,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) bb_error_msg_and_die("bad format {%s}", fmt); } for (savep = ++p; *p != '"';) { - if (*p++ == 0) { + if (*p++ == '\0') { bb_error_msg_and_die("bad format {%s}", fmt); } } @@ -787,7 +785,7 @@ void FAST_FUNC bb_dump_add(dumper_t* pub_dumper, const char *fmt) /* alphabetic escape sequences have to be done in place */ for (p2 = p1;; ++p1, ++p2) { - if (!*p1) { + if (*p1 == '\0') { *p2 = *p1; break; } diff --git a/libbb/endofname.c b/libbb/endofname.c new file mode 100644 index 0000000..305f093 --- /dev/null +++ b/libbb/endofname.c @@ -0,0 +1,26 @@ +/* + * Utility routines. + * + * Copyright (C) 2013 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += endofname.o + +#include "libbb.h" + +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + +const char* FAST_FUNC +endofname(const char *name) +{ + if (!is_name(*name)) + return name; + while (*++name) { + if (!is_in_name(*name)) + break; + } + return name; +} diff --git a/libbb/execable.c b/libbb/execable.c index 82241cd..178a00a 100644 --- a/libbb/execable.c +++ b/libbb/execable.c @@ -4,7 +4,7 @@ * * Copyright (C) 2006 Gabriel Somlo * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -68,12 +68,12 @@ int FAST_FUNC exists_execable(const char *filename) } #if ENABLE_FEATURE_PREFER_APPLETS -/* just like the real execvp, but try to launch an applet named 'file' first - */ -int FAST_FUNC bb_execvp(const char *file, char *const argv[]) +/* just like the real execvp, but try to launch an applet named 'file' first */ +int FAST_FUNC BB_EXECVP(const char *file, char *const argv[]) { - return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, - argv); + if (find_applet_by_name(file) >= 0) + execvp(bb_busybox_exec_path, argv); + return execvp(file, argv); } #endif diff --git a/libbb/fclose_nonstdin.c b/libbb/fclose_nonstdin.c index 6f3f373..1b14413 100644 --- a/libbb/fclose_nonstdin.c +++ b/libbb/fclose_nonstdin.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* A number of standard utilities can accept multiple command line args @@ -18,7 +18,8 @@ int FAST_FUNC fclose_if_not_stdin(FILE *f) { /* Some more paranoid applets want ferror() check too */ int r = ferror(f); /* NB: does NOT set errno! */ - if (r) errno = EIO; /* so we'll help it */ + if (r) + errno = EIO; /* so we'll help it */ if (f != stdin) return (r | fclose(f)); /* fclose does set errno on error */ return r; diff --git a/libbb/fflush_stdout_and_exit.c b/libbb/fflush_stdout_and_exit.c index 742fb9f..9ad5dbf 100644 --- a/libbb/fflush_stdout_and_exit.c +++ b/libbb/fflush_stdout_and_exit.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Attempt to fflush(stdout), and exit with an error code if stdout is diff --git a/libbb/fgets_str.c b/libbb/fgets_str.c index 3fe61cd..89210a3 100644 --- a/libbb/fgets_str.c +++ b/libbb/fgets_str.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/find_mount_point.c b/libbb/find_mount_point.c index bcb18ef..9676b5f 100644 --- a/libbb/find_mount_point.c +++ b/libbb/find_mount_point.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -30,7 +30,8 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) devno_of_name = s.st_dev; block_dev = 0; - if (S_ISBLK(s.st_mode)) { + /* Why S_ISCHR? - UBI volumes use char devices, not block */ + if (S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode)) { devno_of_name = s.st_rdev; block_dev = 1; } @@ -43,7 +44,7 @@ struct mntent* FAST_FUNC find_mount_point(const char *name, int subdir_too) /* rootfs mount in Linux 2.6 exists always, * and it makes sense to always ignore it. * Otherwise people can't reference their "real" root! */ - if (strcmp(mountEntry->mnt_fsname, "rootfs") == 0) + if (ENABLE_FEATURE_SKIP_ROOTFS && strcmp(mountEntry->mnt_fsname, "rootfs") == 0) continue; if (strcmp(name, mountEntry->mnt_dir) == 0 diff --git a/libbb/find_pid_by_name.c b/libbb/find_pid_by_name.c index 52a0c6d..db823d0 100644 --- a/libbb/find_pid_by_name.c +++ b/libbb/find_pid_by_name.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/find_root_device.c b/libbb/find_root_device.c index ca46bf5..8436cd6 100644 --- a/libbb/find_root_device.c +++ b/libbb/find_root_device.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -29,14 +29,15 @@ static char *find_block_device_in_dir(struct arena *ap) char *retpath = NULL; int len, rem; - dir = opendir(ap->devpath); - if (!dir) - return NULL; - len = strlen(ap->devpath); rem = DEVNAME_MAX-2 - len; if (rem <= 0) return NULL; + + dir = opendir(ap->devpath); + if (!dir) + return NULL; + ap->devpath[len++] = '/'; while ((entry = readdir(dir)) != NULL) { diff --git a/libbb/full_write.c b/libbb/full_write.c index f353b7d..777fbd9 100644 --- a/libbb/full_write.c +++ b/libbb/full_write.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -30,7 +30,7 @@ ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len) /* user can do another write to know the error code */ return total; } - return cc; /* write() returns -1 on failure. */ + return cc; /* write() returns -1 on failure. */ } total += cc; diff --git a/libbb/get_console.c b/libbb/get_console.c index 74022b5..9b6407b 100644 --- a/libbb/get_console.c +++ b/libbb/get_console.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. If you wrote this, please * acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/get_cpu_count.c b/libbb/get_cpu_count.c new file mode 100644 index 0000000..ab468af --- /dev/null +++ b/libbb/get_cpu_count.c @@ -0,0 +1,47 @@ +/* vi: set sw=4 ts=4: */ +/* + * Factored out of mpstat/iostat. + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" + +/* Does str start with "cpu"? */ +int FAST_FUNC starts_with_cpu(const char *str) +{ + return ((str[0] - 'c') | (str[1] - 'p') | (str[2] - 'u')) == 0; +} + +/* + * Get number of processors. Uses /proc/stat. + * Return value 0 means one CPU and non SMP kernel. + * Otherwise N means N processor(s) and SMP kernel. + */ +unsigned FAST_FUNC get_cpu_count(void) +{ + FILE *fp; + char line[256]; + int proc_nr = -1; + + fp = xfopen_for_read("/proc/stat"); + while (fgets(line, sizeof(line), fp)) { + if (!starts_with_cpu(line)) { + if (proc_nr >= 0) + break; /* we are past "cpuN..." lines */ + continue; + } + if (line[3] != ' ') { /* "cpuN" */ + int num_proc; + if (sscanf(line + 3, "%u", &num_proc) == 1 + && num_proc > proc_nr + ) { + proc_nr = num_proc; + } + } + } + + fclose(fp); + return proc_nr + 1; +} diff --git a/libbb/get_last_path_component.c b/libbb/get_last_path_component.c index 7c99116..04fdf2a 100644 --- a/libbb/get_last_path_component.c +++ b/libbb/get_last_path_component.c @@ -4,10 +4,18 @@ * * Copyright (C) 2001 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - #include "libbb.h" + +const char* FAST_FUNC bb_basename(const char *name) +{ + const char *cp = strrchr(name, '/'); + if (cp) + return cp + 1; + return name; +} + /* * "/" -> "/" * "abc" -> "abc" diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c index cbfb45b..a98dd35 100644 --- a/libbb/get_line_from_file.c +++ b/libbb/get_line_from_file.c @@ -6,43 +6,26 @@ * Copyright (C) 2004 Erik Andersen * Copyright (C) 2001 Matt Krai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -/* This function reads an entire line from a text file, up to a newline - * or NUL byte, inclusive. It returns a malloc'ed char * which - * must be free'ed by the caller. If end is NULL '\n' isn't considered - * end of line. If end isn't NULL, length of the chunk is stored in it. - * If lineno is not NULL, *lineno is incremented for each line, - * and also trailing '\' is recognized as line continuation. - * - * Returns NULL if EOF/error. */ -char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno) +char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) { int ch; - int idx = 0; + unsigned idx = 0; char *linebuf = NULL; - int linebufsz = 0; while ((ch = getc(file)) != EOF) { /* grow the line buffer as necessary */ - if (idx >= linebufsz) { - linebufsz += 256; - linebuf = xrealloc(linebuf, linebufsz); - } + if (!(idx & 0xff)) + linebuf = xrealloc(linebuf, idx + 0x100); linebuf[idx++] = (char) ch; - if (!ch) + if (ch == '\0') + break; + if (end && ch == '\n') break; - if (end && ch == '\n') { - if (lineno == NULL) - break; - (*lineno)++; - if (idx < 2 || linebuf[idx-2] != '\\') - break; - idx -= 2; - } } if (end) *end = idx; @@ -59,11 +42,6 @@ char* FAST_FUNC bb_get_chunk_with_continuation(FILE *file, int *end, int *lineno return linebuf; } -char* FAST_FUNC bb_get_chunk_from_file(FILE *file, int *end) -{ - return bb_get_chunk_with_continuation(file, end, NULL); -} - /* Get line, including trailing \n if any */ char* FAST_FUNC xmalloc_fgets(FILE *file) { diff --git a/libbb/get_shell_name.c b/libbb/get_shell_name.c new file mode 100644 index 0000000..5aebe9c --- /dev/null +++ b/libbb/get_shell_name.c @@ -0,0 +1,25 @@ +/* + * Copyright 2011, Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += get_shell_name.o + +#include "libbb.h" + +const char* FAST_FUNC get_shell_name(void) +{ + struct passwd *pw; + char *shell; + + shell = getenv("SHELL"); + if (shell && shell[0]) + return shell; + + pw = getpwuid(getuid()); + if (pw && pw->pw_shell && pw->pw_shell[0]) + return pw->pw_shell; + + return DEFAULT_SHELL; +} diff --git a/libbb/get_volsize.c b/libbb/get_volsize.c index 5b02709..241ceda 100644 --- a/libbb/get_volsize.c +++ b/libbb/get_volsize.c @@ -4,7 +4,7 @@ * * Copyright (C) 2010 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/getopt32.c b/libbb/getopt32.c index b5f83c1..d0e83d8 100644 --- a/libbb/getopt32.c +++ b/libbb/getopt32.c @@ -4,10 +4,12 @@ * * Copyright (C) 2003-2005 Vladimir Oleynik * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -#include +#if ENABLE_LONG_OPTS || ENABLE_FEATURE_GETOPT_LONG +# include +#endif #include "libbb.h" /* Documentation @@ -80,9 +82,9 @@ const char *applet_long_options This struct allows you to define long options: static const char applet_longopts[] ALIGN1 = - //"name\0" has_arg val - "verbose\0" No_argument "v" - ; + //"name\0" has_arg val + "verbose\0" No_argument "v" + ; applet_long_options = applet_longopts; The last member of struct option (val) typically is set to @@ -115,7 +117,7 @@ const char *opt_complementary found. "ww" Adjacent double options have a counter associated which indicates - the number of occurences of the option. + the number of occurrences of the option. For example the ps applet needs: if w is given once, GNU ps sets the width to 132, if w is given more than once, it is "unlimited" @@ -226,14 +228,14 @@ Special characters: if specified together. In this case you must set opt_complementary = "b--cf:c--bf:f--bc". If two of the mutually exclusive options are found, getopt32 will call - bb_show_usage() and die. + bb_show_usage() and die. "x--x" Variation of the above, it means that -x option should occur at most once. "a+" A plus after a char in opt_complementary means that the parameter for this option is a nonnegative integer. It will be processed - with xatoi_u() - allowed range is 0..INT_MAX. + with xatoi_positive() - allowed range is 0..INT_MAX. int param; // "unsigned param;" will also work opt_complementary = "p+"; @@ -465,13 +467,17 @@ getopt32(char **argv, const char *applet_opts, ...) } for (on_off = complementary; on_off->opt_char; on_off++) if (on_off->opt_char == *s) - break; + goto found_opt; + /* Without this, diagnostic of such bugs is not easy */ + bb_error_msg_and_die("NO OPT %c!", *s); + found_opt: if (c == ':' && s[2] == ':') { on_off->param_type = PARAM_LIST; continue; } if (c == '+' && (s[2] == ':' || s[2] == '\0')) { on_off->param_type = PARAM_INT; + s++; continue; } if (c == ':' || c == '\0') { @@ -531,7 +537,7 @@ getopt32(char **argv, const char *applet_opts, ...) /* In case getopt32 was already called: * reset the libc getopt() function, which keeps internal state. - * run_nofork_applet_prime() does this, but we might end up here + * run_nofork_applet() does this, but we might end up here * also via gunzip_main() -> gzip_main(). Play safe. */ #ifdef __GLIBC__ @@ -542,8 +548,6 @@ getopt32(char **argv, const char *applet_opts, ...) #endif /* optarg = NULL; opterr = 0; optopt = 0; - do we need this?? */ - pargv = NULL; - /* Note: just "getopt() <= 0" will not work well for * "fake" short options, like this one: * wget $'-\203' "Test: test" http://kernel.org/ @@ -574,19 +578,16 @@ getopt32(char **argv, const char *applet_opts, ...) flags ^= trigger; if (on_off->counter) (*(on_off->counter))++; - if (on_off->param_type == PARAM_LIST) { - if (optarg) + if (optarg) { + if (on_off->param_type == PARAM_LIST) { llist_add_to_end((llist_t **)(on_off->optarg), optarg); - } else if (on_off->param_type == PARAM_INT) { - if (optarg) -//TODO: xatoi_u indirectly pulls in printf machinery - *(unsigned*)(on_off->optarg) = xatoi_u(optarg); - } else if (on_off->optarg) { - if (optarg) + } else if (on_off->param_type == PARAM_INT) { +//TODO: xatoi_positive indirectly pulls in printf machinery + *(unsigned*)(on_off->optarg) = xatoi_positive(optarg); + } else if (on_off->optarg) { *(char **)(on_off->optarg) = optarg; + } } - if (pargv != NULL) - break; } /* check depending requires for given options */ diff --git a/libbb/getpty.c b/libbb/getpty.c index 4bffd9a..435e4d0 100644 --- a/libbb/getpty.c +++ b/libbb/getpty.c @@ -3,7 +3,7 @@ * Mini getpty implementation for busybox * Bjorn Wesen, Axis Communications AB (bjornw@axis.com) * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -19,20 +19,22 @@ int FAST_FUNC xgetpty(char *line) if (p > 0) { grantpt(p); /* chmod+chown corresponding slave pty */ unlockpt(p); /* (what does this do?) */ -#if 0 /* if ptsname_r is not available... */ - const char *name; - name = ptsname(p); /* find out the name of slave pty */ - if (!name) { - bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); +# ifndef HAVE_PTSNAME_R + { + const char *name; + name = ptsname(p); /* find out the name of slave pty */ + if (!name) { + bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); + } + safe_strncpy(line, name, GETPTY_BUFSIZE); } - safe_strncpy(line, name, GETPTY_BUFSIZE); -#else +# else /* find out the name of slave pty */ if (ptsname_r(p, line, GETPTY_BUFSIZE-1) != 0) { bb_perror_msg_and_die("ptsname error (is /dev/pts mounted?)"); } line[GETPTY_BUFSIZE-1] = '\0'; -#endif +# endif return p; } #else diff --git a/libbb/hash_md5_sha.c b/libbb/hash_md5_sha.c new file mode 100644 index 0000000..3f743ac --- /dev/null +++ b/libbb/hash_md5_sha.c @@ -0,0 +1,1168 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2010 Denys Vlasenko + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +#include "libbb.h" + +/* gcc 4.2.1 optimizes rotr64 better with inline than with macro + * (for rotX32, there is no difference). Why? My guess is that + * macro requires clever common subexpression elimination heuristics + * in gcc, while inline basically forces it to happen. + */ +//#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) +static ALWAYS_INLINE uint32_t rotl32(uint32_t x, unsigned n) +{ + return (x << n) | (x >> (32 - n)); +} +//#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) +static ALWAYS_INLINE uint32_t rotr32(uint32_t x, unsigned n) +{ + return (x >> n) | (x << (32 - n)); +} +/* rotr64 in needed for sha512 only: */ +//#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) +static ALWAYS_INLINE uint64_t rotr64(uint64_t x, unsigned n) +{ + return (x >> n) | (x << (64 - n)); +} + +/* rotl64 only used for sha3 currently */ +static ALWAYS_INLINE uint64_t rotl64(uint64_t x, unsigned n) +{ + return (x << n) | (x >> (64 - n)); +} + +/* Feed data through a temporary buffer. + * The internal buffer remembers previous data until it has 64 + * bytes worth to pass on. + */ +static void FAST_FUNC common64_hash(md5_ctx_t *ctx, const void *buffer, size_t len) +{ + unsigned bufpos = ctx->total64 & 63; + + ctx->total64 += len; + + while (1) { + unsigned remaining = 64 - bufpos; + if (remaining > len) + remaining = len; + /* Copy data into aligned buffer */ + memcpy(ctx->wbuffer + bufpos, buffer, remaining); + len -= remaining; + buffer = (const char *)buffer + remaining; + bufpos += remaining; + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ + bufpos -= 64; + if (bufpos != 0) + break; + /* Buffer is filled up, process it */ + ctx->process_block(ctx); + /*bufpos = 0; - already is */ + } +} + +/* Process the remaining bytes in the buffer */ +static void FAST_FUNC common64_end(md5_ctx_t *ctx, int swap_needed) +{ + unsigned bufpos = ctx->total64 & 63; + /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ + ctx->wbuffer[bufpos++] = 0x80; + + /* This loop iterates either once or twice, no more, no less */ + while (1) { + unsigned remaining = 64 - bufpos; + memset(ctx->wbuffer + bufpos, 0, remaining); + /* Do we have enough space for the length count? */ + if (remaining >= 8) { + /* Store the 64-bit counter of bits in the buffer */ + uint64_t t = ctx->total64 << 3; + if (swap_needed) + t = bb_bswap_64(t); + /* wbuffer is suitably aligned for this */ + *(bb__aliased_uint64_t *) (&ctx->wbuffer[64 - 8]) = t; + } + ctx->process_block(ctx); + if (remaining >= 8) + break; + bufpos = 0; + } +} + + +/* + * Compute MD5 checksum of strings according to the + * definition of MD5 in RFC 1321 from April 1992. + * + * Written by Ulrich Drepper , 1995. + * + * Copyright (C) 1995-1999 Free Software Foundation, Inc. + * Copyright (C) 2001 Manuel Novoa III + * Copyright (C) 2003 Glenn L. McGrath + * Copyright (C) 2003 Erik Andersen + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +/* 0: fastest, 3: smallest */ +#if CONFIG_MD5_SMALL < 0 +# define MD5_SMALL 0 +#elif CONFIG_MD5_SMALL > 3 +# define MD5_SMALL 3 +#else +# define MD5_SMALL CONFIG_MD5_SMALL +#endif + +/* These are the four functions used in the four steps of the MD5 algorithm + * and defined in the RFC 1321. The first function is a little bit optimized + * (as found in Colin Plumbs public domain implementation). + * #define FF(b, c, d) ((b & c) | (~b & d)) + */ +#undef FF +#undef FG +#undef FH +#undef FI +#define FF(b, c, d) (d ^ (b & (c ^ d))) +#define FG(b, c, d) FF(d, b, c) +#define FH(b, c, d) (b ^ c ^ d) +#define FI(b, c, d) (c ^ (b | ~d)) + +/* Hash a single block, 64 bytes long and 4-byte aligned */ +static void FAST_FUNC md5_process_block64(md5_ctx_t *ctx) +{ +#if MD5_SMALL > 0 + /* Before we start, one word to the strange constants. + They are defined in RFC 1321 as + T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64 + */ + static const uint32_t C_array[] = { + /* round 1 */ + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + /* round 2 */ + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + /* round 3 */ + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + /* round 4 */ + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 + }; + static const char P_array[] ALIGN1 = { +# if MD5_SMALL > 1 + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ +# endif + 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ + 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ + 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ + }; +#endif + uint32_t *words = (void*) ctx->wbuffer; + uint32_t A = ctx->hash[0]; + uint32_t B = ctx->hash[1]; + uint32_t C = ctx->hash[2]; + uint32_t D = ctx->hash[3]; + +#if MD5_SMALL >= 2 /* 2 or 3 */ + + static const char S_array[] ALIGN1 = { + 7, 12, 17, 22, + 5, 9, 14, 20, + 4, 11, 16, 23, + 6, 10, 15, 21 + }; + const uint32_t *pc; + const char *pp; + const char *ps; + int i; + uint32_t temp; + + if (BB_BIG_ENDIAN) + for (i = 0; i < 16; i++) + words[i] = SWAP_LE32(words[i]); + +# if MD5_SMALL == 3 + pc = C_array; + pp = P_array; + ps = S_array - 4; + + for (i = 0; i < 64; i++) { + if ((i & 0x0f) == 0) + ps += 4; + temp = A; + switch (i >> 4) { + case 0: + temp += FF(B, C, D); + break; + case 1: + temp += FG(B, C, D); + break; + case 2: + temp += FH(B, C, D); + break; + case 3: + temp += FI(B, C, D); + } + temp += words[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } +# else /* MD5_SMALL == 2 */ + pc = C_array; + pp = P_array; + ps = S_array; + + for (i = 0; i < 16; i++) { + temp = A + FF(B, C, D) + words[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FG(B, C, D) + words[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FH(B, C, D) + words[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } + ps += 4; + for (i = 0; i < 16; i++) { + temp = A + FI(B, C, D) + words[(int) (*pp++)] + *pc++; + temp = rotl32(temp, ps[i & 3]); + temp += B; + A = D; + D = C; + C = B; + B = temp; + } +# endif + /* Add checksum to the starting values */ + ctx->hash[0] += A; + ctx->hash[1] += B; + ctx->hash[2] += C; + ctx->hash[3] += D; + +#else /* MD5_SMALL == 0 or 1 */ + + uint32_t A_save = A; + uint32_t B_save = B; + uint32_t C_save = C; + uint32_t D_save = D; +# if MD5_SMALL == 1 + const uint32_t *pc; + const char *pp; + int i; +# endif + + /* First round: using the given function, the context and a constant + the next context is computed. Because the algorithm's processing + unit is a 32-bit word and it is determined to work on words in + little endian byte order we perhaps have to change the byte order + before the computation. To reduce the work for the next steps + we save swapped words in WORDS array. */ +# undef OP +# define OP(a, b, c, d, s, T) \ + do { \ + a += FF(b, c, d) + (*words IF_BIG_ENDIAN(= SWAP_LE32(*words))) + T; \ + words++; \ + a = rotl32(a, s); \ + a += b; \ + } while (0) + + /* Round 1 */ +# if MD5_SMALL == 1 + pc = C_array; + for (i = 0; i < 4; i++) { + OP(A, B, C, D, 7, *pc++); + OP(D, A, B, C, 12, *pc++); + OP(C, D, A, B, 17, *pc++); + OP(B, C, D, A, 22, *pc++); + } +# else + OP(A, B, C, D, 7, 0xd76aa478); + OP(D, A, B, C, 12, 0xe8c7b756); + OP(C, D, A, B, 17, 0x242070db); + OP(B, C, D, A, 22, 0xc1bdceee); + OP(A, B, C, D, 7, 0xf57c0faf); + OP(D, A, B, C, 12, 0x4787c62a); + OP(C, D, A, B, 17, 0xa8304613); + OP(B, C, D, A, 22, 0xfd469501); + OP(A, B, C, D, 7, 0x698098d8); + OP(D, A, B, C, 12, 0x8b44f7af); + OP(C, D, A, B, 17, 0xffff5bb1); + OP(B, C, D, A, 22, 0x895cd7be); + OP(A, B, C, D, 7, 0x6b901122); + OP(D, A, B, C, 12, 0xfd987193); + OP(C, D, A, B, 17, 0xa679438e); + OP(B, C, D, A, 22, 0x49b40821); +# endif + words -= 16; + + /* For the second to fourth round we have the possibly swapped words + in WORDS. Redefine the macro to take an additional first + argument specifying the function to use. */ +# undef OP +# define OP(f, a, b, c, d, k, s, T) \ + do { \ + a += f(b, c, d) + words[k] + T; \ + a = rotl32(a, s); \ + a += b; \ + } while (0) + + /* Round 2 */ +# if MD5_SMALL == 1 + pp = P_array; + for (i = 0; i < 4; i++) { + OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); + OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++); + OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++); + OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++); + } +# else + OP(FG, A, B, C, D, 1, 5, 0xf61e2562); + OP(FG, D, A, B, C, 6, 9, 0xc040b340); + OP(FG, C, D, A, B, 11, 14, 0x265e5a51); + OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); + OP(FG, A, B, C, D, 5, 5, 0xd62f105d); + OP(FG, D, A, B, C, 10, 9, 0x02441453); + OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); + OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); + OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); + OP(FG, D, A, B, C, 14, 9, 0xc33707d6); + OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); + OP(FG, B, C, D, A, 8, 20, 0x455a14ed); + OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); + OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); + OP(FG, C, D, A, B, 7, 14, 0x676f02d9); + OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); +# endif + + /* Round 3 */ +# if MD5_SMALL == 1 + for (i = 0; i < 4; i++) { + OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); + OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); + OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++); + OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++); + } +# else + OP(FH, A, B, C, D, 5, 4, 0xfffa3942); + OP(FH, D, A, B, C, 8, 11, 0x8771f681); + OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); + OP(FH, B, C, D, A, 14, 23, 0xfde5380c); + OP(FH, A, B, C, D, 1, 4, 0xa4beea44); + OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); + OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); + OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); + OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); + OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); + OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); + OP(FH, B, C, D, A, 6, 23, 0x04881d05); + OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); + OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); + OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); + OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); +# endif + + /* Round 4 */ +# if MD5_SMALL == 1 + for (i = 0; i < 4; i++) { + OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); + OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); + OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++); + OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++); + } +# else + OP(FI, A, B, C, D, 0, 6, 0xf4292244); + OP(FI, D, A, B, C, 7, 10, 0x432aff97); + OP(FI, C, D, A, B, 14, 15, 0xab9423a7); + OP(FI, B, C, D, A, 5, 21, 0xfc93a039); + OP(FI, A, B, C, D, 12, 6, 0x655b59c3); + OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); + OP(FI, C, D, A, B, 10, 15, 0xffeff47d); + OP(FI, B, C, D, A, 1, 21, 0x85845dd1); + OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); + OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); + OP(FI, C, D, A, B, 6, 15, 0xa3014314); + OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); + OP(FI, A, B, C, D, 4, 6, 0xf7537e82); + OP(FI, D, A, B, C, 11, 10, 0xbd3af235); + OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); + OP(FI, B, C, D, A, 9, 21, 0xeb86d391); +# undef OP +# endif + /* Add checksum to the starting values */ + ctx->hash[0] = A_save + A; + ctx->hash[1] = B_save + B; + ctx->hash[2] = C_save + C; + ctx->hash[3] = D_save + D; +#endif +} +#undef FF +#undef FG +#undef FH +#undef FI + +/* Initialize structure containing state of computation. + * (RFC 1321, 3.3: Step 3) + */ +void FAST_FUNC md5_begin(md5_ctx_t *ctx) +{ + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->total64 = 0; + ctx->process_block = md5_process_block64; +} + +/* Used also for sha1 and sha256 */ +void FAST_FUNC md5_hash(md5_ctx_t *ctx, const void *buffer, size_t len) +{ + common64_hash(ctx, buffer, len); +} + +/* Process the remaining bytes in the buffer and put result from CTX + * in first 16 bytes following RESBUF. The result is always in little + * endian byte order, so that a byte-wise output yields to the wanted + * ASCII representation of the message digest. + */ +void FAST_FUNC md5_end(md5_ctx_t *ctx, void *resbuf) +{ + /* MD5 stores total in LE, need to swap on BE arches: */ + common64_end(ctx, /*swap_needed:*/ BB_BIG_ENDIAN); + + /* The MD5 result is in little endian byte order */ + if (BB_BIG_ENDIAN) { + ctx->hash[0] = SWAP_LE32(ctx->hash[0]); + ctx->hash[1] = SWAP_LE32(ctx->hash[1]); + ctx->hash[2] = SWAP_LE32(ctx->hash[2]); + ctx->hash[3] = SWAP_LE32(ctx->hash[3]); + } + + memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * 4); +} + + +/* + * SHA1 part is: + * Copyright 2007 Rob Landley + * + * Based on the public domain SHA-1 in C by Steve Reid + * from http://www.mirrors.wiretapped.net/security/cryptography/hashes/sha1/ + * + * Licensed under GPLv2, see file LICENSE in this source tree. + * + * --------------------------------------------------------------------------- + * + * SHA256 and SHA512 parts are: + * Released into the Public Domain by Ulrich Drepper . + * Shrank by Denys Vlasenko. + * + * --------------------------------------------------------------------------- + * + * The best way to test random blocksizes is to go to coreutils/md5_sha1_sum.c + * and replace "4096" with something like "2000 + time(NULL) % 2097", + * then rebuild and compare "shaNNNsum bigfile" results. + */ + +static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) +{ + static const uint32_t rconsts[] = { + 0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6 + }; + int i, j; + int cnt; + uint32_t W[16+16]; + uint32_t a, b, c, d, e; + + /* On-stack work buffer frees up one register in the main loop + * which otherwise will be needed to hold ctx pointer */ + for (i = 0; i < 16; i++) + W[i] = W[i+16] = SWAP_BE32(((uint32_t*)ctx->wbuffer)[i]); + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + + /* 4 rounds of 20 operations each */ + cnt = 0; + for (i = 0; i < 4; i++) { + j = 19; + do { + uint32_t work; + + work = c ^ d; + if (i == 0) { + work = (work & b) ^ d; + if (j <= 3) + goto ge16; + /* Used to do SWAP_BE32 here, but this + * requires ctx (see comment above) */ + work += W[cnt]; + } else { + if (i == 2) + work = ((b | c) & d) | (b & c); + else /* i = 1 or 3 */ + work ^= b; + ge16: + W[cnt] = W[cnt+16] = rotl32(W[cnt+13] ^ W[cnt+8] ^ W[cnt+2] ^ W[cnt], 1); + work += W[cnt]; + } + work += e + rotl32(a, 5) + rconsts[i]; + + /* Rotate by one for next time */ + e = d; + d = c; + c = /* b = */ rotl32(b, 30); + b = a; + a = work; + cnt = (cnt + 1) & 15; + } while (--j >= 0); + } + + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; +} + +/* Constants for SHA512 from FIPS 180-2:4.2.3. + * SHA256 constants from FIPS 180-2:4.2.2 + * are the most significant half of first 64 elements + * of the same array. + */ +static const uint64_t sha_K[80] = { + 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, + 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, + 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, + 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, + 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, + 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, + 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, + 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, + 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, + 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, + 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, + 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, + 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, + 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, + 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, + 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, + 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, + 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, + 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, + 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, + 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, + 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, + 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, + 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, + 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, + 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, + 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, + 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, + 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, + 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, + 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, + 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, + 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, /* [64]+ are used for sha512 only */ + 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, + 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, + 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, + 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, + 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, + 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, + 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL +}; + +#undef Ch +#undef Maj +#undef S0 +#undef S1 +#undef R0 +#undef R1 + +static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx) +{ + unsigned t; + uint32_t W[64], a, b, c, d, e, f, g, h; + const uint32_t *words = (uint32_t*) ctx->wbuffer; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22)) +#define S1(x) (rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25)) +#define R0(x) (rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3)) +#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10)) + + /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ + for (t = 0; t < 16; ++t) + W[t] = SWAP_BE32(words[t]); + for (/*t = 16*/; t < 64; ++t) + W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; + + a = ctx->hash[0]; + b = ctx->hash[1]; + c = ctx->hash[2]; + d = ctx->hash[3]; + e = ctx->hash[4]; + f = ctx->hash[5]; + g = ctx->hash[6]; + h = ctx->hash[7]; + + /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ + for (t = 0; t < 64; ++t) { + /* Need to fetch upper half of sha_K[t] + * (I hope compiler is clever enough to just fetch + * upper half) + */ + uint32_t K_t = sha_K[t] >> 32; + uint32_t T1 = h + S1(e) + Ch(e, f, g) + K_t + W[t]; + uint32_t T2 = S0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#undef Ch +#undef Maj +#undef S0 +#undef S1 +#undef R0 +#undef R1 + /* Add the starting values of the context according to FIPS 180-2:6.2.2 + step 4. */ + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} + +static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx) +{ + unsigned t; + uint64_t W[80]; + /* On i386, having assignments here (not later as sha256 does) + * produces 99 bytes smaller code with gcc 4.3.1 + */ + uint64_t a = ctx->hash[0]; + uint64_t b = ctx->hash[1]; + uint64_t c = ctx->hash[2]; + uint64_t d = ctx->hash[3]; + uint64_t e = ctx->hash[4]; + uint64_t f = ctx->hash[5]; + uint64_t g = ctx->hash[6]; + uint64_t h = ctx->hash[7]; + const uint64_t *words = (uint64_t*) ctx->wbuffer; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39)) +#define S1(x) (rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41)) +#define R0(x) (rotr64(x, 1) ^ rotr64(x, 8) ^ (x >> 7)) +#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6)) + + /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */ + for (t = 0; t < 16; ++t) + W[t] = SWAP_BE64(words[t]); + for (/*t = 16*/; t < 80; ++t) + W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; + + /* The actual computation according to FIPS 180-2:6.3.2 step 3. */ + for (t = 0; t < 80; ++t) { + uint64_t T1 = h + S1(e) + Ch(e, f, g) + sha_K[t] + W[t]; + uint64_t T2 = S0(a) + Maj(a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } +#undef Ch +#undef Maj +#undef S0 +#undef S1 +#undef R0 +#undef R1 + /* Add the starting values of the context according to FIPS 180-2:6.3.2 + step 4. */ + ctx->hash[0] += a; + ctx->hash[1] += b; + ctx->hash[2] += c; + ctx->hash[3] += d; + ctx->hash[4] += e; + ctx->hash[5] += f; + ctx->hash[6] += g; + ctx->hash[7] += h; +} + + +void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) +{ + ctx->hash[0] = 0x67452301; + ctx->hash[1] = 0xefcdab89; + ctx->hash[2] = 0x98badcfe; + ctx->hash[3] = 0x10325476; + ctx->hash[4] = 0xc3d2e1f0; + ctx->total64 = 0; + ctx->process_block = sha1_process_block64; +} + +static const uint32_t init256[] = { + 0, + 0, + 0x6a09e667, + 0xbb67ae85, + 0x3c6ef372, + 0xa54ff53a, + 0x510e527f, + 0x9b05688c, + 0x1f83d9ab, + 0x5be0cd19, +}; +static const uint32_t init512_lo[] = { + 0, + 0, + 0xf3bcc908, + 0x84caa73b, + 0xfe94f82b, + 0x5f1d36f1, + 0xade682d1, + 0x2b3e6c1f, + 0xfb41bd6b, + 0x137e2179, +}; + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.2) */ +void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) +{ + memcpy(&ctx->total64, init256, sizeof(init256)); + /*ctx->total64 = 0; - done by prepending two 32-bit zeros to init256 */ + ctx->process_block = sha256_process_block64; +} + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.3) */ +void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) +{ + int i; + /* Two extra iterations zero out ctx->total64[2] */ + uint64_t *tp = ctx->total64; + for (i = 0; i < 2+8; i++) + tp[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; + /*ctx->total64[0] = ctx->total64[1] = 0; - already done */ +} + +void FAST_FUNC sha512_hash(sha512_ctx_t *ctx, const void *buffer, size_t len) +{ + unsigned bufpos = ctx->total64[0] & 127; + unsigned remaining; + + /* First increment the byte count. FIPS 180-2 specifies the possible + length of the file up to 2^128 _bits_. + We compute the number of _bytes_ and convert to bits later. */ + ctx->total64[0] += len; + if (ctx->total64[0] < len) + ctx->total64[1]++; +#if 0 + remaining = 128 - bufpos; + + /* Hash whole blocks */ + while (len >= remaining) { + memcpy(ctx->wbuffer + bufpos, buffer, remaining); + buffer = (const char *)buffer + remaining; + len -= remaining; + remaining = 128; + bufpos = 0; + sha512_process_block128(ctx); + } + + /* Save last, partial blosk */ + memcpy(ctx->wbuffer + bufpos, buffer, len); +#else + while (1) { + remaining = 128 - bufpos; + if (remaining > len) + remaining = len; + /* Copy data into aligned buffer */ + memcpy(ctx->wbuffer + bufpos, buffer, remaining); + len -= remaining; + buffer = (const char *)buffer + remaining; + bufpos += remaining; + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ + bufpos -= 128; + if (bufpos != 0) + break; + /* Buffer is filled up, process it */ + sha512_process_block128(ctx); + /*bufpos = 0; - already is */ + } +#endif +} + +/* Used also for sha256 */ +void FAST_FUNC sha1_end(sha1_ctx_t *ctx, void *resbuf) +{ + unsigned hash_size; + + /* SHA stores total in BE, need to swap on LE arches: */ + common64_end(ctx, /*swap_needed:*/ BB_LITTLE_ENDIAN); + + hash_size = (ctx->process_block == sha1_process_block64) ? 5 : 8; + /* This way we do not impose alignment constraints on resbuf: */ + if (BB_LITTLE_ENDIAN) { + unsigned i; + for (i = 0; i < hash_size; ++i) + ctx->hash[i] = SWAP_BE32(ctx->hash[i]); + } + memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * hash_size); +} + +void FAST_FUNC sha512_end(sha512_ctx_t *ctx, void *resbuf) +{ + unsigned bufpos = ctx->total64[0] & 127; + + /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... */ + ctx->wbuffer[bufpos++] = 0x80; + + while (1) { + unsigned remaining = 128 - bufpos; + memset(ctx->wbuffer + bufpos, 0, remaining); + if (remaining >= 16) { + /* Store the 128-bit counter of bits in the buffer in BE format */ + uint64_t t; + t = ctx->total64[0] << 3; + t = SWAP_BE64(t); + *(bb__aliased_uint64_t *) (&ctx->wbuffer[128 - 8]) = t; + t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61); + t = SWAP_BE64(t); + *(bb__aliased_uint64_t *) (&ctx->wbuffer[128 - 16]) = t; + } + sha512_process_block128(ctx); + if (remaining >= 16) + break; + bufpos = 0; + } + + if (BB_LITTLE_ENDIAN) { + unsigned i; + for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) + ctx->hash[i] = SWAP_BE64(ctx->hash[i]); + } + memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); +} + + +/* + * The Keccak sponge function, designed by Guido Bertoni, Joan Daemen, + * Michael Peeters and Gilles Van Assche. For more information, feedback or + * questions, please refer to our website: http://keccak.noekeon.org/ + * + * Implementation by Ronny Van Keer, + * hereby denoted as "the implementer". + * + * To the extent possible under law, the implementer has waived all copyright + * and related or neighboring rights to the source code in this file. + * http://creativecommons.org/publicdomain/zero/1.0/ + * + * Busybox modifications (C) Lauri Kasanen, under the GPLv2. + */ + +#if CONFIG_SHA3_SMALL < 0 +# define SHA3_SMALL 0 +#elif CONFIG_SHA3_SMALL > 1 +# define SHA3_SMALL 1 +#else +# define SHA3_SMALL CONFIG_SHA3_SMALL +#endif + +enum { + SHA3_IBLK_BYTES = 72, /* 576 bits / 8 */ +}; + +/* + * In the crypto literature this function is usually called Keccak-f(). + */ +static void sha3_process_block72(uint64_t *state) +{ + enum { NROUNDS = 24 }; + + /* Elements should be 64-bit, but top half is always zero or 0x80000000. + * We encode 63rd bits in a separate word below. + * Same is true for 31th bits, which lets us use 16-bit table instead of 64-bit. + * The speed penalty is lost in the noise. + */ + static const uint16_t IOTA_CONST[NROUNDS] = { + 0x0001, + 0x8082, + 0x808a, + 0x8000, + 0x808b, + 0x0001, + 0x8081, + 0x8009, + 0x008a, + 0x0088, + 0x8009, + 0x000a, + 0x808b, + 0x008b, + 0x8089, + 0x8003, + 0x8002, + 0x0080, + 0x800a, + 0x000a, + 0x8081, + 0x8080, + 0x0001, + 0x8008, + }; + /* bit for CONST[0] is in msb: 0011 0011 0000 0111 1101 1101 */ + const uint32_t IOTA_CONST_bit63 = (uint32_t)(0x3307dd00); + /* bit for CONST[0] is in msb: 0001 0110 0011 1000 0001 1011 */ + const uint32_t IOTA_CONST_bit31 = (uint32_t)(0x16381b00); + + static const uint8_t ROT_CONST[24] = { + 1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, + 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44, + }; + static const uint8_t PI_LANE[24] = { + 10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, + 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1, + }; + /*static const uint8_t MOD5[10] = { 0, 1, 2, 3, 4, 0, 1, 2, 3, 4, };*/ + + unsigned x, y; + unsigned round; + + if (BB_BIG_ENDIAN) { + for (x = 0; x < 25; x++) { + state[x] = SWAP_LE64(state[x]); + } + } + + for (round = 0; round < NROUNDS; ++round) { + /* Theta */ + { + uint64_t BC[10]; + for (x = 0; x < 5; ++x) { + BC[x + 5] = BC[x] = state[x] + ^ state[x + 5] ^ state[x + 10] + ^ state[x + 15] ^ state[x + 20]; + } + /* Using 2x5 vector above eliminates the need to use + * BC[MOD5[x+N]] trick below to fetch BC[(x+N) % 5], + * and the code is a bit _smaller_. + */ + for (x = 0; x < 5; ++x) { + uint64_t temp = BC[x + 4] ^ rotl64(BC[x + 1], 1); + state[x] ^= temp; + state[x + 5] ^= temp; + state[x + 10] ^= temp; + state[x + 15] ^= temp; + state[x + 20] ^= temp; + } + } + + /* Rho Pi */ + if (SHA3_SMALL) { + uint64_t t1 = state[1]; + for (x = 0; x < 24; ++x) { + uint64_t t0 = state[PI_LANE[x]]; + state[PI_LANE[x]] = rotl64(t1, ROT_CONST[x]); + t1 = t0; + } + } else { + /* Especially large benefit for 32-bit arch (75% faster): + * 64-bit rotations by non-constant usually are SLOW on those. + * We resort to unrolling here. + * This optimizes out PI_LANE[] and ROT_CONST[], + * but generates 300-500 more bytes of code. + */ + uint64_t t0; + uint64_t t1 = state[1]; +#define RhoPi_twice(x) \ + t0 = state[PI_LANE[x ]]; \ + state[PI_LANE[x ]] = rotl64(t1, ROT_CONST[x ]); \ + t1 = state[PI_LANE[x+1]]; \ + state[PI_LANE[x+1]] = rotl64(t0, ROT_CONST[x+1]); + RhoPi_twice(0); RhoPi_twice(2); + RhoPi_twice(4); RhoPi_twice(6); + RhoPi_twice(8); RhoPi_twice(10); + RhoPi_twice(12); RhoPi_twice(14); + RhoPi_twice(16); RhoPi_twice(18); + RhoPi_twice(20); RhoPi_twice(22); +#undef RhoPi_twice + } + + /* Chi */ + for (y = 0; y <= 20; y += 5) { + uint64_t BC0, BC1, BC2, BC3, BC4; + BC0 = state[y + 0]; + BC1 = state[y + 1]; + BC2 = state[y + 2]; + state[y + 0] = BC0 ^ ((~BC1) & BC2); + BC3 = state[y + 3]; + state[y + 1] = BC1 ^ ((~BC2) & BC3); + BC4 = state[y + 4]; + state[y + 2] = BC2 ^ ((~BC3) & BC4); + state[y + 3] = BC3 ^ ((~BC4) & BC0); + state[y + 4] = BC4 ^ ((~BC0) & BC1); + } + + /* Iota */ + state[0] ^= IOTA_CONST[round] + | (uint32_t)((IOTA_CONST_bit31 << round) & 0x80000000) + | (uint64_t)((IOTA_CONST_bit63 << round) & 0x80000000) << 32; + } + + if (BB_BIG_ENDIAN) { + for (x = 0; x < 25; x++) { + state[x] = SWAP_LE64(state[x]); + } + } +} + +void FAST_FUNC sha3_begin(sha3_ctx_t *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); +} + +void FAST_FUNC sha3_hash(sha3_ctx_t *ctx, const void *buffer, size_t len) +{ +#if SHA3_SMALL + const uint8_t *data = buffer; + unsigned bufpos = ctx->bytes_queued; + + while (1) { + unsigned remaining = SHA3_IBLK_BYTES - bufpos; + if (remaining > len) + remaining = len; + len -= remaining; + /* XOR data into buffer */ + while (remaining != 0) { + uint8_t *buf = (uint8_t*)ctx->state; + buf[bufpos] ^= *data++; + bufpos++; + remaining--; + } + /* Clever way to do "if (bufpos != N) break; ... ; bufpos = 0;" */ + bufpos -= SHA3_IBLK_BYTES; + if (bufpos != 0) + break; + /* Buffer is filled up, process it */ + sha3_process_block72(ctx->state); + /*bufpos = 0; - already is */ + } + ctx->bytes_queued = bufpos + SHA3_IBLK_BYTES; +#else + /* +50 bytes code size, but a bit faster because of long-sized XORs */ + const uint8_t *data = buffer; + unsigned bufpos = ctx->bytes_queued; + + /* If already data in queue, continue queuing first */ + while (len != 0 && bufpos != 0) { + uint8_t *buf = (uint8_t*)ctx->state; + buf[bufpos] ^= *data++; + len--; + bufpos++; + if (bufpos == SHA3_IBLK_BYTES) { + bufpos = 0; + goto do_block; + } + } + + /* Absorb complete blocks */ + while (len >= SHA3_IBLK_BYTES) { + /* XOR data onto beginning of state[]. + * We try to be efficient - operate one word at a time, not byte. + * Careful wrt unaligned access: can't just use "*(long*)data"! + */ + unsigned count = SHA3_IBLK_BYTES / sizeof(long); + long *buf = (long*)ctx->state; + do { + long v; + move_from_unaligned_long(v, (long*)data); + *buf++ ^= v; + data += sizeof(long); + } while (--count); + len -= SHA3_IBLK_BYTES; + do_block: + sha3_process_block72(ctx->state); + } + + /* Queue remaining data bytes */ + while (len != 0) { + uint8_t *buf = (uint8_t*)ctx->state; + buf[bufpos] ^= *data++; + bufpos++; + len--; + } + + ctx->bytes_queued = bufpos; +#endif +} + +void FAST_FUNC sha3_end(sha3_ctx_t *ctx, void *resbuf) +{ + /* Padding */ + uint8_t *buf = (uint8_t*)ctx->state; + buf[ctx->bytes_queued] ^= 1; + buf[SHA3_IBLK_BYTES - 1] ^= 0x80; + + sha3_process_block72(ctx->state); + + /* Output */ + memcpy(resbuf, ctx->state, 64); +} diff --git a/libbb/md5prime.c b/libbb/hash_md5prime.c similarity index 96% rename from libbb/md5prime.c rename to libbb/hash_md5prime.c index 7986f4d..e089a15 100644 --- a/libbb/md5prime.c +++ b/libbb/hash_md5prime.c @@ -59,7 +59,7 @@ * Completely removed static PADDING array. * * Reintroduced the loop unrolling in md5_transform and added the - * MD5_SIZE_VS_SPEED option for configurability. Define below as: + * MD5_SMALL option for configurability. Define below as: * 0 fully unrolled loops * 1 partially unrolled (4 ops per loop) * 2 no unrolling -- introduces the need to swap 4 variables (slow) @@ -75,12 +75,12 @@ #include "libbb.h" /* 1: fastest, 3: smallest */ -#if CONFIG_MD5_SIZE_VS_SPEED < 1 -# define MD5_SIZE_VS_SPEED 1 -#elif CONFIG_MD5_SIZE_VS_SPEED > 3 -# define MD5_SIZE_VS_SPEED 3 +#if CONFIG_MD5_SMALL < 1 +# define MD5_SMALL 1 +#elif CONFIG_MD5_SMALL > 3 +# define MD5_SMALL 3 #else -# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED +# define MD5_SMALL CONFIG_MD5_SMALL #endif #if BB_LITTLE_ENDIAN @@ -152,7 +152,7 @@ memcpy32_le2cpu(uint32_t *output, const unsigned char *input, unsigned len) static void md5_transform(uint32_t state[4], const unsigned char block[64]) { uint32_t a, b, c, d, x[16]; -#if MD5_SIZE_VS_SPEED > 1 +#if MD5_SMALL > 1 uint32_t temp; const unsigned char *ps; @@ -162,9 +162,9 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) 4, 11, 16, 23, 6, 10, 15, 21 }; -#endif /* MD5_SIZE_VS_SPEED > 1 */ +#endif /* MD5_SMALL > 1 */ -#if MD5_SIZE_VS_SPEED > 0 +#if MD5_SMALL > 0 const uint32_t *pc; const unsigned char *pp; int i; @@ -198,7 +198,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ }; -#endif /* MD5_SIZE_VS_SPEED > 0 */ +#endif /* MD5_SMALL > 0 */ memcpy32_le2cpu(x, block, 64); @@ -207,7 +207,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) c = state[2]; d = state[3]; -#if MD5_SIZE_VS_SPEED > 2 +#if MD5_SMALL > 2 pc = C; pp = P; ps = S - 4; @@ -233,7 +233,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) temp += b; a = d; d = c; c = b; b = temp; } -#elif MD5_SIZE_VS_SPEED > 1 +#elif MD5_SMALL > 1 pc = C; pp = P; ps = S; @@ -260,7 +260,7 @@ static void md5_transform(uint32_t state[4], const unsigned char block[64]) II(a, b, c, d, x[*pp], ps[i & 0x3], *pc); pp++; pc++; temp = d; d = c; c = b; b = a; a = temp; } -#elif MD5_SIZE_VS_SPEED > 0 +#elif MD5_SMALL > 0 pc = C; pp = P; /* Round 1 */ diff --git a/libbb/herror_msg.c b/libbb/herror_msg.c index ca9274c..d041076 100644 --- a/libbb/herror_msg.c +++ b/libbb/herror_msg.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/human_readable.c b/libbb/human_readable.c index 4228aaf..0b2eb77 100644 --- a/libbb/human_readable.c +++ b/libbb/human_readable.c @@ -25,7 +25,7 @@ * Some code to omit the decimal point and tenths digit is sketched out * and "#if 0"'d below. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -53,8 +53,8 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val, u = unit_chars; if (display_unit) { - val += display_unit/2; /* Deal with rounding */ - val /= display_unit; /* Don't combine with the line above! */ + val += display_unit/2; /* Deal with rounding */ + val /= display_unit; /* Don't combine with the line above! */ /* will just print it as ulonglong (below) */ } else { while ((val >= 1024) @@ -94,7 +94,7 @@ const char* FAST_FUNC make_human_readable_str(unsigned long long val, /* Convert unsigned long long value into compact 5-char representation. * String is not terminated (buf[5] is untouched) */ -void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *scale) +char* FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[5], const char *scale) { const char *fmt; char c; @@ -145,12 +145,13 @@ void FAST_FUNC smart_ulltoa5(unsigned long long ul, char buf[6], const char *sca buf[3] = "0123456789"[v]; buf[4] = scale[idx]; /* typically scale = " kmgt..." */ } + return buf + 5; } /* Convert unsigned long long value into compact 4-char * representation. Examples: "1234", "1.2k", " 27M", "123T" * String is not terminated (buf[4] is untouched) */ -void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *scale) +char* FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[4], const char *scale) { const char *fmt; char c; @@ -194,4 +195,5 @@ void FAST_FUNC smart_ulltoa4(unsigned long long ul, char buf[5], const char *sca buf[2] = "0123456789"[v]; buf[3] = scale[idx]; /* typically scale = " kmgt..." */ } + return buf + 4; } diff --git a/libbb/in_ether.c b/libbb/in_ether.c new file mode 100644 index 0000000..1de383b --- /dev/null +++ b/libbb/in_ether.c @@ -0,0 +1,59 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + */ + +//kbuild:lib-$(CONFIG_ARP) += in_ether.o +//kbuild:lib-$(CONFIG_IFCONFIG) += in_ether.o +//kbuild:lib-$(CONFIG_IFENSLAVE) += in_ether.o + +#include "libbb.h" +#include +#include + +/* Convert Ethernet address from "XX[:]XX[:]XX[:]XX[:]XX[:]XX" to sockaddr. + * Return nonzero on error. + */ +int FAST_FUNC in_ether(const char *bufp, struct sockaddr *sap) +{ + char *ptr; + int i, j; + unsigned char val; + unsigned char c; + + sap->sa_family = ARPHRD_ETHER; + ptr = (char *) sap->sa_data; + + i = ETH_ALEN; + goto first; + do { + /* We might get a semicolon here */ + if (*bufp == ':') + bufp++; + first: + j = val = 0; + do { + c = *bufp; + if (((unsigned char)(c - '0')) <= 9) { + c -= '0'; + } else if ((unsigned char)((c|0x20) - 'a') <= 5) { + c = (unsigned char)((c|0x20) - 'a') + 10; + } else { + if (j && (c == ':' || c == '\0')) + /* One-digit byte: __:X:__ */ + break; + return -1; + } + ++bufp; + val <<= 4; + val += c; + j ^= 1; + } while (j); + + *ptr++ = val; + + } while (--i); + + /* Error if we aren't at end of string */ + return *bufp; +} diff --git a/libbb/inet_cksum.c b/libbb/inet_cksum.c new file mode 100644 index 0000000..3d5dc3a --- /dev/null +++ b/libbb/inet_cksum.c @@ -0,0 +1,36 @@ +/* + * Checksum routine for Internet Protocol family headers (C Version) + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +#include "libbb.h" + +uint16_t FAST_FUNC inet_cksum(uint16_t *addr, int nleft) +{ + /* + * Our algorithm is simple, using a 32 bit accumulator, + * we add sequential 16 bit words to it, and at the end, fold + * back all the carry bits from the top 16 bits into the lower + * 16 bits. + */ + unsigned sum = 0; + while (nleft > 1) { + sum += *addr++; + nleft -= 2; + } + + /* Mop up an odd byte, if necessary */ + if (nleft == 1) { + if (BB_LITTLE_ENDIAN) + sum += *(uint8_t*)addr; + else + sum += *(uint8_t*)addr << 8; + } + + /* Add back carry outs from top 16 bits to low 16 bits */ + sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ + sum += (sum >> 16); /* add carry */ + + return (uint16_t)~sum; +} diff --git a/libbb/inet_common.c b/libbb/inet_common.c index 0fc08d6..b3e0802 100644 --- a/libbb/inet_common.c +++ b/libbb/inet_common.c @@ -5,7 +5,7 @@ * * Heavily modified by Manuel Novoa III Mar 12, 2001 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -23,7 +23,7 @@ int FAST_FUNC INET_resolve(const char *name, struct sockaddr_in *s_in, int hostf s_in->sin_port = 0; /* Default is special, meaning 0.0.0.0. */ - if (!strcmp(name, bb_str_default)) { + if (strcmp(name, "default") == 0) { s_in->sin_addr.s_addr = INADDR_ANY; return 1; } @@ -97,7 +97,7 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne if (s_in->sin_family != AF_INET) { #ifdef DEBUG bb_error_msg("rresolve: unsupported address family %d!", - s_in->sin_family); + s_in->sin_family); #endif errno = EAFNOSUPPORT; return NULL; @@ -109,7 +109,7 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne if (ad == INADDR_ANY) { if ((numeric & 0x0FFF) == 0) { if (numeric & 0x8000) - return xstrdup(bb_str_default); + return xstrdup("default"); return xstrdup("*"); } } @@ -164,17 +164,17 @@ char* FAST_FUNC INET_rresolve(struct sockaddr_in *s_in, int numeric, uint32_t ne int FAST_FUNC INET6_resolve(const char *name, struct sockaddr_in6 *sin6) { - struct addrinfo req, *ai; + struct addrinfo req, *ai = NULL; int s; - memset(&req, '\0', sizeof req); + memset(&req, 0, sizeof(req)); req.ai_family = AF_INET6; s = getaddrinfo(name, NULL, &req, &ai); - if (s) { + if (s != 0) { bb_error_msg("getaddrinfo: %s: %d", name, s); return -1; } - memcpy(sin6, ai->ai_addr, sizeof(struct sockaddr_in6)); + memcpy(sin6, ai->ai_addr, sizeof(*sin6)); freeaddrinfo(ai); return 0; } @@ -194,7 +194,7 @@ char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) if (sin6->sin6_family != AF_INET6) { #ifdef DEBUG bb_error_msg("rresolve: unsupported address family %d!", - sin6->sin6_family); + sin6->sin6_family); #endif errno = EAFNOSUPPORT; return NULL; @@ -205,17 +205,19 @@ char* FAST_FUNC INET6_rresolve(struct sockaddr_in6 *sin6, int numeric) } if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { if (numeric & 0x8000) - return xstrdup(bb_str_default); + return xstrdup("default"); return xstrdup("*"); } - s = getnameinfo((struct sockaddr *) sin6, sizeof(struct sockaddr_in6), - name, sizeof(name), NULL, 0, 0); - if (s) { + s = getnameinfo((struct sockaddr *) sin6, sizeof(*sin6), + name, sizeof(name), + /*serv,servlen:*/ NULL, 0, + 0); + if (s != 0) { bb_error_msg("getnameinfo failed"); return NULL; } return xstrdup(name); } -#endif /* CONFIG_FEATURE_IPV6 */ +#endif /* CONFIG_FEATURE_IPV6 */ diff --git a/libbb/info_msg.c b/libbb/info_msg.c index 81164fa..56ca2ef 100644 --- a/libbb/info_msg.c +++ b/libbb/info_msg.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/inode_hash.c b/libbb/inode_hash.c index b32bd26..715535e 100644 --- a/libbb/inode_hash.c +++ b/libbb/inode_hash.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -17,8 +17,8 @@ typedef struct ino_dev_hash_bucket_struct { char name[1]; } ino_dev_hashtable_bucket_t; -#define HASH_SIZE 311 /* Should be prime */ -#define hash_inode(i) ((i) % HASH_SIZE) +#define HASH_SIZE 311 /* Should be prime */ +#define hash_inode(i) ((i) % HASH_SIZE) /* array of [HASH_SIZE] elements */ static ino_dev_hashtable_bucket_t **ino_dev_hashtable; diff --git a/libbb/isdirectory.c b/libbb/isdirectory.c index 4a2961e..ba6c52c 100644 --- a/libbb/isdirectory.c +++ b/libbb/isdirectory.c @@ -3,9 +3,9 @@ * Utility routines. * * Based in part on code from sash, Copyright (c) 1999 by David I. Bell - * Permission has been granted to redistribute this code under the GPL. + * Permission has been granted to redistribute this code under GPL. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include @@ -15,22 +15,17 @@ * Return TRUE if fileName is a directory. * Nonexistent files return FALSE. */ -int FAST_FUNC is_directory(const char *fileName, int followLinks, struct stat *statBuf) +int FAST_FUNC is_directory(const char *fileName, int followLinks) { int status; - struct stat astatBuf; - - if (statBuf == NULL) { - /* use auto stack buffer */ - statBuf = &astatBuf; - } + struct stat statBuf; if (followLinks) - status = stat(fileName, statBuf); + status = stat(fileName, &statBuf); else - status = lstat(fileName, statBuf); + status = lstat(fileName, &statBuf); - status = (status == 0 && S_ISDIR(statBuf->st_mode)); + status = (status == 0 && S_ISDIR(statBuf.st_mode)); return status; } diff --git a/libbb/kernel_version.c b/libbb/kernel_version.c index cc23712..738ed02 100644 --- a/libbb/kernel_version.c +++ b/libbb/kernel_version.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -20,18 +20,15 @@ int FAST_FUNC get_linux_version_code(void) { struct utsname name; - char *s; + char *s, *t; int i, r; - if (uname(&name) == -1) { - bb_perror_msg("can't get system information"); - return 0; - } - + uname(&name); /* never fails */ s = name.release; r = 0; for (i = 0; i < 3; i++) { - r = r * 256 + atoi(strtok(s, ".")); + t = strtok(s, "."); + r = r * 256 + (t ? atoi(t) : 0); s = NULL; } return r; diff --git a/libbb/last_char_is.c b/libbb/last_char_is.c index b059256..65e6cdf 100644 --- a/libbb/last_char_is.c +++ b/libbb/last_char_is.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Larry Doolittle, * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/lineedit.c b/libbb/lineedit.c index a9b790c..8564307 100644 --- a/libbb/lineedit.c +++ b/libbb/lineedit.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Termios command line History and Editing. + * Command line editing. * * Copyright (c) 1986-2003 may safely be consumed by a BSD or GPL license. * Written by: Vladimir Oleynik @@ -38,9 +38,21 @@ * and the \] escape to signal the end of such a sequence. Example: * * PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] ' + * + * Unicode in PS1 is not fully supported: prompt length calulation is wrong, + * resulting in line wrap problems with long (multi-line) input. + * + * Multi-line PS1 (e.g. PS1="\n[\w]\n$ ") has problems with history + * browsing: up/down arrows result in scrolling. + * It stems from simplistic "cmdedit_y = cmdedit_prmt_len / cmdedit_termw" + * calculation of how many lines the prompt takes. */ #include "libbb.h" #include "unicode.h" +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE '\0' +#endif + #ifdef TEST # define ENABLE_FEATURE_EDITING 0 @@ -53,19 +65,15 @@ #if ENABLE_FEATURE_EDITING -#define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \ +#define ENABLE_USERNAME_OR_HOMEDIR \ (ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT) -#define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...) -#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR -#undef IF_FEATURE_GETUSERNAME_AND_HOMEDIR -#define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__ +#define IF_USERNAME_OR_HOMEDIR(...) +#if ENABLE_USERNAME_OR_HOMEDIR +# undef IF_USERNAME_OR_HOMEDIR +# define IF_USERNAME_OR_HOMEDIR(...) __VA_ARGS__ #endif -#define SEQ_CLEAR_TILL_END_OF_SCREEN "\033[J" -//#define SEQ_CLEAR_TILL_END_OF_LINE "\033[K" - - #undef CHAR_T #if ENABLE_UNICODE_SUPPORT # define BB_NUL ((wchar_t)0) @@ -90,24 +98,27 @@ static bool BB_ispunct(CHAR_T c) { return ((unsigned)c < 256 && ispunct(c)); } # define BB_isalnum(c) isalnum(c) # define BB_ispunct(c) ispunct(c) #endif +#if ENABLE_UNICODE_PRESERVE_BROKEN +# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000) +# define unicode_is_raw_byte(wc) ((wc) & 0x20000000) +#else +# define unicode_is_raw_byte(wc) 0 +#endif -# if ENABLE_UNICODE_PRESERVE_BROKEN -# define unicode_mark_raw_byte(wc) ((wc) | 0x20000000) -# define unicode_is_raw_byte(wc) ((wc) & 0x20000000) -# else -# define unicode_is_raw_byte(wc) 0 -# endif +#define ESC "\033" + +#define SEQ_CLEAR_TILL_END_OF_SCREEN ESC"[J" +//#define SEQ_CLEAR_TILL_END_OF_LINE ESC"[K" enum { - /* We use int16_t for positions, need to limit line len */ MAX_LINELEN = CONFIG_FEATURE_EDITING_MAX_LEN < 0x7ff0 ? CONFIG_FEATURE_EDITING_MAX_LEN : 0x7ff0 }; -#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR +#if ENABLE_USERNAME_OR_HOMEDIR static const char null_str[] ALIGN1 = ""; #endif @@ -130,11 +141,8 @@ struct lineedit_statics { CHAR_T *command_ps; const char *cmdedit_prompt; -#if ENABLE_FEATURE_EDITING_FANCY_PROMPT - int num_ok_lines; /* = 1; */ -#endif -#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR +#if ENABLE_USERNAME_OR_HOMEDIR char *user_buf; char *home_pwd_buf; /* = (char*)null_str; */ #endif @@ -145,7 +153,7 @@ struct lineedit_statics { #endif #if ENABLE_FEATURE_EDITING_VI -#define DELBUFSIZ 128 +# define DELBUFSIZ 128 CHAR_T *delptr; smallint newdelflag; /* whether delbuf should be reused yet */ CHAR_T delbuf[DELBUFSIZ]; /* a place to store deleted characters */ @@ -153,14 +161,6 @@ struct lineedit_statics { #if ENABLE_FEATURE_EDITING_ASK_TERMINAL smallint sent_ESC_br6n; #endif - - /* Formerly these were big buffers on stack: */ -#if ENABLE_FEATURE_TAB_COMPLETION - char exe_n_cwd_tab_completion__dirbuf[MAX_LINELEN]; - char input_tab__matchBuf[MAX_LINELEN]; - int16_t find_match__int_buf[MAX_LINELEN + 1]; /* need to have 9 bits at least */ - int16_t find_match__pos_buf[MAX_LINELEN + 1]; -#endif }; /* See lineedit_ptr_hack.c */ @@ -177,7 +177,6 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; #define command_len (S.command_len ) #define command_ps (S.command_ps ) #define cmdedit_prompt (S.cmdedit_prompt ) -#define num_ok_lines (S.num_ok_lines ) #define user_buf (S.user_buf ) #define home_pwd_buf (S.home_pwd_buf ) #define matches (S.matches ) @@ -190,17 +189,18 @@ extern struct lineedit_statics *const lineedit_ptr_to_statics; (*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \ barrier(); \ cmdedit_termw = 80; \ - IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \ - IF_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \ + IF_USERNAME_OR_HOMEDIR(home_pwd_buf = (char*)null_str;) \ + IF_FEATURE_EDITING_VI(delptr = delbuf;) \ } while (0) + static void deinit_S(void) { #if ENABLE_FEATURE_EDITING_FANCY_PROMPT /* This one is allocated only if FANCY_PROMPT is on - * (otherwise it points to verbatim prompt (NOT malloced) */ + * (otherwise it points to verbatim prompt (NOT malloced)) */ free((char*)cmdedit_prompt); #endif -#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR +#if ENABLE_USERNAME_OR_HOMEDIR free(user_buf); if (home_pwd_buf != null_str) free(home_pwd_buf); @@ -211,64 +211,87 @@ static void deinit_S(void) #if ENABLE_UNICODE_SUPPORT -static size_t load_string(const char *src, int maxsize) +static size_t load_string(const char *src) { - ssize_t len = mbstowcs(command_ps, src, maxsize - 1); - if (len < 0) - len = 0; - command_ps[len] = 0; - return len; + if (unicode_status == UNICODE_ON) { + ssize_t len = mbstowcs(command_ps, src, S.maxsize - 1); + if (len < 0) + len = 0; + command_ps[len] = BB_NUL; + return len; + } else { + unsigned i = 0; + while (src[i] && i < S.maxsize - 1) { + command_ps[i] = src[i]; + i++; + } + command_ps[i] = BB_NUL; + return i; + } } static unsigned save_string(char *dst, unsigned maxsize) { + if (unicode_status == UNICODE_ON) { # if !ENABLE_UNICODE_PRESERVE_BROKEN - ssize_t len = wcstombs(dst, command_ps, maxsize - 1); - if (len < 0) - len = 0; - dst[len] = '\0'; - return len; + ssize_t len = wcstombs(dst, command_ps, maxsize - 1); + if (len < 0) + len = 0; + dst[len] = '\0'; + return len; # else - unsigned dstpos = 0; - unsigned srcpos = 0; - - maxsize--; - while (dstpos < maxsize) { - wchar_t wc; - int n = srcpos; - while ((wc = command_ps[srcpos]) != 0 - && !unicode_is_raw_byte(wc) - ) { + unsigned dstpos = 0; + unsigned srcpos = 0; + + maxsize--; + while (dstpos < maxsize) { + wchar_t wc; + int n = srcpos; + + /* Convert up to 1st invalid byte (or up to end) */ + while ((wc = command_ps[srcpos]) != BB_NUL + && !unicode_is_raw_byte(wc) + ) { + srcpos++; + } + command_ps[srcpos] = BB_NUL; + n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); + if (n < 0) /* should not happen */ + break; + dstpos += n; + if (wc == BB_NUL) /* usually is */ + break; + + /* We do have invalid byte here! */ + command_ps[srcpos] = wc; /* restore it */ srcpos++; + if (dstpos == maxsize) + break; + dst[dstpos++] = (char) wc; } - command_ps[srcpos] = 0; - n = wcstombs(dst + dstpos, command_ps + n, maxsize - dstpos); - if (n < 0) /* should not happen */ - break; - dstpos += n; - if (wc == 0) /* usually is */ - break; - /* We do have invalid byte here! */ - command_ps[srcpos] = wc; /* restore it */ - srcpos++; - if (dstpos == maxsize) - break; - dst[dstpos++] = (char) wc; - } - dst[dstpos] = '\0'; - return dstpos; + dst[dstpos] = '\0'; + return dstpos; # endif + } else { + unsigned i = 0; + while ((dst[i] = command_ps[i]) != 0) + i++; + return i; + } } /* I thought just fputwc(c, stdout) would work. But no... */ static void BB_PUTCHAR(wchar_t c) { - char buf[MB_CUR_MAX + 1]; - mbstate_t mbst = { 0 }; - ssize_t len; - - len = wcrtomb(buf, c, &mbst); - if (len > 0) { - buf[len] = '\0'; - fputs(buf, stdout); + if (unicode_status == UNICODE_ON) { + char buf[MB_CUR_MAX + 1]; + mbstate_t mbst = { 0 }; + ssize_t len = wcrtomb(buf, c, &mbst); + if (len > 0) { + buf[len] = '\0'; + fputs(buf, stdout); + } + } else { + /* In this case, c is always one byte */ + putchar(c); } } # if ENABLE_UNICODE_COMBINING_WCHARS || ENABLE_UNICODE_WIDE_WCHARS @@ -303,9 +326,9 @@ static wchar_t adjust_width_and_validate_wc(wchar_t wc) return wc; } #else /* !UNICODE */ -static size_t load_string(const char *src, int maxsize) +static size_t load_string(const char *src) { - safe_strncpy(command_ps, src, maxsize); + safe_strncpy(command_ps, src, S.maxsize); return strlen(command_ps); } # if ENABLE_FEATURE_TAB_COMPLETION @@ -454,7 +477,7 @@ static void input_backward(unsigned num) } while (--num); return; } - printf("\033[%uD", num); + printf(ESC"[%uD", num); return; } @@ -479,7 +502,7 @@ static void input_backward(unsigned num) */ unsigned sv_cursor; /* go to 1st column; go up to first line */ - printf("\r" "\033[%uA", cmdedit_y); + printf("\r" ESC"[%uA", cmdedit_y); cmdedit_y = 0; sv_cursor = cursor; put_prompt(); /* sets cursor to 0 */ @@ -496,12 +519,12 @@ static void input_backward(unsigned num) cmdedit_x = (width * cmdedit_y - num) % width; cmdedit_y -= lines_up; /* go to 1st column; go up */ - printf("\r" "\033[%uA", lines_up); + printf("\r" ESC"[%uA", lines_up); /* go to correct column. * xterm, konsole, Linux VT interpret 0 as 1 below! wow. * need to *make sure* we skip it if cmdedit_x == 0 */ if (cmdedit_x) - printf("\033[%uC", cmdedit_x); + printf(ESC"[%uC", cmdedit_x); } } @@ -509,7 +532,7 @@ static void input_backward(unsigned num) static void redraw(int y, int back_cursor) { if (y > 0) /* up y lines */ - printf("\033[%uA", y); + printf(ESC"[%uA", y); bb_putchar('\r'); put_prompt(); put_till_end_and_adv_cursor(); @@ -590,6 +613,12 @@ static void input_forward(void) #if ENABLE_FEATURE_TAB_COMPLETION +//FIXME: +//needs to be more clever: currently it thinks that "foo\ b +//matches the file named "foo bar", which is untrue. +//Also, perhaps "foo b needs to complete to "foo bar" , +//not "foo bar ... + static void free_tab_completion_data(void) { if (matches) { @@ -607,56 +636,63 @@ static void add_match(char *matched) num_matches++; } -#if ENABLE_FEATURE_USERNAME_COMPLETION -static void username_tab_completion(char *ud, char *with_shash_flg) +# if ENABLE_FEATURE_USERNAME_COMPLETION +/* Replace "~user/..." with "/homedir/...". + * The parameter is malloced, free it or return it + * unchanged if no user is matched. + */ +static char *username_path_completion(char *ud) { struct passwd *entry; - int userlen; + char *tilde_name = ud; + char *home = NULL; - ud++; /* ~user/... to user/... */ - userlen = strlen(ud); + ud++; /* skip ~ */ + if (*ud == '/') { /* "~/..." */ + home = home_pwd_buf; + } else { + /* "~user/..." */ + ud = strchr(ud, '/'); + *ud = '\0'; /* "~user" */ + entry = getpwnam(tilde_name + 1); + *ud = '/'; /* restore "~user/..." */ + if (entry) + home = entry->pw_dir; + } + if (home) { + ud = concat_path_file(home, ud); + free(tilde_name); + tilde_name = ud; + } + return tilde_name; +} - if (with_shash_flg) { /* "~/..." or "~user/..." */ - char *sav_ud = ud - 1; - char *home = NULL; +/* ~use - find all users with this prefix. + * Return the length of the prefix used for matching. + */ +static NOINLINE unsigned complete_username(const char *ud) +{ + /* Using _r function to avoid pulling in static buffers */ + char line_buff[256]; + struct passwd pwd; + struct passwd *result; + unsigned userlen; - if (*ud == '/') { /* "~/..." */ - home = home_pwd_buf; - } else { - /* "~user/..." */ - char *temp; - temp = strchr(ud, '/'); - *temp = '\0'; /* ~user\0 */ - entry = getpwnam(ud); - *temp = '/'; /* restore ~user/... */ - ud = temp; - if (entry) - home = entry->pw_dir; - } - if (home) { - if ((userlen + strlen(home) + 1) < MAX_LINELEN) { - /* /home/user/... */ - sprintf(sav_ud, "%s%s", home, ud); - } - } - } else { - /* "~[^/]*" */ - /* Using _r function to avoid pulling in static buffers */ - char line_buff[256]; - struct passwd pwd; - struct passwd *result; - - setpwent(); - while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) { - /* Null usernames should result in all users as possible completions. */ - if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { - add_match(xasprintf("~%s/", pwd.pw_name)); - } + ud++; /* skip ~ */ + userlen = strlen(ud); + + setpwent(); + while (!getpwent_r(&pwd, line_buff, sizeof(line_buff), &result)) { + /* Null usernames should result in all users as possible completions. */ + if (/*!userlen || */ strncmp(ud, pwd.pw_name, userlen) == 0) { + add_match(xasprintf("~%s/", pwd.pw_name)); } - endpwent(); } + endpwent(); + + return 1 + userlen; } -#endif /* FEATURE_COMMAND_USERNAME_COMPLETION */ +# endif /* FEATURE_USERNAME_COMPLETION */ enum { FIND_EXE_ONLY = 0, @@ -664,22 +700,19 @@ enum { FIND_FILE_ONLY = 2, }; -static int path_parse(char ***p, int flags) +static int path_parse(char ***p) { int npth; const char *pth; char *tmp; char **res; - /* if not setenv PATH variable, to search cur dir "." */ - if (flags != FIND_EXE_ONLY) - return 1; - if (state->flags & WITH_PATH_LOOKUP) pth = state->path_lookup; else pth = getenv("PATH"); - /* PATH= or PATH=: */ + + /* PATH="" or PATH=":"? */ if (!pth || !pth[0] || LONE_CHAR(pth, ':')) return 1; @@ -689,12 +722,13 @@ static int path_parse(char ***p, int flags) tmp = strchr(tmp, ':'); if (!tmp) break; - if (*++tmp == '\0') + tmp++; + if (*tmp == '\0') break; /* : */ npth++; } - res = xmalloc(npth * sizeof(char*)); + *p = res = xmalloc(npth * sizeof(res[0])); res[0] = tmp = xstrdup(pth); npth = 1; while (1) { @@ -706,235 +740,241 @@ static int path_parse(char ***p, int flags) break; /* : */ res[npth++] = tmp; } - *p = res; return npth; } -static void exe_n_cwd_tab_completion(char *command, int type) +/* Complete command, directory or file name. + * Return the length of the prefix used for matching. + */ +static NOINLINE unsigned complete_cmd_dir_file(const char *command, int type) { - DIR *dir; - struct dirent *next; - struct stat st; char *path1[1]; char **paths = path1; int npaths; int i; - char *found; - char *pfind = strrchr(command, '/'); -/* char dirbuf[MAX_LINELEN]; */ -#define dirbuf (S.exe_n_cwd_tab_completion__dirbuf) + unsigned pf_len; + const char *pfind; + char *dirbuf = NULL; npaths = 1; path1[0] = (char*)"."; - if (pfind == NULL) { - /* no dir, if flags==EXE_ONLY - get paths, else "." */ - npaths = path_parse(&paths, type); + pfind = strrchr(command, '/'); + if (!pfind) { + if (type == FIND_EXE_ONLY) + npaths = path_parse(&paths); pfind = command; } else { - /* dirbuf = ".../.../.../" */ - safe_strncpy(dirbuf, command, (pfind - command) + 2); -#if ENABLE_FEATURE_USERNAME_COMPLETION - if (dirbuf[0] == '~') /* ~/... or ~user/... */ - username_tab_completion(dirbuf, dirbuf); -#endif - paths[0] = dirbuf; /* point to 'l' in "..../last_component" */ pfind++; + /* dirbuf = ".../.../.../" */ + dirbuf = xstrndup(command, pfind - command); +# if ENABLE_FEATURE_USERNAME_COMPLETION + if (dirbuf[0] == '~') /* ~/... or ~user/... */ + dirbuf = username_path_completion(dirbuf); +# endif + path1[0] = dirbuf; } + pf_len = strlen(pfind); for (i = 0; i < npaths; i++) { + DIR *dir; + struct dirent *next; + struct stat st; + char *found; + dir = opendir(paths[i]); if (!dir) continue; /* don't print an error */ while ((next = readdir(dir)) != NULL) { - int len1; - const char *str_found = next->d_name; + unsigned len; + const char *name_found = next->d_name; - /* matched? */ - if (strncmp(str_found, pfind, strlen(pfind))) + /* .../: bash 3.2.0 shows dotfiles, but not . and .. */ + if (!pfind[0] && DOT_OR_DOTDOT(name_found)) continue; - /* not see .name without .match */ - if (*str_found == '.' && *pfind == '\0') { - if (NOT_LONE_CHAR(paths[i], '/') || str_found[1]) - continue; - str_found = ""; /* only "/" */ - } - found = concat_path_file(paths[i], str_found); - /* hmm, remove in progress? */ + /* match? */ + if (strncmp(name_found, pfind, pf_len) != 0) + continue; /* no */ + + found = concat_path_file(paths[i], name_found); /* NB: stat() first so that we see is it a directory; * but if that fails, use lstat() so that * we still match dangling links */ if (stat(found, &st) && lstat(found, &st)) - goto cont; - /* find with dirs? */ - if (paths[i] != dirbuf) - strcpy(found, next->d_name); /* only name */ + goto cont; /* hmm, remove in progress? */ - len1 = strlen(found); - found = xrealloc(found, len1 + 2); - found[len1] = '\0'; - found[len1+1] = '\0'; + /* Save only name */ + len = strlen(name_found); + found = xrealloc(found, len + 2); /* +2: for slash and NUL */ + strcpy(found, name_found); if (S_ISDIR(st.st_mode)) { - /* name is a directory */ - if (found[len1-1] != '/') { - found[len1] = '/'; - } + /* name is a directory, add slash */ + found[len] = '/'; + found[len + 1] = '\0'; } else { - /* not put found file if search only dirs for cd */ + /* skip files if looking for dirs only (example: cd) */ if (type == FIND_DIR_ONLY) goto cont; } - /* Add it to the list */ + /* add it to the list */ add_match(found); continue; cont: free(found); } closedir(dir); - } + } /* for every path */ + if (paths != path1) { free(paths[0]); /* allocated memory is only in first member */ free(paths); } -#undef dirbuf + free(dirbuf); + + return pf_len; } +/* build_match_prefix: + * On entry, match_buf contains everything up to cursor at the moment + * was pressed. This function looks at it, figures out what part of it + * constitutes the command/file/directory prefix to use for completion, + * and rewrites match_buf to contain only that part. + */ +#define dbg_bmp 0 +/* Helpers: */ /* QUOT is used on elements of int_buf[], which are bytes, * not Unicode chars. Therefore it works correctly even in Unicode mode. */ #define QUOT (UCHAR_MAX+1) - -#define int_buf (S.find_match__int_buf) -#define pos_buf (S.find_match__pos_buf) -/* is must be <= in */ -static void collapse_pos(int is, int in) +static void remove_chunk(int16_t *int_buf, int beg, int end) { - memmove(int_buf+is, int_buf+in, (MAX_LINELEN+1-in)*sizeof(int_buf[0])); - memmove(pos_buf+is, pos_buf+in, (MAX_LINELEN+1-in)*sizeof(pos_buf[0])); + /* beg must be <= end */ + if (beg == end) + return; + + while ((int_buf[beg] = int_buf[end]) != 0) + beg++, end++; + + if (dbg_bmp) { + int i; + for (i = 0; int_buf[i]; i++) + bb_putchar((unsigned char)int_buf[i]); + bb_putchar('\n'); + } } -static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) +/* Caller ensures that match_buf points to a malloced buffer + * big enough to hold strlen(match_buf)*2 + 2 + */ +static NOINLINE int build_match_prefix(char *match_buf) { int i, j; int command_mode; - int c, c2; -/* Were local, but it uses too much stack */ -/* int16_t int_buf[MAX_LINELEN + 1]; */ -/* int16_t pos_buf[MAX_LINELEN + 1]; */ - - /* set to integer dimension characters and own positions */ - for (i = 0;; i++) { - int_buf[i] = (unsigned char)matchBuf[i]; - if (int_buf[i] == 0) { - pos_buf[i] = -1; /* end-fo-line indicator */ - break; - } - pos_buf[i] = i; - } + int16_t *int_buf = (int16_t*)match_buf; - /* mask \+symbol and convert '\t' to ' ' */ - for (i = j = 0; matchBuf[i]; i++, j++) { - if (matchBuf[i] == '\\') { - collapse_pos(j, j + 1); - int_buf[j] |= QUOT; - i++; + if (dbg_bmp) printf("\n%s\n", match_buf); + + /* Copy in reverse order, since they overlap */ + i = strlen(match_buf); + do { + int_buf[i] = (unsigned char)match_buf[i]; + i--; + } while (i >= 0); + + /* Mark every \c as "quoted c" */ + for (i = 0; int_buf[i]; i++) { + if (int_buf[i] == '\\') { + remove_chunk(int_buf, i, i + 1); + int_buf[i] |= QUOT; } } - /* mask "symbols" or 'symbols' */ - c2 = 0; - for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - if (c == '\'' || c == '"') { - if (c2 == 0) - c2 = c; - else { - if (c == c2) - c2 = 0; - else - int_buf[i] |= QUOT; + /* Quote-mark "chars" and 'chars', drop delimiters */ + { + int in_quote = 0; + i = 0; + while (int_buf[i]) { + int cur = int_buf[i]; + if (!cur) + break; + if (cur == '\'' || cur == '"') { + if (!in_quote || (cur == in_quote)) { + in_quote ^= cur; + remove_chunk(int_buf, i, i + 1); + continue; + } } - } else if (c2 != 0 && c != '$') - int_buf[i] |= QUOT; + if (in_quote) + int_buf[i] = cur | QUOT; + i++; + } } - /* skip commands with arguments if line has commands delimiters */ - /* ';' ';;' '&' '|' '&&' '||' but `>&' `<&' `>|' */ + /* Remove everything up to command delimiters: + * ';' ';;' '&' '|' '&&' '||', + * but careful with '>&' '<&' '>|' + */ for (i = 0; int_buf[i]; i++) { - c = int_buf[i]; - c2 = int_buf[i + 1]; - j = i ? int_buf[i - 1] : -1; - command_mode = 0; - if (c == ';' || c == '&' || c == '|') { - command_mode = 1 + (c == c2); - if (c == '&') { - if (j == '>' || j == '<') - command_mode = 0; - } else if (c == '|' && j == '>') - command_mode = 0; - } - if (command_mode) { - collapse_pos(0, i + command_mode); - i = -1; /* hack incremet */ + int cur = int_buf[i]; + if (cur == ';' || cur == '&' || cur == '|') { + int prev = i ? int_buf[i - 1] : 0; + if (cur == '&' && (prev == '>' || prev == '<')) { + continue; + } else if (cur == '|' && prev == '>') { + continue; + } + remove_chunk(int_buf, 0, i + 1 + (cur == int_buf[i + 1])); + i = -1; /* back to square 1 */ } } - /* collapse `command...` */ + /* Remove all `cmd` */ for (i = 0; int_buf[i]; i++) { if (int_buf[i] == '`') { - for (j = i + 1; int_buf[j]; j++) + for (j = i + 1; int_buf[j]; j++) { if (int_buf[j] == '`') { - collapse_pos(i, j + 1); - j = 0; - break; + /* `cmd` should count as a word: + * `cmd` c should search for files c*, + * not commands c*. Therefore we don't drop + * `cmd` entirely, we replace it with single `. + */ + remove_chunk(int_buf, i, j); + goto next; } - if (j) { - /* not found closing ` - command mode, collapse all previous */ - collapse_pos(0, i + 1); - break; - } else - i--; /* hack incremet */ + } + /* No closing ` - command mode, remove all up to ` */ + remove_chunk(int_buf, 0, i + 1); + break; + next: ; } } - /* collapse (command...(command...)...) or {command...{command...}...} */ - c = 0; /* "recursive" level */ - c2 = 0; + /* Remove "cmd (" and "cmd {" + * Example: "if { c" + * In this example, c should be matched as command pfx. + */ for (i = 0; int_buf[i]; i++) { if (int_buf[i] == '(' || int_buf[i] == '{') { - if (int_buf[i] == '(') - c++; - else - c2++; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ - } - } - for (i = 0; pos_buf[i] >= 0 && (c > 0 || c2 > 0); i++) { - if ((int_buf[i] == ')' && c > 0) || (int_buf[i] == '}' && c2 > 0)) { - if (int_buf[i] == ')') - c--; - else - c2--; - collapse_pos(0, i + 1); - i = -1; /* hack incremet */ + remove_chunk(int_buf, 0, i + 1); + i = -1; /* back to square 1 */ } } - /* skip first not quote space */ + /* Remove leading unquoted spaces */ for (i = 0; int_buf[i]; i++) if (int_buf[i] != ' ') break; - if (i) - collapse_pos(0, i); + remove_chunk(int_buf, 0, i); - /* set find mode for completion */ + /* Determine completion mode */ command_mode = FIND_EXE_ONLY; for (i = 0; int_buf[i]; i++) { if (int_buf[i] == ' ' || int_buf[i] == '<' || int_buf[i] == '>') { - if (int_buf[i] == ' ' && command_mode == FIND_EXE_ONLY - && matchBuf[pos_buf[0]] == 'c' - && matchBuf[pos_buf[1]] == 'd' + if (int_buf[i] == ' ' + && command_mode == FIND_EXE_ONLY + && (char)int_buf[0] == 'c' + && (char)int_buf[1] == 'd' + && i == 2 /* -> int_buf[2] == ' ' */ ) { command_mode = FIND_DIR_ONLY; } else { @@ -943,44 +983,32 @@ static NOINLINE int find_match(char *matchBuf, int *len_with_quotes) } } } - for (i = 0; int_buf[i]; i++) - /* "strlen" */; - /* find last word */ + if (dbg_bmp) printf("command_mode(0:exe/1:dir/2:file):%d\n", command_mode); + + /* Remove everything except last word */ + for (i = 0; int_buf[i]; i++) /* quasi-strlen(int_buf) */ + continue; for (--i; i >= 0; i--) { - c = int_buf[i]; - if (c == ' ' || c == '<' || c == '>' || c == '|' || c == '&') { - collapse_pos(0, i + 1); + int cur = int_buf[i]; + if (cur == ' ' || cur == '<' || cur == '>' || cur == '|' || cur == '&') { + remove_chunk(int_buf, 0, i + 1); break; } } - /* skip first not quoted '\'' or '"' */ - for (i = 0; int_buf[i] == '\'' || int_buf[i] == '"'; i++) - /*skip*/; - /* collapse quote or unquote // or /~ */ - while ((int_buf[i] & ~QUOT) == '/' - && ((int_buf[i+1] & ~QUOT) == '/' || (int_buf[i+1] & ~QUOT) == '~') - ) { + + /* Convert back to string of _chars_ */ + i = 0; + while ((match_buf[i] = int_buf[i]) != '\0') i++; - } - /* set only match and destroy quotes */ - j = 0; - for (c = 0; pos_buf[i] >= 0; i++) { - matchBuf[c++] = matchBuf[pos_buf[i]]; - j = pos_buf[i] + 1; - } - matchBuf[c] = '\0'; - /* old length matchBuf with quotes symbols */ - *len_with_quotes = j ? j - pos_buf[0] : 0; + if (dbg_bmp) printf("final match_buf:'%s'\n", match_buf); return command_mode; } -#undef int_buf -#undef pos_buf /* - * display by column (original idea from ls applet, - * very optimized by me :) + * Display by column (original idea from ls applet, + * very optimized by me [Vladimir] :) */ static void showfiles(void) { @@ -1022,13 +1050,18 @@ static void showfiles(void) } } -static char *add_quote_for_spec_chars(char *found) +static const char *is_special_char(char c) +{ + return strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", c); +} + +static char *quote_special_chars(char *found) { int l = 0; char *s = xzalloc((strlen(found) + 1) * 2); while (*found) { - if (strchr(" `\"#$%^&*()=+{}[]:;'|\\<>", *found)) + if (is_special_char(*found)) s[l++] = '\\'; s[l++] = *found++; } @@ -1037,168 +1070,213 @@ static char *add_quote_for_spec_chars(char *found) } /* Do TAB completion */ -static void input_tab(smallint *lastWasTab) +static NOINLINE void input_tab(smallint *lastWasTab) { + char *chosen_match; + char *match_buf; + size_t len_found; + /* Length of string used for matching */ + unsigned match_pfx_len = match_pfx_len; + int find_type; +# if ENABLE_UNICODE_SUPPORT + /* cursor pos in command converted to multibyte form */ + int cursor_mb; +# endif if (!(state->flags & TAB_COMPLETION)) return; - if (!*lastWasTab) { - char *tmp, *tmp1; - size_t len_found; -/* char matchBuf[MAX_LINELEN]; */ -#define matchBuf (S.input_tab__matchBuf) - int find_type; - int recalc_pos; -#if ENABLE_UNICODE_SUPPORT - /* cursor pos in command converted to multibyte form */ - int cursor_mb; -#endif + if (*lastWasTab) { + /* The last char was a TAB too. + * Print a list of all the available choices. + */ + if (num_matches > 0) { + /* cursor will be changed by goto_new_line() */ + int sav_cursor = cursor; + goto_new_line(); + showfiles(); + redraw(0, command_len - sav_cursor); + } + return; + } - *lastWasTab = TRUE; /* flop trigger */ + *lastWasTab = 1; + chosen_match = NULL; - /* Make a local copy of the string -- - * up to the position of the cursor */ - save_string(matchBuf, cursor + 1); -#if ENABLE_UNICODE_SUPPORT - cursor_mb = strlen(matchBuf); -#endif - tmp = matchBuf; + /* Make a local copy of the string up to the position of the cursor. + * build_match_prefix will expand it into int16_t's, need to allocate + * twice as much as the string_len+1. + * (we then also (ab)use this extra space later - see (**)) + */ + match_buf = xmalloc(MAX_LINELEN * sizeof(int16_t)); +# if !ENABLE_UNICODE_SUPPORT + save_string(match_buf, cursor + 1); /* +1 for NUL */ +# else + { + CHAR_T wc = command_ps[cursor]; + command_ps[cursor] = BB_NUL; + save_string(match_buf, MAX_LINELEN); + command_ps[cursor] = wc; + cursor_mb = strlen(match_buf); + } +# endif + find_type = build_match_prefix(match_buf); - find_type = find_match(matchBuf, &recalc_pos); + /* Free up any memory already allocated */ + free_tab_completion_data(); - /* Free up any memory already allocated */ - free_tab_completion_data(); +# if ENABLE_FEATURE_USERNAME_COMPLETION + /* If the word starts with ~ and there is no slash in the word, + * then try completing this word as a username. */ + if (state->flags & USERNAME_COMPLETION) + if (match_buf[0] == '~' && strchr(match_buf, '/') == NULL) + match_pfx_len = complete_username(match_buf); +# endif + /* If complete_username() did not match, + * try to match a command in $PATH, or a directory, or a file */ + if (!matches) + match_pfx_len = complete_cmd_dir_file(match_buf, find_type); -#if ENABLE_FEATURE_USERNAME_COMPLETION - /* If the word starts with `~' and there is no slash in the word, - * then try completing this word as a username. */ - if (state->flags & USERNAME_COMPLETION) - if (matchBuf[0] == '~' && strchr(matchBuf, '/') == NULL) - username_tab_completion(matchBuf, NULL); -#endif - /* Try to match any executable in our path and everything - * in the current working directory */ - if (!matches) - exe_n_cwd_tab_completion(matchBuf, find_type); - /* Sort, then remove any duplicates found */ - if (matches) { - unsigned i; - int n = 0; - qsort_string_vector(matches, num_matches); - for (i = 0; i < num_matches - 1; ++i) { - if (matches[i] && matches[i+1]) { /* paranoia */ - if (strcmp(matches[i], matches[i+1]) == 0) { - free(matches[i]); - matches[i] = NULL; /* paranoia */ - } else { - matches[n++] = matches[i]; - } + /* Account for backslashes which will be inserted + * by quote_special_chars() later */ + { + const char *e = match_buf + strlen(match_buf); + const char *s = e - match_pfx_len; + while (s < e) + if (is_special_char(*s++)) + match_pfx_len++; + } + + /* Remove duplicates */ + if (matches) { + unsigned i, n = 0; + qsort_string_vector(matches, num_matches); + for (i = 0; i < num_matches - 1; ++i) { + //if (matches[i] && matches[i+1]) { /* paranoia */ + if (strcmp(matches[i], matches[i+1]) == 0) { + free(matches[i]); + //matches[i] = NULL; /* paranoia */ + } else { + matches[n++] = matches[i]; } - } - matches[n] = matches[i]; - num_matches = n + 1; + //} } - /* Did we find exactly one match? */ - if (!matches || num_matches > 1) { /* no */ - beep(); - if (!matches) - return; /* not found */ - /* find minimal match */ - tmp1 = xstrdup(matches[0]); - for (tmp = tmp1; *tmp; tmp++) { - for (len_found = 1; len_found < num_matches; len_found++) { - if (matches[len_found][tmp - tmp1] != *tmp) { - *tmp = '\0'; - break; - } + matches[n++] = matches[i]; + num_matches = n; + } + + /* Did we find exactly one match? */ + if (num_matches != 1) { /* no */ + char *cp; + beep(); + if (!matches) + goto ret; /* no matches at all */ + /* Find common prefix */ + chosen_match = xstrdup(matches[0]); + for (cp = chosen_match; *cp; cp++) { + unsigned n; + for (n = 1; n < num_matches; n++) { + if (matches[n][cp - chosen_match] != *cp) { + goto stop; } } - if (*tmp1 == '\0') { /* have unique */ - free(tmp1); - return; - } - tmp = add_quote_for_spec_chars(tmp1); - free(tmp1); - } else { /* one match */ - tmp = add_quote_for_spec_chars(matches[0]); - /* for next completion current found */ - *lastWasTab = FALSE; - - len_found = strlen(tmp); - if (tmp[len_found-1] != '/') { - tmp[len_found] = ' '; - tmp[len_found+1] = '\0'; - } } + stop: + if (cp == chosen_match) { /* have unique prefix? */ + goto ret; /* no */ + } + *cp = '\0'; + cp = quote_special_chars(chosen_match); + free(chosen_match); + chosen_match = cp; + len_found = strlen(chosen_match); + } else { /* exactly one match */ + /* Next is not a double-tab */ + *lastWasTab = 0; + + chosen_match = quote_special_chars(matches[0]); + len_found = strlen(chosen_match); + if (chosen_match[len_found-1] != '/') { + chosen_match[len_found] = ' '; + chosen_match[++len_found] = '\0'; + } + } - len_found = strlen(tmp); -#if !ENABLE_UNICODE_SUPPORT - /* have space to place the match? */ - /* The result consists of three parts with these lengths: */ - /* (cursor - recalc_pos) + len_found + (command_len - cursor) */ - /* it simplifies into: */ - if ((int)(len_found + command_len - recalc_pos) < S.maxsize) { +# if !ENABLE_UNICODE_SUPPORT + /* Have space to place the match? */ + /* The result consists of three parts with these lengths: */ + /* cursor + (len_found - match_pfx_len) + (command_len - cursor) */ + /* it simplifies into: */ + if ((int)(len_found - match_pfx_len + command_len) < S.maxsize) { + int pos; + /* save tail */ + strcpy(match_buf, &command_ps[cursor]); + /* add match and tail */ + sprintf(&command_ps[cursor], "%s%s", chosen_match + match_pfx_len, match_buf); + command_len = strlen(command_ps); + /* new pos */ + pos = cursor + len_found - match_pfx_len; + /* write out the matched command */ + redraw(cmdedit_y, command_len - pos); + } +# else + { + /* Use 2nd half of match_buf as scratch space - see (**) */ + char *command = match_buf + MAX_LINELEN; + int len = save_string(command, MAX_LINELEN); + /* Have space to place the match? */ + /* cursor_mb + (len_found - match_pfx_len) + (len - cursor_mb) */ + if ((int)(len_found - match_pfx_len + len) < MAX_LINELEN) { + int pos; /* save tail */ - strcpy(matchBuf, command_ps + cursor); + strcpy(match_buf, &command[cursor_mb]); + /* where do we want to have cursor after all? */ + strcpy(&command[cursor_mb], chosen_match + match_pfx_len); + len = load_string(command); /* add match and tail */ - sprintf(&command_ps[cursor - recalc_pos], "%s%s", tmp, matchBuf); - command_len = strlen(command_ps); - /* new pos */ - recalc_pos = cursor - recalc_pos + len_found; + sprintf(&command[cursor_mb], "%s%s", chosen_match + match_pfx_len, match_buf); + command_len = load_string(command); /* write out the matched command */ - redraw(cmdedit_y, command_len - recalc_pos); - } -#else - { - char command[MAX_LINELEN]; - int len = save_string(command, sizeof(command)); - /* have space to place the match? */ - /* (cursor_mb - recalc_pos) + len_found + (len - cursor_mb) */ - if ((int)(len_found + len - recalc_pos) < MAX_LINELEN) { - /* save tail */ - strcpy(matchBuf, command + cursor_mb); - /* where do we want to have cursor after all? */ - strcpy(&command[cursor_mb - recalc_pos], tmp); - len = load_string(command, S.maxsize); - /* add match and tail */ - sprintf(&command[cursor_mb - recalc_pos], "%s%s", tmp, matchBuf); - command_len = load_string(command, S.maxsize); - /* write out the matched command */ - redraw(cmdedit_y, command_len - len); - } - } -#endif - free(tmp); -#undef matchBuf - } else { - /* Ok -- the last char was a TAB. Since they - * just hit TAB again, print a list of all the - * available choices... */ - if (matches && num_matches > 0) { - /* changed by goto_new_line() */ - int sav_cursor = cursor; - - /* Go to the next line */ - goto_new_line(); - showfiles(); - redraw(0, command_len - sav_cursor); + /* paranoia: load_string can return 0 on conv error, + * prevent passing pos = (0 - 12) to redraw */ + pos = command_len - len; + redraw(cmdedit_y, pos >= 0 ? pos : 0); } } +# endif + ret: + free(chosen_match); + free(match_buf); } -#endif /* FEATURE_COMMAND_TAB_COMPLETION */ +#endif /* FEATURE_TAB_COMPLETION */ line_input_t* FAST_FUNC new_line_input_t(int flags) { line_input_t *n = xzalloc(sizeof(*n)); n->flags = flags; +#if MAX_HISTORY > 0 + n->max_history = MAX_HISTORY; +#endif return n; } #if MAX_HISTORY > 0 +unsigned FAST_FUNC size_from_HISTFILESIZE(const char *hp) +{ + int size = MAX_HISTORY; + if (hp) { + size = atoi(hp); + if (size <= 0) + return 1; + if (size > MAX_HISTORY) + return MAX_HISTORY; + } + return size; +} + static void save_command_ps_at_cur_history(void) { if (command_ps[0] != BB_NUL) { @@ -1241,6 +1319,17 @@ static int get_next_history(void) return 0; } +/* Lists command history. Used by shell 'history' builtins */ +void FAST_FUNC show_history(const line_input_t *st) +{ + int i; + + if (!st) + return; + for (i = 0; i < st->cnt_history; i++) + printf("%4d %s\n", i, st->history[i]); +} + # if ENABLE_FEATURE_EDITING_SAVEHISTORY /* We try to ensure that concurrent additions to the history * do not overwrite each other. @@ -1279,7 +1368,8 @@ static void load_history(line_input_t *st_parm) /* fill temp_h[], retaining only last MAX_HISTORY lines */ memset(temp_h, 0, sizeof(temp_h)); - st_parm->cnt_history_in_file = idx = 0; + idx = 0; + st_parm->cnt_history_in_file = 0; while ((line = xmalloc_fgetline(fp)) != NULL) { if (line[0] == '\0') { free(line); @@ -1289,7 +1379,7 @@ static void load_history(line_input_t *st_parm) temp_h[idx] = line; st_parm->cnt_history_in_file++; idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; } fclose(fp); @@ -1298,18 +1388,18 @@ static void load_history(line_input_t *st_parm) if (st_parm->cnt_history_in_file) { while (temp_h[idx] == NULL) { idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; } } /* copy temp_h[] to st_parm->history[] */ - for (i = 0; i < MAX_HISTORY;) { + for (i = 0; i < st_parm->max_history;) { line = temp_h[idx]; if (!line) break; idx++; - if (idx == MAX_HISTORY) + if (idx == st_parm->max_history) idx = 0; line_len = strlen(line); if (line_len >= MAX_LINELEN) @@ -1317,16 +1407,63 @@ static void load_history(line_input_t *st_parm) st_parm->history[i++] = line; } st_parm->cnt_history = i; + if (ENABLE_FEATURE_EDITING_SAVE_ON_EXIT) + st_parm->cnt_history_in_file = i; } } -/* state->flags is already checked to be nonzero */ +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +void save_history(line_input_t *st) +{ + FILE *fp; + + if (!st->hist_file) + return; + if (st->cnt_history <= st->cnt_history_in_file) + return; + + fp = fopen(st->hist_file, "a"); + if (fp) { + int i, fd; + char *new_name; + line_input_t *st_temp; + + for (i = st->cnt_history_in_file; i < st->cnt_history; i++) + fprintf(fp, "%s\n", st->history[i]); + fclose(fp); + + /* we may have concurrently written entries from others. + * load them */ + st_temp = new_line_input_t(st->flags); + st_temp->hist_file = st->hist_file; + st_temp->max_history = st->max_history; + load_history(st_temp); + + /* write out temp file and replace hist_file atomically */ + new_name = xasprintf("%s.%u.new", st->hist_file, (int) getpid()); + fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd >= 0) { + fp = xfdopen_for_write(fd); + for (i = 0; i < st_temp->cnt_history; i++) + fprintf(fp, "%s\n", st_temp->history[i]); + fclose(fp); + if (rename(new_name, st->hist_file) == 0) + st->cnt_history_in_file = st_temp->cnt_history; + } + free(new_name); + free_line_input_t(st_temp); + } +} +# else static void save_history(char *str) { int fd; int len, len2; - fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0666); + if (!state->hist_file) + return; + + fd = open(state->hist_file, O_WRONLY | O_CREAT | O_APPEND, 0600); if (fd < 0) return; xlseek(fd, 0, SEEK_END); /* paranoia */ @@ -1340,22 +1477,25 @@ static void save_history(char *str) /* did we write so much that history file needs trimming? */ state->cnt_history_in_file++; - if (state->cnt_history_in_file > MAX_HISTORY * 4) { - FILE *fp; + if (state->cnt_history_in_file > state->max_history * 4) { char *new_name; line_input_t *st_temp; - int i; /* we may have concurrently written entries from others. * load them */ st_temp = new_line_input_t(state->flags); st_temp->hist_file = state->hist_file; + st_temp->max_history = state->max_history; load_history(st_temp); /* write out temp file and replace hist_file atomically */ new_name = xasprintf("%s.%u.new", state->hist_file, (int) getpid()); - fp = fopen_for_write(new_name); - if (fp) { + fd = open(new_name, O_WRONLY | O_CREAT | O_TRUNC, 0600); + if (fd >= 0) { + FILE *fp; + int i; + + fp = xfdopen_for_write(fd); for (i = 0; i < st_temp->cnt_history; i++) fprintf(fp, "%s\n", st_temp->history[i]); fclose(fp); @@ -1366,6 +1506,7 @@ static void save_history(char *str) free_line_input_t(st_temp); } } +# endif # else # define load_history(a) ((void)0) # define save_history(a) ((void)0) @@ -1384,27 +1525,29 @@ static void remember_in_history(char *str) if (i && strcmp(state->history[i-1], str) == 0) return; - free(state->history[MAX_HISTORY]); /* redundant, paranoia */ - state->history[MAX_HISTORY] = NULL; /* redundant, paranoia */ + free(state->history[state->max_history]); /* redundant, paranoia */ + state->history[state->max_history] = NULL; /* redundant, paranoia */ /* If history[] is full, remove the oldest command */ - /* we need to keep history[MAX_HISTORY] empty, hence >=, not > */ - if (i >= MAX_HISTORY) { + /* we need to keep history[state->max_history] empty, hence >=, not > */ + if (i >= state->max_history) { free(state->history[0]); - for (i = 0; i < MAX_HISTORY-1; i++) + for (i = 0; i < state->max_history-1; i++) state->history[i] = state->history[i+1]; - /* i == MAX_HISTORY-1 */ + /* i == state->max_history-1 */ +# if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + if (state->cnt_history_in_file) + state->cnt_history_in_file--; +# endif } - /* i <= MAX_HISTORY-1 */ + /* i <= state->max_history-1 */ state->history[i++] = xstrdup(str); - /* i <= MAX_HISTORY */ + /* i <= state->max_history */ state->cur_history = i; state->cnt_history = i; -# if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY - if ((state->flags & SAVE_HISTORY) && state->hist_file) - save_history(str); +# if ENABLE_FEATURE_EDITING_SAVEHISTORY && !ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(str); # endif - IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) } #else /* MAX_HISTORY == 0 */ @@ -1609,7 +1752,7 @@ static void ask_terminal(void) * write(1, "~/srcdevel/bbox/fix/busybox.t4 # ", 33) = 33 * poll([{fd=0, events=POLLIN}], 1, 0) = 0 (Timeout) <-- no input exists * write(1, "\33[6n", 4) = 4 <-- send the ESC sequence, quick! - * poll([{fd=0, events=POLLIN}], 1, 4294967295) = 1 ([{fd=0, revents=POLLIN}]) + * poll([{fd=0, events=POLLIN}], 1, -1) = 1 ([{fd=0, revents=POLLIN}]) * read(0, "\n", 1) = 1 <-- oh crap, user's input got in first */ struct pollfd pfd; @@ -1618,7 +1761,7 @@ static void ask_terminal(void) pfd.events = POLLIN; if (safe_poll(&pfd, 1, 0) == 0) { S.sent_ESC_br6n = 1; - fputs("\033" "[6n", stdout); + fputs(ESC"[6n", stdout); fflush_all(); /* make terminal see it ASAP! */ } } @@ -1626,87 +1769,143 @@ static void ask_terminal(void) #define ask_terminal() ((void)0) #endif +/* Called just once at read_line_input() init time */ #if !ENABLE_FEATURE_EDITING_FANCY_PROMPT static void parse_and_put_prompt(const char *prmt_ptr) { + const char *p; cmdedit_prompt = prmt_ptr; - cmdedit_prmt_len = strlen(prmt_ptr); + p = strrchr(prmt_ptr, '\n'); + cmdedit_prmt_len = unicode_strwidth(p ? p+1 : prmt_ptr); put_prompt(); } #else static void parse_and_put_prompt(const char *prmt_ptr) { - int prmt_len = 0; - size_t cur_prmt_len = 0; - char flg_not_length = '['; + int prmt_size = 0; char *prmt_mem_ptr = xzalloc(1); - char *cwd_buf = xrealloc_getcwd_or_warn(NULL); +# if ENABLE_USERNAME_OR_HOMEDIR + char *cwd_buf = NULL; +# endif + char flg_not_length = '['; char cbuf[2]; - char c; - char *pbuf; - cmdedit_prmt_len = 0; - - if (!cwd_buf) { - cwd_buf = (char *)bb_msg_unknown; - } + /*cmdedit_prmt_len = 0; - already is */ cbuf[1] = '\0'; /* never changes */ while (*prmt_ptr) { + char timebuf[sizeof("HH:MM:SS")]; char *free_me = NULL; + char *pbuf; + char c; pbuf = cbuf; c = *prmt_ptr++; if (c == '\\') { - const char *cp = prmt_ptr; + const char *cp; int l; - - c = bb_process_escape_sequence(&prmt_ptr); +/* + * Supported via bb_process_escape_sequence: + * \a ASCII bell character (07) + * \e ASCII escape character (033) + * \n newline + * \r carriage return + * \\ backslash + * \nnn char with octal code nnn + * Supported: + * \$ if the effective UID is 0, a #, otherwise a $ + * \w current working directory, with $HOME abbreviated with a tilde + * Note: we do not support $PROMPT_DIRTRIM=n feature + * \W basename of the current working directory, with $HOME abbreviated with a tilde + * \h hostname up to the first '.' + * \H hostname + * \u username + * \[ begin a sequence of non-printing characters + * \] end a sequence of non-printing characters + * \T current time in 12-hour HH:MM:SS format + * \@ current time in 12-hour am/pm format + * \A current time in 24-hour HH:MM format + * \t current time in 24-hour HH:MM:SS format + * (all of the above work as \A) + * Not supported: + * \! history number of this command + * \# command number of this command + * \j number of jobs currently managed by the shell + * \l basename of the shell's terminal device name + * \s name of the shell, the basename of $0 (the portion following the final slash) + * \V release of bash, version + patch level (e.g., 2.00.0) + * \d date in "Weekday Month Date" format (e.g., "Tue May 26") + * \D{format} + * format is passed to strftime(3). + * An empty format results in a locale-specific time representation. + * The braces are required. + * Mishandled by bb_process_escape_sequence: + * \v version of bash (e.g., 2.00) + */ + cp = prmt_ptr; + c = *cp; + if (c != 't') /* don't treat \t as tab */ + c = bb_process_escape_sequence(&prmt_ptr); if (prmt_ptr == cp) { if (*cp == '\0') break; c = *prmt_ptr++; switch (c) { -# if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR +# if ENABLE_USERNAME_OR_HOMEDIR case 'u': pbuf = user_buf ? user_buf : (char*)""; break; # endif + case 'H': case 'h': pbuf = free_me = safe_gethostname(); - *strchrnul(pbuf, '.') = '\0'; + if (c == 'h') + strchrnul(pbuf, '.')[0] = '\0'; break; case '$': c = (geteuid() == 0 ? '#' : '$'); break; -# if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR - case 'w': - /* /home/user[/something] -> ~[/something] */ - pbuf = cwd_buf; - l = strlen(home_pwd_buf); - if (l != 0 - && strncmp(home_pwd_buf, cwd_buf, l) == 0 - && (cwd_buf[l]=='/' || cwd_buf[l]=='\0') - && strlen(cwd_buf + l) < PATH_MAX - ) { - pbuf = free_me = xasprintf("~%s", cwd_buf + l); - } + case 'T': /* 12-hour HH:MM:SS format */ + case '@': /* 12-hour am/pm format */ + case 'A': /* 24-hour HH:MM format */ + case 't': /* 24-hour HH:MM:SS format */ + /* We show all of them as 24-hour HH:MM */ + strftime_HHMMSS(timebuf, sizeof(timebuf), NULL)[-3] = '\0'; + pbuf = timebuf; break; -# endif - case 'W': +# if ENABLE_USERNAME_OR_HOMEDIR + case 'w': /* current dir */ + case 'W': /* basename of cur dir */ + if (!cwd_buf) { + cwd_buf = xrealloc_getcwd_or_warn(NULL); + if (!cwd_buf) + cwd_buf = (char *)bb_msg_unknown; + else { + /* /home/user[/something] -> ~[/something] */ + l = strlen(home_pwd_buf); + if (l != 0 + && strncmp(home_pwd_buf, cwd_buf, l) == 0 + && (cwd_buf[l] == '/' || cwd_buf[l] == '\0') + ) { + cwd_buf[0] = '~'; + overlapping_strcpy(cwd_buf + 1, cwd_buf + l); + } + } + } pbuf = cwd_buf; + if (c == 'w') + break; cp = strrchr(pbuf, '/'); - if (cp != NULL && cp != pbuf) - pbuf += (cp-pbuf) + 1; - break; - case '!': - pbuf = free_me = xasprintf("%d", num_ok_lines); - break; - case 'e': case 'E': /* \e \E = \033 */ - c = '\033'; + if (cp) + pbuf = (char*)cp + 1; break; +# endif +// bb_process_escape_sequence does this now: +// case 'e': case 'E': /* \e \E = \033 */ +// c = '\033'; +// break; case 'x': case 'X': { char buf2[4]; for (l = 0; l < 3;) { @@ -1728,7 +1927,8 @@ static void parse_and_put_prompt(const char *prmt_ptr) } case '[': case ']': if (c == flg_not_length) { - flg_not_length = (flg_not_length == '[' ? ']' : '['); + /* Toggle '['/']' hex 5b/5d */ + flg_not_length ^= 6; continue; } break; @@ -1736,16 +1936,29 @@ static void parse_and_put_prompt(const char *prmt_ptr) } /* if */ } /* if */ cbuf[0] = c; - cur_prmt_len = strlen(pbuf); - prmt_len += cur_prmt_len; - if (flg_not_length != ']') - cmdedit_prmt_len += cur_prmt_len; - prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_len+1), pbuf); + { + int n = strlen(pbuf); + prmt_size += n; + if (c == '\n') + cmdedit_prmt_len = 0; + else if (flg_not_length != ']') { +#if 0 /*ENABLE_UNICODE_SUPPORT*/ +/* Won't work, pbuf is one BYTE string here instead of an one Unicode char string. */ +/* FIXME */ + cmdedit_prmt_len += unicode_strwidth(pbuf); +#else + cmdedit_prmt_len += n; +#endif + } + } + prmt_mem_ptr = strcat(xrealloc(prmt_mem_ptr, prmt_size+1), pbuf); free(free_me); } /* while */ +# if ENABLE_USERNAME_OR_HOMEDIR if (cwd_buf != (char *)bb_msg_unknown) free(cwd_buf); +# endif cmdedit_prompt = prmt_mem_ptr; put_prompt(); } @@ -1767,17 +1980,17 @@ static void win_changed(int nsig) { int sv_errno = errno; unsigned width; + get_terminal_width_height(0, &width, NULL); - cmdedit_setwidth(width, nsig /* - just a yes/no flag */); - if (nsig == SIGWINCH) - signal(SIGWINCH, win_changed); /* rearm ourself */ +//FIXME: cmdedit_setwidth() -> redraw() -> printf() -> KABOOM! (we are in signal handler!) + cmdedit_setwidth(width, /*redraw_flg:*/ nsig); + errno = sv_errno; } -static int lineedit_read_key(char *read_key_buffer) +static int lineedit_read_key(char *read_key_buffer, int timeout) { int64_t ic; - int timeout = -1; #if ENABLE_UNICODE_SUPPORT char unicode_buf[MB_CUR_MAX + 1]; int unicode_idx = 0; @@ -1807,7 +2020,15 @@ static int lineedit_read_key(char *read_key_buffer) S.sent_ESC_br6n = 0; if (cursor == 0) { /* otherwise it may be bogus */ int col = ((ic >> 32) & 0x7fff) - 1; - if (col > cmdedit_prmt_len) { + /* + * Is col > cmdedit_prmt_len? + * If yes (terminal says cursor is farther to the right + * of where we think it should be), + * the prompt wasn't printed starting at col 1, + * there was additional text before it. + */ + if ((int)(col - cmdedit_prmt_len) > 0) { + /* Fix our understanding of current x position */ cmdedit_x += (col - cmdedit_prmt_len); while (cmdedit_x >= cmdedit_termw) { cmdedit_x -= cmdedit_termw; @@ -1876,17 +2097,153 @@ static int isrtl_str(void) #undef CTRL #define CTRL(a) ((a) & ~0x40) +enum { + VI_CMDMODE_BIT = 0x40000000, + /* 0x80000000 bit flags KEYCODE_xxx */ +}; + +#if ENABLE_FEATURE_REVERSE_SEARCH +/* Mimic readline Ctrl-R reverse history search. + * When invoked, it shows the following prompt: + * (reverse-i-search)'': user_input [cursor pos unchanged by Ctrl-R] + * and typing results in search being performed: + * (reverse-i-search)'tmp': cd /tmp [cursor under t in /tmp] + * Search is performed by looking at progressively older lines in history. + * Ctrl-R again searches for the next match in history. + * Backspace deletes last matched char. + * Control keys exit search and return to normal editing (at current history line). + */ +static int32_t reverse_i_search(void) +{ + char match_buf[128]; /* for user input */ + char read_key_buffer[KEYCODE_BUFFER_SIZE]; + const char *matched_history_line; + const char *saved_prompt; + unsigned saved_prmt_len; + int32_t ic; + + matched_history_line = NULL; + read_key_buffer[0] = 0; + match_buf[0] = '\0'; + + /* Save and replace the prompt */ + saved_prompt = cmdedit_prompt; + saved_prmt_len = cmdedit_prmt_len; + goto set_prompt; + + while (1) { + int h; + unsigned match_buf_len = strlen(match_buf); + + fflush_all(); +//FIXME: correct timeout? + ic = lineedit_read_key(read_key_buffer, -1); + + switch (ic) { + case CTRL('R'): /* searching for the next match */ + break; + + case '\b': + case '\x7f': + /* Backspace */ + if (unicode_status == UNICODE_ON) { + while (match_buf_len != 0) { + uint8_t c = match_buf[--match_buf_len]; + if ((c & 0xc0) != 0x80) /* start of UTF-8 char? */ + break; /* yes */ + } + } else { + if (match_buf_len != 0) + match_buf_len--; + } + match_buf[match_buf_len] = '\0'; + break; + + default: + if (ic < ' ' + || (!ENABLE_UNICODE_SUPPORT && ic >= 256) + || (ENABLE_UNICODE_SUPPORT && ic >= VI_CMDMODE_BIT) + ) { + goto ret; + } + + /* Append this char */ +#if ENABLE_UNICODE_SUPPORT + if (unicode_status == UNICODE_ON) { + mbstate_t mbstate = { 0 }; + char buf[MB_CUR_MAX + 1]; + int len = wcrtomb(buf, ic, &mbstate); + if (len > 0) { + buf[len] = '\0'; + if (match_buf_len + len < sizeof(match_buf)) + strcpy(match_buf + match_buf_len, buf); + } + } else +#endif + if (match_buf_len < sizeof(match_buf) - 1) { + match_buf[match_buf_len] = ic; + match_buf[match_buf_len + 1] = '\0'; + } + break; + } /* switch (ic) */ + + /* Search in history for match_buf */ + h = state->cur_history; + if (ic == CTRL('R')) + h--; + while (h >= 0) { + if (state->history[h]) { + char *match = strstr(state->history[h], match_buf); + if (match) { + state->cur_history = h; + matched_history_line = state->history[h]; + command_len = load_string(matched_history_line); + cursor = match - matched_history_line; +//FIXME: cursor position for Unicode case + + free((char*)cmdedit_prompt); + set_prompt: + cmdedit_prompt = xasprintf("(reverse-i-search)'%s': ", match_buf); + cmdedit_prmt_len = unicode_strwidth(cmdedit_prompt); + goto do_redraw; + } + } + h--; + } + + /* Not found */ + match_buf[match_buf_len] = '\0'; + beep(); + continue; + + do_redraw: + redraw(cmdedit_y, command_len - cursor); + } /* while (1) */ + + ret: + if (matched_history_line) + command_len = load_string(matched_history_line); + + free((char*)cmdedit_prompt); + cmdedit_prompt = saved_prompt; + cmdedit_prmt_len = saved_prmt_len; + redraw(cmdedit_y, command_len - cursor); + + return ic; +} +#endif + /* maxsize must be >= 2. * Returns: * -1 on read errors or EOF, or on bare Ctrl-D, * 0 on ctrl-C (the line entered is still returned in 'command'), * >0 length of input string, including terminating '\n' */ -int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, line_input_t *st) +int FAST_FUNC read_line_input(line_input_t *st, const char *prompt, char *command, int maxsize, int timeout) { int len; #if ENABLE_FEATURE_TAB_COMPLETION - smallint lastWasTab = FALSE; + smallint lastWasTab = 0; #endif smallint break_out = 0; #if ENABLE_FEATURE_EDITING_VI @@ -1919,11 +2276,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li maxsize = MAX_LINELEN; S.maxsize = maxsize; - /* With null flags, no other fields are ever used */ + /* With zero flags, no other fields are ever used */ state = st ? st : (line_input_t*) &const_int_0; #if MAX_HISTORY > 0 # if ENABLE_FEATURE_EDITING_SAVEHISTORY - if ((state->flags & SAVE_HISTORY) && state->hist_file) + if (state->hist_file) if (state->cnt_history == 0) load_history(state); # endif @@ -1943,23 +2300,20 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #define command command_must_not_be_used new_settings = initial_settings; - new_settings.c_lflag &= ~ICANON; /* unbuffered input */ - /* Turn off echoing and CTRL-C, so we can trap it */ - new_settings.c_lflag &= ~(ECHO | ECHONL | ISIG); - /* Hmm, in linux c_cc[] is not parsed if ICANON is off */ + /* ~ICANON: unbuffered input (most c_cc[] are disabled, VMIN/VTIME are enabled) */ + /* ~ECHO, ~ECHONL: turn off echoing, including newline echoing */ + /* ~ISIG: turn off INTR (ctrl-C), QUIT, SUSP */ + new_settings.c_lflag &= ~(ICANON | ECHO | ECHONL | ISIG); + /* reads would block only if < 1 char is available */ new_settings.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ new_settings.c_cc[VTIME] = 0; - /* Turn off CTRL-C, so we can trap it */ -#ifndef _POSIX_VDISABLE -# define _POSIX_VDISABLE '\0' -#endif - new_settings.c_cc[VINTR] = _POSIX_VDISABLE; + /* Should be not needed if ISIG is off: */ + /* Turn off CTRL-C */ + /* new_settings.c_cc[VINTR] = _POSIX_VDISABLE; */ tcsetattr_stdin_TCSANOW(&new_settings); - /* Now initialize things */ - previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); - win_changed(0); /* do initial resizing */ -#if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR +#if ENABLE_USERNAME_OR_HOMEDIR { struct passwd *entry; @@ -1972,7 +2326,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #endif #if 0 - for (i = 0; i <= MAX_HISTORY; i++) + for (i = 0; i <= state->max_history; i++) bb_error_msg("history[%d]:'%s'", i, state->history[i]); bb_error_msg("cur_history:%d cnt_history:%d", state->cur_history, state->cnt_history); #endif @@ -1981,6 +2335,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li parse_and_put_prompt(prompt); ask_terminal(); + /* Install window resize handler (NB: after *all* init is complete) */ +//FIXME: save entire sigaction! + previous_SIGWINCH_handler = signal(SIGWINCH, win_changed); + win_changed(0); /* get initial window size */ + read_key_buffer[0] = 0; while (1) { /* @@ -1991,15 +2350,14 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li * clutters the big switch a bit, but keeps all the code * in one place. */ - enum { - VI_CMDMODE_BIT = 0x40000000, - /* 0x80000000 bit flags KEYCODE_xxx */ - }; int32_t ic, ic_raw; fflush_all(); - ic = ic_raw = lineedit_read_key(read_key_buffer); + ic = ic_raw = lineedit_read_key(read_key_buffer, timeout); +#if ENABLE_FEATURE_REVERSE_SEARCH + again: +#endif #if ENABLE_FEATURE_EDITING_VI newdelflag = 1; if (vi_cmdmode) { @@ -2066,7 +2424,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case CTRL('L'): vi_case(CTRL('L')|VI_CMDMODE_BIT:) /* Control-l -- clear screen */ - printf("\033[H"); /* cursor to top,left */ + printf(ESC"[H"); /* cursor to top,left */ redraw(0, command_len - cursor); break; #if MAX_HISTORY > 0 @@ -2103,6 +2461,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li while (cursor > 0 && !BB_isspace(command_ps[cursor-1])) input_backspace(); break; +#if ENABLE_FEATURE_REVERSE_SEARCH + case CTRL('R'): + ic = ic_raw = reverse_i_search(); + goto again; +#endif #if ENABLE_FEATURE_EDITING_VI case 'i'|VI_CMDMODE_BIT: @@ -2159,9 +2522,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li case 'd'|VI_CMDMODE_BIT: { int nc, sc; - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ - goto prepare_to_die; + goto return_error_indicator; if (ic == ic_raw) { /* "cc", "dd" */ input_backward(cursor); goto clear_to_eol; @@ -2223,9 +2586,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li break; case 'r'|VI_CMDMODE_BIT: //FIXME: unicode case? - ic = lineedit_read_key(read_key_buffer); + ic = lineedit_read_key(read_key_buffer, timeout); if (errno) /* error */ - goto prepare_to_die; + goto return_error_indicator; if (ic < ' ' || ic > 255) { beep(); } else { @@ -2240,6 +2603,44 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li vi_cmdmode = 1; input_backward(1); } + /* Handle a few ESC- combinations the same way + * standard readline bindings (IOW: bash) do. + * Often, Alt- generates ESC-. + */ + ic = lineedit_read_key(read_key_buffer, timeout); + switch (ic) { + //case KEYCODE_LEFT: - bash doesn't do this + case 'b': + ctrl_left(); + break; + //case KEYCODE_RIGHT: - bash doesn't do this + case 'f': + ctrl_right(); + break; + //case KEYCODE_DELETE: - bash doesn't do this + case 'd': /* Alt-D */ + { + /* Delete word forward */ + int nc, sc = cursor; + ctrl_right(); + nc = cursor - sc; + input_backward(nc); + while (--nc >= 0) + input_delete(1); + break; + } + case '\b': /* Alt-Backspace(?) */ + case '\x7f': /* Alt-Backspace(?) */ + //case 'w': - bash doesn't do this + { + /* Delete word backward */ + int sc = cursor; + ctrl_left(); + while (sc-- > cursor) + input_delete(1); + break; + } + } break; #endif /* FEATURE_COMMAND_EDITING_VI */ @@ -2256,7 +2657,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li /* Rewrite the line with the selected history item */ /* change command */ command_len = load_string(state->history[state->cur_history] ? - state->history[state->cur_history] : "", maxsize); + state->history[state->cur_history] : ""); /* redraw and go to eol (bol, in vi) */ redraw(cmdedit_y, (state->flags & VI_MODE) ? 9999 : 0); break; @@ -2268,9 +2669,11 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li input_backward(1); break; case KEYCODE_CTRL_LEFT: + case KEYCODE_ALT_LEFT: /* bash doesn't do it */ ctrl_left(); break; case KEYCODE_CTRL_RIGHT: + case KEYCODE_ALT_RIGHT: /* bash doesn't do it */ ctrl_right(); break; case KEYCODE_HOME: @@ -2297,9 +2700,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li * or exit if len=0 and no chars to delete */ if (command_len == 0) { errno = 0; -#if ENABLE_FEATURE_EDITING_VI - prepare_to_die: -#endif + + case -1: /* error (e.g. EIO when tty is destroyed) */ + IF_FEATURE_EDITING_VI(return_error_indicator:) break_out = command_len = -1; break; } @@ -2309,7 +2712,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li // /* Control-V -- force insert of next char */ // if (c == CTRL('V')) { // if (safe_read(STDIN_FILENO, &c, 1) < 1) -// goto prepare_to_die; +// goto return_error_indicator; // if (c == 0) { // beep(); // break; @@ -2362,7 +2765,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li #if ENABLE_FEATURE_TAB_COMPLETION if (ic_raw != '\t') - lastWasTab = FALSE; + lastWasTab = 0; #endif } /* while (1) */ @@ -2381,7 +2784,7 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li } #endif -/* Stop bug catching using "command_must_not_be_used" trick */ +/* End of bug-catching "command_must_not_be_used" trick */ #undef command #if ENABLE_UNICODE_SUPPORT @@ -2391,8 +2794,9 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li free(command_ps); #endif - if (command_len > 0) + if (command_len > 0) { remember_in_history(command); + } if (break_out > 0) { command[command_len++] = '\n'; @@ -2415,18 +2819,19 @@ int FAST_FUNC read_line_input(const char *prompt, char *command, int maxsize, li return len; /* can't return command_len, DEINIT_S() destroys it */ } -#else +#else /* !FEATURE_EDITING */ #undef read_line_input int FAST_FUNC read_line_input(const char* prompt, char* command, int maxsize) { fputs(prompt, stdout); fflush_all(); - fgets(command, maxsize, stdin); + if (!fgets(command, maxsize, stdin)) + return -1; return strlen(command); } -#endif /* FEATURE_EDITING */ +#endif /* !FEATURE_EDITING */ /* @@ -2456,7 +2861,7 @@ int main(int argc, char **argv) l = read_line_input(prompt, buff); if (l <= 0 || buff[l-1] != '\n') break; - buff[l-1] = 0; + buff[l-1] = '\0'; printf("*** read_line_input() returned line =%s=\n", buff); } printf("*** read_line_input() detect ^D\n"); diff --git a/libbb/lineedit_ptr_hack.c b/libbb/lineedit_ptr_hack.c index 53716a2..dc45855 100644 --- a/libbb/lineedit_ptr_hack.c +++ b/libbb/lineedit_ptr_hack.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2008 by Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ struct lineedit_statics; diff --git a/libbb/llist.c b/libbb/llist.c index 51b1ce6..032e9fa 100644 --- a/libbb/llist.c +++ b/libbb/llist.c @@ -7,7 +7,7 @@ * Copyright (C) 2005 Bernhard Reutner-Fischer * Copyright (C) 2006 Rob Landley * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -62,7 +62,7 @@ void FAST_FUNC llist_unlink(llist_t **head, llist_t *elm) /* Recursively free all elements in the linked list. If freeit != NULL * call it on each datum in the list */ -void FAST_FUNC llist_free(llist_t *elm, void (*freeit) (void *data)) +void FAST_FUNC llist_free(llist_t *elm, void (*freeit)(void *data)) { while (elm) { void *data = llist_pop(&elm); diff --git a/libbb/login.c b/libbb/login.c index 740c588..8f080b7 100644 --- a/libbb/login.c +++ b/libbb/login.c @@ -6,7 +6,7 @@ * * Optimize and correcting OCRNL by Vladimir Oleynik * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -16,7 +16,6 @@ #define LOGIN " login: " static const char fmtstr_d[] ALIGN1 = "%A, %d %B %Y"; -static const char fmtstr_t[] ALIGN1 = "%H:%M:%S"; void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) { @@ -30,7 +29,7 @@ void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) time(&t); uname(&uts); - puts("\r"); /* start a new line */ + puts("\r"); /* start a new line */ fp = fopen_for_read(issue_file); if (!fp) @@ -73,7 +72,7 @@ void FAST_FUNC print_login_issue(const char *issue_file, const char *tty) strftime(buf, sizeof(buf), fmtstr_d, localtime(&t)); break; case 't': - strftime(buf, sizeof(buf), fmtstr_t, localtime(&t)); + strftime_HHMMSS(buf, sizeof(buf), &t); break; case 'l': outbuf = tty; diff --git a/libbb/loop.c b/libbb/loop.c index eb7016d..823fba0 100644 --- a/libbb/loop.c +++ b/libbb/loop.c @@ -5,7 +5,7 @@ * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2005 by Rob Landley * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include @@ -84,7 +84,7 @@ int FAST_FUNC del_loop(const char *device) search will re-use an existing loop device already bound to that file/offset if it finds one. */ -int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset) +int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offset, int ro) { char dev[LOOP_NAMESIZE]; char *try; @@ -93,11 +93,13 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse int i, dfd, ffd, mode, rc = -1; /* Open the file. Barf if this doesn't work. */ - mode = O_RDWR; + mode = ro ? O_RDONLY : O_RDWR; ffd = open(file, mode); if (ffd < 0) { - mode = O_RDONLY; - ffd = open(file, mode); + if (mode != O_RDONLY) { + mode = O_RDONLY; + ffd = open(file, mode); + } if (ffd < 0) return -errno; } @@ -148,9 +150,9 @@ int FAST_FUNC set_loop(char **device, const char *file, unsigned long long offse } /* If this block device already set up right, re-use it. - (Yes this is racy, but associating two loop devices with the same - file isn't pretty either. In general, mounting the same file twice - without using losetup manually is problematic.) + * (Yes this is racy, but associating two loop devices with the same + * file isn't pretty either. In general, mounting the same file twice + * without using losetup manually is problematic.) */ } else if (strcmp(file, (char *)loopinfo.lo_file_name) != 0 diff --git a/libbb/make_directory.c b/libbb/make_directory.c index 4486eb1..7826b90 100644 --- a/libbb/make_directory.c +++ b/libbb/make_directory.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Mar 5, 2003 Manuel Novoa III @@ -44,7 +44,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) while (1) { c = '\0'; - if (flags & FILEUTILS_RECUR) { /* Get the parent */ + if (flags & FILEUTILS_RECUR) { /* Get the parent */ /* Bypass leading non-'/'s and then subsequent '/'s */ while (*s) { if (*s == '/') { @@ -86,7 +86,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) if (mkdir(path, 0777) < 0) { /* If we failed for any other reason than the directory * already exists, output a diagnostic and return -1 */ - if (errno != EEXIST + if ((errno != EEXIST && errno != EISDIR) || !(flags & FILEUTILS_RECUR) || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) ) { @@ -107,6 +107,10 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) * an error. */ if ((mode != -1) && (chmod(path, mode) < 0)) { fail_msg = "set permissions of"; + if (flags & FILEUTILS_IGNORE_CHMOD_ERR) { + flags = 0; + goto print_err; + } break; } goto ret0; @@ -116,8 +120,9 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) *s = c; } /* while (1) */ - bb_perror_msg("can't %s directory '%s'", fail_msg, path); flags = -1; + print_err: + bb_perror_msg("can't %s directory '%s'", fail_msg, path); goto ret; ret0: flags = 0; diff --git a/libbb/makedev.c b/libbb/makedev.c index ca71fdb..06c4039 100644 --- a/libbb/makedev.c +++ b/libbb/makedev.c @@ -3,21 +3,28 @@ * * Copyright (C) 2006 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* We do not include libbb.h - #define makedev() is there! */ #include "platform.h" -#include -#include + +/* Different Unixes want different headers for makedev */ +#if defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) +# include +#else +# include +# include +#endif #ifdef __GLIBC__ -/* At least glibc has horrendously large inline for this, so wrap it */ +/* At least glibc has horrendously large inline for this, so wrap it. */ /* uclibc people please check - do we need "&& !__UCLIBC__" above? */ -/* suppress gcc "no previous prototype" warning */ -unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor); -unsigned long long FAST_FUNC bb_makedev(unsigned int major, unsigned int minor) +/* Suppress gcc "no previous prototype" warning */ +unsigned long long FAST_FUNC bb_makedev(unsigned major, unsigned minor); +unsigned long long FAST_FUNC bb_makedev(unsigned major, unsigned minor) { return makedev(major, minor); } diff --git a/libbb/match_fstype.c b/libbb/match_fstype.c index 9360e75..32c3d7f 100644 --- a/libbb/match_fstype.c +++ b/libbb/match_fstype.c @@ -7,11 +7,13 @@ * * Returns 1 for a match, otherwise 0 * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" +#ifdef HAVE_MNTENT_H + int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) { int match = 1; @@ -40,3 +42,5 @@ int FAST_FUNC match_fstype(const struct mntent *mt, const char *t_fstype) return !match; } + +#endif /* HAVE_MNTENT_H */ diff --git a/libbb/md5.c b/libbb/md5.c deleted file mode 100644 index a98631d..0000000 --- a/libbb/md5.c +++ /dev/null @@ -1,427 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * md5.c - Compute MD5 checksum of strings according to the - * definition of MD5 in RFC 1321 from April 1992. - * - * Written by Ulrich Drepper , 1995. - * - * Copyright (C) 1995-1999 Free Software Foundation, Inc. - * Copyright (C) 2001 Manuel Novoa III - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - */ - -#include "libbb.h" - -/* 0: fastest, 3: smallest */ -#if CONFIG_MD5_SIZE_VS_SPEED < 0 -# define MD5_SIZE_VS_SPEED 0 -#elif CONFIG_MD5_SIZE_VS_SPEED > 3 -# define MD5_SIZE_VS_SPEED 3 -#else -# define MD5_SIZE_VS_SPEED CONFIG_MD5_SIZE_VS_SPEED -#endif - -/* Initialize structure containing state of computation. - * (RFC 1321, 3.3: Step 3) - */ -void FAST_FUNC md5_begin(md5_ctx_t *ctx) -{ - ctx->A = 0x67452301; - ctx->B = 0xefcdab89; - ctx->C = 0x98badcfe; - ctx->D = 0x10325476; - ctx->total = 0; - ctx->buflen = 0; -} - -/* These are the four functions used in the four steps of the MD5 algorithm - * and defined in the RFC 1321. The first function is a little bit optimized - * (as found in Colin Plumbs public domain implementation). - * #define FF(b, c, d) ((b & c) | (~b & d)) - */ -#define FF(b, c, d) (d ^ (b & (c ^ d))) -#define FG(b, c, d) FF(d, b, c) -#define FH(b, c, d) (b ^ c ^ d) -#define FI(b, c, d) (c ^ (b | ~d)) - -#define rotl32(w, s) (((w) << (s)) | ((w) >> (32 - (s)))) - -/* Hash a single block, 64 bytes long and 4-byte aligned. */ -static void md5_hash_block(const void *buffer, md5_ctx_t *ctx) -{ - uint32_t correct_words[16]; - const uint32_t *words = buffer; - -#if MD5_SIZE_VS_SPEED > 0 - static const uint32_t C_array[] = { - /* round 1 */ - 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, - 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, - 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, - 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, - /* round 2 */ - 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, - 0xd62f105d, 0x2441453, 0xd8a1e681, 0xe7d3fbc8, - 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, - 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, - /* round 3 */ - 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, - 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, - 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x4881d05, - 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, - /* round 4 */ - 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, - 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, - 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, - 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391 - }; - static const char P_array[] ALIGN1 = { -# if MD5_SIZE_VS_SPEED > 1 - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, /* 1 */ -# endif - 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12, /* 2 */ - 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2, /* 3 */ - 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9 /* 4 */ - }; -# if MD5_SIZE_VS_SPEED > 1 - static const char S_array[] ALIGN1 = { - 7, 12, 17, 22, - 5, 9, 14, 20, - 4, 11, 16, 23, - 6, 10, 15, 21 - }; -# endif /* MD5_SIZE_VS_SPEED > 1 */ -#endif - uint32_t A = ctx->A; - uint32_t B = ctx->B; - uint32_t C = ctx->C; - uint32_t D = ctx->D; - - /* Process all bytes in the buffer with 64 bytes in each round of - the loop. */ - uint32_t *cwp = correct_words; - uint32_t A_save = A; - uint32_t B_save = B; - uint32_t C_save = C; - uint32_t D_save = D; - -#if MD5_SIZE_VS_SPEED > 1 - const uint32_t *pc; - const char *pp; - const char *ps; - int i; - uint32_t temp; - - for (i = 0; i < 16; i++) - cwp[i] = SWAP_LE32(words[i]); - words += 16; - -# if MD5_SIZE_VS_SPEED > 2 - pc = C_array; - pp = P_array; - ps = S_array - 4; - - for (i = 0; i < 64; i++) { - if ((i & 0x0f) == 0) - ps += 4; - temp = A; - switch (i >> 4) { - case 0: - temp += FF(B, C, D); - break; - case 1: - temp += FG(B, C, D); - break; - case 2: - temp += FH(B, C, D); - break; - case 3: - temp += FI(B, C, D); - } - temp += cwp[(int) (*pp++)] + *pc++; - temp = rotl32(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } -# else - pc = C_array; - pp = P_array; - ps = S_array; - - for (i = 0; i < 16; i++) { - temp = A + FF(B, C, D) + cwp[(int) (*pp++)] + *pc++; - temp = rotl32(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FG(B, C, D) + cwp[(int) (*pp++)] + *pc++; - temp = rotl32(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FH(B, C, D) + cwp[(int) (*pp++)] + *pc++; - temp = rotl32(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - ps += 4; - for (i = 0; i < 16; i++) { - temp = A + FI(B, C, D) + cwp[(int) (*pp++)] + *pc++; - temp = rotl32(temp, ps[i & 3]); - temp += B; - A = D; - D = C; - C = B; - B = temp; - } - -# endif /* MD5_SIZE_VS_SPEED > 2 */ -#else - /* First round: using the given function, the context and a constant - the next context is computed. Because the algorithms processing - unit is a 32-bit word and it is determined to work on words in - little endian byte order we perhaps have to change the byte order - before the computation. To reduce the work for the next steps - we store the swapped words in the array CORRECT_WORDS. */ -# define OP(a, b, c, d, s, T) \ - do { \ - a += FF(b, c, d) + (*cwp++ = SWAP_LE32(*words)) + T; \ - ++words; \ - a = rotl32(a, s); \ - a += b; \ - } while (0) - - /* Before we start, one word to the strange constants. - They are defined in RFC 1321 as - T[i] = (int)(4294967296.0 * fabs(sin(i))), i=1..64 - */ - -# if MD5_SIZE_VS_SPEED == 1 - const uint32_t *pc; - const char *pp; - int i; -# endif /* MD5_SIZE_VS_SPEED */ - - /* Round 1. */ -# if MD5_SIZE_VS_SPEED == 1 - pc = C_array; - for (i = 0; i < 4; i++) { - OP(A, B, C, D, 7, *pc++); - OP(D, A, B, C, 12, *pc++); - OP(C, D, A, B, 17, *pc++); - OP(B, C, D, A, 22, *pc++); - } -# else - OP(A, B, C, D, 7, 0xd76aa478); - OP(D, A, B, C, 12, 0xe8c7b756); - OP(C, D, A, B, 17, 0x242070db); - OP(B, C, D, A, 22, 0xc1bdceee); - OP(A, B, C, D, 7, 0xf57c0faf); - OP(D, A, B, C, 12, 0x4787c62a); - OP(C, D, A, B, 17, 0xa8304613); - OP(B, C, D, A, 22, 0xfd469501); - OP(A, B, C, D, 7, 0x698098d8); - OP(D, A, B, C, 12, 0x8b44f7af); - OP(C, D, A, B, 17, 0xffff5bb1); - OP(B, C, D, A, 22, 0x895cd7be); - OP(A, B, C, D, 7, 0x6b901122); - OP(D, A, B, C, 12, 0xfd987193); - OP(C, D, A, B, 17, 0xa679438e); - OP(B, C, D, A, 22, 0x49b40821); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* For the second to fourth round we have the possibly swapped words - in CORRECT_WORDS. Redefine the macro to take an additional first - argument specifying the function to use. */ -# undef OP -# define OP(f, a, b, c, d, k, s, T) \ - do { \ - a += f(b, c, d) + correct_words[k] + T; \ - a = rotl32(a, s); \ - a += b; \ - } while (0) - - /* Round 2. */ -# if MD5_SIZE_VS_SPEED == 1 - pp = P_array; - for (i = 0; i < 4; i++) { - OP(FG, A, B, C, D, (int) (*pp++), 5, *pc++); - OP(FG, D, A, B, C, (int) (*pp++), 9, *pc++); - OP(FG, C, D, A, B, (int) (*pp++), 14, *pc++); - OP(FG, B, C, D, A, (int) (*pp++), 20, *pc++); - } -# else - OP(FG, A, B, C, D, 1, 5, 0xf61e2562); - OP(FG, D, A, B, C, 6, 9, 0xc040b340); - OP(FG, C, D, A, B, 11, 14, 0x265e5a51); - OP(FG, B, C, D, A, 0, 20, 0xe9b6c7aa); - OP(FG, A, B, C, D, 5, 5, 0xd62f105d); - OP(FG, D, A, B, C, 10, 9, 0x02441453); - OP(FG, C, D, A, B, 15, 14, 0xd8a1e681); - OP(FG, B, C, D, A, 4, 20, 0xe7d3fbc8); - OP(FG, A, B, C, D, 9, 5, 0x21e1cde6); - OP(FG, D, A, B, C, 14, 9, 0xc33707d6); - OP(FG, C, D, A, B, 3, 14, 0xf4d50d87); - OP(FG, B, C, D, A, 8, 20, 0x455a14ed); - OP(FG, A, B, C, D, 13, 5, 0xa9e3e905); - OP(FG, D, A, B, C, 2, 9, 0xfcefa3f8); - OP(FG, C, D, A, B, 7, 14, 0x676f02d9); - OP(FG, B, C, D, A, 12, 20, 0x8d2a4c8a); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* Round 3. */ -# if MD5_SIZE_VS_SPEED == 1 - for (i = 0; i < 4; i++) { - OP(FH, A, B, C, D, (int) (*pp++), 4, *pc++); - OP(FH, D, A, B, C, (int) (*pp++), 11, *pc++); - OP(FH, C, D, A, B, (int) (*pp++), 16, *pc++); - OP(FH, B, C, D, A, (int) (*pp++), 23, *pc++); - } -# else - OP(FH, A, B, C, D, 5, 4, 0xfffa3942); - OP(FH, D, A, B, C, 8, 11, 0x8771f681); - OP(FH, C, D, A, B, 11, 16, 0x6d9d6122); - OP(FH, B, C, D, A, 14, 23, 0xfde5380c); - OP(FH, A, B, C, D, 1, 4, 0xa4beea44); - OP(FH, D, A, B, C, 4, 11, 0x4bdecfa9); - OP(FH, C, D, A, B, 7, 16, 0xf6bb4b60); - OP(FH, B, C, D, A, 10, 23, 0xbebfbc70); - OP(FH, A, B, C, D, 13, 4, 0x289b7ec6); - OP(FH, D, A, B, C, 0, 11, 0xeaa127fa); - OP(FH, C, D, A, B, 3, 16, 0xd4ef3085); - OP(FH, B, C, D, A, 6, 23, 0x04881d05); - OP(FH, A, B, C, D, 9, 4, 0xd9d4d039); - OP(FH, D, A, B, C, 12, 11, 0xe6db99e5); - OP(FH, C, D, A, B, 15, 16, 0x1fa27cf8); - OP(FH, B, C, D, A, 2, 23, 0xc4ac5665); -# endif /* MD5_SIZE_VS_SPEED == 1 */ - - /* Round 4. */ -# if MD5_SIZE_VS_SPEED == 1 - for (i = 0; i < 4; i++) { - OP(FI, A, B, C, D, (int) (*pp++), 6, *pc++); - OP(FI, D, A, B, C, (int) (*pp++), 10, *pc++); - OP(FI, C, D, A, B, (int) (*pp++), 15, *pc++); - OP(FI, B, C, D, A, (int) (*pp++), 21, *pc++); - } -# else - OP(FI, A, B, C, D, 0, 6, 0xf4292244); - OP(FI, D, A, B, C, 7, 10, 0x432aff97); - OP(FI, C, D, A, B, 14, 15, 0xab9423a7); - OP(FI, B, C, D, A, 5, 21, 0xfc93a039); - OP(FI, A, B, C, D, 12, 6, 0x655b59c3); - OP(FI, D, A, B, C, 3, 10, 0x8f0ccc92); - OP(FI, C, D, A, B, 10, 15, 0xffeff47d); - OP(FI, B, C, D, A, 1, 21, 0x85845dd1); - OP(FI, A, B, C, D, 8, 6, 0x6fa87e4f); - OP(FI, D, A, B, C, 15, 10, 0xfe2ce6e0); - OP(FI, C, D, A, B, 6, 15, 0xa3014314); - OP(FI, B, C, D, A, 13, 21, 0x4e0811a1); - OP(FI, A, B, C, D, 4, 6, 0xf7537e82); - OP(FI, D, A, B, C, 11, 10, 0xbd3af235); - OP(FI, C, D, A, B, 2, 15, 0x2ad7d2bb); - OP(FI, B, C, D, A, 9, 21, 0xeb86d391); -# endif /* MD5_SIZE_VS_SPEED == 1 */ -#endif /* MD5_SIZE_VS_SPEED > 1 */ - - /* Add the starting values of the context. */ - A += A_save; - B += B_save; - C += C_save; - D += D_save; - - /* Put checksum in context given as argument. */ - ctx->A = A; - ctx->B = B; - ctx->C = C; - ctx->D = D; -} - -/* Feed data through a temporary buffer to call md5_hash_aligned_block() - * with chunks of data that are 4-byte aligned and a multiple of 64 bytes. - * This function's internal buffer remembers previous data until it has 64 - * bytes worth to pass on. Call md5_end() to flush this buffer. */ -void FAST_FUNC md5_hash(const void *buffer, size_t len, md5_ctx_t *ctx) -{ - char *buf = (char *)buffer; - - /* RFC 1321 specifies the possible length of the file up to 2^64 bits, - * Here we only track the number of bytes. */ - ctx->total += len; - - /* Process all input. */ - while (len) { - unsigned i = 64 - ctx->buflen; - - /* Copy data into aligned buffer. */ - if (i > len) - i = len; - memcpy(ctx->buffer + ctx->buflen, buf, i); - len -= i; - ctx->buflen += i; - buf += i; - - /* When buffer fills up, process it. */ - if (ctx->buflen == 64) { - md5_hash_block(ctx->buffer, ctx); - ctx->buflen = 0; - } - } -} - -/* Process the remaining bytes in the buffer and put result from CTX - * in first 16 bytes following RESBUF. The result is always in little - * endian byte order, so that a byte-wise output yields to the wanted - * ASCII representation of the message digest. - */ -void FAST_FUNC md5_end(void *resbuf, md5_ctx_t *ctx) -{ - char *buf = ctx->buffer; - int i; - - /* Pad data to block size. */ - buf[ctx->buflen++] = 0x80; - memset(buf + ctx->buflen, 0, 128 - ctx->buflen); - - /* Put the 64-bit file length in *bits* at the end of the buffer. */ - ctx->total <<= 3; - if (ctx->buflen > 56) - buf += 64; - for (i = 0; i < 8; i++) - buf[56 + i] = ctx->total >> (i*8); - - /* Process last bytes. */ - if (buf != ctx->buffer) - md5_hash_block(ctx->buffer, ctx); - md5_hash_block(buf, ctx); - - /* The MD5 result is in little endian byte order. - * We (ab)use the fact that A-D are consecutive in memory. - */ -#if BB_BIG_ENDIAN - ctx->A = SWAP_LE32(ctx->A); - ctx->B = SWAP_LE32(ctx->B); - ctx->C = SWAP_LE32(ctx->C); - ctx->D = SWAP_LE32(ctx->D); -#endif - memcpy(resbuf, &ctx->A, sizeof(ctx->A) * 4); -} diff --git a/libbb/messages.c b/libbb/messages.c index 1d0e587..fad82c9 100644 --- a/libbb/messages.c +++ b/libbb/messages.c @@ -2,7 +2,7 @@ /* * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -22,10 +22,8 @@ const char bb_banner[] ALIGN1 = BANNER; -const char bb_msg_memory_exhausted[] ALIGN1 = "memory exhausted"; +const char bb_msg_memory_exhausted[] ALIGN1 = "out of memory"; const char bb_msg_invalid_date[] ALIGN1 = "invalid date '%s'"; -const char bb_msg_write_error[] ALIGN1 = "write error"; -const char bb_msg_read_error[] ALIGN1 = "read error"; const char bb_msg_unknown[] ALIGN1 = "(unknown)"; const char bb_msg_can_not_create_raw_socket[] ALIGN1 = "can't create raw socket"; const char bb_msg_perm_denied_are_you_root[] ALIGN1 = "permission denied (are you root?)"; @@ -35,15 +33,8 @@ const char bb_msg_invalid_arg[] ALIGN1 = "invalid argument '%s' to '%s'"; const char bb_msg_standard_input[] ALIGN1 = "standard input"; const char bb_msg_standard_output[] ALIGN1 = "standard output"; -const char bb_str_default[] ALIGN1 = "default"; const char bb_hexdigits_upcase[] ALIGN1 = "0123456789ABCDEF"; -const char bb_path_passwd_file[] ALIGN1 = "/etc/passwd"; -const char bb_path_shadow_file[] ALIGN1 = "/etc/shadow"; -const char bb_path_group_file[] ALIGN1 = "/etc/group"; -const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow"; -const char bb_path_motd_file[] ALIGN1 = "/etc/motd"; -const char bb_dev_null[] ALIGN1 = "/dev/null"; const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, @@ -57,15 +48,16 @@ const int const_int_1 = 1; * and it will end up in bss */ const int const_int_0 = 0; -#include +#if ENABLE_FEATURE_WTMP /* This is usually something like "/var/adm/wtmp" or "/var/log/wtmp" */ const char bb_path_wtmp_file[] ALIGN1 = -#if defined _PATH_WTMP +# if defined _PATH_WTMP _PATH_WTMP; -#elif defined WTMP_FILE +# elif defined WTMP_FILE WTMP_FILE; -#else -#error unknown path to wtmp file +# else +# error unknown path to wtmp file +# endif #endif /* We use it for "global" data via *(struct global*)&bb_common_bufsiz1. diff --git a/libbb/missing_syscalls.c b/libbb/missing_syscalls.c new file mode 100644 index 0000000..dd430e3 --- /dev/null +++ b/libbb/missing_syscalls.c @@ -0,0 +1,42 @@ +/* + * Copyright 2012, Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += missing_syscalls.o + +/*#include - for struct timex, but may collide with */ +#include +#include "libbb.h" + +#if defined(ANDROID) || defined(__ANDROID__) +pid_t getsid(pid_t pid) +{ + return syscall(__NR_getsid, pid); +} + +int stime(const time_t *t) +{ + struct timeval tv; + tv.tv_sec = *t; + tv.tv_usec = 0; + return settimeofday(&tv, NULL); +} + +int sethostname(const char *name, size_t len) +{ + return syscall(__NR_sethostname, name, len); +} + +struct timex; +int adjtimex(struct timex *buf) +{ + return syscall(__NR_adjtimex, buf); +} + +int pivot_root(const char *new_root, const char *put_old) +{ + return syscall(__NR_pivot_root, new_root, put_old); +} +#endif diff --git a/libbb/mode_string.c b/libbb/mode_string.c index 7d4e514..f1afe7d 100644 --- a/libbb/mode_string.c +++ b/libbb/mode_string.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Aug 13, 2003 diff --git a/libbb/mtab.c b/libbb/mtab.c index 586a661..22bff64 100644 --- a/libbb/mtab.c +++ b/libbb/mtab.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include diff --git a/libbb/mtab_file.c b/libbb/mtab_file.c deleted file mode 100644 index c9d9a69..0000000 --- a/libbb/mtab_file.c +++ /dev/null @@ -1,15 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Utility routines. - * - * Copyright (C) 1999-2004 by Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -#include "libbb.h" - -/* Busybox mount uses either /proc/mounts or /etc/mtab to - * get the list of currently mounted filesystems */ -const char bb_path_mtab_file[] ALIGN1 = -IF_FEATURE_MTAB_SUPPORT("/etc/mtab")IF_NOT_FEATURE_MTAB_SUPPORT("/proc/mounts"); diff --git a/libbb/nuke_str.c b/libbb/nuke_str.c new file mode 100644 index 0000000..56b808b --- /dev/null +++ b/libbb/nuke_str.c @@ -0,0 +1,21 @@ +/* vi: set sw=4 ts=4: */ +/* + * Utility routines. + * + * Copyright (C) 2008 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += nuke_str.o + +#include "libbb.h" + +void FAST_FUNC nuke_str(char *str) +{ + if (str) { + while (*str) + *str++ = 0; + /* or: memset(str, 0, strlen(str)); - not as small as above */ + } +} diff --git a/libbb/obscure.c b/libbb/obscure.c index 19b8752..9ecc1f6 100644 --- a/libbb/obscure.c +++ b/libbb/obscure.c @@ -4,7 +4,7 @@ * * Copyright (C) 2006 Tito Ragusa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* A good password: @@ -45,53 +45,59 @@ static int string_checker_helper(const char *p1, const char *p2) __attribute__ ( static int string_checker_helper(const char *p1, const char *p2) { - /* as-is or capitalized */ - if (strcasecmp(p1, p2) == 0 /* as sub-string */ - || strcasestr(p2, p1) != NULL + if (strcasestr(p2, p1) != NULL /* invert in case haystack is shorter than needle */ - || strcasestr(p1, p2) != NULL) + || strcasestr(p1, p2) != NULL + /* as-is or capitalized */ + /* || strcasecmp(p1, p2) == 0 - 1st strcasestr should catch this too */ + ) { return 1; + } return 0; } static int string_checker(const char *p1, const char *p2) { - int size; + int size, i; /* check string */ int ret = string_checker_helper(p1, p2); - /* Make our own copy */ + /* make our own copy */ char *p = xstrdup(p1); - /* reverse string */ - size = strlen(p); - while (size--) { - *p = p1[size]; - p++; + /* reverse string */ + i = size = strlen(p1); + while (--i >= 0) { + *p++ = p1[i]; } - /* restore pointer */ - p -= strlen(p1); + p -= size; /* restore pointer */ + /* check reversed string */ ret |= string_checker_helper(p, p2); + /* clean up */ - memset(p, 0, strlen(p1)); + memset(p, 0, size); free(p); + return ret; } -#define LOWERCASE 1 -#define UPPERCASE 2 -#define NUMBERS 4 -#define SPECIAL 8 +#define CATEGORIES 4 + +#define LOWERCASE 1 +#define UPPERCASE 2 +#define NUMBERS 4 +#define SPECIAL 8 + +#define LAST_CAT 8 static const char *obscure_msg(const char *old_p, const char *new_p, const struct passwd *pw) { - int i; - int c; - int length; - int mixed = 0; - /* Add 2 for each type of characters to the minlen of password */ - int size = CONFIG_PASSWORD_MINLEN + 8; + unsigned length; + unsigned size; + unsigned mixed; + unsigned c; + unsigned i; const char *p; char *hostname; @@ -103,10 +109,12 @@ static const char *obscure_msg(const char *old_p, const char *new_p, const struc if (string_checker(new_p, pw->pw_name)) { return "similar to username"; } +#ifndef __BIONIC__ /* no gecos as-is, as sub-string, reversed, capitalized, doubled */ - if (*pw->pw_gecos && string_checker(new_p, pw->pw_gecos)) { + if (pw->pw_gecos[0] && string_checker(new_p, pw->pw_gecos)) { return "similar to gecos"; } +#endif /* hostname as-is, as sub-string, reversed, capitalized, doubled */ hostname = safe_gethostname(); i = string_checker(new_p, hostname); @@ -115,6 +123,7 @@ static const char *obscure_msg(const char *old_p, const char *new_p, const struc return "similar to hostname"; /* Should / Must contain a mix of: */ + mixed = 0; for (i = 0; i < length; i++) { if (islower(new_p[i])) { /* a-z */ mixed |= LOWERCASE; @@ -125,7 +134,7 @@ static const char *obscure_msg(const char *old_p, const char *new_p, const struc } else { /* special characters */ mixed |= SPECIAL; } - /* More than 50% similar characters ? */ + /* Count i'th char */ c = 0; p = new_p; while (1) { @@ -134,26 +143,31 @@ static const char *obscure_msg(const char *old_p, const char *new_p, const struc break; } c++; - if (!++p) { - break; /* move past the matched char if possible */ + p++; + if (!*p) { + break; } } - - if (c >= (length / 2)) { + /* More than 50% similar characters ? */ + if (c*2 >= length) { return "too many similar characters"; } } - for (i=0; i<4; i++) - if (mixed & (1< * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * Also for use in uClibc (http://uclibc.org/) licensed under LGPLv2.1 or later. */ +/* Uncomment to enable test applet */ +////config:config PARSE +////config: bool "Uniform config file parser debugging applet: parse" +////config: default n +////config: help +////config: Typical usage of parse API: +////config: char *t[3]; +////config: parser_t *p = config_open(filename); +////config: while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens +////config: bb_error_msg("TOKENS: '%s''%s''%s'", t[0], t[1], t[2]); +////config: } +////config: config_close(p); + +////applet:IF_PARSE(APPLET(parse, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-y += parse_config.o + +//usage:#define parse_trivial_usage +//usage: "[-x] [-n MAXTOKENS] [-m MINTOKENS] [-d DELIMS] [-f FLAGS] FILE..." +//usage:#define parse_full_usage "\n\n" +//usage: " -x Suppress output (for benchmarking)" + #include "libbb.h" #if defined ENABLE_PARSE && ENABLE_PARSE @@ -15,52 +37,34 @@ int parse_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int parse_main(int argc UNUSED_PARAM, char **argv) { const char *delims = "# \t"; + char **t; unsigned flags = PARSE_NORMAL; int mintokens = 0, ntokens = 128; + unsigned noout; opt_complementary = "-1:n+:m+:f+"; - getopt32(argv, "n:m:d:f:", &ntokens, &mintokens, &delims, &flags); + noout = 1 & getopt32(argv, "xn:m:d:f:", &ntokens, &mintokens, &delims, &flags); //argc -= optind; argv += optind; + + t = xmalloc(sizeof(t[0]) * ntokens); while (*argv) { + int n; parser_t *p = config_open(*argv); - if (p) { - int n; - char **t = xmalloc(sizeof(char *) * ntokens); - while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) { + while ((n = config_read(p, t, ntokens, mintokens, delims, flags)) != 0) { + if (!noout) { for (int i = 0; i < n; ++i) printf("[%s]", t[i]); puts(""); } - config_close(p); } + config_close(p); argv++; } return EXIT_SUCCESS; } #endif -/* - -Typical usage: - ------ CUT ----- - char *t[3]; // tokens placeholder - parser_t *p = config_open(filename); - if (p) { - // parse line-by-line - while (config_read(p, t, 3, 0, delimiters, flags)) { // 1..3 tokens - // use tokens - bb_error_msg("TOKENS: [%s][%s][%s]", t[0], t[1], t[2]); - } - ... - // free parser - config_close(p); - } ------ CUT ----- - -*/ - parser_t* FAST_FUNC config_open2(const char *filename, FILE* FAST_FUNC (*fopen_func)(const char *path)) { FILE* fp; @@ -79,25 +83,58 @@ parser_t* FAST_FUNC config_open(const char *filename) return config_open2(filename, fopen_or_warn_stdin); } -static void config_free_data(parser_t *parser) -{ - free(parser->line); - parser->line = NULL; - if (PARSE_KEEP_COPY) { /* compile-time constant */ - free(parser->data); - parser->data = NULL; - } -} - void FAST_FUNC config_close(parser_t *parser) { if (parser) { - config_free_data(parser); + if (PARSE_KEEP_COPY) /* compile-time constant */ + free(parser->data); fclose(parser->fp); + free(parser->line); + free(parser->nline); free(parser); } } +/* This function reads an entire line from a text file, + * up to a newline, exclusive. + * Trailing '\' is recognized as line continuation. + * Returns -1 if EOF/error. + */ +static int get_line_with_continuation(parser_t *parser) +{ + ssize_t len, nlen; + char *line; + + len = getline(&parser->line, &parser->line_alloc, parser->fp); + if (len <= 0) + return len; + + line = parser->line; + for (;;) { + parser->lineno++; + if (line[len - 1] == '\n') + len--; + if (len == 0 || line[len - 1] != '\\') + break; + len--; + + nlen = getline(&parser->nline, &parser->nline_alloc, parser->fp); + if (nlen <= 0) + break; + + if (parser->line_alloc < len + nlen + 1) { + parser->line_alloc = len + nlen + 1; + line = parser->line = xrealloc(line, parser->line_alloc); + } + memcpy(&line[len], parser->nline, nlen); + len += nlen; + } + + line[len] = '\0'; + return len; +} + + /* 0. If parser is NULL return 0. 1. Read a line from config file. If nothing to read then return 0. @@ -126,27 +163,22 @@ int FAST_FUNC config_read(parser_t *parser, char **tokens, unsigned flags, const { char *line; int ntokens, mintokens; - int t, len; + int t; + + if (!parser) + return 0; ntokens = (uint8_t)flags; mintokens = (uint8_t)(flags >> 8); - if (parser == NULL) - return 0; - -again: + again: memset(tokens, 0, sizeof(tokens[0]) * ntokens); - config_free_data(parser); /* Read one line (handling continuations with backslash) */ - line = bb_get_chunk_with_continuation(parser->fp, &len, &parser->lineno); - if (line == NULL) + if (get_line_with_continuation(parser) < 0) return 0; - parser->line = line; - /* Strip trailing line-feed if any */ - if (len && line[len-1] == '\n') - line[len-1] = '\0'; + line = parser->line; /* Skip token in the start of line? */ if (flags & PARSE_TRIM) @@ -155,8 +187,10 @@ again: if (line[0] == '\0' || line[0] == delims[0]) goto again; - if (flags & PARSE_KEEP_COPY) + if (flags & PARSE_KEEP_COPY) { + free(parser->data); parser->data = xstrdup(line); + } /* Tokenize the line */ t = 0; @@ -170,7 +204,7 @@ again: line += strcspn(line, delims[0] ? delims : delims + 1); } else { /* Combining, find comment char if any */ - line = strchrnul(line, delims[0]); + line = strchrnul(line, PARSE_EOL_COMMENTS ? delims[0] : '\0'); /* Trim any extra delimiters from the end */ if (flags & PARSE_TRIM) { @@ -187,19 +221,7 @@ again: #if 0 /* unused so far */ if (flags & PARSE_ESCAPE) { - const char *from; - char *to; - - from = to = tokens[t]; - while (*from) { - if (*from == '\\') { - from++; - *to++ = bb_process_escape_sequence(&from); - } else { - *to++ = *from++; - } - } - *to = '\0'; + strcpy_and_process_escape_sequences(tokens[t], tokens[t]); } #endif /* Skip possible delimiters */ @@ -214,8 +236,6 @@ again: parser->lineno, t, mintokens); if (flags & PARSE_MIN_DIE) xfunc_die(); - if (flags & PARSE_KEEP_COPY) - free(parser->data); goto again; } diff --git a/libbb/parse_mode.c b/libbb/parse_mode.c index 6eca00a..5a4e1c5 100644 --- a/libbb/parse_mode.c +++ b/libbb/parse_mode.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* http://www.opengroup.org/onlinepubs/007904975/utilities/chmod.html */ @@ -57,8 +57,8 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) /* Note: we allow empty clauses, and hence empty modes. * We treat an empty mode as no change to perms. */ - while (*s) { /* Process clauses. */ - if (*s == ',') { /* We allow empty clauses. */ + while (*s) { /* Process clauses. */ + if (*s == ',') { /* We allow empty clauses. */ ++s; continue; } @@ -77,7 +77,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) } } while (*++p); - do { /* Process action list. */ + do { /* Process action list. */ if ((*s != '+') && (*s != '-')) { if (*s != '=') { return 0; @@ -93,7 +93,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) op = *s++; /* Check for permcopy. */ - p = who_chars + 1; /* Skip 'a' entry. */ + p = who_chars + 1; /* Skip 'a' entry. */ do { if (*p == *s) { int i = 0; @@ -128,7 +128,7 @@ int FAST_FUNC bb_parse_mode(const char *s, mode_t *current_mode) } } while (*++p); GOT_ACTION: - if (permlist) { /* The permlist was nonempty. */ + if (permlist) { /* The permlist was nonempty. */ mode_t tmp = wholist; if (!wholist) { mode_t u_mask = umask(0); diff --git a/libbb/percent_decode.c b/libbb/percent_decode.c new file mode 100644 index 0000000..9a9d80c --- /dev/null +++ b/libbb/percent_decode.c @@ -0,0 +1,69 @@ +/* vi: set sw=4 ts=4: */ +/* + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//kbuild:lib-y += percent_decode.o + +#include "libbb.h" + +static unsigned hex_to_bin(unsigned char c) +{ + unsigned v; + + v = c - '0'; + if (v <= 9) + return v; + /* c | 0x20: letters to lower case, non-letters + * to (potentially different) non-letters */ + v = (unsigned)(c | 0x20) - 'a'; + if (v <= 5) + return v + 10; + return ~0; +/* For testing: +void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } +int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); +t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } +*/ +} + +char* FAST_FUNC percent_decode_in_place(char *str, int strict) +{ + /* note that decoded string is always shorter than original */ + char *src = str; + char *dst = str; + char c; + + while ((c = *src++) != '\0') { + unsigned v; + + if (!strict && c == '+') { + *dst++ = ' '; + continue; + } + if (c != '%') { + *dst++ = c; + continue; + } + v = hex_to_bin(src[0]); + if (v > 15) { + bad_hex: + if (strict) + return NULL; + *dst++ = '%'; + continue; + } + v = (v * 16) | hex_to_bin(src[1]); + if (v > 255) + goto bad_hex; + if (strict && (v == '/' || v == '\0')) { + /* caller takes it as indication of invalid + * (dangerous wrt exploits) chars */ + return str + 1; + } + *dst++ = v; + src += 2; + } + *dst = '\0'; + return str; +} diff --git a/libbb/perror_msg.c b/libbb/perror_msg.c index cbba805..fa1f0d3 100644 --- a/libbb/perror_msg.c +++ b/libbb/perror_msg.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/perror_nomsg.c b/libbb/perror_nomsg.c index a157caa..a2a11cc 100644 --- a/libbb/perror_nomsg.c +++ b/libbb/perror_nomsg.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* gcc warns about a null format string, therefore we provide diff --git a/libbb/perror_nomsg_and_die.c b/libbb/perror_nomsg_and_die.c index d56e05d..543ff51 100644 --- a/libbb/perror_nomsg_and_die.c +++ b/libbb/perror_nomsg_and_die.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* gcc warns about a null format string, therefore we provide diff --git a/libbb/pidfile.c b/libbb/pidfile.c index 7b8fee2..a48dfc3 100644 --- a/libbb/pidfile.c +++ b/libbb/pidfile.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 by Stephane Billiart * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Override ENABLE_FEATURE_PIDFILE */ diff --git a/libbb/platform.c b/libbb/platform.c index 7a8b176..1973451 100644 --- a/libbb/platform.c +++ b/libbb/platform.c @@ -4,7 +4,7 @@ * * Copyright (C) 2009 by Dan Fandrich , et. al. * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -28,23 +28,25 @@ int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) r = vsnprintf(buf, 128, format, p); va_end(p); + /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ + if (r < 128) { va_end(p2); - *string_ptr = xstrdup(buf); - return r; + *string_ptr = strdup(buf); + return (*string_ptr ? r : -1); } - *string_ptr = xmalloc(r+1); - r = vsnprintf(*string_ptr, r+1, format, p2); + *string_ptr = malloc(r+1); + r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); va_end(p2); return r; } #endif -#ifndef HAVE_FDPRINTF -/* dprintf is now actually part of POSIX.1, but was only added in 2008 */ -int fdprintf(int fd, const char *format, ...) +#ifndef HAVE_DPRINTF +/* dprintf is now part of POSIX.1, but was only added in 2008 */ +int dprintf(int fd, const char *format, ...) { va_list p; int r; @@ -134,3 +136,43 @@ char* FAST_FUNC strsep(char **stringp, const char *delim) return start; } #endif + +#ifndef HAVE_STPCPY +char* FAST_FUNC stpcpy(char *p, const char *to_add) +{ + while ((*p = *to_add) != '\0') { + p++; + to_add++; + } + return p; +} +#endif + +#ifndef HAVE_GETLINE +ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream) +{ + int ch; + char *line = *lineptr; + size_t alloced = *n; + size_t len = 0; + + do { + ch = fgetc(stream); + if (ch == EOF) + break; + if (len + 1 >= alloced) { + alloced += alloced/4 + 64; + line = xrealloc(line, alloced); + } + line[len++] = ch; + } while (ch != '\n'); + + if (len == 0) + return -1; + + line[len] = '\0'; + *lineptr = line; + *n = alloced; + return len; +} +#endif diff --git a/libbb/print_flags.c b/libbb/print_flags.c index 9639dc6..eaec731 100644 --- a/libbb/print_flags.c +++ b/libbb/print_flags.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 Natanael Copa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/printable.c b/libbb/printable.c index ae93359..9a42343 100644 --- a/libbb/printable.c +++ b/libbb/printable.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -32,3 +32,27 @@ void FAST_FUNC fputc_printable(int ch, FILE *file) } fputc(ch, file); } + +void FAST_FUNC visible(unsigned ch, char *buf, int flags) +{ + if (ch == '\t' && !(flags & VISIBLE_SHOW_TABS)) { + goto raw; + } + if (ch == '\n') { + if (flags & VISIBLE_ENDLINE) + *buf++ = '$'; + } else { + if (ch >= 128) { + ch -= 128; + *buf++ = 'M'; + *buf++ = '-'; + } + if (ch < 32 || ch == 127) { + *buf++ = '^'; + ch ^= 0x40; + } + } + raw: + *buf++ = ch; + *buf = '\0'; +} diff --git a/libbb/printable_string.c b/libbb/printable_string.c index 83a4821..a316f60 100644 --- a/libbb/printable_string.c +++ b/libbb/printable_string.c @@ -4,7 +4,7 @@ * * Copyright (C) 2010 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include "unicode.h" diff --git a/libbb/process_escape_sequence.c b/libbb/process_escape_sequence.c index 3ad908b..346ecfa 100644 --- a/libbb/process_escape_sequence.c +++ b/libbb/process_escape_sequence.c @@ -5,7 +5,7 @@ * Copyright (C) Manuel Novoa III * and Vladimir Oleynik * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -18,52 +18,42 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) { - /* bash builtin "echo -e '\ec'" interprets \e as ESC, - * but coreutils "/bin/echo -e '\ec'" does not. - * manpages tend to support coreutils way. - * Update: coreutils added support for \e on 28 Oct 2009. */ - static const char charmap[] ALIGN1 = { - 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', 0, - '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\' }; - - const char *p; const char *q; unsigned num_digits; - unsigned r; unsigned n; - unsigned d; unsigned base; num_digits = n = 0; base = 8; q = *ptr; -#ifdef WANT_HEX_ESCAPES - if (*q == 'x') { + if (WANT_HEX_ESCAPES && *q == 'x') { ++q; base = 16; ++num_digits; } -#endif /* bash requires leading 0 in octal escapes: * \02 works, \2 does not (prints \ and 2). * We treat \2 as a valid octal escape sequence. */ do { - d = (unsigned char)(*q) - '0'; -#ifdef WANT_HEX_ESCAPES - if (d >= 10) { - d = (unsigned char)(_tolower(*q)) - 'a' + 10; - } + unsigned r; +#if !WANT_HEX_ESCAPES + unsigned d = (unsigned char)(*q) - '0'; +#else + unsigned d = (unsigned char)_tolower(*q) - '0'; + if (d >= 10) + d += ('0' - 'a' + 10); #endif - if (d >= base) { -#ifdef WANT_HEX_ESCAPES - if ((base == 16) && (!--num_digits)) { -/* return '\\'; */ - --q; + if (WANT_HEX_ESCAPES && base == 16) { + --num_digits; + if (num_digits == 0) { + /* \x: return '\', + * leave ptr pointing to x */ + return '\\'; + } } -#endif break; } @@ -76,21 +66,47 @@ char FAST_FUNC bb_process_escape_sequence(const char **ptr) ++q; } while (++num_digits < 3); - if (num_digits == 0) { /* mnemonic escape sequence? */ - p = charmap; + if (num_digits == 0) { + /* Not octal or hex escape sequence. + * Is it one-letter one? */ + + /* bash builtin "echo -e '\ec'" interprets \e as ESC, + * but coreutils "/bin/echo -e '\ec'" does not. + * Manpages tend to support coreutils way. + * Update: coreutils added support for \e on 28 Oct 2009. */ + static const char charmap[] ALIGN1 = { + 'a', 'b', 'e', 'f', 'n', 'r', 't', 'v', '\\', '\0', + '\a', '\b', 27, '\f', '\n', '\r', '\t', '\v', '\\', '\\', + }; + const char *p = charmap; do { if (*p == *q) { q++; break; } - } while (*++p); + } while (*++p != '\0'); /* p points to found escape char or NUL, - * advance it and find what it translates to */ - p += sizeof(charmap) / 2; - n = *p; + * advance it and find what it translates to. + * Note that \NUL and unrecognized sequence \z return '\' + * and leave ptr pointing to NUL or z. */ + n = p[sizeof(charmap) / 2]; } *ptr = q; return (char) n; } + +char* FAST_FUNC strcpy_and_process_escape_sequences(char *dst, const char *src) +{ + while (1) { + char c, c1; + c = c1 = *src++; + if (c1 == '\\') + c1 = bb_process_escape_sequence(&src); + *dst = c1; + if (c == '\0') + return dst; + dst++; + } +} diff --git a/libbb/procps.c b/libbb/procps.c index 48e60a7..5b68d34 100644 --- a/libbb/procps.c +++ b/libbb/procps.c @@ -6,19 +6,19 @@ * Copyright (C) 2002 by Vladimir Oleynik * SELinux support: (c) 2007 by Yuichi Nakamura * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -typedef struct unsigned_to_name_map_t { - long id; +typedef struct id_to_name_map_t { + uid_t id; char name[USERNAME_MAX_SIZE]; -} unsigned_to_name_map_t; +} id_to_name_map_t; typedef struct cache_t { - unsigned_to_name_map_t *cache; + id_to_name_map_t *cache; int size; } cache_t; @@ -39,7 +39,7 @@ void FAST_FUNC clear_username_cache(void) #if 0 /* more generic, but we don't need that yet */ /* Returns -N-1 if not found. */ /* cp->cache[N] is allocated and must be filled in this case */ -static int get_cached(cache_t *cp, unsigned id) +static int get_cached(cache_t *cp, uid_t id) { int i; for (i = 0; i < cp->size; i++) @@ -52,8 +52,8 @@ static int get_cached(cache_t *cp, unsigned id) } #endif -static char* get_cached(cache_t *cp, long id, - char* FAST_FUNC x2x_utoa(long id)) +static char* get_cached(cache_t *cp, uid_t id, + char* FAST_FUNC x2x_utoa(uid_t id)) { int i; for (i = 0; i < cp->size; i++) @@ -120,43 +120,43 @@ void FAST_FUNC free_procps_scan(procps_status_t* sp) free(sp); } -#if ENABLE_FEATURE_TOPMEM +#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP static unsigned long fast_strtoul_16(char **endptr) { unsigned char c; char *str = *endptr; unsigned long n = 0; - while ((c = *str++) != ' ') { + /* Need to stop on both ' ' and '\n' */ + while ((c = *str++) > ' ') { c = ((c|0x20) - '0'); if (c > 9) - // c = c + '0' - 'a' + 10: + /* c = c + '0' - 'a' + 10: */ c = c - ('a' - '0' - 10); n = n*16 + c; } *endptr = str; /* We skip trailing space! */ return n; } -/* TOPMEM uses fast_strtoul_10, so... */ -# undef ENABLE_FEATURE_FAST_TOP -# define ENABLE_FEATURE_FAST_TOP 1 #endif -#if ENABLE_FEATURE_FAST_TOP +#if ENABLE_FEATURE_FAST_TOP || ENABLE_FEATURE_TOPMEM || ENABLE_PMAP /* We cut a lot of corners here for speed */ static unsigned long fast_strtoul_10(char **endptr) { - char c; + unsigned char c; char *str = *endptr; unsigned long n = *str - '0'; - while ((c = *++str) != ' ') + /* Need to stop on both ' ' and '\n' */ + while ((c = *++str) > ' ') n = n*10 + (c - '0'); *endptr = str + 1; /* We skip trailing space! */ return n; } +# if ENABLE_FEATURE_FAST_TOP static long fast_strtol_10(char **endptr) { if (**endptr != '-') @@ -165,6 +165,7 @@ static long fast_strtol_10(char **endptr) (*endptr)++; return - (long)fast_strtoul_10(endptr); } +# endif static char *skip_fields(char *str, int count) { @@ -177,24 +178,128 @@ static char *skip_fields(char *str, int count) } #endif -void BUG_comm_size(void); -procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) +#if ENABLE_FEATURE_TOPMEM || ENABLE_PMAP +int FAST_FUNC procps_read_smaps(pid_t pid, struct smaprec *total, + void (*cb)(struct smaprec *, void *), void *data) { - struct dirent *entry; + FILE *file; + struct smaprec currec; + char filename[sizeof("/proc/%u/smaps") + sizeof(int)*3]; char buf[PROCPS_BUFSIZE]; - char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; - char *filename_tail; - long tasknice; - unsigned pid; - int n; - struct stat sb; +#if !ENABLE_PMAP + void (*cb)(struct smaprec *, void *) = NULL; + void *data = NULL; +#endif + + sprintf(filename, "/proc/%u/smaps", (int)pid); + + file = fopen_for_read(filename); + if (!file) + return 1; + + memset(&currec, 0, sizeof(currec)); + while (fgets(buf, PROCPS_BUFSIZE, file)) { + // Each mapping datum has this form: + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME + // Size: nnn kB + // Rss: nnn kB + // ..... + + char *tp = buf, *p; + +#define SCAN(S, X) \ + if (strncmp(tp, S, sizeof(S)-1) == 0) { \ + tp = skip_whitespace(tp + sizeof(S)-1); \ + total->X += currec.X = fast_strtoul_10(&tp); \ + continue; \ + } + if (cb) { + SCAN("Pss:" , smap_pss ); + SCAN("Swap:" , smap_swap ); + } + SCAN("Private_Dirty:", private_dirty); + SCAN("Private_Clean:", private_clean); + SCAN("Shared_Dirty:" , shared_dirty ); + SCAN("Shared_Clean:" , shared_clean ); +#undef SCAN + tp = strchr(buf, '-'); + if (tp) { + // We reached next mapping - the line of this form: + // f7d29000-f7d39000 rw-s FILEOFS M:m INODE FILENAME + + if (cb) { + /* If we have a previous record, there's nothing more + * for it, call the callback and clear currec + */ + if (currec.smap_size) + cb(&currec, data); + free(currec.smap_name); + } + memset(&currec, 0, sizeof(currec)); + + *tp = ' '; + tp = buf; + currec.smap_start = fast_strtoul_16(&tp); + currec.smap_size = (fast_strtoul_16(&tp) - currec.smap_start) >> 10; + + strncpy(currec.smap_mode, tp, sizeof(currec.smap_mode)-1); + + // skipping "rw-s FILEOFS M:m INODE " + tp = skip_whitespace(skip_fields(tp, 4)); + // filter out /dev/something (something != zero) + if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { + if (currec.smap_mode[1] == 'w') { + currec.mapped_rw = currec.smap_size; + total->mapped_rw += currec.smap_size; + } else if (currec.smap_mode[1] == '-') { + currec.mapped_ro = currec.smap_size; + total->mapped_ro += currec.smap_size; + } + } + + if (strcmp(tp, "[stack]\n") == 0) + total->stack += currec.smap_size; + if (cb) { + p = skip_non_whitespace(tp); + if (p == tp) { + currec.smap_name = xstrdup(" [ anon ]"); + } else { + *p = '\0'; + currec.smap_name = xstrdup(tp); + } + } + total->smap_size += currec.smap_size; + } + } + fclose(file); + + if (cb) { + if (currec.smap_size) + cb(&currec, data); + free(currec.smap_name); + } + + return 0; +} +#endif +void BUG_comm_size(void); +procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) +{ if (!sp) sp = alloc_procps_scan(); for (;;) { + struct dirent *entry; + char buf[PROCPS_BUFSIZE]; + long tasknice; + unsigned pid; + int n; + char filename[sizeof("/proc/%u/task/%u/cmdline") + sizeof(int)*3 * 2]; + char *filename_tail; + #if ENABLE_FEATURE_SHOW_THREADS - if ((flags & PSSCAN_TASKS) && sp->task_dir) { + if (sp->task_dir) { entry = readdir(sp->task_dir); if (entry) goto got_entry; @@ -216,9 +321,10 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) /* We found another /proc/PID. Do not use it, * there will be /proc/PID/task/PID (same PID!), * so just go ahead and dive into /proc/PID/task. */ - char task_dir[sizeof("/proc/%u/task") + sizeof(int)*3]; - sprintf(task_dir, "/proc/%u/task", pid); - sp->task_dir = xopendir(task_dir); + sprintf(filename, "/proc/%u/task", pid); + /* Note: if opendir fails, we just go to next /proc/XXX */ + sp->task_dir = opendir(filename); + sp->main_thread_pid = pid; continue; } #endif @@ -241,9 +347,15 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) } #endif - filename_tail = filename + sprintf(filename, "/proc/%u/", pid); +#if ENABLE_FEATURE_SHOW_THREADS + if (sp->task_dir) + filename_tail = filename + sprintf(filename, "/proc/%u/task/%u/", sp->main_thread_pid, pid); + else +#endif + filename_tail = filename + sprintf(filename, "/proc/%u/", pid); if (flags & PSSCAN_UIDGID) { + struct stat sb; if (stat(filename, &sb)) continue; /* process probably exited */ /* Effective UID/GID, not real */ @@ -251,7 +363,14 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) sp->gid = sb.st_gid; } - if (flags & PSSCAN_STAT) { + /* These are all retrieved from proc/NN/stat in one go: */ + if (flags & (PSSCAN_PPID | PSSCAN_PGID | PSSCAN_SID + | PSSCAN_COMM | PSSCAN_STATE + | PSSCAN_VSZ | PSSCAN_RSS + | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_START_TIME + | PSSCAN_TTY | PSSCAN_NICE + | PSSCAN_CPU) + ) { char *cp, *comm1; int tty; #if !ENABLE_FEATURE_FAST_TOP @@ -306,7 +425,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) if (n < 11) continue; /* bogus data, get next /proc/XXX */ # if ENABLE_FEATURE_TOP_SMP_PROCESS - if (n < 11+15) + if (n == 11) sp->last_seen_on_cpu = 0; # endif @@ -346,7 +465,7 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) //FIXME: is it safe to assume this field exists? sp->last_seen_on_cpu = fast_strtoul_10(&cp); # endif -#endif /* end of !ENABLE_FEATURE_TOP_SMP_PROCESS */ +#endif /* FEATURE_FAST_TOP */ #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS sp->niceness = tasknice; @@ -365,54 +484,8 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) } #if ENABLE_FEATURE_TOPMEM - if (flags & (PSSCAN_SMAPS)) { - FILE *file; - - strcpy(filename_tail, "smaps"); - file = fopen_for_read(filename); - if (file) { - while (fgets(buf, sizeof(buf), file)) { - unsigned long sz; - char *tp; - char w; -#define SCAN(str, name) \ - if (strncmp(buf, str, sizeof(str)-1) == 0) { \ - tp = skip_whitespace(buf + sizeof(str)-1); \ - sp->name += fast_strtoul_10(&tp); \ - continue; \ - } - SCAN("Shared_Clean:" , shared_clean ); - SCAN("Shared_Dirty:" , shared_dirty ); - SCAN("Private_Clean:", private_clean); - SCAN("Private_Dirty:", private_dirty); -#undef SCAN - // f7d29000-f7d39000 rw-s ADR M:m OFS FILE - tp = strchr(buf, '-'); - if (tp) { - *tp = ' '; - tp = buf; - sz = fast_strtoul_16(&tp); /* start */ - sz = (fast_strtoul_16(&tp) - sz) >> 10; /* end - start */ - // tp -> "rw-s" string - w = tp[1]; - // skipping "rw-s ADR M:m OFS " - tp = skip_whitespace(skip_fields(tp, 4)); - // filter out /dev/something (something != zero) - if (strncmp(tp, "/dev/", 5) != 0 || strcmp(tp, "/dev/zero\n") == 0) { - if (w == 'w') { - sp->mapped_rw += sz; - } else if (w == '-') { - sp->mapped_ro += sz; - } - } -//else printf("DROPPING %s (%s)\n", buf, tp); - if (strcmp(tp, "[stack]\n") == 0) - sp->stack += sz; - } - } - fclose(file); - } - } + if (flags & PSSCAN_SMAPS) + procps_read_smaps(pid, &sp->smaps, NULL, NULL); #endif /* TOPMEM */ #if ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS if (flags & PSSCAN_RUIDGID) { @@ -499,18 +572,49 @@ procps_status_t* FAST_FUNC procps_scan(procps_status_t* sp, int flags) void FAST_FUNC read_cmdline(char *buf, int col, unsigned pid, const char *comm) { int sz; - char filename[sizeof("/proc//cmdline") + sizeof(int)*3]; + char filename[sizeof("/proc/%u/cmdline") + sizeof(int)*3]; sprintf(filename, "/proc/%u/cmdline", pid); sz = open_read_close(filename, buf, col - 1); if (sz > 0) { + const char *base; + int comm_len; + buf[sz] = '\0'; while (--sz >= 0 && buf[sz] == '\0') continue; - do { + /* Prevent basename("process foo/bar") = "bar" */ + strchrnul(buf, ' ')[0] = '\0'; + base = bb_basename(buf); /* before we replace argv0's NUL with space */ + while (sz >= 0) { if ((unsigned char)(buf[sz]) < ' ') buf[sz] = ' '; - } while (--sz >= 0); + sz--; + } + + /* If comm differs from argv0, prepend "{comm} ". + * It allows to see thread names set by prctl(PR_SET_NAME). + */ + if (base[0] == '-') /* "-sh" (login shell)? */ + base++; + comm_len = strlen(comm); + /* Why compare up to comm_len, not COMM_LEN-1? + * Well, some processes rewrite argv, and use _spaces_ there + * while rewriting. (KDE is observed to do it). + * I prefer to still treat argv0 "process foo bar" + * as 'equal' to comm "process". + */ + if (strncmp(base, comm, comm_len) != 0) { + comm_len += 3; + if (col > comm_len) + memmove(buf + comm_len, buf, col - comm_len); + snprintf(buf, col, "{%s}", comm); + if (col <= comm_len) + return; + buf[comm_len - 1] = ' '; + buf[col - 1] = '\0'; + } + } else { snprintf(buf, col, "[%s]", comm); } diff --git a/libbb/progress.c b/libbb/progress.c index e960390..372feb0 100644 --- a/libbb/progress.c +++ b/libbb/progress.c @@ -7,7 +7,7 @@ */ /*- * Copyright (c) 1992, 1993 - * The Regents of the University of California. All rights reserved. + * 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 @@ -18,8 +18,8 @@ * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * - * 3. + * 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 @@ -52,102 +52,156 @@ static unsigned int get_tty2_width(void) return width; } -void FAST_FUNC bb_progress_init(bb_progress_t *p) +void FAST_FUNC bb_progress_init(bb_progress_t *p, const char *curfile) { +#if ENABLE_UNICODE_SUPPORT + init_unicode(); + p->curfile = unicode_conv_to_printable_fixedwidth(/*NULL,*/ curfile, 20); +#else + p->curfile = curfile; +#endif p->start_sec = monotonic_sec(); - p->lastupdate_sec = p->start_sec; - p->lastsize = 0; - p->inited = 1; + p->last_update_sec = p->start_sec; + p->last_change_sec = p->start_sec; + p->last_size = 0; } +/* File already had beg_size bytes. + * Then we started downloading. + * We downloaded "transferred" bytes so far. + * Download is expected to stop when total size (beg_size + transferred) + * will be "totalsize" bytes. + * If totalsize == 0, then it is unknown. + */ void FAST_FUNC bb_progress_update(bb_progress_t *p, - const char *curfile, - off_t beg_range, - off_t transferred, - off_t totalsize) + uoff_t beg_size, + uoff_t transferred, + uoff_t totalsize) { - off_t abbrevsize; + uoff_t beg_and_transferred; unsigned since_last_update, elapsed; - unsigned ratio; - int barlength, i; - - ratio = 100; - if (totalsize) { - /* long long helps to have it working even if !LFS */ - ratio = (unsigned) (100ULL * (transferred+beg_range) / totalsize); - if (ratio > 100) ratio = 100; + int barlength; + int kiloscale; + + //transferred = 1234; /* use for stall detection testing */ + //totalsize = 0; /* use for unknown size download testing */ + + elapsed = monotonic_sec(); + since_last_update = elapsed - p->last_update_sec; + p->last_update_sec = elapsed; + + if (totalsize != 0 && transferred >= totalsize - beg_size) { + /* Last call. Do not skip this update */ + transferred = totalsize - beg_size; /* sanitize just in case */ + } + else if (since_last_update == 0) { + /* + * Do not update on every call + * (we can be called on every network read!) + */ + return; } -#if ENABLE_UNICODE_SUPPORT - init_unicode(); - /* libbb candidate? */ - { - wchar_t wbuf21[21]; - char *buf = xstrdup(curfile); - unsigned len; - - /* trim to 20 wide chars max (sets wbuf21[20] to 0) - * also, in case mbstowcs fails, we at least - * dont get garbage */ - memset(wbuf21, 0, sizeof(wbuf21)); - /* convert to wide chars, no more than 20 */ - len = mbstowcs(wbuf21, curfile, 20); /* NB: may return -1 */ - /* back to multibyte; cant overflow */ - wcstombs(buf, wbuf21, INT_MAX); - len = (len > 20) ? 0 : 20 - len; - fprintf(stderr, "\r%s%*s%4d%% ", buf, len, "", ratio); - free(buf); + kiloscale = 0; + /* + * Scale sizes down if they are close to overflowing. + * This allows calculations like (100 * transferred / totalsize) + * without risking overflow: we guarantee 10 highest bits to be 0. + * Introduced error is less than 1 / 2^12 ~= 0.025% + */ + if (ULONG_MAX > 0xffffffff || sizeof(off_t) == 4 || sizeof(off_t) != 8) { + /* + * 64-bit CPU || small off_t: in either case, + * >> is cheap, single-word operation. + * ... || strange off_t: also use this code + * (it is safe, just suboptimal wrt code size), + * because 32/64 optimized one works only for 64-bit off_t. + */ + if (totalsize >= (1 << 22)) { + totalsize >>= 10; + beg_size >>= 10; + transferred >>= 10; + kiloscale = 1; + } + } else { + /* 32-bit CPU and 64-bit off_t. + * Use a 40-bit shift, it is easier to do on 32-bit CPU. + */ +/* ONE suppresses "warning: shift count >= width of type" */ +#define ONE (sizeof(off_t) > 4) + if (totalsize >= (uoff_t)(1ULL << 54*ONE)) { + totalsize = (uint32_t)(totalsize >> 32*ONE) >> 8; + beg_size = (uint32_t)(beg_size >> 32*ONE) >> 8; + transferred = (uint32_t)(transferred >> 32*ONE) >> 8; + kiloscale = 4; + } } -#else - fprintf(stderr, "\r%-20.20s%4d%% ", curfile, ratio); -#endif - barlength = get_tty2_width() - 49; - if (barlength > 0) { - /* god bless gcc for variable arrays :) */ - i = barlength * ratio / 100; - { - char buf[i+1]; - memset(buf, '*', i); - buf[i] = '\0'; - fprintf(stderr, "|%s%*s|", buf, barlength - i, ""); + if (ENABLE_UNICODE_SUPPORT) + fprintf(stderr, "\r%s", p->curfile); + else + fprintf(stderr, "\r%-20.20s", p->curfile); + + beg_and_transferred = beg_size + transferred; + + if (totalsize != 0) { + unsigned ratio = 100 * beg_and_transferred / totalsize; + fprintf(stderr, "%4u%%", ratio); + + barlength = get_tty2_width() - 49; + if (barlength > 0) { + /* god bless gcc for variable arrays :) */ + char buf[barlength + 1]; + unsigned stars = (unsigned)barlength * beg_and_transferred / totalsize; + memset(buf, ' ', barlength); + buf[barlength] = '\0'; + memset(buf, '*', stars); + fprintf(stderr, " |%s|", buf); } } - i = 0; - abbrevsize = transferred + beg_range; - while (abbrevsize >= 100000) { - i++; - abbrevsize >>= 10; + + while (beg_and_transferred >= 100000) { + beg_and_transferred >>= 10; + kiloscale++; } /* see http://en.wikipedia.org/wiki/Tera */ - fprintf(stderr, "%6d%c ", (int)abbrevsize, " kMGTPEZY"[i]); + fprintf(stderr, "%6u%c", (unsigned)beg_and_transferred, " kMGTPEZY"[kiloscale]); +#define beg_and_transferred dont_use_beg_and_transferred_below() - elapsed = monotonic_sec(); - since_last_update = elapsed - p->lastupdate_sec; - if (transferred > p->lastsize) { - p->lastupdate_sec = elapsed; - p->lastsize = transferred; + since_last_update = elapsed - p->last_change_sec; + if ((unsigned)transferred != p->last_size) { + p->last_change_sec = elapsed; + p->last_size = (unsigned)transferred; if (since_last_update >= STALLTIME) { - /* We "cut off" these seconds from elapsed time + /* We "cut out" these seconds from elapsed time * by adjusting start time */ p->start_sec += since_last_update; } since_last_update = 0; /* we are un-stalled now */ } + elapsed -= p->start_sec; /* now it's "elapsed since start" */ if (since_last_update >= STALLTIME) { - fprintf(stderr, " - stalled -"); + fprintf(stderr, " - stalled -"); + } else if (!totalsize || !transferred || (int)elapsed < 0) { + fprintf(stderr, " --:--:-- ETA"); } else { - off_t to_download = totalsize - beg_range; - if (!totalsize || transferred <= 0 || (int)elapsed <= 0 || transferred > to_download) { - fprintf(stderr, "--:--:-- ETA"); - } else { - /* to_download / (transferred/elapsed) - elapsed: */ - int eta = (int) ((unsigned long long)to_download*elapsed/transferred - elapsed); - /* (long long helps to have working ETA even if !LFS) */ - i = eta % 3600; - fprintf(stderr, "%02d:%02d:%02d ETA", eta / 3600, i / 60, i % 60); - } + unsigned eta, secs, hours; + + totalsize -= beg_size; /* now it's "total to upload" */ + + /* Estimated remaining time = + * estimated_sec_to_dl_totalsize_bytes - elapsed_sec = + * totalsize / average_bytes_sec_so_far - elapsed = + * totalsize / (transferred/elapsed) - elapsed = + * totalsize * elapsed / transferred - elapsed + */ + eta = totalsize * elapsed / transferred - elapsed; + if (eta >= 1000*60*60) + eta = 1000*60*60 - 1; + secs = eta % 3600; + hours = eta / 3600; + fprintf(stderr, "%3u:%02u:%02u ETA", hours, secs / 60, secs % 60); } } diff --git a/libbb/ptr_to_globals.c b/libbb/ptr_to_globals.c index 5f30e2a..1074538 100644 --- a/libbb/ptr_to_globals.c +++ b/libbb/ptr_to_globals.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2008 by Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include diff --git a/libbb/pw_encrypt.c b/libbb/pw_encrypt.c index 6fc0ba8..39ffa08 100644 --- a/libbb/pw_encrypt.c +++ b/libbb/pw_encrypt.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -27,9 +27,10 @@ static int i64c(int i) return ('a' - 38 + i); } -int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) +int FAST_FUNC crypt_make_salt(char *p, int cnt /*, int x */) { - x += getpid() + time(NULL); + /* was: x += ... */ + int x = getpid() + monotonic_us(); do { /* x = (x*1664525 + 1013904223) % 2^32 generator is lame * (low-order bit is not "random", etc...), @@ -47,6 +48,26 @@ int FAST_FUNC crypt_make_salt(char *p, int cnt, int x) return x; } +char* FAST_FUNC crypt_make_pw_salt(char salt[MAX_PW_SALT_LEN], const char *algo) +{ + int len = 2/2; + char *salt_ptr = salt; + if (algo[0] != 'd') { /* not des */ + len = 8/2; /* so far assuming md5 */ + *salt_ptr++ = '$'; + *salt_ptr++ = '1'; + *salt_ptr++ = '$'; +#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA + if (algo[0] == 's') { /* sha */ + salt[1] = '5' + (strcmp(algo, "sha512") == 0); + len = 16/2; + } +#endif + } + crypt_make_salt(salt_ptr, len); + return salt_ptr; +} + #if ENABLE_USE_BB_CRYPT static char* diff --git a/libbb/pw_encrypt_md5.c b/libbb/pw_encrypt_md5.c index 58964b5..1e52eca 100644 --- a/libbb/pw_encrypt_md5.c +++ b/libbb/pw_encrypt_md5.c @@ -86,16 +86,16 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned /* Get the length of the salt including "$1$" */ sl = 3; - while (salt[sl] && salt[sl] != '$' && sl < (3 + 8)) + while (sl < (3 + 8) && salt[sl] && salt[sl] != '$') sl++; /* Hash. the password first, since that is what is most unknown */ md5_begin(&ctx); pw_len = strlen((char*)pw); - md5_hash(pw, pw_len, &ctx); + md5_hash(&ctx, pw, pw_len); /* Then the salt including "$1$" */ - md5_hash(salt, sl, &ctx); + md5_hash(&ctx, salt, sl); /* Copy salt to result; skip "$1$" */ memcpy(result, salt, sl); @@ -105,19 +105,19 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned /* Then just as many characters of the MD5(pw, salt, pw) */ md5_begin(&ctx1); - md5_hash(pw, pw_len, &ctx1); - md5_hash(salt, sl, &ctx1); - md5_hash(pw, pw_len, &ctx1); - md5_end(final, &ctx1); + md5_hash(&ctx1, pw, pw_len); + md5_hash(&ctx1, salt, sl); + md5_hash(&ctx1, pw, pw_len); + md5_end(&ctx1, final); for (pl = pw_len; pl > 0; pl -= 16) - md5_hash(final, pl > 16 ? 16 : pl, &ctx); + md5_hash(&ctx, final, pl > 16 ? 16 : pl); /* Then something really weird... */ memset(final, 0, sizeof(final)); for (i = pw_len; i; i >>= 1) { - md5_hash(((i & 1) ? final : (const unsigned char *) pw), 1, &ctx); + md5_hash(&ctx, ((i & 1) ? final : (const unsigned char *) pw), 1); } - md5_end(final, &ctx); + md5_end(&ctx, final); /* And now, just to make sure things don't run too fast. * On a 60 Mhz Pentium this takes 34 msec, so you would @@ -126,21 +126,21 @@ md5_crypt(char result[MD5_OUT_BUFSIZE], const unsigned char *pw, const unsigned for (i = 0; i < 1000; i++) { md5_begin(&ctx1); if (i & 1) - md5_hash(pw, pw_len, &ctx1); + md5_hash(&ctx1, pw, pw_len); else - md5_hash(final, 16, &ctx1); + md5_hash(&ctx1, final, 16); if (i % 3) - md5_hash(salt, sl, &ctx1); + md5_hash(&ctx1, salt, sl); if (i % 7) - md5_hash(pw, pw_len, &ctx1); + md5_hash(&ctx1, pw, pw_len); if (i & 1) - md5_hash(final, 16, &ctx1); + md5_hash(&ctx1, final, 16); else - md5_hash(pw, pw_len, &ctx1); - md5_end(final, &ctx1); + md5_hash(&ctx1, pw, pw_len); + md5_end(&ctx1, final); } p = result + sl + 4; /* 12 bytes max (sl is up to 8 bytes) */ diff --git a/libbb/pw_encrypt_sha.c b/libbb/pw_encrypt_sha.c index 070e0d4..8aeaaca 100644 --- a/libbb/pw_encrypt_sha.c +++ b/libbb/pw_encrypt_sha.c @@ -3,7 +3,7 @@ */ /* Prefix for optional rounds specification. */ -static const char str_rounds[] = "rounds=%u$"; +static const char str_rounds[] ALIGN1 = "rounds=%u$"; /* Maximum salt string length. */ #define SALT_LEN_MAX 16 @@ -19,8 +19,8 @@ NOINLINE sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) { void (*sha_begin)(void *ctx) FAST_FUNC; - void (*sha_hash)(const void *buffer, size_t len, void *ctx) FAST_FUNC; - void (*sha_end)(void *resbuf, void *ctx) FAST_FUNC; + void (*sha_hash)(void *ctx, const void *buffer, size_t len) FAST_FUNC; + void (*sha_end)(void *ctx, void *resbuf) FAST_FUNC; int _32or64; char *result, *resptr; @@ -103,40 +103,40 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* Add KEY, SALT. */ sha_begin(&ctx); - sha_hash(key_data, key_len, &ctx); - sha_hash(salt_data, salt_len, &ctx); + sha_hash(&ctx, key_data, key_len); + sha_hash(&ctx, salt_data, salt_len); /* Compute alternate SHA sum with input KEY, SALT, and KEY. The final result will be added to the first context. */ sha_begin(&alt_ctx); - sha_hash(key_data, key_len, &alt_ctx); - sha_hash(salt_data, salt_len, &alt_ctx); - sha_hash(key_data, key_len, &alt_ctx); - sha_end(alt_result, &alt_ctx); + sha_hash(&alt_ctx, key_data, key_len); + sha_hash(&alt_ctx, salt_data, salt_len); + sha_hash(&alt_ctx, key_data, key_len); + sha_end(&alt_ctx, alt_result); /* Add result of this to the other context. */ /* Add for any character in the key one byte of the alternate sum. */ for (cnt = key_len; cnt > _32or64; cnt -= _32or64) - sha_hash(alt_result, _32or64, &ctx); - sha_hash(alt_result, cnt, &ctx); + sha_hash(&ctx, alt_result, _32or64); + sha_hash(&ctx, alt_result, cnt); /* Take the binary representation of the length of the key and for every 1 add the alternate sum, for every 0 the key. */ for (cnt = key_len; cnt != 0; cnt >>= 1) if ((cnt & 1) != 0) - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); else - sha_hash(key_data, key_len, &ctx); + sha_hash(&ctx, key_data, key_len); /* Create intermediate result. */ - sha_end(alt_result, &ctx); + sha_end(&ctx, alt_result); /* Start computation of P byte sequence. */ /* For every character in the password add the entire password. */ sha_begin(&alt_ctx); for (cnt = 0; cnt < key_len; ++cnt) - sha_hash(key_data, key_len, &alt_ctx); - sha_end(temp_result, &alt_ctx); + sha_hash(&alt_ctx, key_data, key_len); + sha_end(&alt_ctx, temp_result); /* NB: past this point, raw key_data is not used anymore */ @@ -153,8 +153,8 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* For every character in the password add the entire password. */ sha_begin(&alt_ctx); for (cnt = 0; cnt < 16 + alt_result[0]; ++cnt) - sha_hash(salt_data, salt_len, &alt_ctx); - sha_end(temp_result, &alt_ctx); + sha_hash(&alt_ctx, salt_data, salt_len); + sha_end(&alt_ctx, temp_result); /* NB: past this point, raw salt_data is not used anymore */ @@ -174,31 +174,31 @@ sha_crypt(/*const*/ char *key_data, /*const*/ char *salt_data) /* Add key or last result. */ if ((cnt & 1) != 0) - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); else - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); /* Add salt for numbers not divisible by 3. */ if (cnt % 3 != 0) - sha_hash(s_bytes, salt_len, &ctx); + sha_hash(&ctx, s_bytes, salt_len); /* Add key for numbers not divisible by 7. */ if (cnt % 7 != 0) - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); /* Add key or last result. */ if ((cnt & 1) != 0) - sha_hash(alt_result, _32or64, &ctx); + sha_hash(&ctx, alt_result, _32or64); else - sha_hash(p_bytes, key_len, &ctx); + sha_hash(&ctx, p_bytes, key_len); - sha_end(alt_result, &ctx); + sha_end(&ctx, alt_result); } /* Append encrypted password to result buffer */ //TODO: replace with something like // bb_uuencode(cp, src, length, bb_uuenc_tbl_XXXbase64); #define b64_from_24bit(B2, B1, B0, N) \ -do { \ - unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ - resptr = to64(resptr, w, N); \ +do { \ + unsigned w = ((B2) << 16) | ((B1) << 8) | (B0); \ + resptr = to64(resptr, w, N); \ } while (0) if (is_sha512 == '5') { unsigned i = 0; diff --git a/libbb/read.c b/libbb/read.c index 1ed7c5f..5906bc2 100644 --- a/libbb/read.c +++ b/libbb/read.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/read_key.c b/libbb/read_key.c index 64557ab..ace23de 100644 --- a/libbb/read_key.c +++ b/libbb/read_key.c @@ -5,7 +5,7 @@ * Copyright (C) 2008 Rob Landley * Copyright (C) 2008 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -15,7 +15,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) const char *seq; int n; - /* Known escape sequences for cursor and function keys */ + /* Known escape sequences for cursor and function keys. + * See "Xterm Control Sequences" + * http://invisible-island.net/xterm/ctlseqs/ctlseqs.html + */ static const char esccmds[] ALIGN1 = { 'O','A' |0x80,KEYCODE_UP , 'O','B' |0x80,KEYCODE_DOWN , @@ -40,13 +43,16 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) '[','C' |0x80,KEYCODE_RIGHT , '[','D' |0x80,KEYCODE_LEFT , /* ESC [ 1 ; 2 x, where x = A/B/C/D: Shift- */ - /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt- */ + /* ESC [ 1 ; 3 x, where x = A/B/C/D: Alt- - implemented below */ /* ESC [ 1 ; 4 x, where x = A/B/C/D: Alt-Shift- */ /* ESC [ 1 ; 5 x, where x = A/B/C/D: Ctrl- - implemented below */ /* ESC [ 1 ; 6 x, where x = A/B/C/D: Ctrl-Shift- */ + /* ESC [ 1 ; 7 x, where x = A/B/C/D: Ctrl-Alt- */ + /* ESC [ 1 ; 8 x, where x = A/B/C/D: Ctrl-Alt-Shift- */ '[','H' |0x80,KEYCODE_HOME , /* xterm */ - /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home */ '[','F' |0x80,KEYCODE_END , /* xterm */ + /* [ESC] ESC [ [2] H - [Alt-][Shift-]Home (End similarly?) */ + /* '[','Z' |0x80,KEYCODE_SHIFT_TAB, */ '[','1','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ '[','2','~' |0x80,KEYCODE_INSERT , /* ESC [ 2 ; 3 ~ - Alt-Insert */ @@ -63,10 +69,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) '[','7','~' |0x80,KEYCODE_HOME , /* vt100? linux vt? or what? */ '[','8','~' |0x80,KEYCODE_END , /* vt100? linux vt? or what? */ #if 0 - '[','1','1','~'|0x80,KEYCODE_FUN1 , - '[','1','2','~'|0x80,KEYCODE_FUN2 , - '[','1','3','~'|0x80,KEYCODE_FUN3 , - '[','1','4','~'|0x80,KEYCODE_FUN4 , + '[','1','1','~'|0x80,KEYCODE_FUN1 , /* old xterm, deprecated by ESC O P */ + '[','1','2','~'|0x80,KEYCODE_FUN2 , /* old xterm... */ + '[','1','3','~'|0x80,KEYCODE_FUN3 , /* old xterm... */ + '[','1','4','~'|0x80,KEYCODE_FUN4 , /* old xterm... */ '[','1','5','~'|0x80,KEYCODE_FUN5 , /* [ESC] ESC [ 1 5 [;2] ~ - [Alt-][Shift-]F5 */ '[','1','7','~'|0x80,KEYCODE_FUN6 , @@ -86,8 +92,12 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) /* '[','1',';','5','B' |0x80,KEYCODE_CTRL_DOWN , - unused */ '[','1',';','5','C' |0x80,KEYCODE_CTRL_RIGHT, '[','1',';','5','D' |0x80,KEYCODE_CTRL_LEFT , + /* '[','1',';','3','A' |0x80,KEYCODE_ALT_UP , - unused */ + /* '[','1',';','3','B' |0x80,KEYCODE_ALT_DOWN , - unused */ + '[','1',';','3','C' |0x80,KEYCODE_ALT_RIGHT, + '[','1',';','3','D' |0x80,KEYCODE_ALT_LEFT , + /* '[','3',';','3','~' |0x80,KEYCODE_ALT_DELETE, - unused */ 0 - /* ESC [ Z - Shift-Tab */ }; pfd.fd = fd; @@ -214,7 +224,10 @@ int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout) } n++; /* Try to decipher "ESC [ NNN ; NNN R" sequence */ - if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL || ENABLE_FEATURE_VI_ASK_TERMINAL) + if ((ENABLE_FEATURE_EDITING_ASK_TERMINAL + || ENABLE_FEATURE_VI_ASK_TERMINAL + || ENABLE_FEATURE_LESS_ASK_TERMINAL + ) && n >= 5 && buffer[0] == '[' && buffer[n-1] == 'R' diff --git a/libbb/read_printf.c b/libbb/read_printf.c index 1b215f9..5ed6e36 100644 --- a/libbb/read_printf.c +++ b/libbb/read_printf.c @@ -4,20 +4,10 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#define ZIPPED (ENABLE_FEATURE_SEAMLESS_LZMA \ - || ENABLE_FEATURE_SEAMLESS_BZ2 \ - || ENABLE_FEATURE_SEAMLESS_GZ \ - /* || ENABLE_FEATURE_SEAMLESS_Z */ \ -) - -#if ZIPPED -# include "unarchive.h" -#endif - /* Suppose that you are a shell. You start child processes. * They work and eventually exit. You want to get user input. @@ -55,32 +45,35 @@ * which detects EAGAIN and uses poll() to wait on the fd. * Thankfully, poll() doesn't care about O_NONBLOCK flag. */ -ssize_t FAST_FUNC nonblock_safe_read(int fd, void *buf, size_t count) +ssize_t FAST_FUNC nonblock_immune_read(int fd, void *buf, size_t count, int loop_on_EINTR) { struct pollfd pfd[1]; ssize_t n; while (1) { - n = safe_read(fd, buf, count); + n = loop_on_EINTR ? safe_read(fd, buf, count) : read(fd, buf, count); if (n >= 0 || errno != EAGAIN) return n; /* fd is in O_NONBLOCK mode. Wait using poll and repeat */ pfd[0].fd = fd; pfd[0].events = POLLIN; - safe_poll(pfd, 1, -1); /* note: this pulls in printf */ + /* note: safe_poll pulls in printf */ + loop_on_EINTR ? safe_poll(pfd, 1, -1) : poll(pfd, 1, -1); } } // Reads one line a-la fgets (but doesn't save terminating '\n'). // Reads byte-by-byte. Useful when it is important to not read ahead. // Bytes are appended to pfx (which must be malloced, or NULL). -char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) +char* FAST_FUNC xmalloc_reads(int fd, size_t *maxsz_p) { char *p; - size_t sz = buf ? strlen(buf) : 0; + char *buf = NULL; + size_t sz = 0; size_t maxsz = maxsz_p ? *maxsz_p : (INT_MAX - 4095); goto jump_in; + while (sz < maxsz) { if ((size_t)(p - buf) == sz) { jump_in: @@ -88,8 +81,8 @@ char* FAST_FUNC xmalloc_reads(int fd, char *buf, size_t *maxsz_p) p = buf + sz; sz += 128; } - /* nonblock_safe_read() because we are used by e.g. shells */ - if (nonblock_safe_read(fd, p, 1) != 1) { /* EOF/error */ + if (nonblock_immune_read(fd, p, 1, /*loop_on_EINTR:*/ 1) != 1) { + /* EOF/error */ if (p == buf) { /* we read nothing */ free(buf); return NULL; @@ -241,132 +234,3 @@ void* FAST_FUNC xmalloc_xopen_read_close(const char *filename, size_t *maxsz_p) bb_perror_msg_and_die("can't read '%s'", filename); return buf; } - -/* Used by e.g. rpm which gives us a fd without filename, - * thus we can't guess the format from filename's extension. - */ -#if ZIPPED -void FAST_FUNC setup_unzip_on_fd(int fd /*, int fail_if_not_detected*/) -{ - const int fail_if_not_detected = 1; - union { - uint8_t b[4]; - uint16_t b16[2]; - uint32_t b32[1]; - } magic; - int offset = -2; -# if BB_MMU - IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd); - enum { xformer_prog = 0 }; -# else - enum { xformer = 0 }; - const char *xformer_prog; -# endif - - /* .gz and .bz2 both have 2-byte signature, and their - * unpack_XXX_stream wants this header skipped. */ - xread(fd, magic.b16, sizeof(magic.b16[0])); - if (ENABLE_FEATURE_SEAMLESS_GZ - && magic.b16[0] == GZIP_MAGIC - ) { -# if BB_MMU - xformer = unpack_gz_stream; -# else - xformer_prog = "gunzip"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_BZ2 - && magic.b16[0] == BZIP2_MAGIC - ) { -# if BB_MMU - xformer = unpack_bz2_stream; -# else - xformer_prog = "bunzip2"; -# endif - goto found_magic; - } - if (ENABLE_FEATURE_SEAMLESS_XZ - && magic.b16[0] == XZ_MAGIC1 - ) { - offset = -6; - xread(fd, magic.b32, sizeof(magic.b32[0])); - if (magic.b32[0] == XZ_MAGIC2) { -# if BB_MMU - xformer = unpack_xz_stream; - /* unpack_xz_stream wants fd at position 6, no need to seek */ - //xlseek(fd, offset, SEEK_CUR); -# else - xformer_prog = "unxz"; -# endif - goto found_magic; - } - } - - /* No known magic seen */ - if (fail_if_not_detected) - bb_error_msg_and_die("no gzip" - IF_FEATURE_SEAMLESS_BZ2("/bzip2") - IF_FEATURE_SEAMLESS_XZ("/xz") - " magic"); - xlseek(fd, offset, SEEK_CUR); - return; - - found_magic: -# if !BB_MMU - /* NOMMU version of open_transformer execs - * an external unzipper that wants - * file position at the start of the file */ - xlseek(fd, offset, SEEK_CUR); -# endif - open_transformer(fd, xformer, xformer_prog); -} -#endif /* ZIPPED */ - -int FAST_FUNC open_zipped(const char *fname) -{ -#if !ZIPPED - return open(fname, O_RDONLY); -#else - char *sfx; - int fd; - - fd = open(fname, O_RDONLY); - if (fd < 0) - return fd; - - sfx = strrchr(fname, '.'); - if (sfx) { - sfx++; - if (ENABLE_FEATURE_SEAMLESS_LZMA && strcmp(sfx, "lzma") == 0) - /* .lzma has no header/signature, just trust it */ - open_transformer(fd, unpack_lzma_stream, "unlzma"); - else - if ((ENABLE_FEATURE_SEAMLESS_GZ && strcmp(sfx, "gz") == 0) - || (ENABLE_FEATURE_SEAMLESS_BZ2 && strcmp(sfx, "bz2") == 0) - || (ENABLE_FEATURE_SEAMLESS_XZ && strcmp(sfx, "xz") == 0) - ) { - setup_unzip_on_fd(fd /*, fail_if_not_detected: 1*/); - } - } - - return fd; -#endif -} - -void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_p) -{ - int fd; - char *image; - - fd = open_zipped(fname); - 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; -} diff --git a/libbb/recursive_action.c b/libbb/recursive_action.c index 57262cd..b5cf7c0 100644 --- a/libbb/recursive_action.c +++ b/libbb/recursive_action.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/remove_file.c b/libbb/remove_file.c index da14885..5b75f7f 100644 --- a/libbb/remove_file.c +++ b/libbb/remove_file.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Matt Kraai * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -33,7 +33,7 @@ int FAST_FUNC remove_file(const char *path, int flags) int status = 0; if (!(flags & FILEUTILS_RECUR)) { - bb_error_msg("%s: is a directory", path); + bb_error_msg("'%s' is a directory", path); return -1; } diff --git a/libbb/rtc.c b/libbb/rtc.c index fcd6c64..97455e8 100644 --- a/libbb/rtc.c +++ b/libbb/rtc.c @@ -1,7 +1,7 @@ /* * Common RTC functions * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -22,13 +22,6 @@ int FAST_FUNC rtc_adjtime_is_utc(void) char buffer[128]; while (fgets(buffer, sizeof(buffer), f)) { - int len = strlen(buffer); - - while (len && isspace(buffer[len - 1])) - len--; - - buffer[len] = 0; - if (strncmp(buffer, "UTC", 3) == 0) { utc = 1; break; diff --git a/libbb/safe_gethostname.c b/libbb/safe_gethostname.c index 05e0954..cac99ae 100644 --- a/libbb/safe_gethostname.c +++ b/libbb/safe_gethostname.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 Tito Ragusa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -50,25 +50,3 @@ char* FAST_FUNC safe_gethostname(void) uname(&uts); return xstrndup(!uts.nodename[0] ? "?" : uts.nodename, sizeof(uts.nodename)); } - -/* - * On success return the current malloced and NUL terminated domainname. - * On error return malloced and NUL terminated string "?". - * This is an illegal first character for a domainname. - * The returned malloced string must be freed by the caller. - */ -char* FAST_FUNC safe_getdomainname(void) -{ -#if defined(__linux__) -/* The field domainname of struct utsname is Linux specific. */ - struct utsname uts; - uname(&uts); - return xstrndup(!uts.domainname[0] ? "?" : uts.domainname, sizeof(uts.domainname)); -#else - /* We really don't care about people with domain names wider than most screens */ - char buf[256]; - int r = getdomainname(buf, sizeof(buf)); - buf[sizeof(buf)-1] = '\0'; - return xstrdup(r < 0 ? "?" : buf); -#endif -} diff --git a/libbb/safe_poll.c b/libbb/safe_poll.c index 58c7bda..b492a81 100644 --- a/libbb/safe_poll.c +++ b/libbb/safe_poll.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 by Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/safe_strncpy.c b/libbb/safe_strncpy.c index 4acd976..5eb0db0 100644 --- a/libbb/safe_strncpy.c +++ b/libbb/safe_strncpy.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -20,8 +20,13 @@ char* FAST_FUNC safe_strncpy(char *dst, const char *src, size_t size) /* Like strcpy but can copy overlapping strings. */ void FAST_FUNC overlapping_strcpy(char *dst, const char *src) { - while ((*dst = *src) != '\0') { - dst++; - src++; + /* Cheap optimization for dst == src case - + * better to have it here than in many callers. + */ + if (dst != src) { + while ((*dst = *src) != '\0') { + dst++; + src++; + } } } diff --git a/libbb/safe_write.c b/libbb/safe_write.c index e3561f3..8f76280 100644 --- a/libbb/safe_write.c +++ b/libbb/safe_write.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/selinux_common.c b/libbb/selinux_common.c index 7b56967..c258555 100644 --- a/libbb/selinux_common.c +++ b/libbb/selinux_common.c @@ -4,13 +4,13 @@ * * Copyright 2007 KaiGai Kohei * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include context_t FAST_FUNC set_security_context_component(security_context_t cur_context, - char *user, char *role, char *type, char *range) + char *user, char *role, char *type, char *range) { context_t con = context_new(cur_context); if (!con) @@ -53,4 +53,3 @@ void FAST_FUNC selinux_preserve_fcontext(int fdesc) setfscreatecon_or_die(context); freecon(context); } - diff --git a/libbb/setup_environment.c b/libbb/setup_environment.c index a95fbc5..4258656 100644 --- a/libbb/setup_environment.c +++ b/libbb/setup_environment.c @@ -32,11 +32,16 @@ void FAST_FUNC setup_environment(const char *shell, int flags, const struct passwd *pw) { + if (!shell || !shell[0]) + shell = DEFAULT_SHELL; + /* Change the current working directory to be the home directory * of the user */ - if (chdir(pw->pw_dir)) { - xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/"); - bb_error_msg("can't chdir to home directory '%s'", pw->pw_dir); + if (!(flags & SETUP_ENV_NO_CHDIR)) { + if (chdir(pw->pw_dir) != 0) { + bb_error_msg("can't change directory to '%s'", pw->pw_dir); + xchdir((flags & SETUP_ENV_TO_TMP) ? "/tmp" : "/"); + } } if (flags & SETUP_ENV_CLEARENV) { diff --git a/libbb/sha1.c b/libbb/sha1.c deleted file mode 100644 index 5f42532..0000000 --- a/libbb/sha1.c +++ /dev/null @@ -1,480 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * Based on shasum from http://www.netsw.org/crypto/hash/ - * Majorly hacked up to use Dr Brian Gladman's sha1 code - * - * Copyright (C) 2002 Dr Brian Gladman , Worcester, UK. - * Copyright (C) 2003 Glenn L. McGrath - * Copyright (C) 2003 Erik Andersen - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * --------------------------------------------------------------------------- - * Issue Date: 10/11/2002 - * - * This is a byte oriented version of SHA1 that operates on arrays of bytes - * stored in memory. It runs at 22 cycles per byte on a Pentium P4 processor - * - * --------------------------------------------------------------------------- - * - * SHA256 and SHA512 parts are: - * Released into the Public Domain by Ulrich Drepper . - * Shrank by Denys Vlasenko. - * - * --------------------------------------------------------------------------- - * - * The best way to test random blocksizes is to go to coreutils/md5_sha1_sum.c - * and replace "4096" with something like "2000 + time(NULL) % 2097", - * then rebuild and compare "shaNNNsum bigfile" results. - */ - -#include "libbb.h" - -#define rotl32(x,n) (((x) << (n)) | ((x) >> (32 - (n)))) -#define rotr32(x,n) (((x) >> (n)) | ((x) << (32 - (n)))) -/* for sha512: */ -#define rotr64(x,n) (((x) >> (n)) | ((x) << (64 - (n)))) -#if BB_LITTLE_ENDIAN -static inline uint64_t hton64(uint64_t v) -{ - return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); -} -#else -#define hton64(v) (v) -#endif -#define ntoh64(v) hton64(v) - -/* To check alignment gcc has an appropriate operator. Other - compilers don't. */ -#if defined(__GNUC__) && __GNUC__ >= 2 -# define UNALIGNED_P(p,type) (((uintptr_t) p) % __alignof__(type) != 0) -#else -# define UNALIGNED_P(p,type) (((uintptr_t) p) % sizeof(type) != 0) -#endif - - -/* Some arch headers have conflicting defines */ -#undef ch -#undef parity -#undef maj -#undef rnd - -static void FAST_FUNC sha1_process_block64(sha1_ctx_t *ctx) -{ - unsigned t; - uint32_t W[80], a, b, c, d, e; - const uint32_t *words = (uint32_t*) ctx->wbuffer; - - for (t = 0; t < 16; ++t) { - W[t] = ntohl(*words); - words++; - } - - for (/*t = 16*/; t < 80; ++t) { - uint32_t T = W[t - 3] ^ W[t - 8] ^ W[t - 14] ^ W[t - 16]; - W[t] = rotl32(T, 1); - } - - a = ctx->hash[0]; - b = ctx->hash[1]; - c = ctx->hash[2]; - d = ctx->hash[3]; - e = ctx->hash[4]; - -/* Reverse byte order in 32-bit words */ -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define parity(x,y,z) ((x) ^ (y) ^ (z)) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) | (y)))) -/* A normal version as set out in the FIPS. This version uses */ -/* partial loop unrolling and is optimised for the Pentium 4 */ -#define rnd(f,k) \ - do { \ - uint32_t T = a; \ - a = rotl32(a, 5) + f(b, c, d) + e + k + W[t]; \ - e = d; \ - d = c; \ - c = rotl32(b, 30); \ - b = T; \ - } while (0) - - for (t = 0; t < 20; ++t) - rnd(ch, 0x5a827999); - - for (/*t = 20*/; t < 40; ++t) - rnd(parity, 0x6ed9eba1); - - for (/*t = 40*/; t < 60; ++t) - rnd(maj, 0x8f1bbcdc); - - for (/*t = 60*/; t < 80; ++t) - rnd(parity, 0xca62c1d6); -#undef ch -#undef parity -#undef maj -#undef rnd - - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; -} - -/* Constants for SHA512 from FIPS 180-2:4.2.3. - * SHA256 constants from FIPS 180-2:4.2.2 - * are the most significant half of first 64 elements - * of the same array. - */ -static const uint64_t sha_K[80] = { - 0x428a2f98d728ae22ULL, 0x7137449123ef65cdULL, - 0xb5c0fbcfec4d3b2fULL, 0xe9b5dba58189dbbcULL, - 0x3956c25bf348b538ULL, 0x59f111f1b605d019ULL, - 0x923f82a4af194f9bULL, 0xab1c5ed5da6d8118ULL, - 0xd807aa98a3030242ULL, 0x12835b0145706fbeULL, - 0x243185be4ee4b28cULL, 0x550c7dc3d5ffb4e2ULL, - 0x72be5d74f27b896fULL, 0x80deb1fe3b1696b1ULL, - 0x9bdc06a725c71235ULL, 0xc19bf174cf692694ULL, - 0xe49b69c19ef14ad2ULL, 0xefbe4786384f25e3ULL, - 0x0fc19dc68b8cd5b5ULL, 0x240ca1cc77ac9c65ULL, - 0x2de92c6f592b0275ULL, 0x4a7484aa6ea6e483ULL, - 0x5cb0a9dcbd41fbd4ULL, 0x76f988da831153b5ULL, - 0x983e5152ee66dfabULL, 0xa831c66d2db43210ULL, - 0xb00327c898fb213fULL, 0xbf597fc7beef0ee4ULL, - 0xc6e00bf33da88fc2ULL, 0xd5a79147930aa725ULL, - 0x06ca6351e003826fULL, 0x142929670a0e6e70ULL, - 0x27b70a8546d22ffcULL, 0x2e1b21385c26c926ULL, - 0x4d2c6dfc5ac42aedULL, 0x53380d139d95b3dfULL, - 0x650a73548baf63deULL, 0x766a0abb3c77b2a8ULL, - 0x81c2c92e47edaee6ULL, 0x92722c851482353bULL, - 0xa2bfe8a14cf10364ULL, 0xa81a664bbc423001ULL, - 0xc24b8b70d0f89791ULL, 0xc76c51a30654be30ULL, - 0xd192e819d6ef5218ULL, 0xd69906245565a910ULL, - 0xf40e35855771202aULL, 0x106aa07032bbd1b8ULL, - 0x19a4c116b8d2d0c8ULL, 0x1e376c085141ab53ULL, - 0x2748774cdf8eeb99ULL, 0x34b0bcb5e19b48a8ULL, - 0x391c0cb3c5c95a63ULL, 0x4ed8aa4ae3418acbULL, - 0x5b9cca4f7763e373ULL, 0x682e6ff3d6b2b8a3ULL, - 0x748f82ee5defb2fcULL, 0x78a5636f43172f60ULL, - 0x84c87814a1f0ab72ULL, 0x8cc702081a6439ecULL, - 0x90befffa23631e28ULL, 0xa4506cebde82bde9ULL, - 0xbef9a3f7b2c67915ULL, 0xc67178f2e372532bULL, - 0xca273eceea26619cULL, 0xd186b8c721c0c207ULL, /* [64]+ are used for sha512 only */ - 0xeada7dd6cde0eb1eULL, 0xf57d4f7fee6ed178ULL, - 0x06f067aa72176fbaULL, 0x0a637dc5a2c898a6ULL, - 0x113f9804bef90daeULL, 0x1b710b35131c471bULL, - 0x28db77f523047d84ULL, 0x32caab7b40c72493ULL, - 0x3c9ebe0a15c9bebcULL, 0x431d67c49c100d4cULL, - 0x4cc5d4becb3e42b6ULL, 0x597f299cfc657e2aULL, - 0x5fcb6fab3ad6faecULL, 0x6c44198c4a475817ULL -}; - -#undef Ch -#undef Maj -#undef S0 -#undef S1 -#undef R0 -#undef R1 - -static void FAST_FUNC sha256_process_block64(sha256_ctx_t *ctx) -{ - unsigned t; - uint32_t W[64], a, b, c, d, e, f, g, h; - const uint32_t *words = (uint32_t*) ctx->wbuffer; - - /* Operators defined in FIPS 180-2:4.1.2. */ -#define Ch(x, y, z) ((x & y) ^ (~x & z)) -#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) -#define S0(x) (rotr32(x, 2) ^ rotr32(x, 13) ^ rotr32(x, 22)) -#define S1(x) (rotr32(x, 6) ^ rotr32(x, 11) ^ rotr32(x, 25)) -#define R0(x) (rotr32(x, 7) ^ rotr32(x, 18) ^ (x >> 3)) -#define R1(x) (rotr32(x, 17) ^ rotr32(x, 19) ^ (x >> 10)) - - /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ - for (t = 0; t < 16; ++t) { - W[t] = ntohl(*words); - words++; - } - - for (/*t = 16*/; t < 64; ++t) - W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; - - a = ctx->hash[0]; - b = ctx->hash[1]; - c = ctx->hash[2]; - d = ctx->hash[3]; - e = ctx->hash[4]; - f = ctx->hash[5]; - g = ctx->hash[6]; - h = ctx->hash[7]; - - /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ - for (t = 0; t < 64; ++t) { - /* Need to fetch upper half of sha_K[t] - * (I hope compiler is clever enough to just fetch - * upper half) - */ - uint32_t K_t = sha_K[t] >> 32; - uint32_t T1 = h + S1(e) + Ch(e, f, g) + K_t + W[t]; - uint32_t T2 = S0(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - } -#undef Ch -#undef Maj -#undef S0 -#undef S1 -#undef R0 -#undef R1 - /* Add the starting values of the context according to FIPS 180-2:6.2.2 - step 4. */ - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; - ctx->hash[5] += f; - ctx->hash[6] += g; - ctx->hash[7] += h; -} - -static void FAST_FUNC sha512_process_block128(sha512_ctx_t *ctx) -{ - unsigned t; - uint64_t W[80]; - /* On i386, having assignments here (not later as sha256 does) - * produces 99 bytes smaller code with gcc 4.3.1 - */ - uint64_t a = ctx->hash[0]; - uint64_t b = ctx->hash[1]; - uint64_t c = ctx->hash[2]; - uint64_t d = ctx->hash[3]; - uint64_t e = ctx->hash[4]; - uint64_t f = ctx->hash[5]; - uint64_t g = ctx->hash[6]; - uint64_t h = ctx->hash[7]; - const uint64_t *words = (uint64_t*) ctx->wbuffer; - - /* Operators defined in FIPS 180-2:4.1.2. */ -#define Ch(x, y, z) ((x & y) ^ (~x & z)) -#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) -#define S0(x) (rotr64(x, 28) ^ rotr64(x, 34) ^ rotr64(x, 39)) -#define S1(x) (rotr64(x, 14) ^ rotr64(x, 18) ^ rotr64(x, 41)) -#define R0(x) (rotr64(x, 1) ^ rotr64(x, 8) ^ (x >> 7)) -#define R1(x) (rotr64(x, 19) ^ rotr64(x, 61) ^ (x >> 6)) - - /* Compute the message schedule according to FIPS 180-2:6.3.2 step 2. */ - for (t = 0; t < 16; ++t) { - W[t] = ntoh64(*words); - words++; - } - for (/*t = 16*/; t < 80; ++t) - W[t] = R1(W[t - 2]) + W[t - 7] + R0(W[t - 15]) + W[t - 16]; - - /* The actual computation according to FIPS 180-2:6.3.2 step 3. */ - for (t = 0; t < 80; ++t) { - uint64_t T1 = h + S1(e) + Ch(e, f, g) + sha_K[t] + W[t]; - uint64_t T2 = S0(a) + Maj(a, b, c); - h = g; - g = f; - f = e; - e = d + T1; - d = c; - c = b; - b = a; - a = T1 + T2; - } -#undef Ch -#undef Maj -#undef S0 -#undef S1 -#undef R0 -#undef R1 - /* Add the starting values of the context according to FIPS 180-2:6.3.2 - step 4. */ - ctx->hash[0] += a; - ctx->hash[1] += b; - ctx->hash[2] += c; - ctx->hash[3] += d; - ctx->hash[4] += e; - ctx->hash[5] += f; - ctx->hash[6] += g; - ctx->hash[7] += h; -} - - -void FAST_FUNC sha1_begin(sha1_ctx_t *ctx) -{ - ctx->hash[0] = 0x67452301; - ctx->hash[1] = 0xefcdab89; - ctx->hash[2] = 0x98badcfe; - ctx->hash[3] = 0x10325476; - ctx->hash[4] = 0xc3d2e1f0; - ctx->total64 = 0; - ctx->process_block = sha1_process_block64; -} - -static const uint32_t init256[] = { - 0x6a09e667, - 0xbb67ae85, - 0x3c6ef372, - 0xa54ff53a, - 0x510e527f, - 0x9b05688c, - 0x1f83d9ab, - 0x5be0cd19 -}; -static const uint32_t init512_lo[] = { - 0xf3bcc908, - 0x84caa73b, - 0xfe94f82b, - 0x5f1d36f1, - 0xade682d1, - 0x2b3e6c1f, - 0xfb41bd6b, - 0x137e2179 -}; - -/* Initialize structure containing state of computation. - (FIPS 180-2:5.3.2) */ -void FAST_FUNC sha256_begin(sha256_ctx_t *ctx) -{ - memcpy(ctx->hash, init256, sizeof(init256)); - ctx->total64 = 0; - ctx->process_block = sha256_process_block64; -} - -/* Initialize structure containing state of computation. - (FIPS 180-2:5.3.3) */ -void FAST_FUNC sha512_begin(sha512_ctx_t *ctx) -{ - int i; - for (i = 0; i < 8; i++) - ctx->hash[i] = ((uint64_t)(init256[i]) << 32) + init512_lo[i]; - ctx->total64[0] = ctx->total64[1] = 0; -} - - -/* Used also for sha256 */ -void FAST_FUNC sha1_hash(const void *buffer, size_t len, sha1_ctx_t *ctx) -{ - unsigned in_buf = ctx->total64 & 63; - unsigned add = 64 - in_buf; - - ctx->total64 += len; - - while (len >= add) { /* transfer whole blocks while possible */ - memcpy(ctx->wbuffer + in_buf, buffer, add); - buffer = (const char *)buffer + add; - len -= add; - add = 64; - in_buf = 0; - ctx->process_block(ctx); - } - - memcpy(ctx->wbuffer + in_buf, buffer, len); -} - -void FAST_FUNC sha512_hash(const void *buffer, size_t len, sha512_ctx_t *ctx) -{ - unsigned in_buf = ctx->total64[0] & 127; - unsigned add = 128 - in_buf; - - /* First increment the byte count. FIPS 180-2 specifies the possible - length of the file up to 2^128 _bits_. - We compute the number of _bytes_ and convert to bits later. */ - ctx->total64[0] += len; - if (ctx->total64[0] < len) - ctx->total64[1]++; - - while (len >= add) { /* transfer whole blocks while possible */ - memcpy(ctx->wbuffer + in_buf, buffer, add); - buffer = (const char *)buffer + add; - len -= add; - add = 128; - in_buf = 0; - sha512_process_block128(ctx); - } - - memcpy(ctx->wbuffer + in_buf, buffer, len); -} - - -/* Used also for sha256 */ -void FAST_FUNC sha1_end(void *resbuf, sha1_ctx_t *ctx) -{ - unsigned pad, in_buf; - - in_buf = ctx->total64 & 63; - /* Pad the buffer to the next 64-byte boundary with 0x80,0,0,0... */ - ctx->wbuffer[in_buf++] = 0x80; - - /* This loop iterates either once or twice, no more, no less */ - while (1) { - pad = 64 - in_buf; - memset(ctx->wbuffer + in_buf, 0, pad); - in_buf = 0; - /* Do we have enough space for the length count? */ - if (pad >= 8) { - /* Store the 64-bit counter of bits in the buffer in BE format */ - uint64_t t = ctx->total64 << 3; - t = hton64(t); - /* wbuffer is suitably aligned for this */ - *(uint64_t *) (&ctx->wbuffer[64 - 8]) = t; - } - ctx->process_block(ctx); - if (pad >= 8) - break; - } - - in_buf = (ctx->process_block == sha1_process_block64) ? 5 : 8; - /* This way we do not impose alignment constraints on resbuf: */ - if (BB_LITTLE_ENDIAN) { - unsigned i; - for (i = 0; i < in_buf; ++i) - ctx->hash[i] = htonl(ctx->hash[i]); - } - memcpy(resbuf, ctx->hash, sizeof(ctx->hash[0]) * in_buf); -} - -void FAST_FUNC sha512_end(void *resbuf, sha512_ctx_t *ctx) -{ - unsigned pad, in_buf; - - in_buf = ctx->total64[0] & 127; - /* Pad the buffer to the next 128-byte boundary with 0x80,0,0,0... - * (FIPS 180-2:5.1.2) - */ - ctx->wbuffer[in_buf++] = 0x80; - - while (1) { - pad = 128 - in_buf; - memset(ctx->wbuffer + in_buf, 0, pad); - in_buf = 0; - if (pad >= 16) { - /* Store the 128-bit counter of bits in the buffer in BE format */ - uint64_t t; - t = ctx->total64[0] << 3; - t = hton64(t); - *(uint64_t *) (&ctx->wbuffer[128 - 8]) = t; - t = (ctx->total64[1] << 3) | (ctx->total64[0] >> 61); - t = hton64(t); - *(uint64_t *) (&ctx->wbuffer[128 - 16]) = t; - } - sha512_process_block128(ctx); - if (pad >= 16) - break; - } - - if (BB_LITTLE_ENDIAN) { - unsigned i; - for (i = 0; i < ARRAY_SIZE(ctx->hash); ++i) - ctx->hash[i] = hton64(ctx->hash[i]); - } - memcpy(resbuf, ctx->hash, sizeof(ctx->hash)); -} diff --git a/libbb/signals.c b/libbb/signals.c index a528756..5651247 100644 --- a/libbb/signals.c +++ b/libbb/signals.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Rob Landley * Copyright (C) 2006 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -39,7 +39,7 @@ void FAST_FUNC bb_signals(int sigs, void (*f)(int)) while (sigs) { if (sigs & bit) { - sigs &= ~bit; + sigs -= bit; signal(sig_no, f); } sig_no++; @@ -60,7 +60,7 @@ void FAST_FUNC bb_signals_recursive_norestart(int sigs, void (*f)(int)) while (sigs) { if (sigs & bit) { - sigs &= ~bit; + sigs -= bit; sigaction_set(sig_no, &sa); } sig_no++; @@ -97,7 +97,7 @@ void FAST_FUNC kill_myself_with_sig(int sig) signal(sig, SIG_DFL); sig_unblock(sig); raise(sig); - _exit(EXIT_FAILURE); /* Should not reach it */ + _exit(sig | 128); /* Should not reach it */ } void FAST_FUNC signal_SA_RESTART_empty_mask(int sig, void (*handler)(int)) diff --git a/libbb/simplify_path.c b/libbb/simplify_path.c index f80e3e8..89dc5bd 100644 --- a/libbb/simplify_path.c +++ b/libbb/simplify_path.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -15,17 +15,17 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) p = s = start; do { if (*p == '/') { - if (*s == '/') { /* skip duplicate (or initial) slash */ + if (*s == '/') { /* skip duplicate (or initial) slash */ continue; } if (*s == '.') { - if (s[1] == '/' || !s[1]) { /* remove extra '.' */ + if (s[1] == '/' || !s[1]) { /* remove extra '.' */ continue; } if ((s[1] == '.') && (s[2] == '/' || !s[2])) { ++s; if (p > start) { - while (*--p != '/') /* omit previous dir */ + while (*--p != '/') /* omit previous dir */ continue; } continue; @@ -35,8 +35,8 @@ char* FAST_FUNC bb_simplify_abs_path_inplace(char *start) *++p = *s; } while (*++s); - if ((p == start) || (*p != '/')) { /* not a trailing slash */ - ++p; /* so keep last character */ + if ((p == start) || (*p != '/')) { /* not a trailing slash */ + ++p; /* so keep last character */ } *p = '\0'; return p; diff --git a/libbb/single_argv.c b/libbb/single_argv.c index 6173c88..64844dd 100644 --- a/libbb/single_argv.c +++ b/libbb/single_argv.c @@ -4,12 +4,14 @@ * * Copyright (C) 2009 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" char* FAST_FUNC single_argv(char **argv) { + if (argv[1] && strcmp(argv[1], "--") == 0) + argv++; if (!argv[1] || argv[2]) bb_show_usage(); return argv[1]; diff --git a/libbb/skip_whitespace.c b/libbb/skip_whitespace.c index f5a61a3..8c7b674 100644 --- a/libbb/skip_whitespace.c +++ b/libbb/skip_whitespace.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/speed_table.c b/libbb/speed_table.c index af676e1..45159f1 100644 --- a/libbb/speed_table.c +++ b/libbb/speed_table.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -29,12 +29,12 @@ static const struct speed_map speeds[] = { {B2400, 2400}, {B4800, 4800}, {B9600, 9600}, -#ifdef B19200 +#ifdef B19200 {B19200, 19200}, #elif defined(EXTA) {EXTA, 19200}, #endif -#ifdef B38400 +#ifdef B38400 {B38400, 38400/256 + 0x8000U}, #elif defined(EXTB) {EXTB, 38400/256 + 0x8000U}, diff --git a/libbb/str_tolower.c b/libbb/str_tolower.c index f402e8e..c2d5637 100644 --- a/libbb/str_tolower.c +++ b/libbb/str_tolower.c @@ -1,7 +1,7 @@ /* vi set: sw=4 ts=4: */ /* Convert string str to lowercase, return str. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/strrstr.c b/libbb/strrstr.c index a803dd9..d8823fc 100644 --- a/libbb/strrstr.c +++ b/libbb/strrstr.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifdef __DO_STRRSTR_TEST diff --git a/libbb/systemd_support.c b/libbb/systemd_support.c new file mode 100644 index 0000000..542a3ef --- /dev/null +++ b/libbb/systemd_support.c @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2011 Davide Cavalca + * + * Based on http://cgit.freedesktop.org/systemd/tree/src/sd-daemon.c + * Copyright 2010 Lennart Poettering + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation files + * (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, + * publish, distribute, sublicense, and/or sell copies of the Software, + * and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +#include "libbb.h" + +//config:config FEATURE_SYSTEMD +//config: bool "Enable systemd support" +//config: default y +//config: help +//config: If you plan to use busybox daemons on a system where daemons +//config: are controlled by systemd, enable this option. +//config: If you don't use systemd, it is still safe to enable it, +//config: but the downside is increased code size. + +//kbuild:lib-$(CONFIG_FEATURE_SYSTEMD) += systemd_support.o + +int sd_listen_fds(void) +{ + const char *e; + int n; + int fd; + + e = getenv("LISTEN_PID"); + if (!e) + return 0; + n = xatoi_positive(e); + /* Is this for us? */ + if (getpid() != (pid_t) n) + return 0; + + e = getenv("LISTEN_FDS"); + if (!e) + return 0; + n = xatoi_positive(e); + for (fd = SD_LISTEN_FDS_START; fd < SD_LISTEN_FDS_START + n; fd++) + close_on_exec_on(fd); + + return n; +} diff --git a/libbb/time.c b/libbb/time.c index 8d176e5..ea2f72e 100644 --- a/libbb/time.c +++ b/libbb/time.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -23,14 +23,16 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) if (sscanf(date_str, "%u:%u%c", &ptm->tm_hour, &ptm->tm_min, - &end) >= 2) { + &end) >= 2 + ) { /* no adjustments needed */ } else /* mm.dd-HH:MM */ if (sscanf(date_str, "%u.%u-%u:%u%c", &ptm->tm_mon, &ptm->tm_mday, &ptm->tm_hour, &ptm->tm_min, - &end) >= 4) { + &end) >= 4 + ) { /* Adjust month from 1-12 to 0-11 */ ptm->tm_mon -= 1; } else @@ -38,15 +40,13 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) if (sscanf(date_str, "%u.%u.%u-%u:%u%c", &ptm->tm_year, &ptm->tm_mon, &ptm->tm_mday, &ptm->tm_hour, &ptm->tm_min, - &end) >= 5) { - ptm->tm_year -= 1900; /* Adjust years */ - ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ - } else + &end) >= 5 /* yyyy-mm-dd HH:MM */ - if (sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year, + || sscanf(date_str, "%u-%u-%u %u:%u%c", &ptm->tm_year, &ptm->tm_mon, &ptm->tm_mday, &ptm->tm_hour, &ptm->tm_min, - &end) >= 5) { + &end) >= 5 + ) { ptm->tm_year -= 1900; /* Adjust years */ ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ } else @@ -58,7 +58,6 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) return; /* don't fall through to end == ":" check */ } else #endif -//TODO: coreutils 6.9 also accepts "yyyy-mm-dd HH" (no minutes) { bb_error_msg_and_die(bb_msg_invalid_date, date_str); } @@ -68,7 +67,21 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) end = '\0'; /* else end != NUL and we error out */ } - } else if (date_str[0] == '@') { + } else + /* yyyy-mm-dd HH */ + if (sscanf(date_str, "%u-%u-%u %u%c", &ptm->tm_year, + &ptm->tm_mon, &ptm->tm_mday, + &ptm->tm_hour, + &end) >= 4 + /* yyyy-mm-dd */ + || sscanf(date_str, "%u-%u-%u%c", &ptm->tm_year, + &ptm->tm_mon, &ptm->tm_mday, + &end) >= 3 + ) { + ptm->tm_year -= 1900; /* Adjust years */ + ptm->tm_mon -= 1; /* Adjust month from 1-12 to 0-11 */ + } else + if (date_str[0] == '@') { time_t t = bb_strtol(date_str + 1, NULL, 10); if (!errno) { struct tm *lt = localtime(&t); @@ -91,8 +104,15 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) * .SS Seconds, a number from 0 to 61 (with leap seconds) * Everything but the minutes is optional * - * This coincides with the format of "touch -t TIME" + * "touch -t DATETIME" format: [[[[[YY]YY]MM]DD]hh]mm[.ss] + * Some, but not all, Unix "date DATETIME" commands + * move [[YY]YY] past minutes mm field (!). + * Coreutils date does it, and SUS mandates it. + * (date -s DATETIME does not support this format. lovely!) + * In bbox, this format is special-cased in date applet + * (IOW: this function assumes "touch -t" format). */ + unsigned cur_year = ptm->tm_year; int len = strchrnul(date_str, '.') - date_str; /* MM[.SS] */ @@ -133,6 +153,17 @@ void FAST_FUNC parse_datestr(const char *date_str, struct tm *ptm) &end) >= 5) { /* Adjust month from 1-12 to 0-11 */ ptm->tm_mon -= 1; + if ((int)cur_year >= 50) { /* >= 1950 */ + /* Adjust year: */ + /* 1. Put it in the current century */ + ptm->tm_year += (cur_year / 100) * 100; + /* 2. If too far in the past, +100 years */ + if (ptm->tm_year < cur_year - 50) + ptm->tm_year += 100; + /* 3. If too far in the future, -100 years */ + if (ptm->tm_year > cur_year + 50) + ptm->tm_year -= 100; + } } else /* ccyymmddHHMM[.SS] */ if (len == 12 && sscanf(date_str, "%4u%2u%2u%2u%2u%c", @@ -169,6 +200,27 @@ time_t FAST_FUNC validate_tm_time(const char *date_str, struct tm *ptm) return t; } +static char* strftime_fmt(char *buf, unsigned len, time_t *tp, const char *fmt) +{ + time_t t; + if (!tp) { + tp = &t; + time(tp); + } + /* Returns pointer to NUL */ + return buf + strftime(buf, len, fmt, localtime(tp)); +} + +char* FAST_FUNC strftime_HHMMSS(char *buf, unsigned len, time_t *tp) +{ + return strftime_fmt(buf, len, tp, "%H:%M:%S"); +} + +char* FAST_FUNC strftime_YYYYMMDDHHMMSS(char *buf, unsigned len, time_t *tp) +{ + return strftime_fmt(buf, len, tp, "%Y-%m-%d %H:%M:%S"); +} + #if ENABLE_MONOTONIC_SYSCALL #include diff --git a/libbb/trim.c b/libbb/trim.c index df00b84..16cb4fb 100644 --- a/libbb/trim.c +++ b/libbb/trim.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/u_signal_names.c b/libbb/u_signal_names.c index 915eea5..8c78f5e 100644 --- a/libbb/u_signal_names.c +++ b/libbb/u_signal_names.c @@ -4,9 +4,16 @@ * * Copyright 2006 Rob Landley * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config FEATURE_RTMINMAX +//config: bool "Support RTMIN[+n] and RTMAX[-n] signal names" +//config: default y +//config: help +//config: Support RTMIN[+n] and RTMAX[-n] signal names +//config: in kill, killall etc. This costs ~250 bytes. + #include "libbb.h" /* Believe it or not, but some arches have more than 32 SIGs! @@ -117,6 +124,16 @@ static const char signals[][7] = { #ifdef SIGSYS [SIGSYS ] = "SYS", #endif +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMIN + [__SIGRTMIN] = "RTMIN", +# endif +// This makes array about x2 bigger. +// More compact approach is to special-case SIGRTMAX in print_signames() +//# ifdef __SIGRTMAX +// [__SIGRTMAX] = "RTMAX", +//# endif +#endif }; // Convert signal name to number. @@ -134,20 +151,54 @@ int FAST_FUNC get_signum(const char *name) if (strcasecmp(name, signals[i]) == 0) return i; -#if ENABLE_DESKTOP && (defined(SIGIOT) || defined(SIGIO)) +#if ENABLE_DESKTOP +# if defined(SIGIOT) || defined(SIGIO) /* SIGIO[T] are aliased to other names, * thus cannot be stored in the signals[] array. * Need special code to recognize them */ if ((name[0] | 0x20) == 'i' && (name[1] | 0x20) == 'o') { -#ifdef SIGIO +# ifdef SIGIO if (!name[2]) return SIGIO; -#endif -#ifdef SIGIOT +# endif +# ifdef SIGIOT if ((name[2] | 0x20) == 't' && !name[3]) return SIGIOT; -#endif +# endif } +# endif +#endif + +#if ENABLE_FEATURE_RTMINMAX +# if defined(SIGRTMIN) && defined(SIGRTMAX) +/* libc may use some rt sigs for pthreads and therefore "remap" SIGRTMIN/MAX, + * but we want to use "raw" SIGRTMIN/MAX. Underscored names, if exist, provide + * them. If they don't exist, fall back to non-underscored ones: */ +# if !defined(__SIGRTMIN) +# define __SIGRTMIN SIGRTMIN +# endif +# if !defined(__SIGRTMAX) +# define __SIGRTMAX SIGRTMAX +# endif + if (strncasecmp(name, "RTMIN", 5) == 0) { + if (!name[5]) + return __SIGRTMIN; + if (name[5] == '+') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMIN + i; + } + } + else if (strncasecmp(name, "RTMAX", 5) == 0) { + if (!name[5]) + return __SIGRTMAX; + if (name[5] == '-') { + i = bb_strtou(name + 6, NULL, 10); + if (!errno && i <= __SIGRTMAX - __SIGRTMIN) + return __SIGRTMAX - i; + } + } +# endif #endif return -1; @@ -175,6 +226,11 @@ void FAST_FUNC print_signames(void) for (signo = 1; signo < ARRAY_SIZE(signals); signo++) { const char *name = signals[signo]; if (name[0]) - puts(name); + printf("%2u) %s\n", signo, name); } +#if ENABLE_FEATURE_RTMINMAX +# ifdef __SIGRTMAX + printf("%2u) %s\n", __SIGRTMAX, "RTMAX"); +# endif +#endif } diff --git a/libbb/udp_io.c b/libbb/udp_io.c index 24237be..7985a97 100644 --- a/libbb/udp_io.c +++ b/libbb/udp_io.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -13,7 +13,7 @@ * We don't check for errors here. Not supported == won't be used */ void FAST_FUNC -socket_want_pktinfo(int fd) +socket_want_pktinfo(int fd UNUSED_PARAM) { #ifdef IP_PKTINFO setsockopt(fd, IPPROTO_IP, IP_PKTINFO, &const_int_1, sizeof(int)); diff --git a/libbb/unicode.c b/libbb/unicode.c index d6fcf7a..9c4da50 100644 --- a/libbb/unicode.c +++ b/libbb/unicode.c @@ -4,7 +4,7 @@ * * Copyright (C) 2009 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include "unicode.h" @@ -23,37 +23,66 @@ uint8_t unicode_status; /* Unicode support using libc locale support. */ -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG) { static const char unicode_0x394[] = { 0xce, 0x94, 0 }; size_t width; - if (unicode_status != UNICODE_UNKNOWN) - return; + /* We pass "" instead of "C" because some libc's have + * non-ASCII default locale for setlocale("") call + * (this allows users of such libc to have Unicoded + * system without having to mess with env). + * + * We set LC_CTYPE because (a) we may be called with $LC_CTYPE + * value in LANG, not with $LC_ALL, (b) internationalized + * LC_NUMERIC and LC_TIME are more PITA than benefit + * (for one, some utilities have hard time with comma + * used as a fractional separator). + */ +//TODO: avoid repeated calls by caching last string? + setlocale(LC_CTYPE, LANG ? LANG : ""); + /* In unicode, this is a one character string */ -// can use unicode_strlen(string) too, but otherwise unicode_strlen() is unused - width = mbstowcs(NULL, unicode_0x394, INT_MAX); + width = unicode_strlen(unicode_0x394); unicode_status = (width == 1 ? UNICODE_ON : UNICODE_OFF); } +void FAST_FUNC init_unicode(void) +{ + /* Some people set only $LC_CTYPE, not $LC_ALL, because they want + * only Unicode to be activated on their system, not the whole + * shebang of wrong decimal points, strange date formats and so on. + */ + if (unicode_status == UNICODE_UNKNOWN) { + char *s = getenv("LC_ALL"); + if (!s) s = getenv("LC_CTYPE"); + if (!s) s = getenv("LANG"); + reinit_unicode(s); + } +} + #else /* Homegrown Unicode support. It knows only C and Unicode locales. */ # if ENABLE_FEATURE_CHECK_UNICODE_IN_ENV -void FAST_FUNC init_unicode(void) +void FAST_FUNC reinit_unicode(const char *LANG) { - char *lang; - - if (unicode_status != UNICODE_UNKNOWN) - return; - unicode_status = UNICODE_OFF; - lang = getenv("LANG"); - if (!lang || !(strstr(lang, ".utf") || strstr(lang, ".UTF"))) + if (!LANG || !(strstr(LANG, ".utf") || strstr(LANG, ".UTF"))) return; unicode_status = UNICODE_ON; } + +void FAST_FUNC init_unicode(void) +{ + if (unicode_status == UNICODE_UNKNOWN) { + char *s = getenv("LC_ALL"); + if (!s) s = getenv("LC_CTYPE"); + if (!s) s = getenv("LANG"); + reinit_unicode(s); + } +} # endif static size_t wcrtomb_internal(char *s, wchar_t wc) @@ -131,7 +160,7 @@ size_t FAST_FUNC wcstombs(char *dest, const wchar_t *src, size_t n) size_t len = wcrtomb_internal(tbuf, wc); if (len > n) - len = n; + break; memcpy(dest, tbuf, len); if (wc == L'\0') return org_n - n; @@ -956,7 +985,6 @@ int FAST_FUNC unicode_bidi_is_neutral_wchar(wint_t wc) /* The rest is mostly same for libc and for "homegrown" support */ -#if 0 // UNUSED size_t FAST_FUNC unicode_strlen(const char *string) { size_t width = mbstowcs(NULL, string, INT_MAX); @@ -964,7 +992,6 @@ size_t FAST_FUNC unicode_strlen(const char *string) return strlen(string); return width; } -#endif size_t FAST_FUNC unicode_strwidth(const char *string) { @@ -1005,8 +1032,11 @@ static char* FAST_FUNC unicode_conv_to_printable2(uni_stat_t *stats, const char d++; } } - if (stats) - stats->byte_count = stats->unicode_count = (d - dst); + if (stats) { + stats->byte_count = (d - dst); + stats->unicode_count = (d - dst); + stats->unicode_width = (d - dst); + } return dst; } @@ -1104,16 +1134,17 @@ char* FAST_FUNC unicode_conv_to_printable(uni_stat_t *stats, const char *src) { return unicode_conv_to_printable2(stats, src, INT_MAX, 0); } -char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth) +char* FAST_FUNC unicode_conv_to_printable_fixedwidth(/*uni_stat_t *stats,*/ const char *src, unsigned width) { - return unicode_conv_to_printable2(stats, src, maxwidth, 0); + return unicode_conv_to_printable2(/*stats:*/ NULL, src, width, UNI_FLAG_PAD); } -char* FAST_FUNC unicode_conv_to_printable_fixedwidth(uni_stat_t *stats, const char *src, unsigned width) + +#ifdef UNUSED +char* FAST_FUNC unicode_conv_to_printable_maxwidth(uni_stat_t *stats, const char *src, unsigned maxwidth) { - return unicode_conv_to_printable2(stats, src, width, UNI_FLAG_PAD); + return unicode_conv_to_printable2(stats, src, maxwidth, 0); } -#ifdef UNUSED unsigned FAST_FUNC unicode_padding_to_width(unsigned width, const char *src) { if (unicode_status != UNICODE_ON) { diff --git a/libbb/update_passwd.c b/libbb/update_passwd.c index f5ce1f9..a30af6f 100644 --- a/libbb/update_passwd.c +++ b/libbb/update_passwd.c @@ -11,7 +11,7 @@ * Modified to be able to add or delete users, groups and users to/from groups * by Tito Ragusa * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -22,7 +22,7 @@ static void check_selinux_update_passwd(const char *username) char *seuser; if (getuid() != (uid_t)0 || is_selinux_enabled() == 0) - return; /* No need to check */ + return; /* No need to check */ if (getprevcon_raw(&context) < 0) bb_perror_msg_and_die("getprevcon failed"); @@ -58,7 +58,7 @@ static void check_selinux_update_passwd(const char *username) 6) delete a user from a group: update_passwd(FILE, GROUP, NULL, MEMBER) only if CONFIG_FEATURE_DEL_USER_FROM_GROUP=y and member != NULL - 7) change user's passord: update_passwd(FILE, USER, NEW_PASSWD, NULL) + 7) change user's password: update_passwd(FILE, USER, NEW_PASSWD, NULL) only if CONFIG_PASSWD=y and applet_name[0] == 'p' like in passwd or if CONFIG_CHPASSWD=y and applet_name[0] == 'c' like in chpasswd @@ -133,7 +133,7 @@ int FAST_FUNC update_passwd(const char *filename, goto close_old_fp; created: - if (!fstat(old_fd, &sb)) { + if (fstat(old_fd, &sb) == 0) { fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ fchown(new_fd, sb.st_uid, sb.st_gid); } diff --git a/libbb/utmp.c b/libbb/utmp.c index 68c358e..09443fb 100644 --- a/libbb/utmp.c +++ b/libbb/utmp.c @@ -4,10 +4,9 @@ * * Copyright (C) 2010 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" -#include static void touch(const char *filename) { diff --git a/libbb/uuencode.c b/libbb/uuencode.c index 67d98d5..f7b2484 100644 --- a/libbb/uuencode.c +++ b/libbb/uuencode.c @@ -1,14 +1,16 @@ /* vi: set sw=4 ts=4: */ /* - * Copyright 2006 Rob Landley + * Copyright 2003, Glenn McGrath + * Copyright 2006, Rob Landley + * Copyright 2010, Denys Vlasenko * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" /* Conversion table. for base 64 */ -const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { +const char bb_uuenc_tbl_base64[65 + 1] ALIGN1 = { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', @@ -18,7 +20,7 @@ const char bb_uuenc_tbl_base64[65 + 2] ALIGN1 = { 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '=' /* termination character */, - '\n', '\0' /* needed for uudecode.c */ + '\0' /* needed for uudecode.c only */ }; const char bb_uuenc_tbl_std[65] ALIGN1 = { @@ -69,3 +71,154 @@ void FAST_FUNC bb_uuencode(char *p, const void *src, int length, const char *tbl length++; } } + +/* + * Decode base64 encoded string. Stops on '\0'. + * + * Returns: pointer to the undecoded part of source. + * If points to '\0', then the source was fully decoded. + * (*pp_dst): advanced past the last written byte. + */ +const char* FAST_FUNC decode_base64(char **pp_dst, const char *src) +{ + char *dst = *pp_dst; + const char *src_tail; + + while (1) { + unsigned char six_bit[4]; + int count = 0; + + /* Fetch up to four 6-bit values */ + src_tail = src; + while (count < 4) { + char *table_ptr; + int ch; + + /* Get next _valid_ character. + * bb_uuenc_tbl_base64[] contains this string: + * 0 1 2 3 4 5 6 + * 01234567890123456789012345678901234567890123456789012345678901234 + * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=" + */ + do { + ch = *src; + if (ch == '\0') { + if (count == 0) { + /* Example: + * If we decode "QUJD ", we want + * to return ptr to NUL, not to ' ', + * because we did fully decode + * the string (to "ABC"). + */ + src_tail = src; + } + goto ret; + } + src++; + table_ptr = strchr(bb_uuenc_tbl_base64, ch); +//TODO: add BASE64_FLAG_foo to die on bad char? + } while (!table_ptr); + + /* Convert encoded character to decimal */ + ch = table_ptr - bb_uuenc_tbl_base64; + + /* ch is 64 if char was '=', otherwise 0..63 */ + if (ch == 64) + break; + six_bit[count] = ch; + count++; + } + + /* Transform 6-bit values to 8-bit ones. + * count can be < 4 when we decode the tail: + * "eQ==" -> "y", not "y NUL NUL". + * Note that (count > 1) is always true, + * "x===" encoding is not valid: + * even a single zero byte encodes as "AA==". + * However, with current logic we come here with count == 1 + * when we decode "==" tail. + */ + if (count > 1) + *dst++ = six_bit[0] << 2 | six_bit[1] >> 4; + if (count > 2) + *dst++ = six_bit[1] << 4 | six_bit[2] >> 2; + if (count > 3) + *dst++ = six_bit[2] << 6 | six_bit[3]; + /* Note that if we decode "AA==" and ate first '=', + * we just decoded one char (count == 2) and now we'll + * do the loop once more to decode second '='. + */ + } /* while (1) */ + ret: + *pp_dst = dst; + return src_tail; +} + +/* + * Decode base64 encoded stream. + * Can stop on EOF, specified char, or on uuencode-style "====" line: + * flags argument controls it. + */ +void FAST_FUNC read_base64(FILE *src_stream, FILE *dst_stream, int flags) +{ +/* Note that EOF _can_ be passed as exit_char too */ +#define exit_char ((int)(signed char)flags) +#define uu_style_end (flags & BASE64_FLAG_UU_STOP) + + /* uuencoded files have 61 byte lines. Use 64 byte buffer + * to process line at a time. + */ + enum { BUFFER_SIZE = 64 }; + + char in_buf[BUFFER_SIZE + 2]; + char out_buf[BUFFER_SIZE / 4 * 3 + 2]; + char *out_tail; + const char *in_tail; + int term_seen = 0; + int in_count = 0; + + while (1) { + while (in_count < BUFFER_SIZE) { + int ch = fgetc(src_stream); + if (ch == exit_char) { + if (in_count == 0) + return; + term_seen = 1; + break; + } + if (ch == EOF) { + term_seen = 1; + break; + } + /* Prevent "====" line to be split: stop if we see '\n'. + * We can also skip other whitespace and skirt the problem + * of files with NULs by stopping on any control char or space: + */ + if (ch <= ' ') + break; + in_buf[in_count++] = ch; + } + in_buf[in_count] = '\0'; + + /* Did we encounter "====" line? */ + if (uu_style_end && strcmp(in_buf, "====") == 0) + return; + + out_tail = out_buf; + in_tail = decode_base64(&out_tail, in_buf); + + fwrite(out_buf, (out_tail - out_buf), 1, dst_stream); + + if (term_seen) { + /* Did we consume ALL characters? */ + if (*in_tail == '\0') + return; + /* No */ + bb_error_msg_and_die("truncated base64 input"); + } + + /* It was partial decode */ + in_count = strlen(in_tail); + memmove(in_buf, in_tail, in_count); + } +} diff --git a/libbb/vdprintf.c b/libbb/vdprintf.c index 09fffbc..0542687 100644 --- a/libbb/vdprintf.c +++ b/libbb/vdprintf.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -12,10 +12,10 @@ #if defined(__GLIBC__) && __GLIBC__ < 2 int FAST_FUNC vdprintf(int d, const char *format, va_list ap) { - char buf[BUF_SIZE]; + char buf[8 * 1024]; int len; - len = vsnprintf(buf, BUF_SIZE, format, ap); + len = vsnprintf(buf, sizeof(buf), format, ap); return write(d, buf, len); } #endif diff --git a/libbb/verror_msg.c b/libbb/verror_msg.c index c5fbc38..ee95be3 100644 --- a/libbb/verror_msg.c +++ b/libbb/verror_msg.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #if ENABLE_FEATURE_SYSLOG diff --git a/libbb/vfork_daemon_rexec.c b/libbb/vfork_daemon_rexec.c index 5c2c529..ed1f86f 100644 --- a/libbb/vfork_daemon_rexec.c +++ b/libbb/vfork_daemon_rexec.c @@ -12,7 +12,7 @@ * * Modified for uClibc by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "busybox.h" /* uses applet tables */ @@ -52,6 +52,7 @@ pid_t FAST_FUNC spawn(char **argv) * Interested party can wait on pid and learn exit code. * If 111 - then it (most probably) failed to exec */ if (failed) { + safe_waitpid(pid, NULL, 0); /* prevent zombie */ errno = failed; return -1; } @@ -68,17 +69,22 @@ pid_t FAST_FUNC xspawn(char **argv) } #if ENABLE_FEATURE_PREFER_APPLETS -void FAST_FUNC save_nofork_data(struct nofork_save_area *save) +struct nofork_save_area { + jmp_buf die_jmp; + const char *applet_name; + uint32_t option_mask32; + int die_sleep; + uint8_t xfunc_error_retval; +}; +static void save_nofork_data(struct nofork_save_area *save) { memcpy(&save->die_jmp, &die_jmp, sizeof(die_jmp)); save->applet_name = applet_name; save->xfunc_error_retval = xfunc_error_retval; save->option_mask32 = option_mask32; save->die_sleep = die_sleep; - save->saved = 1; } - -void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) +static void restore_nofork_data(struct nofork_save_area *save) { memcpy(&die_jmp, &save->die_jmp, sizeof(die_jmp)); applet_name = save->applet_name; @@ -87,19 +93,17 @@ void FAST_FUNC restore_nofork_data(struct nofork_save_area *save) die_sleep = save->die_sleep; } -int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_no, char **argv) +int FAST_FUNC run_nofork_applet(int applet_no, char **argv) { int rc, argc; + struct nofork_save_area old; + + save_nofork_data(&old); applet_name = APPLET_NAME(applet_no); xfunc_error_retval = EXIT_FAILURE; - /* Special flag for xfunc_die(). If xfunc will "die" - * in NOFORK applet, xfunc_die() sees negative - * die_sleep and longjmp here instead. */ - die_sleep = -1; - /* In case getopt() or getopt32() was already called: * reset the libc getopt() function, which keeps internal state. * @@ -129,6 +133,11 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n while (argv[argc]) argc++; + /* Special flag for xfunc_die(). If xfunc will "die" + * in NOFORK applet, xfunc_die() sees negative + * die_sleep and longjmp here instead. */ + die_sleep = -1; + rc = setjmp(die_jmp); if (!rc) { /* Some callers (xargs) @@ -137,15 +146,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n memcpy(tmp_argv, argv, (argc+1) * sizeof(tmp_argv[0])); /* Finally we can call NOFORK applet's main() */ rc = applet_main[applet_no](argc, tmp_argv); - - /* The whole reason behind nofork_save_area is that _main - * may exit non-locally! For example, in hush Ctrl-Z tries - * (modulo bugs) to dynamically create a child (backgrounded task) - * if it detects that Ctrl-Z was pressed when a NOFORK was running. - * Testcase: interactive "rm -i". - * Don't fool yourself into thinking "and _main() returns - * quickly here" and removing "useless" nofork_save_area code. */ - } else { /* xfunc died in NOFORK applet */ /* in case they meant to return 0... */ if (rc == -2222) @@ -153,7 +153,7 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n } /* Restoring some globals */ - restore_nofork_data(old); + restore_nofork_data(&old); /* Other globals can be simply reset to defaults */ #ifdef __GLIBC__ @@ -164,15 +164,6 @@ int FAST_FUNC run_nofork_applet_prime(struct nofork_save_area *old, int applet_n return rc & 0xff; /* don't confuse people with "exitcodes" >255 */ } - -int FAST_FUNC run_nofork_applet(int applet_no, char **argv) -{ - struct nofork_save_area old; - - /* Saving globals */ - save_nofork_data(&old); - return run_nofork_applet_prime(&old, applet_no, argv); -} #endif /* FEATURE_PREFER_APPLETS */ int FAST_FUNC spawn_and_wait(char **argv) @@ -182,17 +173,17 @@ int FAST_FUNC spawn_and_wait(char **argv) int a = find_applet_by_name(argv[0]); if (a >= 0 && (APPLET_IS_NOFORK(a) -#if BB_MMU +# if BB_MMU || APPLET_IS_NOEXEC(a) /* NOEXEC trick needs fork() */ -#endif +# endif )) { -#if BB_MMU +# if BB_MMU if (APPLET_IS_NOFORK(a)) -#endif +# endif { return run_nofork_applet(a, argv); } -#if BB_MMU +# if BB_MMU /* MMU only */ /* a->noexec is true */ rc = fork(); @@ -201,7 +192,7 @@ int FAST_FUNC spawn_and_wait(char **argv) /* child */ xfunc_error_retval = EXIT_FAILURE; run_applet_no_and_exit(a, argv); -#endif +# endif } #endif /* FEATURE_PREFER_APPLETS */ rc = spawn(argv); @@ -262,11 +253,19 @@ void FAST_FUNC bb_daemonize_or_rexec(int flags, char **argv) if (!(flags & DAEMON_ONLY_SANITIZE)) { if (fork_or_rexec(argv)) exit(EXIT_SUCCESS); /* parent */ - /* if daemonizing, make sure we detach from stdio & ctty */ + /* if daemonizing, detach from stdio & ctty */ setsid(); dup2(fd, 0); dup2(fd, 1); dup2(fd, 2); + if (flags & DAEMON_DOUBLE_FORK) { + /* On Linux, session leader can acquire ctty + * unknowingly, by opening a tty. + * Prevent this: stop being a session leader. + */ + if (fork_or_rexec(argv)) + exit(EXIT_SUCCESS); /* parent */ + } } while (fd > 2) { close(fd--); diff --git a/libbb/warn_ignoring_args.c b/libbb/warn_ignoring_args.c index fa33c25..3f3025c 100644 --- a/libbb/warn_ignoring_args.c +++ b/libbb/warn_ignoring_args.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/wfopen.c b/libbb/wfopen.c index deec79a..76dc8b8 100644 --- a/libbb/wfopen.c +++ b/libbb/wfopen.c @@ -4,7 +4,7 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/wfopen_input.c b/libbb/wfopen_input.c index 46ff7a6..d8b1c4a 100644 --- a/libbb/wfopen_input.c +++ b/libbb/wfopen_input.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* A number of applets need to open a file for reading, where the filename @@ -31,7 +31,7 @@ FILE* FAST_FUNC xfopen_stdin(const char *filename) FILE *fp = fopen_or_warn_stdin(filename); if (fp) return fp; - xfunc_die(); /* We already output an error message. */ + xfunc_die(); /* We already output an error message. */ } int FAST_FUNC open_or_warn_stdin(const char *filename) @@ -46,3 +46,11 @@ int FAST_FUNC open_or_warn_stdin(const char *filename) return fd; } + +int FAST_FUNC xopen_stdin(const char *filename) +{ + int fd = open_or_warn_stdin(filename); + if (fd >= 0) + return fd; + xfunc_die(); /* We already output an error message. */ +} diff --git a/libbb/write.c b/libbb/write.c index 116e4d1..2d67a72 100644 --- a/libbb/write.c +++ b/libbb/write.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/xatonum.c b/libbb/xatonum.c index 3cdf634..6f4e023 100644 --- a/libbb/xatonum.c +++ b/libbb/xatonum.c @@ -4,7 +4,7 @@ * * Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -59,7 +59,7 @@ unsigned bb_strtoui(const char *str, char **end, int b) /* A few special cases */ -int FAST_FUNC xatoi_u(const char *numstr) +int FAST_FUNC xatoi_positive(const char *numstr) { return xatou_range(numstr, 0, INT_MAX); } @@ -68,3 +68,10 @@ uint16_t FAST_FUNC xatou16(const char *numstr) { return xatou_range(numstr, 0, 0xffff); } + +const struct suffix_mult bkm_suffixes[] = { + { "b", 512 }, + { "k", 1024 }, + { "m", 1024*1024 }, + { "", 0 } +}; diff --git a/libbb/xatonum_template.c b/libbb/xatonum_template.c index c97a4b7..e047198 100644 --- a/libbb/xatonum_template.c +++ b/libbb/xatonum_template.c @@ -1,6 +1,6 @@ /* * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* You need to define the following (example): @@ -41,7 +41,7 @@ unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base, if (errno || numstr == e) goto inval; /* error / no digits / illegal trailing chars */ - errno = old_errno; /* Ok. So restore errno. */ + errno = old_errno; /* Ok. So restore errno. */ /* Do optional suffix parsing. Allow 'empty' suffix tables. * Note that we also allow nul suffixes with associated multipliers, @@ -59,7 +59,7 @@ unsigned type FAST_FUNC xstrtou(_range_sfx)(const char *numstr, int base, } /* Note: trailing space is an error. - It would be easy enough to allow though if desired. */ + * It would be easy enough to allow though if desired. */ if (*e) goto inval; chk_range: diff --git a/libbb/xconnect.c b/libbb/xconnect.c index 2de6de7..1c8bb2b 100644 --- a/libbb/xconnect.c +++ b/libbb/xconnect.c @@ -4,7 +4,7 @@ * * Connect to host at port using address resolution from getaddrinfo * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include @@ -134,16 +134,18 @@ int FAST_FUNC get_nport(const struct sockaddr *sa) return -1; } -void FAST_FUNC set_nport(len_and_sockaddr *lsa, unsigned port) +void FAST_FUNC set_nport(struct sockaddr *sa, unsigned port) { #if ENABLE_FEATURE_IPV6 - if (lsa->u.sa.sa_family == AF_INET6) { - lsa->u.sin6.sin6_port = port; + if (sa->sa_family == AF_INET6) { + struct sockaddr_in6 *sin6 = (void*) sa; + sin6->sin6_port = port; return; } #endif - if (lsa->u.sa.sa_family == AF_INET) { - lsa->u.sin.sin_port = port; + if (sa->sa_family == AF_INET) { + struct sockaddr_in *sin = (void*) sa; + sin->sin_port = port; return; } /* What? UNIX socket? IPX?? :) */ @@ -255,7 +257,7 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) memset(&hint, 0 , sizeof(hint)); hint.ai_family = af; - /* Needed. Or else we will get each address thrice (or more) + /* Need SOCK_STREAM, or else we get each address thrice (or more) * for each possible socket type (tcp,udp,raw...): */ hint.ai_socktype = SOCK_STREAM; hint.ai_flags = ai_flags & ~DIE_ON_ERROR; @@ -283,9 +285,10 @@ IF_NOT_FEATURE_IPV6(sa_family_t af = AF_INET;) memcpy(&r->u.sa, used_res->ai_addr, used_res->ai_addrlen); set_port: - set_nport(r, htons(port)); + set_nport(&r->u.sa, htons(port)); ret: - freeaddrinfo(result); + if (result) + freeaddrinfo(result); return r; } #if !ENABLE_FEATURE_IPV6 @@ -319,26 +322,28 @@ len_and_sockaddr* FAST_FUNC xdotted2sockaddr(const char *host, int port) return str2sockaddr(host, port, AF_UNSPEC, AI_NUMERICHOST | DIE_ON_ERROR); } -#undef xsocket_type -int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type) +int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, int family, int sock_type) { - IF_NOT_FEATURE_IPV6(enum { family = AF_INET };) len_and_sockaddr *lsa; int fd; int len; -#if ENABLE_FEATURE_IPV6 if (family == AF_UNSPEC) { +#if ENABLE_FEATURE_IPV6 fd = socket(AF_INET6, sock_type, 0); if (fd >= 0) { family = AF_INET6; goto done; } +#endif family = AF_INET; } -#endif + fd = xsocket(family, sock_type, 0); + len = sizeof(struct sockaddr_in); + if (family == AF_UNIX) + len = sizeof(struct sockaddr_un); #if ENABLE_FEATURE_IPV6 if (family == AF_INET6) { done: @@ -354,7 +359,7 @@ int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap) { - return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM); + return xsocket_type(lsap, AF_UNSPEC, SOCK_STREAM); } static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) @@ -367,8 +372,8 @@ static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type) /* user specified bind addr dictates family */ fd = xsocket(lsa->u.sa.sa_family, sock_type, 0); } else { - fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type); - set_nport(lsa, htons(port)); + fd = xsocket_type(&lsa, AF_UNSPEC, sock_type); + set_nport(&lsa->u.sa, htons(port)); } setsockopt_reuseaddr(fd); xbind(fd, &lsa->u.sa, lsa->len); diff --git a/libbb/xfunc_die.c b/libbb/xfunc_die.c index ba9fe93..204e5e4 100644 --- a/libbb/xfunc_die.c +++ b/libbb/xfunc_die.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 by Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* Keeping it separate allows to NOT suck in stdio for VERY small applets. diff --git a/libbb/xfuncs.c b/libbb/xfuncs.c index 275dd4b..23f2751 100644 --- a/libbb/xfuncs.c +++ b/libbb/xfuncs.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Rob Landley * Copyright (C) 2006 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* We need to have separate xfuncs.c and xfuncs_printf.c because @@ -25,19 +25,25 @@ #include "libbb.h" /* Turn on nonblocking I/O on a fd */ -int FAST_FUNC ndelay_on(int fd) +void FAST_FUNC ndelay_on(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (flags & O_NONBLOCK) + return; + fcntl(fd, F_SETFL, flags | O_NONBLOCK); } -int FAST_FUNC ndelay_off(int fd) +void FAST_FUNC ndelay_off(int fd) { - return fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) & ~O_NONBLOCK); + int flags = fcntl(fd, F_GETFL); + if (!(flags & O_NONBLOCK)) + return; + fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); } -int FAST_FUNC close_on_exec_on(int fd) +void FAST_FUNC close_on_exec_on(int fd) { - return fcntl(fd, F_SETFD, FD_CLOEXEC); + fcntl(fd, F_SETFD, FD_CLOEXEC); } char* FAST_FUNC strncpy_IFNAMSIZ(char *dst, const char *src) @@ -234,7 +240,7 @@ static int wh_helper(int value, int def_val, const char *env_name, int *err) char *s = getenv(env_name); if (s) { value = atoi(s); - /* If LINES/COLUMNS are set, pretent that there is + /* If LINES/COLUMNS are set, pretend that there is * no error getting w/h, this prevents some ugly * cursor tricks by our callers */ *err = 0; diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index 7069a7c..e4ac6a0 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -6,7 +6,7 @@ * Copyright (C) 2006 Rob Landley * Copyright (C) 2006 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* We need to have separate xfuncs.c and xfuncs_printf.c because @@ -134,21 +134,12 @@ int FAST_FUNC xopen3(const char *pathname, int flags, int mode) return ret; } -// Die if we can't open an existing file and return a fd. +// Die if we can't open a file and return a fd. int FAST_FUNC xopen(const char *pathname, int flags) { return xopen3(pathname, flags, 0666); } -/* Die if we can't open an existing file readonly with O_NONBLOCK - * and return the fd. - * Note that for ioctl O_RDONLY is sufficient. - */ -int FAST_FUNC xopen_nonblocking(const char *pathname) -{ - return xopen(pathname, O_RDONLY | O_NONBLOCK); -} - // Warn if we can't open a file and return a fd. int FAST_FUNC open3_or_warn(const char *pathname, int flags, int mode) { @@ -167,6 +158,32 @@ int FAST_FUNC open_or_warn(const char *pathname, int flags) return open3_or_warn(pathname, flags, 0666); } +/* Die if we can't open an existing file readonly with O_NONBLOCK + * and return the fd. + * Note that for ioctl O_RDONLY is sufficient. + */ +int FAST_FUNC xopen_nonblocking(const char *pathname) +{ + return xopen(pathname, O_RDONLY | O_NONBLOCK); +} + +int FAST_FUNC xopen_as_uid_gid(const char *pathname, int flags, uid_t u, gid_t g) +{ + int fd; + uid_t old_euid = geteuid(); + gid_t old_egid = getegid(); + + xsetegid(g); + xseteuid(u); + + fd = xopen(pathname, flags); + + xseteuid(old_euid); + xsetegid(old_egid); + + return fd; +} + void FAST_FUNC xunlink(const char *pathname) { if (unlink(pathname)) @@ -240,6 +257,14 @@ off_t FAST_FUNC xlseek(int fd, off_t offset, int whence) return off; } +int FAST_FUNC xmkstemp(char *template) +{ + int fd = mkstemp(template); + if (fd < 0) + bb_perror_msg_and_die("can't create temp file '%s'", template); + return fd; +} + // Die with supplied filename if this FILE* has ferror set. void FAST_FUNC die_if_ferror(FILE *fp, const char *fn) { @@ -343,17 +368,28 @@ void FAST_FUNC xsetuid(uid_t uid) if (setuid(uid)) bb_perror_msg_and_die("setuid"); } +void FAST_FUNC xsetegid(gid_t egid) +{ + if (setegid(egid)) bb_perror_msg_and_die("setegid"); +} + +void FAST_FUNC xseteuid(uid_t euid) +{ + if (seteuid(euid)) bb_perror_msg_and_die("seteuid"); +} + // Die if we can't chdir to a new path. void FAST_FUNC xchdir(const char *path) { if (chdir(path)) - bb_perror_msg_and_die("chdir(%s)", path); + bb_perror_msg_and_die("can't change directory to '%s'", path); } void FAST_FUNC xchroot(const char *path) { if (chroot(path)) - bb_perror_msg_and_die("can't change root directory to %s", path); + bb_perror_msg_and_die("can't change root directory to '%s'", path); + xchdir("/"); } // Print a warning message if opendir() fails, but don't die. @@ -387,8 +423,12 @@ int FAST_FUNC xsocket(int domain, int type, int protocol) /* Hijack vaguely related config option */ #if ENABLE_VERBOSE_RESOLUTION_ERRORS const char *s = "INET"; +# ifdef AF_PACKET if (domain == AF_PACKET) s = "PACKET"; +# endif +# ifdef AF_NETLINK if (domain == AF_NETLINK) s = "NETLINK"; +# endif IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";) bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol); #else @@ -432,6 +472,16 @@ void FAST_FUNC xstat(const char *name, struct stat *stat_buf) bb_perror_msg_and_die("can't stat '%s'", name); } +void FAST_FUNC xfstat(int fd, struct stat *stat_buf, const char *errmsg) +{ + /* errmsg is usually a file name, but not always: + * xfstat may be called in a spot where file name is no longer + * available, and caller may give e.g. "can't stat input file" string. + */ + if (fstat(fd, stat_buf)) + bb_simple_perror_msg_and_die(errmsg); +} + // selinux_or_die() - die if SELinux is disabled. void FAST_FUNC selinux_or_die(void) { @@ -518,13 +568,11 @@ int FAST_FUNC bb_xioctl(int fd, unsigned request, void *argp) char* FAST_FUNC xmalloc_ttyname(int fd) { - char *buf = xzalloc(128); - int r = ttyname_r(fd, buf, 127); - if (r) { - free(buf); - buf = NULL; - } - return buf; + char buf[128]; + int r = ttyname_r(fd, buf, sizeof(buf) - 1); + if (r) + return NULL; + return xstrdup(buf); } void FAST_FUNC generate_uuid(uint8_t *buf) diff --git a/libbb/xgetcwd.c b/libbb/xgetcwd.c index 10febe3..71720d3 100644 --- a/libbb/xgetcwd.c +++ b/libbb/xgetcwd.c @@ -6,7 +6,7 @@ * * Special function for busybox written by Vladimir Oleynik * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" @@ -24,7 +24,7 @@ xrealloc_getcwd_or_warn(char *cwd) char *ret; unsigned path_max; - path_max = 128; /* 128 + 64 should be enough for 99% of cases */ + path_max = 128; /* 128 + 64 should be enough for 99% of cases */ while (1) { path_max += PATH_INCR; diff --git a/libbb/xgethostbyname.c b/libbb/xgethostbyname.c index 7afa9b6..89d0329 100644 --- a/libbb/xgethostbyname.c +++ b/libbb/xgethostbyname.c @@ -4,7 +4,7 @@ * * Copyright (C) 2001 Matt Kraai . * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/xreadlink.c b/libbb/xreadlink.c index faa0e16..bb63da0 100644 --- a/libbb/xreadlink.c +++ b/libbb/xreadlink.c @@ -3,11 +3,17 @@ * xreadlink.c - safe implementation of readlink. * Returns a NULL on failure... * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" +/* some systems (eg Hurd) does not have MAXSYMLINKS definition, + * set it to some reasonable value if it isn't defined */ +#ifndef MAXSYMLINKS +# define MAXSYMLINKS 20 +#endif + /* * NOTE: This function returns a malloced char* that you will have to free * yourself. @@ -102,7 +108,8 @@ char* FAST_FUNC xmalloc_readlink_or_warn(const char *path) char* FAST_FUNC xmalloc_realpath(const char *path) { -#if defined(__GLIBC__) && !defined(__UCLIBC__) +#if defined(__GLIBC__) || \ + (defined(__UCLIBC__) && UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 31)) /* glibc provides a non-standard extension */ /* new: POSIX.1-2008 specifies this behavior as well */ return realpath(path, NULL); diff --git a/libbb/xrealloc_vector.c b/libbb/xrealloc_vector.c index 98fa967..e8d31b7 100644 --- a/libbb/xrealloc_vector.c +++ b/libbb/xrealloc_vector.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libbb/xregcomp.c b/libbb/xregcomp.c index 61efb5b..344028f 100644 --- a/libbb/xregcomp.c +++ b/libbb/xregcomp.c @@ -5,7 +5,7 @@ * Copyright (C) many different people. * If you wrote this, please acknowledge your work. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/libpwdgrp/Kbuild.src b/libpwdgrp/Kbuild.src index f9f1ddb..d15e3a2 100644 --- a/libpwdgrp/Kbuild.src +++ b/libpwdgrp/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y := uidgid_get.o diff --git a/libpwdgrp/pwd_grp.c b/libpwdgrp/pwd_grp.c index 34690a7..2060d78 100644 --- a/libpwdgrp/pwd_grp.c +++ b/libpwdgrp/pwd_grp.c @@ -1,41 +1,28 @@ /* vi: set sw=4 ts=4: */ -/* Copyright (C) 2003 Manuel Novoa III +/* Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPL v2, or later. See file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* Nov 6, 2003 Initial version. +/* Nov 6, 2003 Initial version. * - * NOTE: This implementation is quite strict about requiring all + * NOTE: This implementation is quite strict about requiring all * field seperators. It also does not allow leading whitespace * except when processing the numeric fields. glibc is more * lenient. See the various glibc difference comments below. * - * TODO: + * TODO: * Move to dynamic allocation of (currently statically allocated) * buffers; especially for the group-related functions since * large group member lists will cause error returns. - * */ #include "libbb.h" #include -#ifndef _PATH_SHADOW -#define _PATH_SHADOW "/etc/shadow" -#endif -#ifndef _PATH_PASSWD -#define _PATH_PASSWD "/etc/passwd" -#endif -#ifndef _PATH_GROUP -#define _PATH_GROUP "/etc/group" -#endif - /**********************************************************************/ /* Sizes for statically allocated buffers. */ -/* If you change these values, also change _SC_GETPW_R_SIZE_MAX and - * _SC_GETGR_R_SIZE_MAX in libc/unistd/sysconf.c to match */ #define PWD_BUFFER_SIZE 256 #define GRP_BUFFER_SIZE 256 @@ -60,46 +47,24 @@ static int FAST_FUNC bb__parsespent(void *sp, char *line); struct statics { /* Smaller things first */ - struct passwd getpwuid_resultbuf; - struct group getgrgid_resultbuf; - struct passwd getpwnam_resultbuf; - struct group getgrnam_resultbuf; - - char getpwuid_buffer[PWD_BUFFER_SIZE]; - char getgrgid_buffer[GRP_BUFFER_SIZE]; - char getpwnam_buffer[PWD_BUFFER_SIZE]; - char getgrnam_buffer[GRP_BUFFER_SIZE]; -#if 0 - struct passwd fgetpwent_resultbuf; - struct group fgetgrent_resultbuf; - struct spwd fgetspent_resultbuf; - char fgetpwent_buffer[PWD_BUFFER_SIZE]; - char fgetgrent_buffer[GRP_BUFFER_SIZE]; - char fgetspent_buffer[PWD_BUFFER_SIZE]; -#endif + /* It's ok to use one buffer for getpwuid and getpwnam. Manpage says: + * "The return value may point to a static area, and may be overwritten + * by subsequent calls to getpwent(), getpwnam(), or getpwuid()." + */ + struct passwd getpw_resultbuf; + struct group getgr_resultbuf; + + char getpw_buffer[PWD_BUFFER_SIZE]; + char getgr_buffer[GRP_BUFFER_SIZE]; #if 0 //ENABLE_USE_BB_SHADOW - struct spwd getspuid_resultbuf; - struct spwd getspnam_resultbuf; - char getspuid_buffer[PWD_BUFFER_SIZE]; - char getspnam_buffer[PWD_BUFFER_SIZE]; + struct spwd getsp_resultbuf; + char getsp_buffer[PWD_BUFFER_SIZE]; #endif // Not converted - too small to bother //pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER; //FILE *pwf /*= NULL*/; //FILE *grf /*= NULL*/; //FILE *spf /*= NULL*/; -#if 0 - struct passwd getpwent_pwd; - struct group getgrent_gr; - char getpwent_line_buff[PWD_BUFFER_SIZE]; - char getgrent_line_buff[GRP_BUFFER_SIZE]; -#endif -#if 0 //ENABLE_USE_BB_SHADOW - struct spwd getspent_spwd; - struct spwd sgetspent_spwd; - char getspent_line_buff[PWD_BUFFER_SIZE]; - char sgetspent_line_buff[PWD_BUFFER_SIZE]; -#endif }; static struct statics *ptr_to_statics; @@ -193,22 +158,22 @@ int fgetspent_r(FILE *__restrict stream, struct spwd *__restrict resultbuf, struct passwd *fgetpwent(FILE *stream) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(fgetpwent); - char *buffer = BUFFER(fgetpwent); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetpwent)), &result); + fgetpwent_r(stream, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } struct group *fgetgrent(FILE *stream) { struct statics *S; - struct group *resultbuf = RESULTBUF(fgetgrent); - char *buffer = BUFFER(fgetgrent); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetgrent)), &result); + fgetgrent_r(stream, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } #endif @@ -218,11 +183,11 @@ struct group *fgetgrent(FILE *stream) struct spwd *fgetspent(FILE *stream) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(fgetspent); - char *buffer = BUFFER(fgetspent); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(fgetspent)), &result); + fgetspent_r(stream, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -310,11 +275,11 @@ int sgetspent_r(const char *string, struct spwd *result_buf, struct passwd *getpwuid(uid_t uid) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwuid); - char *buffer = BUFFER(getpwuid); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpwuid)), &result); + getpwuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -322,11 +287,11 @@ struct passwd *getpwuid(uid_t uid) struct group *getgrgid(gid_t gid) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrgid); - char *buffer = BUFFER(getgrgid); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgrgid)), &result); + getgrgid_r(gid, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -335,8 +300,8 @@ struct group *getgrgid(gid_t gid) * to have been created as a reentrant version of the non-standard * functions getspuid. Why getspuid was added, I do not know. */ int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf, - char *__restrict buffer, size_t buflen, - struct spwd **__restrict result) + char *__restrict buffer, size_t buflen, + struct spwd **__restrict result) { int rv; struct passwd *pp; @@ -357,11 +322,11 @@ int getspuid_r(uid_t uid, struct spwd *__restrict resultbuf, struct spwd *getspuid(uid_t uid) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspuid); - char *buffer = BUFFER(getspuid); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getspuid)), &result); + getspuid_r(uid, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -370,11 +335,11 @@ struct spwd *getspuid(uid_t uid) struct passwd *getpwnam(const char *name) { struct statics *S; - struct passwd *resultbuf = RESULTBUF(getpwnam); - char *buffer = BUFFER(getpwnam); + struct passwd *resultbuf = RESULTBUF(getpw); + char *buffer = BUFFER(getpw); struct passwd *result; - getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpwnam)), &result); + getpwnam_r(name, resultbuf, buffer, sizeof(BUFFER(getpw)), &result); return result; } @@ -382,11 +347,11 @@ struct passwd *getpwnam(const char *name) struct group *getgrnam(const char *name) { struct statics *S; - struct group *resultbuf = RESULTBUF(getgrnam); - char *buffer = BUFFER(getgrnam); + struct group *resultbuf = RESULTBUF(getgr); + char *buffer = BUFFER(getgr); struct group *result; - getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgrnam)), &result); + getgrnam_r(name, resultbuf, buffer, sizeof(BUFFER(getgr)), &result); return result; } @@ -394,11 +359,11 @@ struct group *getgrnam(const char *name) struct spwd *getspnam(const char *name) { struct statics *S; - struct spwd *resultbuf = RESULTBUF(getspnam); - char *buffer = BUFFER(getspnam); + struct spwd *resultbuf = RESULTBUF(getsp); + char *buffer = BUFFER(getsp); struct spwd *result; - getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getspnam)), &result); + getspnam_r(name, resultbuf, buffer, sizeof(BUFFER(getsp)), &result); return result; } #endif @@ -438,8 +403,8 @@ void endpwent(void) int getpwent_r(struct passwd *__restrict resultbuf, - char *__restrict buffer, size_t buflen, - struct passwd **__restrict result) + char *__restrict buffer, size_t buflen, + struct passwd **__restrict result) { int rv; @@ -452,6 +417,7 @@ int getpwent_r(struct passwd *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(pwf)); } rv = bb__pgsreader(bb__parsepwent, resultbuf, buffer, buflen, pwf); @@ -485,8 +451,8 @@ void endgrent(void) } int getgrent_r(struct group *__restrict resultbuf, - char *__restrict buffer, size_t buflen, - struct group **__restrict result) + char *__restrict buffer, size_t buflen, + struct group **__restrict result) { int rv; @@ -499,6 +465,7 @@ int getgrent_r(struct group *__restrict resultbuf, rv = errno; goto ERR; } + close_on_exec_on(fileno(grf)); } rv = bb__pgsreader(bb__parsegrent, resultbuf, buffer, buflen, grf); @@ -534,7 +501,7 @@ void endspent(void) } int getspent_r(struct spwd *resultbuf, char *buffer, - size_t buflen, struct spwd **result) + size_t buflen, struct spwd **result) { int rv; @@ -547,6 +514,7 @@ int getspent_r(struct spwd *resultbuf, char *buffer, rv = errno; goto ERR; } + close_on_exec_on(fileno(spf)); } rv = bb__pgsreader(bb__parsespent, resultbuf, buffer, buflen, spf); diff --git a/libpwdgrp/pwd_grp_internal.c b/libpwdgrp/pwd_grp_internal.c index ffdc85e..d6483be 100644 --- a/libpwdgrp/pwd_grp_internal.c +++ b/libpwdgrp/pwd_grp_internal.c @@ -1,21 +1,20 @@ /* vi: set sw=4 ts=4: */ -/* Copyright (C) 2003 Manuel Novoa III +/* Copyright (C) 2003 Manuel Novoa III * - * Licensed under GPL v2, or later. See file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* Nov 6, 2003 Initial version. +/* Nov 6, 2003 Initial version. * - * NOTE: This implementation is quite strict about requiring all + * NOTE: This implementation is quite strict about requiring all * field seperators. It also does not allow leading whitespace * except when processing the numeric fields. glibc is more * lenient. See the various glibc difference comments below. * - * TODO: + * TODO: * Move to dynamic allocation of (currently statically allocated) * buffers; especially for the group-related functions since * large group member lists will cause error returns. - * */ #ifndef GETXXKEY_R_FUNC @@ -38,12 +37,12 @@ int GETXXKEY_R_FUNC(GETXXKEY_R_KEYTYPE key, while (1) { rv = bb__pgsreader(GETXXKEY_R_PARSER, resultbuf, buffer, buflen, stream); if (!rv) { - if (GETXXKEY_R_TEST(resultbuf)) { /* Found key? */ + if (GETXXKEY_R_TEST(resultbuf)) { /* found key? */ *result = resultbuf; break; } } else { - if (rv == ENOENT) { /* end-of-file encountered. */ + if (rv == ENOENT) { /* EOF encountered */ rv = 0; } break; diff --git a/libpwdgrp/uidgid_get.c b/libpwdgrp/uidgid_get.c index 92290bf..8388be0 100644 --- a/libpwdgrp/uidgid_get.c +++ b/libpwdgrp/uidgid_get.c @@ -71,7 +71,8 @@ int FAST_FUNC get_uidgid(struct bb_uidgid_t *u, const char *ug, int numeric_ok) } } gr = getgrnam(group); - if (!gr) return 0; + if (!gr) + return 0; u->gid = gr->gr_gid; } return 1; diff --git a/loginutils/Config.src b/loginutils/Config.src index 5d497c4..9bf79af 100644 --- a/loginutils/Config.src +++ b/loginutils/Config.src @@ -93,41 +93,18 @@ config USE_BB_CRYPT_SHA With this option off, login will fail password check for any user which has password encrypted with these algorithms. -config ADDGROUP - bool "addgroup" +config ADDUSER + bool "adduser" default y help - Utility for creating a new group account. + Utility for creating a new user account. -config FEATURE_ADDGROUP_LONG_OPTIONS +config FEATURE_ADDUSER_LONG_OPTIONS bool "Enable long options" default y - depends on ADDGROUP && LONG_OPTS - help - Support long options for the addgroup applet. - -config FEATURE_ADDUSER_TO_GROUP - bool "Support for adding users to groups" - default y - depends on ADDGROUP - help - If called with two non-option arguments, - addgroup will add an existing user to an - existing group. - -config DELGROUP - bool "delgroup" - default y - help - Utility for deleting a group account. - -config FEATURE_DEL_USER_FROM_GROUP - bool "Support for removing users from groups" - default y - depends on DELGROUP + depends on ADDUSER && LONG_OPTS help - If called with two non-option arguments, deluser - or delgroup will remove an user from a specified group. + Support long options for the adduser applet. config FEATURE_CHECK_NAMES bool "Enable sanity check on user/group names in adduser and addgroup" @@ -141,19 +118,6 @@ config FEATURE_CHECK_NAMES For compatibility with Samba machine accounts "$" is also supported at the end of the user or group name. -config ADDUSER - bool "adduser" - default y - help - Utility for creating a new user account. - -config FEATURE_ADDUSER_LONG_OPTIONS - bool "Enable long options" - default y - depends on ADDUSER && LONG_OPTS - help - Support long options for the adduser applet. - config FIRST_SYSTEM_ID int "First valid system uid or gid for adduser and addgroup" depends on ADDUSER || ADDGROUP @@ -170,23 +134,70 @@ config LAST_SYSTEM_ID help Last valid system uid or gid for adduser and addgroup +config ADDGROUP + bool "addgroup" + default y + help + Utility for creating a new group account. + +config FEATURE_ADDGROUP_LONG_OPTIONS + bool "Enable long options" + default y + depends on ADDGROUP && LONG_OPTS + help + Support long options for the addgroup applet. + +config FEATURE_ADDUSER_TO_GROUP + bool "Support for adding users to groups" + default y + depends on ADDGROUP + help + If called with two non-option arguments, + addgroup will add an existing user to an + existing group. + config DELUSER bool "deluser" default y help Utility for deleting a user account. +config DELGROUP + bool "delgroup" + default y + help + Utility for deleting a group account. + +config FEATURE_DEL_USER_FROM_GROUP + bool "Support for removing users from groups" + default y + depends on DELGROUP + help + If called with two non-option arguments, deluser + or delgroup will remove an user from a specified group. + config GETTY bool "getty" default y select FEATURE_SYSLOG help - getty lets you log in on a tty, it is normally invoked by init. + getty lets you log in on a tty. It is normally invoked by init. + + Note that you can save a few bytes by disabling it and + using login applet directly. + If you need to reset tty attributes before calling login, + this script approximates getty: + + exec /dev/$1 2>&1 || exit 1 + reset + stty sane; stty ispeed 38400; stty ospeed 38400 + printf "%s login: " "`hostname`" + read -r login + exec /bin/login "$login" config LOGIN bool "login" default y - select FEATURE_SUID select FEATURE_SYSLOG help login is used when signing onto a system. @@ -194,6 +205,17 @@ config LOGIN Note that Busybox binary must be setuid root for this applet to work properly. +config LOGIN_SESSION_AS_CHILD + bool "Run logged in session in a child process" + default y if PAM + depends on LOGIN + help + Run the logged in session in a child process. This allows + login to clean up things such as utmp entries or PAM sessions + when the login session is complete. If you use PAM, you + almost always would want this to be set to Y, else PAM session + will not be cleaned up. + config PAM bool "Support for PAM (Pluggable Authentication Modules)" default n @@ -229,7 +251,6 @@ config FEATURE_SECURETTY config PASSWD bool "passwd" default y - select FEATURE_SUID select FEATURE_SYSLOG help passwd changes passwords for user and group accounts. A normal user @@ -262,10 +283,16 @@ config CHPASSWD Reads a file of user name and password pairs from standard input and uses this information to update a group of existing users. +config FEATURE_DEFAULT_PASSWD_ALGO + string "Default password encryption method (passwd -a, cryptpw -m parameter)" + default "des" + depends on PASSWD || CRYPTPW + help + Possible choices are "d[es]", "m[d5]", "s[ha256]" or "sha512". + config SU bool "su" default y - select FEATURE_SUID select FEATURE_SYSLOG help su is used to become another user during a login session. @@ -295,7 +322,6 @@ config SULOGIN config VLOCK bool "vlock" default y - select FEATURE_SUID help Build the "vlock" applet which allows you to lock (virtual) terminals. diff --git a/loginutils/Kbuild.src b/loginutils/Kbuild.src index fd1ea06..ef416a7 100644 --- a/loginutils/Kbuild.src +++ b/loginutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/loginutils/README b/loginutils/README new file mode 100644 index 0000000..ce88510 --- /dev/null +++ b/loginutils/README @@ -0,0 +1,70 @@ + Getty + +??? Should getty open tty with or without O_NONBLOCK? +For serial lines, it means "should getty wait for Carrier Detect pin?" +I checked other getties: + +- agetty always uses O_NONBLOCK +- mgetty uses O_NONBLOCK unless run with -b, or as "getty" + +??? If we decided to use O_NONBLOCK (perhaps optionally with -b), +when getty should send -I INITSTR data to tty? After open succeeds? +What if we also want to initialize *modem* with some AT commands? + +??? Should we check/create /var/lock/LCK..ttyPFX lockfiles? + +??? mgetty opens tty but does NOT lock it, then waits for input via +select/poll, and when input is available, it checks lock file. +If it exists, mgetty exits (it assumes someone else uses the line). +If no, it creates the file (lock the tty). Sounds like a good algorithm +to use if we are called with -w... + +Getty should establish a new session and process group, and ensure +that tty is a ctty. + +??? Should getty ensure that other processes which might have opened +fds to this tty be dusconnected? agetty has a -R option which makes +agetty call vhangup() after tty is opened. (Then agetty opens it again, +since it probably vhangup'ed its own fd too). + +Getty should leave the tty in approximately the same state as "stty sane" +before it execs login program. Minor things we do conditionally are: + c_iflag |= ICRNL; // if '\r' was used to end username + +??? mgetty uses per-tty file to ignore connects, /etc/nologin.ttyxx - +is it useful? + +It should be possible to run "getty 0 -" from a shell prompt. +[This currently doesn't work from interactive shell since setsid() +fails in process group leader. The workaround is to run it as a child +of something. sh -c 'getty - 0; true' usually works. Should we fix this?] +It should leave tty in a sane state when it exits (Ctrl-D, -t SEC timeout): +echo should be on, speed, control chars properly set, etc. +(However, it can't restore ctty. The symptom is that " + * + * Licensed under GPLv2 or later, see the LICENSE file in this source tree + * for details. + */ + +//applet:IF_ADD_SHELL( APPLET_ODDNAME(add-shell , add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, add_shell )) +//applet:IF_REMOVE_SHELL(APPLET_ODDNAME(remove-shell, add_remove_shell, BB_DIR_USR_SBIN, BB_SUID_DROP, remove_shell)) + +//kbuild:lib-$(CONFIG_ADD_SHELL) += add-remove-shell.o +//kbuild:lib-$(CONFIG_REMOVE_SHELL) += add-remove-shell.o + +//config:config ADD_SHELL +//config: bool "add-shell" +//config: default y if DESKTOP +//config: help +//config: Add shells to /etc/shells. +//config: +//config:config REMOVE_SHELL +//config: bool "remove-shell" +//config: default y if DESKTOP +//config: help +//config: Remove shells from /etc/shells. + +//usage:#define add_shell_trivial_usage +//usage: "SHELL..." +//usage:#define add_shell_full_usage "\n\n" +//usage: "Add SHELLs to /etc/shells" + +//usage:#define remove_shell_trivial_usage +//usage: "SHELL..." +//usage:#define remove_shell_full_usage "\n\n" +//usage: "Remove SHELLs from /etc/shells" + +#include "libbb.h" + +#define SHELLS_FILE "/etc/shells" + +#define REMOVE_SHELL (ENABLE_REMOVE_SHELL && (!ENABLE_ADD_SHELL || applet_name[0] == 'r')) +#define ADD_SHELL (ENABLE_ADD_SHELL && (!ENABLE_REMOVE_SHELL || applet_name[0] == 'a')) + +/* NB: we use the _address_, not the value, of this string + * as a "special value of pointer" in the code. + */ +static const char dont_add[] ALIGN1 = "\n"; + +int add_remove_shell_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int add_remove_shell_main(int argc UNUSED_PARAM, char **argv) +{ + FILE *orig_fp; + char *orig_fn; + char *new_fn; + + argv++; + + orig_fn = xmalloc_follow_symlinks(SHELLS_FILE); + if (!orig_fn) + return EXIT_FAILURE; + orig_fp = fopen_for_read(orig_fn); + + new_fn = xasprintf("%s.tmp", orig_fn); + /* + * O_TRUNC or O_EXCL? At the first glance, O_EXCL looks better, + * since it prevents races. But: (1) it requires a retry loop, + * (2) if /etc/shells.tmp is *stale*, then retry loop + * with O_EXCL will never succeed - it should have a timeout, + * after which it should revert to O_TRUNC. + * For now, I settle for O_TRUNC instead. + */ + xmove_fd(xopen(new_fn, O_WRONLY | O_CREAT | O_TRUNC), STDOUT_FILENO); + + /* TODO: + struct stat sb; + xfstat(fileno(orig_fp), &sb); + xfchown(STDOUT_FILENO, sb.st_uid, sb.st_gid); + xfchmod(STDOUT_FILENO, sb.st_mode); + */ + + if (orig_fp) { + /* Copy old file, possibly skipping removed shell names */ + char *line; + while ((line = xmalloc_fgetline(orig_fp)) != NULL) { + char **cpp = argv; + while (*cpp) { + if (strcmp(*cpp, line) == 0) { + /* Old file has this shell name */ + if (REMOVE_SHELL) { + /* we are remove-shell */ + /* delete this name by not copying it */ + goto next_line; + } + /* we are add-shell */ + /* mark this name as "do not add" */ + *cpp = (char*)dont_add; + } + cpp++; + } + /* copy shell name from old to new file */ + printf("%s\n", line); + next_line: + free(line); + } + if (ENABLE_FEATURE_CLEAN_UP) + fclose(orig_fp); + } + + if (ADD_SHELL) { + char **cpp = argv; + while (*cpp) { + if (*cpp != dont_add) + printf("%s\n", *cpp); + cpp++; + } + } + + /* Ensure we wrote out everything */ + if (fclose(stdout) != 0) { + xunlink(new_fn); + bb_perror_msg_and_die("%s: write error", new_fn); + } + + /* Small hole: if rename fails, /etc/shells.tmp is not removed */ + xrename(new_fn, orig_fn); + + if (ENABLE_FEATURE_CLEAN_UP) { + free(orig_fn); + free(new_fn); + } + + return EXIT_SUCCESS; +} diff --git a/loginutils/addgroup.c b/loginutils/addgroup.c index 215e4a9..b37270f 100644 --- a/loginutils/addgroup.c +++ b/loginutils/addgroup.c @@ -6,9 +6,17 @@ * Copyright (C) 1999,2000,2001 by John Beppu * Copyright (C) 2007 by Tito Ragusa * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * */ + +//usage:#define addgroup_trivial_usage +//usage: "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[USER] ") "GROUP" +//usage:#define addgroup_full_usage "\n\n" +//usage: "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" +//usage: "\n -g GID Group id" +//usage: "\n -S Create a system group" + #include "libbb.h" #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID @@ -168,7 +176,6 @@ int addgroup_main(int argc UNUSED_PARAM, char **argv) { die_if_bad_username(argv[0]); new_group(argv[0], gid); - } /* Reached only on success */ return EXIT_SUCCESS; diff --git a/loginutils/adduser.c b/loginutils/adduser.c index f5dca92..ef390ad 100644 --- a/loginutils/adduser.c +++ b/loginutils/adduser.c @@ -5,8 +5,22 @@ * Copyright (C) 1999 by Lineo, inc. and John Beppu * Copyright (C) 1999,2000,2001 by John Beppu * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define adduser_trivial_usage +//usage: "[OPTIONS] USER [GROUP]" +//usage:#define adduser_full_usage "\n\n" +//usage: "Create new user, or add USER to GROUP\n" +//usage: "\n -h DIR Home directory" +//usage: "\n -g GECOS GECOS field" +//usage: "\n -s SHELL Login shell" +//usage: "\n -G GRP Add user to existing group" +//usage: "\n -S Create a system user" +//usage: "\n -D Don't assign a password" +//usage: "\n -H Don't create home directory" +//usage: "\n -u UID User id" + #include "libbb.h" #if CONFIG_LAST_SYSTEM_ID < CONFIG_FIRST_SYSTEM_ID @@ -52,6 +66,7 @@ static void passwd_study(struct passwd *p) } if (p->pw_uid == max) { bb_error_msg_and_die("no %cids left", 'u'); + /* this format string is reused in adduser and addgroup */ } p->pw_uid++; } @@ -65,24 +80,44 @@ static void passwd_study(struct passwd *p) } } -static void addgroup_wrapper(struct passwd *p, const char *group_name) +static int addgroup_wrapper(struct passwd *p, const char *group_name) { - char *cmd; - - if (group_name) /* Add user to existing group */ - cmd = xasprintf("addgroup '%s' '%s'", p->pw_name, group_name); - else /* Add user to his own group with the first free gid found in passwd_study */ - cmd = xasprintf("addgroup -g %u '%s'", (unsigned)p->pw_gid, p->pw_name); - /* Warning: to be compatible with external addgroup programs we should use --gid instead */ - system(cmd); - free(cmd); + char *argv[6]; + + argv[0] = (char*)"addgroup"; + if (group_name) { + /* Add user to existing group */ + argv[1] = (char*)"--"; + argv[2] = p->pw_name; + argv[3] = (char*)group_name; + argv[4] = NULL; + } else { + /* Add user to his own group with the first free gid + * found in passwd_study. + */ +#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS || !ENABLE_ADDGROUP + /* We try to use --gid, not -g, because "standard" addgroup + * has no short option -g, it has only long --gid. + */ + argv[1] = (char*)"--gid"; +#else + /* Breaks if system in fact does NOT use busybox addgroup */ + argv[1] = (char*)"-g"; +#endif + argv[2] = utoa(p->pw_gid); + argv[3] = (char*)"--"; + argv[4] = p->pw_name; + argv[5] = NULL; + } + + return spawn_and_wait(argv); } -static void passwd_wrapper(const char *login) NORETURN; +static void passwd_wrapper(const char *login_name) NORETURN; -static void passwd_wrapper(const char *login) +static void passwd_wrapper(const char *login_name) { - BB_EXECLP("passwd", "passwd", login, NULL); + BB_EXECLP("passwd", "passwd", "--", login_name, NULL); bb_error_msg_and_die("can't execute passwd, you must set password manually"); } @@ -123,12 +158,13 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) } pw.pw_gecos = (char *)"Linux User,,,"; - pw.pw_shell = (char *)DEFAULT_SHELL; + /* We assume that newly created users "inherit" root's shell setting */ + pw.pw_shell = (char *)get_shell_name(); pw.pw_dir = NULL; - /* exactly one non-option arg */ + /* at least one and at most two non-option args */ /* disable interactive passwd for system accounts */ - opt_complementary = "=1:SD:u+"; + opt_complementary = "-1:?2:SD:u+"; if (sizeof(pw.pw_uid) == sizeof(int)) { opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid); } else { @@ -139,9 +175,16 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) } } argv += optind; + pw.pw_name = argv[0]; + + if (!opts && argv[1]) { + /* if called with two non-option arguments, adduser + * will add an existing user to an existing group. + */ + return addgroup_wrapper(&pw, argv[1]); + } /* fill in the passwd struct */ - pw.pw_name = argv[0]; die_if_bad_username(pw.pw_name); if (!pw.pw_dir) { /* create string for $HOME if not specified already */ @@ -169,7 +212,6 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_CLEAN_UP) free(p); - #if ENABLE_FEATURE_SHADOWPASSWDS /* /etc/shadow fields: * 1. username @@ -203,9 +245,11 @@ int adduser_main(int argc UNUSED_PARAM, char **argv) if (mkdir_err == 0) { /* New home. Copy /etc/skel to it */ const char *args[] = { - "chown", "-R", + "chown", + "-R", xasprintf("%u:%u", (int)pw.pw_uid, (int)pw.pw_gid), - pw.pw_dir, NULL + pw.pw_dir, + NULL }; /* Be silent on any errors (like: no /etc/skel) */ logmode = LOGMODE_NONE; diff --git a/loginutils/chpasswd.c b/loginutils/chpasswd.c index 1817231..54ed737 100644 --- a/loginutils/chpasswd.c +++ b/loginutils/chpasswd.c @@ -3,10 +3,25 @@ * chpasswd.c * * Written for SLIND (from passwd.c) by Alexander Shishkin - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" +//usage:#define chpasswd_trivial_usage +//usage: IF_LONG_OPTS("[--md5|--encrypted]") IF_NOT_LONG_OPTS("[-m|-e]") +//usage:#define chpasswd_full_usage "\n\n" +//usage: "Read user:password from stdin and update /etc/passwd\n" +//usage: IF_LONG_OPTS( +//usage: "\n -e,--encrypted Supplied passwords are in encrypted form" +//usage: "\n -m,--md5 Use MD5 encryption instead of DES" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -e Supplied passwords are in encrypted form" +//usage: "\n -m Use MD5 encryption instead of DES" +//usage: ) + +//TODO: implement -c ALGO + #if ENABLE_LONG_OPTS static const char chpasswd_longopts[] ALIGN1 = "encrypted\0" No_argument "e" @@ -14,18 +29,16 @@ static const char chpasswd_longopts[] ALIGN1 = ; #endif -#define OPT_ENC 1 -#define OPT_MD5 2 +#define OPT_ENC 1 +#define OPT_MD5 2 int chpasswd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chpasswd_main(int argc UNUSED_PARAM, char **argv) { - char *name, *pass; - char salt[sizeof("$N$XXXXXXXX")]; - int opt, rc; - int rnd = rnd; /* we *want* it to be non-initialized! */ + char *name; + int opt; - if (getuid()) + if (getuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); opt_complementary = "m--e:e--m"; @@ -33,6 +46,10 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "em"); while ((name = xmalloc_fgetline(stdin)) != NULL) { + char *free_me; + char *pass; + int rc; + pass = strchr(name, ':'); if (!pass) bb_error_msg_and_die("missing new password"); @@ -40,20 +57,28 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) xuname2uid(name); /* dies if there is no such user */ + free_me = NULL; if (!(opt & OPT_ENC)) { - rnd = crypt_make_salt(salt, 1, rnd); + char salt[sizeof("$N$XXXXXXXX")]; + + crypt_make_salt(salt, 1); if (opt & OPT_MD5) { - strcpy(salt, "$1$"); - rnd = crypt_make_salt(salt + 3, 4, rnd); + salt[0] = '$'; + salt[1] = '1'; + salt[2] = '$'; + crypt_make_salt(salt + 3, 4); } - pass = pw_encrypt(pass, salt, 0); + free_me = pass = pw_encrypt(pass, salt, 0); } /* This is rather complex: if user is not found in /etc/shadow, * we try to find & change his passwd in /etc/passwd */ #if ENABLE_FEATURE_SHADOWPASSWDS rc = update_passwd(bb_path_shadow_file, name, pass, NULL); - if (rc == 0) /* no lines updated, no errors detected */ + if (rc > 0) /* password in /etc/shadow was updated */ + pass = (char*)"x"; + if (rc >= 0) + /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ #endif rc = update_passwd(bb_path_passwd_file, name, pass, NULL); /* LOGMODE_BOTH logs to syslog also */ @@ -64,8 +89,7 @@ int chpasswd_main(int argc UNUSED_PARAM, char **argv) bb_info_msg("Password for '%s' changed", name); logmode = LOGMODE_STDIO; free(name); - if (!(opt & OPT_ENC)) - free(pass); + free(free_me); } return EXIT_SUCCESS; } diff --git a/loginutils/cryptpw.c b/loginutils/cryptpw.c index b44993f..29f0fbe 100644 --- a/loginutils/cryptpw.c +++ b/loginutils/cryptpw.c @@ -2,14 +2,51 @@ /* * cryptpw.c - output a crypt(3)ed password to stdout. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Cooked from passwd.c by Thomas Lundquist * mkpasswd compatible options added by Bernhard Reutner-Fischer * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define cryptpw_trivial_usage +//usage: "[OPTIONS] [PASSWORD] [SALT]" +/* We do support -s, we just don't mention it */ +//usage:#define cryptpw_full_usage "\n\n" +//usage: "Crypt PASSWORD using crypt(3)\n" +//usage: IF_LONG_OPTS( +//usage: "\n -P,--password-fd=N Read password from fd N" +/* //usage: "\n -s,--stdin Use stdin; like -P0" */ +//usage: "\n -m,--method=TYPE Encryption method" +//usage: "\n -S,--salt=SALT" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -P N Read password from fd N" +/* //usage: "\n -s Use stdin; like -P0" */ +//usage: "\n -m TYPE Encryption method TYPE" +//usage: "\n -S SALT" +//usage: ) + +/* mkpasswd is an alias to cryptpw */ +//usage:#define mkpasswd_trivial_usage +//usage: "[OPTIONS] [PASSWORD] [SALT]" +/* We do support -s, we just don't mention it */ +//usage:#define mkpasswd_full_usage "\n\n" +//usage: "Crypt PASSWORD using crypt(3)\n" +//usage: IF_LONG_OPTS( +//usage: "\n -P,--password-fd=N Read password from fd N" +/* //usage: "\n -s,--stdin Use stdin; like -P0" */ +//usage: "\n -m,--method=TYPE Encryption method" +//usage: "\n -S,--salt=SALT" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -P N Read password from fd N" +/* //usage: "\n -s Use stdin; like -P0" */ +//usage: "\n -m TYPE Encryption method TYPE" +//usage: "\n -S SALT" +//usage: ) + #include "libbb.h" /* Debian has 'mkpasswd' utility, manpage says: @@ -53,11 +90,10 @@ to cryptpw. -a option (alias for -m) came from cryptpw. int cryptpw_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int cryptpw_main(int argc UNUSED_PARAM, char **argv) { - /* $N$ + sha_salt_16_bytes + NUL */ - char salt[3 + 16 + 1]; + char salt[MAX_PW_SALT_LEN]; char *salt_ptr; + char *password; const char *opt_m, *opt_S; - int len; int fd; #if ENABLE_LONG_OPTS @@ -70,7 +106,7 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) applet_long_options = mkpasswd_longopts; #endif fd = STDIN_FILENO; - opt_m = "d"; + opt_m = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; opt_S = NULL; /* at most two non-option arguments; -P NUM */ opt_complementary = "?2:P+"; @@ -82,36 +118,25 @@ int cryptpw_main(int argc UNUSED_PARAM, char **argv) if (argv[0] && !opt_S) opt_S = argv[1]; - len = 2/2; - salt_ptr = salt; - if (opt_m[0] != 'd') { /* not des */ - len = 8/2; /* so far assuming md5 */ - *salt_ptr++ = '$'; - *salt_ptr++ = '1'; - *salt_ptr++ = '$'; -#if !ENABLE_USE_BB_CRYPT || ENABLE_USE_BB_CRYPT_SHA - if (opt_m[0] == 's') { /* sha */ - salt[1] = '5' + (strcmp(opt_m, "sha512") == 0); - len = 16/2; - } -#endif - } + salt_ptr = crypt_make_pw_salt(salt, opt_m); if (opt_S) - safe_strncpy(salt_ptr, opt_S, sizeof(salt) - 3); - else - crypt_make_salt(salt_ptr, len, 0); + safe_strncpy(salt_ptr, opt_S, sizeof(salt) - (sizeof("$N$")-1)); xmove_fd(fd, STDIN_FILENO); - puts(pw_encrypt( - argv[0] ? argv[0] : ( - /* Only mkpasswd, and only from tty, prompts. - * Otherwise it is a plain read. */ - (isatty(STDIN_FILENO) && applet_name[0] == 'm') + password = argv[0]; + if (!password) { + /* Only mkpasswd, and only from tty, prompts. + * Otherwise it is a plain read. */ + password = (isatty(STDIN_FILENO) && applet_name[0] == 'm') ? bb_ask_stdin("Password: ") : xmalloc_fgetline(stdin) - ), - salt, 1)); + ; + /* may still be NULL on EOF/error */ + } + + if (password) + puts(pw_encrypt(password, salt, 1)); return EXIT_SUCCESS; } diff --git a/loginutils/deluser.c b/loginutils/deluser.c index 293e324..e39ac55 100644 --- a/loginutils/deluser.c +++ b/loginutils/deluser.c @@ -6,51 +6,110 @@ * Copyright (C) 1999,2000,2001 by John Beppu * Copyright (C) 2007 by Tito Ragusa * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * */ -#include "libbb.h" -static int del_line_matching(char **args, const char *filename) -{ - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) { - return update_passwd(filename, args[2], NULL, args[1]); - } - return update_passwd(filename, args[1], NULL, NULL); -} +//usage:#define deluser_trivial_usage +//usage: "USER" +//usage:#define deluser_full_usage "\n\n" +//usage: "Delete USER from the system" + +//usage:#define delgroup_trivial_usage +//usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" +//usage:#define delgroup_full_usage "\n\n" +//usage: "Delete group GROUP from the system" +//usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") + +#include "libbb.h" int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int deluser_main(int argc, char **argv) { - if (argc != 2 - && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP - || (applet_name[3] != 'g' || argc != 3)) - ) { - bb_show_usage(); - } + /* User or group name */ + char *name; + /* Username (non-NULL only in "delgroup USER GROUP" case) */ + char *member; + /* Name of passwd or group file */ + const char *pfile; + /* Name of shadow or gshadow file */ + const char *sfile; + /* Are we deluser or delgroup? */ + int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); - if (geteuid()) + if (geteuid() != 0) bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); - if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) - || ENABLE_DELUSER - || (ENABLE_DELGROUP && ENABLE_DESKTOP) - ) { - if (ENABLE_DELUSER - && (!ENABLE_DELGROUP || applet_name[3] == 'u') - ) { - if (del_line_matching(argv, bb_path_passwd_file) < 0) + name = argv[1]; + member = NULL; + + switch (argc) { + case 3: + if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) + break; + /* It's "delgroup USER GROUP" */ + member = name; + name = argv[2]; + /* Fallthrough */ + + case 2: + if (do_deluser) { + /* "deluser USER" */ + xgetpwnam(name); /* bail out if USER is wrong */ + pfile = bb_path_passwd_file; + if (ENABLE_FEATURE_SHADOWPASSWDS) + sfile = bb_path_shadow_file; + } else { + struct group *gr; + do_delgroup: + /* "delgroup GROUP" or "delgroup USER GROUP" */ + if (do_deluser < 0) { /* delgroup after deluser? */ + gr = getgrnam(name); + if (!gr) + return EXIT_SUCCESS; + } else { + gr = xgetgrnam(name); /* bail out if GROUP is wrong */ + } + if (!member) { + /* "delgroup GROUP" */ + struct passwd *pw; + struct passwd pwent; + /* Check if the group is in use */ +#define passwd_buf bb_common_bufsiz1 + while (!getpwent_r(&pwent, passwd_buf, sizeof(passwd_buf), &pw)) { + if (pwent.pw_gid == gr->gr_gid) + bb_error_msg_and_die("'%s' still has '%s' as their primary group!", pwent.pw_name, name); + } + //endpwent(); + } + pfile = bb_path_group_file; + if (ENABLE_FEATURE_SHADOWPASSWDS) + sfile = bb_path_gshadow_file; + } + + /* Modify pfile, then sfile */ + do { + if (update_passwd(pfile, name, NULL, member) == -1) return EXIT_FAILURE; if (ENABLE_FEATURE_SHADOWPASSWDS) { - del_line_matching(argv, bb_path_shadow_file); + pfile = sfile; + sfile = NULL; } - } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) - bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); - } - if (del_line_matching(argv, bb_path_group_file) < 0) - return EXIT_FAILURE; - if (ENABLE_FEATURE_SHADOWPASSWDS) { - del_line_matching(argv, bb_path_gshadow_file); + } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); + + if (ENABLE_DELGROUP && do_deluser > 0) { + /* "deluser USER" also should try to delete + * same-named group. IOW: do "delgroup USER" + */ +// On debian deluser is a perl script that calls userdel. +// From man userdel: +// If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will +// delete the group with the same name as the user. + do_deluser = -1; + goto do_delgroup; + } + return EXIT_SUCCESS; } - return EXIT_SUCCESS; + /* Reached only if number of command line args is wrong */ + bb_show_usage(); } diff --git a/loginutils/getty.c b/loginutils/getty.c index 40ec971..0f060ae 100644 --- a/loginutils/getty.c +++ b/loginutils/getty.c @@ -1,43 +1,50 @@ /* vi: set sw=4 ts=4: */ -/* agetty.c - another getty program for Linux. By W. Z. Venema 1989 +/* + * Based on agetty - another getty program for Linux. By W. Z. Venema 1989 * Ported to Linux by Peter Orbaek - * This program is freely distributable. The entire man-page used to - * be here. Now read the real man-page agetty.8 instead. + * This program is freely distributable. * * option added by Eric Rasmussen - 12/28/95 * * 1999-02-22 Arkadiusz Mickiewicz - * - added Native Language Support + * - Added Native Language Support * * 1999-05-05 Thorsten Kranzkowski - * - enable hardware flow control before displaying /etc/issue + * - Enabled hardware flow control before displaying /etc/issue + * + * 2011-01 Venys Vlasenko + * - Removed parity detection code. It can't work reliably: + * if all chars received have bit 7 cleared and odd (or even) parity, + * it is impossible to determine whether other side is 8-bit,no-parity + * or 7-bit,odd(even)-parity. It also interferes with non-ASCII usernames. + * - From now on, we assume that parity is correctly set. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include +#ifndef IUCLC +# define IUCLC 0 +#endif -#if ENABLE_FEATURE_UTMP -# include /* LOGIN_PROCESS */ +#ifndef LOGIN_PROCESS +# undef ENABLE_FEATURE_UTMP +# undef ENABLE_FEATURE_WTMP +# define ENABLE_FEATURE_UTMP 0 +# define ENABLE_FEATURE_WTMP 0 #endif -#ifndef IUCLC -# define IUCLC 0 + +/* The following is used for understandable diagnostics */ +#ifdef DEBUGGING +static FILE *dbf; +# define DEBUGTERM "/dev/ttyp0" +# define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0) +#else +# define debug(...) ((void)0) #endif -/* - * Some heuristics to find out what environment we are in: if it is not - * System V, assume it is SunOS 4. - */ -#ifdef LOGIN_PROCESS /* defined in System V utmp.h */ -#include -#else /* if !sysV style, wtmp/utmp code is off */ -#undef ENABLE_FEATURE_UTMP -#undef ENABLE_FEATURE_WTMP -#define ENABLE_FEATURE_UTMP 0 -#define ENABLE_FEATURE_WTMP 0 -#endif /* LOGIN_PROCESS */ /* * Things you may want to modify. @@ -46,110 +53,77 @@ * below. Note, however, that DEL cannot be used for interrupt generation * and for line editing at the same time. */ - -/* I doubt there are systems which still need this */ -#undef HANDLE_ALLCAPS -#undef ANCIENT_BS_KILL_CHARS - +#undef _PATH_LOGIN #define _PATH_LOGIN "/bin/login" -/* If ISSUE is not defined, getty will never display the contents of the +/* Displayed before the login prompt. + * If ISSUE is not defined, getty will never display the contents of the * /etc/issue file. You will not want to spit out large "issue" files at the * wrong baud rate. */ -#define ISSUE "/etc/issue" /* displayed before the login prompt */ - -/* Some shorthands for control characters. */ -#define CTL(x) ((x) ^ 0100) /* Assumes ASCII dialect */ -#define CR CTL('M') /* carriage return */ -#define NL CTL('J') /* line feed */ -#define BS CTL('H') /* back space */ -#define DEL CTL('?') /* delete */ - -/* Defaults for line-editing etc. characters; you may want to change this. */ -#define DEF_ERASE DEL /* default erase character */ -#define DEF_INTR CTL('C') /* default interrupt character */ -#define DEF_QUIT CTL('\\') /* default quit char */ -#define DEF_KILL CTL('U') /* default kill char */ -#define DEF_EOF CTL('D') /* default EOF char */ -#define DEF_EOL '\n' -#define DEF_SWITCH 0 /* default switch char */ +#define ISSUE "/etc/issue" + +/* Macro to build Ctrl-LETTER. Assumes ASCII dialect */ +#define CTL(x) ((x) ^ 0100) /* - * When multiple baud rates are specified on the command line, the first one - * we will try is the first one specified. + * When multiple baud rates are specified on the command line, + * the first one we will try is the first one specified. */ #define MAX_SPEED 10 /* max. nr. of baud rates */ -/* Storage for command-line options. */ -struct options { - int flags; /* toggle switches, see below */ - unsigned timeout; /* time-out period */ +struct globals { + unsigned timeout; const char *login; /* login program */ - const char *tty; /* name of tty */ - const char *initstring; /* modem init string */ + const char *fakehost; + const char *tty_name; + char *initstring; /* modem init string */ const char *issue; /* alternative issue file */ int numspeed; /* number of baud rates to try */ int speeds[MAX_SPEED]; /* baud rates to be tried */ + unsigned char eol; /* end-of-line char seen (CR or NL) */ + struct termios tty_attrs; + char line_buf[128]; }; -/* Storage for things detected while the login name was read. */ -struct chardata { - unsigned char erase; /* erase character */ - unsigned char kill; /* kill character */ - unsigned char eol; /* end-of-line character */ - unsigned char parity; /* what parity did we see */ - /* (parity & 1): saw odd parity char with 7th bit set */ - /* (parity & 2): saw even parity char with 7th bit set */ - /* parity == 0: probably 7-bit, space parity? */ - /* parity == 1: probably 7-bit, odd parity? */ - /* parity == 2: probably 7-bit, even parity? */ - /* parity == 3: definitely 8 bit, no parity! */ - /* Hmm... with any value of "parity" 8 bit, no parity is possible */ -#ifdef HANDLE_ALLCAPS - unsigned char capslock; /* upper case without lower case */ -#endif -}; - - -/* Initial values for the above. */ -static const struct chardata init_chardata = { - DEF_ERASE, /* default erase character */ - DEF_KILL, /* default kill character */ - 13, /* default eol char */ - 0, /* space parity */ -#ifdef HANDLE_ALLCAPS - 0, /* no capslock */ -#endif -}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +//usage:#define getty_trivial_usage +//usage: "[OPTIONS] BAUD_RATE[,BAUD_RATE]... TTY [TERMTYPE]" +//usage:#define getty_full_usage "\n\n" +//usage: "Open TTY, prompt for login name, then invoke /bin/login\n" +//usage: "\n -h Enable hardware RTS/CTS flow control" +//usage: "\n -L Set CLOCAL (ignore Carrier Detect state)" +//usage: "\n -m Get baud rate from modem's CONNECT status message" +//usage: "\n -n Don't prompt for login name" +//usage: "\n -w Wait for CR or LF before sending /etc/issue" +//usage: "\n -i Don't display /etc/issue" +//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" +//usage: "\n -l LOGIN Invoke LOGIN instead of /bin/login" +//usage: "\n -t SEC Terminate after SEC if no login name is read" +//usage: "\n -I INITSTR Send INITSTR before anything else" +//usage: "\n -H HOST Log HOST into the utmp file as the hostname" +//usage: "\n" +//usage: "\nBAUD_RATE of 0 leaves it unchanged" static const char opt_string[] ALIGN1 = "I:LH:f:hil:mt:wn"; -#define F_INITSTRING (1 << 0) /* -I initstring is set */ -#define F_LOCAL (1 << 1) /* -L force local */ -#define F_FAKEHOST (1 << 2) /* -H fake hostname */ -#define F_CUSTISSUE (1 << 3) /* -f give alternative issue file */ -#define F_RTSCTS (1 << 4) /* -h enable RTS/CTS flow control */ -#define F_ISSUE (1 << 5) /* -i display /etc/issue */ -#define F_LOGIN (1 << 6) /* -l non-default login program */ -#define F_PARSE (1 << 7) /* -m process modem status messages */ -#define F_TIMEOUT (1 << 8) /* -t time out */ -#define F_WAITCRLF (1 << 9) /* -w wait for CR or LF */ -#define F_NOPROMPT (1 << 10) /* -n don't ask for login name */ - - -#define line_buf bb_common_bufsiz1 - -/* The following is used for understandable diagnostics. */ -#ifdef DEBUGGING -static FILE *dbf; -#define DEBUGTERM "/dev/ttyp0" -#define debug(...) do { fprintf(dbf, __VA_ARGS__); fflush(dbf); } while (0) -#else -#define debug(...) ((void)0) -#endif - - -/* bcode - convert speed string to speed code; return <= 0 on failure */ +#define F_INITSTRING (1 << 0) /* -I */ +#define F_LOCAL (1 << 1) /* -L */ +#define F_FAKEHOST (1 << 2) /* -H */ +#define F_CUSTISSUE (1 << 3) /* -f */ +#define F_RTSCTS (1 << 4) /* -h */ +#define F_NOISSUE (1 << 5) /* -i */ +#define F_LOGIN (1 << 6) /* -l */ +#define F_PARSE (1 << 7) /* -m */ +#define F_TIMEOUT (1 << 8) /* -t */ +#define F_WAITCRLF (1 << 9) /* -w */ +#define F_NOPROMPT (1 << 10) /* -n */ + + +/* convert speed string to speed code; return <= 0 on failure */ static int bcode(const char *s) { int value = bb_strtou(s, NULL, 10); /* yes, int is intended! */ @@ -158,67 +132,53 @@ static int bcode(const char *s) return tty_value_to_baud(value); } -/* parse_speeds - parse alternate baud rates */ -static void parse_speeds(struct options *op, char *arg) +/* parse alternate baud rates */ +static void parse_speeds(char *arg) { char *cp; /* NB: at least one iteration is always done */ debug("entered parse_speeds\n"); while ((cp = strsep(&arg, ",")) != NULL) { - op->speeds[op->numspeed] = bcode(cp); - if (op->speeds[op->numspeed] < 0) + G.speeds[G.numspeed] = bcode(cp); + if (G.speeds[G.numspeed] < 0) bb_error_msg_and_die("bad speed: %s", cp); /* note: arg "0" turns into speed B0 */ - op->numspeed++; - if (op->numspeed > MAX_SPEED) + G.numspeed++; + if (G.numspeed > MAX_SPEED) bb_error_msg_and_die("too many alternate speeds"); } debug("exiting parse_speeds\n"); } -/* parse_args - parse command-line arguments */ -static void parse_args(char **argv, struct options *op, char **fakehost_p) +/* parse command-line arguments */ +static void parse_args(char **argv) { char *ts; + int flags; opt_complementary = "-2:t+"; /* at least 2 args; -t N */ - op->flags = getopt32(argv, opt_string, - &(op->initstring), fakehost_p, &(op->issue), - &(op->login), &op->timeout); - argv += optind; - if (op->flags & F_INITSTRING) { - const char *p = op->initstring; - char *q; - - op->initstring = q = xstrdup(p); - /* copy optarg into op->initstring decoding \ddd - octal codes into chars */ - while (*p) { - if (*p == '\\') { - p++; - *q++ = bb_process_escape_sequence(&p); - } else { - *q++ = *p++; - } - } - *q = '\0'; + flags = getopt32(argv, opt_string, + &G.initstring, &G.fakehost, &G.issue, + &G.login, &G.timeout + ); + if (flags & F_INITSTRING) { + G.initstring = xstrdup(G.initstring); + /* decode \ddd octal codes into chars */ + strcpy_and_process_escape_sequences(G.initstring, G.initstring); } - op->flags ^= F_ISSUE; /* invert flag "show /etc/issue" */ + argv += optind; debug("after getopt\n"); - /* we loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ - op->tty = argv[0]; /* tty name */ - ts = argv[1]; /* baud rate(s) */ + /* We loosen up a bit and accept both "baudrate tty" and "tty baudrate" */ + G.tty_name = argv[0]; + ts = argv[1]; /* baud rate(s) */ if (isdigit(argv[0][0])) { - /* a number first, assume it's a speed (BSD style) */ - op->tty = ts; /* tty name is in argv[1] */ - ts = argv[0]; /* baud rate(s) */ + /* A number first, assume it's a speed (BSD style) */ + G.tty_name = ts; /* tty name is in argv[1] */ + ts = argv[0]; /* baud rate(s) */ } - parse_speeds(op, ts); - -// TODO: if applet_name is set to "getty: TTY", bb_error_msg's get simpler! -// grep for "%s:" + parse_speeds(ts); if (argv[2]) xsetenv("TERM", argv[2]); @@ -226,102 +186,208 @@ static void parse_args(char **argv, struct options *op, char **fakehost_p) debug("exiting parse_args\n"); } -/* open_tty - set up tty as standard { input, output, error } */ -static void open_tty(const char *tty) +/* set up tty as standard input, output, error */ +static void open_tty(void) { - /* Set up new standard input, unless we are given an already opened port. */ - if (NOT_LONE_DASH(tty)) { -// struct stat st; -// int cur_dir_fd; -// int fd; - - /* Sanity checks... */ -// cur_dir_fd = xopen(".", O_DIRECTORY | O_NONBLOCK); -// xchdir("/dev"); -// xstat(tty, &st); -// if (!S_ISCHR(st.st_mode)) -// bb_error_msg_and_die("%s: not a character device", tty); - - if (tty[0] != '/') - tty = xasprintf("/dev/%s", tty); /* will leak it */ - - /* Open the tty as standard input. */ + /* Set up new standard input, unless we are given an already opened port */ + if (NOT_LONE_DASH(G.tty_name)) { + if (G.tty_name[0] != '/') + G.tty_name = xasprintf("/dev/%s", G.tty_name); /* will leak it */ + + /* Open the tty as standard input */ debug("open(2)\n"); close(0); - /*fd =*/ xopen(tty, O_RDWR | O_NONBLOCK); /* uses fd 0 */ - -// /* Restore current directory */ -// fchdir(cur_dir_fd); - - /* Open the tty as standard input, continued */ -// xmove_fd(fd, 0); -// /* fd is >= cur_dir_fd, and cur_dir_fd gets closed too here: */ -// while (fd > 2) -// close(fd--); + xopen(G.tty_name, O_RDWR | O_NONBLOCK); /* uses fd 0 */ - /* Set proper protections and ownership. */ + /* Set proper protections and ownership */ fchown(0, 0, 0); /* 0:0 */ fchmod(0, 0620); /* crw--w---- */ } else { + char *n; /* - * Standard input should already be connected to an open port. Make - * sure it is open for read/write. + * Standard input should already be connected to an open port. + * Make sure it is open for read/write. */ - if ((fcntl(0, F_GETFL) & O_RDWR) != O_RDWR) + if ((fcntl(0, F_GETFL) & (O_RDWR|O_RDONLY|O_WRONLY)) != O_RDWR) bb_error_msg_and_die("stdin is not open for read/write"); + + /* Try to get real tty name instead of "-" */ + n = xmalloc_ttyname(0); + if (n) + G.tty_name = n; } + applet_name = xasprintf("getty: %s", skip_dev_pfx(G.tty_name)); } -/* termios_init - initialize termios settings */ -static void termios_init(struct termios *tp, int speed, struct options *op) +static void set_tty_attrs(void) { - speed_t ispeed, ospeed; - /* - * Initial termios settings: 8-bit characters, raw-mode, blocking i/o. + if (tcsetattr_stdin_TCSANOW(&G.tty_attrs) < 0) + bb_perror_msg_and_die("tcsetattr"); +} + +/* We manipulate tty_attrs this way: + * - first, we read existing tty_attrs + * - init_tty_attrs modifies some parts and sets it + * - auto_baud and/or BREAK processing can set different speed and set tty attrs + * - finalize_tty_attrs again modifies some parts and sets tty attrs before + * execing login + */ +static void init_tty_attrs(int speed) +{ + /* Try to drain output buffer, with 5 sec timeout. + * Added on request from users of ~600 baud serial interface + * with biggish buffer on a 90MHz CPU. + * They were losing hundreds of bytes of buffered output + * on tcflush. + */ + signal_no_SA_RESTART_empty_mask(SIGALRM, record_signo); + alarm(5); + tcdrain(STDIN_FILENO); + alarm(0); + + /* Flush input and output queues, important for modems! */ + tcflush(STDIN_FILENO, TCIOFLUSH); + + /* Set speed if it wasn't specified as "0" on command line */ + if (speed != B0) + cfsetspeed(&G.tty_attrs, speed); + + /* Initial settings: 8-bit characters, raw mode, blocking i/o. * Special characters are set after we have read the login name; all - * reads will be done in raw mode anyway. Errors will be dealt with - * later on. + * reads will be done in raw mode anyway. */ -#ifdef __linux__ - /* flush input and output queues, important for modems! */ - ioctl(0, TCFLSH, TCIOFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ + /* Clear all bits except: */ + G.tty_attrs.c_cflag &= (0 + /* 2 stop bits (1 otherwise) + * Enable parity bit (both on input and output) + * Odd parity (else even) + */ + | CSTOPB | PARENB | PARODD +#ifdef CMSPAR + | CMSPAR /* mark or space parity */ +#endif +#ifdef CBAUD + | CBAUD /* (output) baud rate */ +#endif +#ifdef CBAUDEX + | CBAUDEX /* (output) baud rate */ +#endif +#ifdef CIBAUD + | CIBAUD /* input baud rate */ #endif - ispeed = ospeed = speed; - if (speed == B0) { - /* Speed was specified as "0" on command line. - * Just leave it unchanged */ - ispeed = cfgetispeed(tp); - ospeed = cfgetospeed(tp); + ); + /* Set: 8 bits; hang up (drop DTR) on last close; enable receive */ + G.tty_attrs.c_cflag |= CS8 | HUPCL | CREAD; + if (option_mask32 & F_LOCAL) { + /* ignore Carrier Detect pin: + * opens don't block when CD is low, + * losing CD doesn't hang up processes whose ctty is this tty + */ + G.tty_attrs.c_cflag |= CLOCAL; } - tp->c_cflag = CS8 | HUPCL | CREAD; - if (op->flags & F_LOCAL) - tp->c_cflag |= CLOCAL; - cfsetispeed(tp, ispeed); - cfsetospeed(tp, ospeed); - - tp->c_iflag = tp->c_lflag = tp->c_line = 0; - tp->c_oflag = OPOST | ONLCR; - tp->c_cc[VMIN] = 1; - tp->c_cc[VTIME] = 0; - - /* Optionally enable hardware flow control */ #ifdef CRTSCTS - if (op->flags & F_RTSCTS) - tp->c_cflag |= CRTSCTS; + if (option_mask32 & F_RTSCTS) + G.tty_attrs.c_cflag |= CRTSCTS; /* flow control using RTS/CTS pins */ +#endif + G.tty_attrs.c_iflag = 0; + G.tty_attrs.c_lflag = 0; + /* non-raw output; add CR to each NL */ + G.tty_attrs.c_oflag = OPOST | ONLCR; + + /* reads would block only if < 1 char is available */ + G.tty_attrs.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + G.tty_attrs.c_cc[VTIME] = 0; +#ifdef __linux__ + G.tty_attrs.c_line = 0; #endif - tcsetattr_stdin_TCSANOW(tp); + set_tty_attrs(); debug("term_io 2\n"); } -/* auto_baud - extract baud rate from modem status message */ -static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) +static void finalize_tty_attrs(void) +{ + /* software flow control on output (stop sending if XOFF is recvd); + * and on input (send XOFF when buffer is full) + */ + G.tty_attrs.c_iflag |= IXON | IXOFF; + if (G.eol == '\r') { + G.tty_attrs.c_iflag |= ICRNL; /* map CR on input to NL */ + } + /* Other bits in c_iflag: + * IXANY Any recvd char enables output (any char is also a XON) + * INPCK Enable parity check + * IGNPAR Ignore parity errors (drop bad bytes) + * PARMRK Mark parity errors with 0xff, 0x00 prefix + * (else bad byte is received as 0x00) + * ISTRIP Strip parity bit + * IGNBRK Ignore break condition + * BRKINT Send SIGINT on break - maybe set this? + * INLCR Map NL to CR + * IGNCR Ignore CR + * ICRNL Map CR to NL + * IUCLC Map uppercase to lowercase + * IMAXBEL Echo BEL on input line too long + * IUTF8 Appears to affect tty's idea of char widths, + * observed to improve backspacing through Unicode chars + */ + + /* line buffered input (NL or EOL or EOF chars end a line); + * recognize INT/QUIT/SUSP chars; + * echo input chars; + * echo BS-SP-BS on erase character; + * echo kill char specially, not as ^c (ECHOKE controls how exactly); + * erase all input via BS-SP-BS on kill char (else go to next line) + */ + G.tty_attrs.c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; + /* Other bits in c_lflag: + * XCASE Map uppercase to \lowercase [tried, doesn't work] + * ECHONL Echo NL even if ECHO is not set + * ECHOCTL Echo ctrl chars as ^c (else don't echo) - maybe set this? + * ECHOPRT On erase, echo erased chars + * [qwe input looks like "qwe\ewq/" on screen] + * NOFLSH Don't flush input buffer after interrupt or quit chars + * IEXTEN Enable extended functions (??) + * [glibc says it enables c_cc[LNEXT] "enter literal char" + * and c_cc[VDISCARD] "toggle discard buffered output" chars] + * FLUSHO Output being flushed (c_cc[VDISCARD] is in effect) + * PENDIN Retype pending input at next read or input char + * (c_cc[VREPRINT] is being processed) + * TOSTOP Send SIGTTOU for background output + * (why "stty sane" unsets this bit?) + */ + + G.tty_attrs.c_cc[VINTR] = CTL('C'); + G.tty_attrs.c_cc[VQUIT] = CTL('\\'); + G.tty_attrs.c_cc[VEOF] = CTL('D'); + G.tty_attrs.c_cc[VEOL] = '\n'; +#ifdef VSWTC + G.tty_attrs.c_cc[VSWTC] = 0; +#endif +#ifdef VSWTCH + G.tty_attrs.c_cc[VSWTCH] = 0; +#endif + G.tty_attrs.c_cc[VKILL] = CTL('U'); + /* Other control chars: + * VEOL2 + * VERASE, VWERASE - (word) erase. we may set VERASE in get_logname + * VREPRINT - reprint current input buffer + * VLNEXT, VDISCARD, VSTATUS + * VSUSP, VDSUSP - send (delayed) SIGTSTP + * VSTART, VSTOP - chars used for IXON/IXOFF + */ + + set_tty_attrs(); + + /* Now the newline character should be properly written */ + full_write(STDOUT_FILENO, "\n", 1); +} + +/* extract baud rate from modem status message */ +static void auto_baud(void) { - int speed; - int vmin; - unsigned iflag; - char *bp; int nread; /* @@ -339,278 +405,181 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) * modem status messages is enabled. */ - /* - * Use 7-bit characters, don't block if input queue is empty. Errors will - * be dealt with later on. - */ - iflag = tp->c_iflag; - tp->c_iflag |= ISTRIP; /* enable 8th-bit stripping */ - vmin = tp->c_cc[VMIN]; - tp->c_cc[VMIN] = 0; /* don't block if queue empty */ - tcsetattr_stdin_TCSANOW(tp); + G.tty_attrs.c_cc[VMIN] = 0; /* don't block reads (min read is 0 chars) */ + set_tty_attrs(); /* * Wait for a while, then read everything the modem has said so far and * try to extract the speed of the dial-in call. */ sleep(1); - nread = safe_read(STDIN_FILENO, buf, size_buf - 1); + nread = safe_read(STDIN_FILENO, G.line_buf, sizeof(G.line_buf) - 1); if (nread > 0) { - buf[nread] = '\0'; - for (bp = buf; bp < buf + nread; bp++) { + int speed; + char *bp; + G.line_buf[nread] = '\0'; + for (bp = G.line_buf; bp < G.line_buf + nread; bp++) { if (isdigit(*bp)) { speed = bcode(bp); - if (speed > 0) { - tp->c_cflag &= ~CBAUD; - tp->c_cflag |= speed; - } + if (speed > 0) + cfsetspeed(&G.tty_attrs, speed); break; } } } - /* Restore terminal settings. Errors will be dealt with later on. */ - tp->c_iflag = iflag; - tp->c_cc[VMIN] = vmin; - tcsetattr_stdin_TCSANOW(tp); -} - -/* do_prompt - show login prompt, optionally preceded by /etc/issue contents */ -static void do_prompt(struct options *op) -{ -#ifdef ISSUE - print_login_issue(op->issue, op->tty); -#endif - print_login_prompt(); -} - -#ifdef HANDLE_ALLCAPS -/* all_is_upcase - string contains upper case without lower case */ -/* returns 1 if true, 0 if false */ -static int all_is_upcase(const char *s) -{ - while (*s) - if (islower(*s++)) - return 0; - return 1; + /* Restore terminal settings */ + G.tty_attrs.c_cc[VMIN] = 1; /* restore to value set by init_tty_attrs */ + set_tty_attrs(); } -#endif -/* get_logname - get user name, establish parity, speed, erase, kill, eol; - * return NULL on BREAK, logname on success */ -static char *get_logname(char *logname, unsigned size_logname, - struct options *op, struct chardata *cp) +/* get user name, establish parity, speed, erase, kill, eol; + * return NULL on BREAK, logname on success + */ +static char *get_logname(void) { char *bp; - char c; /* input character, full eight bits */ - char ascval; /* low 7 bits of input character */ - int bits; /* # of "1" bits per character */ - int mask; /* mask with 1 bit up */ - static const char erase[][3] = {/* backspace-space-backspace */ - "\010\040\010", /* space parity */ - "\010\040\010", /* odd parity */ - "\210\240\210", /* even parity */ - "\010\040\010", /* 8 bit no parity */ - }; - - /* NB: *cp is pre-initialized with init_chardata */ - - /* Flush pending input (esp. after parsing or switching the baud rate). */ - sleep(1); - ioctl(0, TCFLSH, TCIFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ + char c; - /* Prompt for and read a login name. */ - logname[0] = '\0'; - while (!logname[0]) { - /* Write issue file and prompt, with "parity" bit == 0. */ - do_prompt(op); + /* Flush pending input (esp. after parsing or switching the baud rate) */ + usleep(100*1000); /* 0.1 sec */ + tcflush(STDIN_FILENO, TCIFLUSH); - /* Read name, watch for break, parity, erase, kill, end-of-line. */ - bp = logname; - cp->eol = '\0'; - while (cp->eol == '\0') { + /* Prompt for and read a login name */ + do { + /* Write issue file and prompt */ +#ifdef ISSUE + if (!(option_mask32 & F_NOISSUE)) + print_login_issue(G.issue, G.tty_name); +#endif + print_login_prompt(); - /* Do not report trivial EINTR/EIO errors. */ + /* Read name, watch for break, erase, kill, end-of-line */ + bp = G.line_buf; + while (1) { + /* Do not report trivial EINTR/EIO errors */ errno = EINTR; /* make read of 0 bytes be silent too */ if (read(STDIN_FILENO, &c, 1) < 1) { + finalize_tty_attrs(); if (errno == EINTR || errno == EIO) exit(EXIT_SUCCESS); - bb_perror_msg_and_die("%s: read", op->tty); - } - - /* BREAK. If we have speeds to try, - * return NULL (will switch speeds and return here) */ - if (c == '\0' && op->numspeed > 1) - return NULL; - - /* Do parity bit handling. */ - if (!(op->flags & F_LOCAL) && (c & 0x80)) { /* "parity" bit on? */ - bits = 1; - mask = 1; - while (mask & 0x7f) { - if (mask & c) - bits++; /* count "1" bits */ - mask <<= 1; - } - /* ... |= 2 - even, 1 - odd */ - cp->parity |= 2 - (bits & 1); + bb_perror_msg_and_die(bb_msg_read_error); } - /* Do erase, kill and end-of-line processing. */ - ascval = c & 0x7f; - switch (ascval) { - case CR: - case NL: - *bp = '\0'; /* terminate logname */ - cp->eol = ascval; /* set end-of-line char */ - break; - case BS: - case DEL: -#ifdef ANCIENT_BS_KILL_CHARS - case '#': -#endif - cp->erase = ascval; /* set erase character */ - if (bp > logname) { - full_write(STDOUT_FILENO, erase[cp->parity], 3); + switch (c) { + case '\r': + case '\n': + *bp = '\0'; + G.eol = c; + goto got_logname; + case CTL('H'): + case 0x7f: + G.tty_attrs.c_cc[VERASE] = c; + if (bp > G.line_buf) { + full_write(STDOUT_FILENO, "\010 \010", 3); bp--; } break; case CTL('U'): -#ifdef ANCIENT_BS_KILL_CHARS - case '@': -#endif - cp->kill = ascval; /* set kill character */ - while (bp > logname) { - full_write(STDOUT_FILENO, erase[cp->parity], 3); + while (bp > G.line_buf) { + full_write(STDOUT_FILENO, "\010 \010", 3); bp--; } break; + case CTL('C'): case CTL('D'): + finalize_tty_attrs(); exit(EXIT_SUCCESS); + case '\0': + /* BREAK. If we have speeds to try, + * return NULL (will switch speeds and return here) */ + if (G.numspeed > 1) + return NULL; + /* fall through and ignore it */ default: - if (ascval < ' ') { + if ((unsigned char)c < ' ') { /* ignore garbage characters */ - } else if ((int)(bp - logname) >= size_logname - 1) { - bb_error_msg_and_die("%s: input overrun", op->tty); - } else { - full_write(STDOUT_FILENO, &c, 1); /* echo the character */ - *bp++ = ascval; /* and store it */ + } else if ((int)(bp - G.line_buf) < sizeof(G.line_buf) - 1) { + /* echo and store the character */ + full_write(STDOUT_FILENO, &c, 1); + *bp++ = c; } break; } - } - } - /* Handle names with upper case and no lower case. */ - -#ifdef HANDLE_ALLCAPS - cp->capslock = all_is_upcase(logname); - if (cp->capslock) { - for (bp = logname; *bp; bp++) - if (isupper(*bp)) - *bp = tolower(*bp); /* map name to lower case */ - } -#endif - return logname; + } /* end of get char loop */ + got_logname: ; + } while (G.line_buf[0] == '\0'); /* while logname is empty */ + + return G.line_buf; } -/* termios_final - set the final tty mode bits */ -static void termios_final(struct options *op, struct termios *tp, struct chardata *cp) +static void alarm_handler(int sig UNUSED_PARAM) { - /* General terminal-independent stuff. */ -// tp->c_iflag |= IXON | IXOFF; /* 2-way flow control */ - tp->c_lflag |= ICANON | ISIG | ECHO | ECHOE | ECHOK | ECHOKE; - /* no longer| ECHOCTL | ECHOPRT */ - tp->c_oflag |= OPOST; - /* tp->c_cflag = 0; */ - tp->c_cc[VINTR] = DEF_INTR; /* default interrupt */ - tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ - tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ - tp->c_cc[VEOL] = DEF_EOL; - tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ - - /* Account for special characters seen in input. */ - if (cp->eol == CR) { - tp->c_iflag |= ICRNL; /* map CR in input to NL */ - tp->c_oflag |= ONLCR; /* map NL in output to CR-NL */ - } - tp->c_cc[VERASE] = cp->erase; /* set erase character */ - tp->c_cc[VKILL] = cp->kill; /* set kill character */ - - /* Account for the presence or absence of parity bits in input. */ - switch (cp->parity) { - case 0: /* space (always 0) parity */ -// I bet most people go here - they use only 7-bit chars in usernames.... - break; - case 1: /* odd parity */ - tp->c_cflag |= PARODD; - /* FALLTHROUGH */ - case 2: /* even parity */ - tp->c_cflag |= PARENB; - tp->c_iflag |= INPCK | ISTRIP; - /* FALLTHROUGH */ - case (1 | 2): /* no parity bit */ - tp->c_cflag &= ~CSIZE; - tp->c_cflag |= CS7; -// FIXME: wtf? case 3: we saw both even and odd 8-bit bytes - -// it's probably some umlauts etc, but definitely NOT 7-bit!!! -// Entire parity detection madness here just begs for deletion... - break; - } - - /* Account for upper case without lower case. */ -#ifdef HANDLE_ALLCAPS - if (cp->capslock) { - tp->c_iflag |= IUCLC; - tp->c_lflag |= XCASE; - tp->c_oflag |= OLCUC; - } -#endif - /* Optionally enable hardware flow control */ -#ifdef CRTSCTS - if (op->flags & F_RTSCTS) - tp->c_cflag |= CRTSCTS; -#endif - - /* Finally, make the new settings effective */ - /* It's tcsetattr_stdin_TCSANOW() + error check */ - ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); + finalize_tty_attrs(); + _exit(EXIT_SUCCESS); } int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int getty_main(int argc UNUSED_PARAM, char **argv) { int n; - pid_t pid; - char *fakehost = NULL; /* Fake hostname for ut_host */ - char *logname; /* login name, given to /bin/login */ - /* Merging these into "struct local" may _seem_ to reduce - * parameter passing, but today's gcc will inline - * statics which are called once anyway, so don't do that */ - struct chardata chardata; /* set by get_logname() */ - struct termios termios; /* terminal mode bits */ - struct options options; - - chardata = init_chardata; - - memset(&options, 0, sizeof(options)); - options.login = _PATH_LOGIN; /* default login program */ - options.tty = "tty1"; /* default tty line */ - options.initstring = ""; /* modem init string */ + pid_t pid, tsid; + char *logname; + + INIT_G(); + G.login = _PATH_LOGIN; /* default login program */ #ifdef ISSUE - options.issue = ISSUE; /* default issue file */ + G.issue = ISSUE; /* default issue file */ #endif + G.eol = '\r'; + + /* Parse command-line arguments */ + parse_args(argv); + + /* Create new session and pgrp, lose controlling tty */ + pid = setsid(); /* this also gives us our pid :) */ + if (pid < 0) { + int fd; + /* :( + * docs/ctty.htm says: + * "This is allowed only when the current process + * is not a process group leader". + * Thus, setsid() will fail if we _already_ are + * a session leader - which is quite possible for getty! + */ + pid = getpid(); + if (getsid(0) != pid) { + //for debugging: + //bb_perror_msg_and_die("setsid failed:" + // " pid %d ppid %d" + // " sid %d pgid %d", + // pid, getppid(), + // getsid(0), getpgid(0)); + bb_perror_msg_and_die("setsid"); + } + /* Looks like we are already a session leader. + * In this case (setsid failed) we may still have ctty, + * and it may be different from tty we need to control! + * If we still have ctty, on Linux ioctl(TIOCSCTTY) + * (which we are going to use a bit later) always fails - + * even if we try to take ctty which is already ours! + * Try to drop old ctty now to prevent that. + * Use O_NONBLOCK: old ctty may be a serial line. + */ + fd = open("/dev/tty", O_RDWR | O_NONBLOCK); + if (fd >= 0) { + /* TIOCNOTTY sends SIGHUP to the foreground + * process group - which may include us! + * Make sure to not die on it: + */ + sighandler_t old = signal(SIGHUP, SIG_IGN); + ioctl(fd, TIOCNOTTY); + close(fd); + signal(SIGHUP, old); + } + } - /* Parse command-line arguments. */ - parse_args(argv, &options, &fakehost); - - logmode = LOGMODE_NONE; - - /* Create new session, lose controlling tty, if any */ - /* docs/ctty.htm says: - * "This is allowed only when the current process - * is not a process group leader" - is this a problem? */ - setsid(); - /* close stdio, and stray descriptors, just in case */ + /* Close stdio, and stray descriptors, just in case */ n = xopen(bb_dev_null, O_RDWR); /* dup2(n, 0); - no, we need to handle "getty - 9600" too */ xdup2(n, 1); @@ -634,13 +603,25 @@ int getty_main(int argc UNUSED_PARAM, char **argv) #endif /* Open the tty as standard input, if it is not "-" */ - /* If it's not "-" and not taken yet, it will become our ctty */ debug("calling open_tty\n"); - open_tty(options.tty); - ndelay_off(0); + open_tty(); + ndelay_off(STDIN_FILENO); debug("duping\n"); - xdup2(0, 1); - xdup2(0, 2); + xdup2(STDIN_FILENO, 1); + xdup2(STDIN_FILENO, 2); + + /* Steal ctty if we don't have it yet */ + tsid = tcgetsid(STDIN_FILENO); + if (tsid < 0 || pid != tsid) { + if (ioctl(STDIN_FILENO, TIOCSCTTY, /*force:*/ (long)1) < 0) + bb_perror_msg_and_die("TIOCSCTTY"); + } + +#ifdef __linux__ + /* Make ourself a foreground process group within our session */ + if (tcsetpgrp(STDIN_FILENO, pid) < 0) + bb_perror_msg_and_die("tcsetpgrp"); +#endif /* * The following ioctl will fail if stdin is not a tty, but also when @@ -650,87 +631,70 @@ int getty_main(int argc UNUSED_PARAM, char **argv) * by patching the SunOS kernel variable "zsadtrlow" to a larger value; * 5 seconds seems to be a good value. */ - /* tcgetattr() + error check */ - ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty); - - pid = getpid(); -#ifdef __linux__ -// FIXME: do we need this? Otherwise "-" case seems to be broken... - // /* Forcibly make fd 0 our controlling tty, even if another session - // * has it as a ctty. (Another session loses ctty). */ - // ioctl(0, TIOCSCTTY, (void*)1); - /* Make ourself a foreground process group within our session */ - tcsetpgrp(0, pid); -#endif + if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0) + bb_perror_msg_and_die("tcgetattr"); /* Update the utmp file. This tty is ours now! */ - update_utmp(pid, LOGIN_PROCESS, options.tty, "LOGIN", fakehost); + update_utmp(pid, LOGIN_PROCESS, G.tty_name, "LOGIN", G.fakehost); - /* Initialize the termios settings (raw mode, eight-bit, blocking i/o). */ - debug("calling termios_init\n"); - termios_init(&termios, options.speeds[0], &options); + /* Initialize tty attrs (raw mode, eight-bit, blocking i/o) */ + debug("calling init_tty_attrs\n"); + init_tty_attrs(G.speeds[0]); /* Write the modem init string and DON'T flush the buffers */ - if (options.flags & F_INITSTRING) { + if (option_mask32 & F_INITSTRING) { debug("writing init string\n"); - full_write1_str(options.initstring); + full_write1_str(G.initstring); } /* Optionally detect the baud rate from the modem status message */ debug("before autobaud\n"); - if (options.flags & F_PARSE) - auto_baud(line_buf, sizeof(line_buf), &termios); + if (option_mask32 & F_PARSE) + auto_baud(); /* Set the optional timer */ - alarm(options.timeout); /* if 0, alarm is not set */ + signal(SIGALRM, alarm_handler); + alarm(G.timeout); /* if 0, alarm is not set */ /* Optionally wait for CR or LF before writing /etc/issue */ - if (options.flags & F_WAITCRLF) { + if (option_mask32 & F_WAITCRLF) { char ch; - debug("waiting for cr-lf\n"); while (safe_read(STDIN_FILENO, &ch, 1) == 1) { debug("read %x\n", (unsigned char)ch); - ch &= 0x7f; /* strip "parity bit" */ if (ch == '\n' || ch == '\r') break; } } logname = NULL; - if (!(options.flags & F_NOPROMPT)) { - /* NB:termios_init already set line speed - * to options.speeds[0] */ + if (!(option_mask32 & F_NOPROMPT)) { + /* NB: init_tty_attrs already set line speed + * to G.speeds[0] */ int baud_index = 0; while (1) { - /* Read the login name. */ + /* Read the login name */ debug("reading login name\n"); - logname = get_logname(line_buf, sizeof(line_buf), - &options, &chardata); + logname = get_logname(); if (logname) break; - /* we are here only if options.numspeed > 1 */ - baud_index = (baud_index + 1) % options.numspeed; - cfsetispeed(&termios, options.speeds[baud_index]); - cfsetospeed(&termios, options.speeds[baud_index]); - tcsetattr_stdin_TCSANOW(&termios); + /* We are here only if G.numspeed > 1 */ + baud_index = (baud_index + 1) % G.numspeed; + cfsetspeed(&G.tty_attrs, G.speeds[baud_index]); + set_tty_attrs(); } } - /* Disable timer. */ + /* Disable timer */ alarm(0); - /* Finalize the termios settings. */ - termios_final(&options, &termios, &chardata); - - /* Now the newline character should be properly written. */ - full_write(STDOUT_FILENO, "\n", 1); + finalize_tty_attrs(); - /* Let the login program take care of password validation. */ + /* Let the login program take care of password validation */ /* We use PATH because we trust that root doesn't set "bad" PATH, - * and getty is not suid-root applet. */ + * and getty is not suid-root applet */ /* With -n, logname == NULL, and login will ask for username instead */ - BB_EXECLP(options.login, options.login, "--", logname, NULL); - bb_error_msg_and_die("%s: can't exec %s", options.tty, options.login); + BB_EXECLP(G.login, G.login, "--", logname, (char *)0); + bb_error_msg_and_die("can't execute '%s'", G.login); } diff --git a/loginutils/login.c b/loginutils/login.c index 88ed0af..a4b19cc 100644 --- a/loginutils/login.c +++ b/loginutils/login.c @@ -1,12 +1,18 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define login_trivial_usage +//usage: "[-p] [-h HOST] [[-f] USER]" +//usage:#define login_full_usage "\n\n" +//usage: "Begin a new session on the system\n" +//usage: "\n -f Don't authenticate (user already authenticated)" +//usage: "\n -h Name of the remote host" +//usage: "\n -p Preserve environment" + #include "libbb.h" #include -#if ENABLE_FEATURE_UTMP -# include /* USER_PROCESS */ -#endif #include #if ENABLE_SELINUX @@ -31,11 +37,17 @@ static const struct pam_conv conv = { enum { TIMEOUT = 60, EMPTY_USERNAME_COUNT = 10, - USERNAME_SIZE = 32, + /* Some users found 32 chars limit to be too low: */ + USERNAME_SIZE = 64, TTYNAME_SIZE = 32, }; -static char* short_tty; +struct globals { + struct termios tty_attrs; +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) + #if ENABLE_FEATURE_NOLOGIN static void die_if_nologin(void) @@ -68,7 +80,7 @@ static void die_if_nologin(void) #endif #if ENABLE_FEATURE_SECURETTY && !ENABLE_PAM -static int check_securetty(void) +static int check_securetty(const char *short_tty) { char *buf = (char*)"/etc/securetty"; /* any non-NULL is ok */ parser_t *parser = config_open2("/etc/securetty", fopen_for_read); @@ -83,7 +95,7 @@ static int check_securetty(void) return buf != NULL; } #else -static ALWAYS_INLINE int check_securetty(void) { return 1; } +static ALWAYS_INLINE int check_securetty(const char *short_tty UNUSED_PARAM) { return 1; } #endif #if ENABLE_SELINUX @@ -124,7 +136,7 @@ static void run_login_script(struct passwd *pw, char *full_tty) xsetenv("LOGIN_UID", utoa(pw->pw_uid)); xsetenv("LOGIN_GID", utoa(pw->pw_gid)); xsetenv("LOGIN_SHELL", pw->pw_shell); - spawn_and_wait(t_argv); /* NOMMU-friendly */ + spawn_and_wait(t_argv); /* NOMMU-friendly */ unsetenv("LOGIN_TTY"); unsetenv("LOGIN_USER"); unsetenv("LOGIN_UID"); @@ -136,6 +148,29 @@ static void run_login_script(struct passwd *pw, char *full_tty) void run_login_script(struct passwd *pw, char *full_tty); #endif +#if ENABLE_LOGIN_SESSION_AS_CHILD && ENABLE_PAM +static void login_pam_end(pam_handle_t *pamh) +{ + int pamret; + + pamret = pam_setcred(pamh, PAM_DELETE_CRED); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "setcred", + pam_strerror(pamh, pamret), pamret); + } + pamret = pam_close_session(pamh, 0); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "close_session", + pam_strerror(pamh, pamret), pamret); + } + pamret = pam_end(pamh, pamret); + if (pamret != PAM_SUCCESS) { + bb_error_msg("pam_%s failed: %s (%d)", "end", + pam_strerror(pamh, pamret), pamret); + } +} +#endif /* ENABLE_PAM */ + static void get_username_or_die(char *buf, int size_buf) { int c, cntdown; @@ -179,15 +214,21 @@ static void motd(void) static void alarm_handler(int sig UNUSED_PARAM) { - /* This is the escape hatch! Poor serial line users and the like + /* This is the escape hatch! Poor serial line users and the like * arrive here when their connection is broken. * We don't want to block here */ - ndelay_on(1); - printf("\r\nLogin timed out after %d seconds\r\n", TIMEOUT); + ndelay_on(STDOUT_FILENO); + /* Test for correct attr restoring: + * run "getty 0 -" from a shell, enter bogus username, stop at + * password prompt, let it time out. Without the tcsetattr below, + * when you are back at shell prompt, echo will be still off. + */ + tcsetattr_stdin_TCSANOW(&G.tty_attrs); + printf("\r\nLogin timed out after %u seconds\r\n", TIMEOUT); fflush_all(); /* unix API is brain damaged regarding O_NONBLOCK, * we should undo it, or else we can affect other processes */ - ndelay_off(1); + ndelay_off(STDOUT_FILENO); _exit(EXIT_SUCCESS); } @@ -201,7 +242,6 @@ int login_main(int argc UNUSED_PARAM, char **argv) }; char *fromhost; char username[USERNAME_SIZE]; - const char *shell; int run_by_root; unsigned opt; int count = 0; @@ -209,6 +249,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) char *opt_host = NULL; char *opt_user = opt_user; /* for compiler */ char *full_tty; + char *short_tty; IF_SELINUX(security_context_t user_sid = NULL;) #if ENABLE_PAM int pamret; @@ -217,11 +258,13 @@ int login_main(int argc UNUSED_PARAM, char **argv) const char *failed_msg; struct passwd pwdstruct; char pwdbuf[256]; + char **pamenv; +#endif +#if ENABLE_LOGIN_SESSION_AS_CHILD + pid_t child_pid; #endif - username[0] = '\0'; - signal(SIGALRM, alarm_handler); - alarm(TIMEOUT); + INIT_G(); /* More of suid paranoia if called by non-root: */ /* Clear dangerous stuff, set PATH */ @@ -233,6 +276,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) * (The name of the function is misleading. Not daemonizing here.) */ bb_daemonize_or_rexec(DAEMON_ONLY_SANITIZE | DAEMON_CLOSE_EXTRA_FDS, NULL); + username[0] = '\0'; opt = getopt32(argv, "f:h:p", &opt_user, &opt_host); if (opt & LOGIN_OPT_f) { if (!run_by_root) @@ -243,9 +287,19 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (argv[0]) /* user from command line (getty) */ safe_strncpy(username, argv[0], sizeof(username)); - /* Let's find out and memorize our tty */ - if (!isatty(STDIN_FILENO) || !isatty(STDOUT_FILENO) || !isatty(STDERR_FILENO)) - return EXIT_FAILURE; /* Must be a terminal */ + /* Save tty attributes - and by doing it, check that it's indeed a tty */ + if (tcgetattr(STDIN_FILENO, &G.tty_attrs) < 0 + || !isatty(STDOUT_FILENO) + /*|| !isatty(STDERR_FILENO) - no, guess some people might want to redirect this */ + ) { + return EXIT_FAILURE; /* Must be a terminal */ + } + + /* We install timeout handler only _after_ we saved G.tty_attrs */ + signal(SIGALRM, alarm_handler); + alarm(TIMEOUT); + + /* Find out and memorize our tty name */ full_tty = xmalloc_ttyname(STDIN_FILENO); if (!full_tty) full_tty = xstrdup("UNKNOWN"); @@ -264,7 +318,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) while (1) { /* flush away any type-ahead (as getty does) */ - ioctl(0, TCFLSH, TCIFLUSH); + tcflush(0, TCIFLUSH); if (!username[0]) get_username_or_die(username, sizeof(username)); @@ -281,14 +335,24 @@ int login_main(int argc UNUSED_PARAM, char **argv) failed_msg = "set_item(TTY)"; goto pam_auth_failed; } - pamret = pam_authenticate(pamh, 0); - if (pamret != PAM_SUCCESS) { - failed_msg = "authenticate"; - goto pam_auth_failed; - /* TODO: or just "goto auth_failed" - * since user seems to enter wrong password - * (in this case pamret == 7) - */ + /* set RHOST */ + if (opt_host) { + pamret = pam_set_item(pamh, PAM_RHOST, opt_host); + if (pamret != PAM_SUCCESS) { + failed_msg = "set_item(RHOST)"; + goto pam_auth_failed; + } + } + if (!(opt & LOGIN_OPT_f)) { + pamret = pam_authenticate(pamh, 0); + if (pamret != PAM_SUCCESS) { + failed_msg = "authenticate"; + goto pam_auth_failed; + /* TODO: or just "goto auth_failed" + * since user seems to enter wrong password + * (in this case pamret == 7) + */ + } } /* check that the account is healthy */ pamret = pam_acct_mgmt(pamh, 0); @@ -345,25 +409,32 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (opt & LOGIN_OPT_f) break; /* -f USER: success without asking passwd */ - if (pw->pw_uid == 0 && !check_securetty()) + if (pw->pw_uid == 0 && !check_securetty(short_tty)) goto auth_failed; /* Don't check the password if password entry is empty (!) */ if (!pw->pw_passwd[0]) break; fake_it: - /* authorization takes place here */ - if (correct_password(pw)) + /* Password reading and authorization takes place here. + * Note that reads (in no-echo mode) trash tty attributes. + * If we get interrupted by SIGALRM, we need to restore attrs. + */ + if (ask_and_check_password(pw) > 0) break; #endif /* ENABLE_PAM */ auth_failed: opt &= ~LOGIN_OPT_f; - bb_do_delay(FAIL_DELAY); + bb_do_delay(LOGIN_FAIL_DELAY); /* TODO: doesn't sound like correct English phrase to me */ puts("Login incorrect"); if (++count == 3) { syslog(LOG_WARNING, "invalid password for '%s'%s", username, fromhost); + + if (ENABLE_FEATURE_CLEAN_UP) + free(fromhost); + return EXIT_FAILURE; } username[0] = '\0'; @@ -375,7 +446,22 @@ int login_main(int argc UNUSED_PARAM, char **argv) if (pw->pw_uid != 0) die_if_nologin(); - IF_SELINUX(initselinux(username, full_tty, &user_sid)); +#if ENABLE_LOGIN_SESSION_AS_CHILD + child_pid = vfork(); + if (child_pid != 0) { + if (child_pid < 0) + bb_perror_msg("vfork"); + else { + if (safe_waitpid(child_pid, NULL, 0) == -1) + bb_perror_msg("waitpid"); + update_utmp(child_pid, DEAD_PROCESS, NULL, NULL, NULL); + } + IF_PAM(login_pam_end(pamh);) + return 0; + } +#endif + + IF_SELINUX(initselinux(username, full_tty, &user_sid);) /* Try these, but don't complain if they fail. * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ @@ -389,18 +475,28 @@ int login_main(int argc UNUSED_PARAM, char **argv) run_login_script(pw, full_tty); change_identity(pw); - shell = pw->pw_shell; - if (!shell || !shell[0]) - shell = DEFAULT_SHELL; - setup_environment(shell, + setup_environment(pw->pw_shell, (!(opt & LOGIN_OPT_p) * SETUP_ENV_CLEARENV) + SETUP_ENV_CHANGEENV, pw); +#if ENABLE_PAM + /* Modules such as pam_env will setup the PAM environment, + * which should be copied into the new environment. */ + pamenv = pam_getenvlist(pamh); + if (pamenv) while (*pamenv) { + putenv(*pamenv); + pamenv++; + } +#endif + motd(); if (pw->pw_uid == 0) syslog(LOG_INFO, "root login%s", fromhost); + if (ENABLE_FEATURE_CLEAN_UP) + free(fromhost); + /* well, a simple setexeccon() here would do the job as well, * but let's play the game for now */ IF_SELINUX(set_current_security_context(user_sid);) @@ -427,7 +523,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, SIG_DFL); /* Exec login shell with no additional parameters */ - run_shell(shell, 1, NULL, NULL); + run_shell(pw->pw_shell, 1, NULL, NULL); /* return EXIT_FAILURE; - not reached */ } diff --git a/loginutils/passwd.c b/loginutils/passwd.c index b447af2..1509089 100644 --- a/loginutils/passwd.c +++ b/loginutils/passwd.c @@ -1,24 +1,31 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define passwd_trivial_usage +//usage: "[OPTIONS] [USER]" +//usage:#define passwd_full_usage "\n\n" +//usage: "Change USER's password (default: current user)" +//usage: "\n" +//usage: "\n -a ALG Encryption method" +//usage: "\n -d Set password to ''" +//usage: "\n -l Lock (disable) account" +//usage: "\n -u Unlock (enable) account" + #include "libbb.h" #include +#include /* setrlimit */ -static void nuke_str(char *str) -{ - if (str) memset(str, 0, strlen(str)); -} - -static char* new_password(const struct passwd *pw, uid_t myuid, int algo) +static char* new_password(const struct passwd *pw, uid_t myuid, const char *algo) { - char salt[sizeof("$N$XXXXXXXX")]; /* "$N$XXXXXXXX" or "XX" */ + char salt[MAX_PW_SALT_LEN]; char *orig = (char*)""; char *newp = NULL; char *cp = NULL; char *ret = NULL; /* failure so far */ - if (myuid && pw->pw_passwd[0]) { + if (myuid != 0 && pw->pw_passwd[0]) { char *encrypted; orig = bb_ask_stdin("Old password: "); /* returns ptr to static */ @@ -26,13 +33,13 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) goto err_ret; encrypted = pw_encrypt(orig, pw->pw_passwd, 1); /* returns malloced str */ if (strcmp(encrypted, pw->pw_passwd) != 0) { - syslog(LOG_WARNING, "incorrect password for %s", - pw->pw_name); - bb_do_delay(FAIL_DELAY); + syslog(LOG_WARNING, "incorrect password for %s", pw->pw_name); + bb_do_delay(LOGIN_FAIL_DELAY); puts("Incorrect password"); goto err_ret; } - if (ENABLE_FEATURE_CLEAN_UP) free(encrypted); + if (ENABLE_FEATURE_CLEAN_UP) + free(encrypted); } orig = xstrdup(orig); /* or else bb_ask_stdin() will destroy it */ newp = bb_ask_stdin("New password: "); /* returns ptr to static */ @@ -40,22 +47,22 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) goto err_ret; newp = xstrdup(newp); /* we are going to bb_ask_stdin() again, so save it */ if (ENABLE_FEATURE_PASSWD_WEAK_CHECK - && obscure(orig, newp, pw) && myuid) + && obscure(orig, newp, pw) + && myuid != 0 + ) { goto err_ret; /* non-root is not allowed to have weak passwd */ + } cp = bb_ask_stdin("Retype password: "); if (!cp) goto err_ret; - if (strcmp(cp, newp)) { + if (strcmp(cp, newp) != 0) { puts("Passwords don't match"); goto err_ret; } - crypt_make_salt(salt, 1, 0); /* des */ - if (algo) { /* MD5 */ - strcpy(salt, "$1$"); - crypt_make_salt(salt + 3, 4, 0); - } + crypt_make_pw_salt(salt, algo); + /* pw_encrypt returns malloced str */ ret = pw_encrypt(newp, salt, 1); /* whee, success! */ @@ -63,8 +70,10 @@ static char* new_password(const struct passwd *pw, uid_t myuid, int algo) err_ret: nuke_str(orig); if (ENABLE_FEATURE_CLEAN_UP) free(orig); + nuke_str(newp); if (ENABLE_FEATURE_CLEAN_UP) free(newp); + nuke_str(cp); return ret; } @@ -73,17 +82,15 @@ int passwd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int passwd_main(int argc UNUSED_PARAM, char **argv) { enum { - OPT_algo = 0x1, /* -a - password algorithm */ - OPT_lock = 0x2, /* -l - lock account */ - OPT_unlock = 0x4, /* -u - unlock account */ - OPT_delete = 0x8, /* -d - delete password */ - OPT_lud = 0xe, - STATE_ALGO_md5 = 0x10, - //STATE_ALGO_des = 0x20, not needed yet + OPT_algo = (1 << 0), /* -a - password algorithm */ + OPT_lock = (1 << 1), /* -l - lock account */ + OPT_unlock = (1 << 2), /* -u - unlock account */ + OPT_delete = (1 << 3), /* -d - delete password */ + OPT_lud = OPT_lock | OPT_unlock | OPT_delete, }; unsigned opt; int rc; - const char *opt_a = ""; + const char *opt_a = CONFIG_FEATURE_DEFAULT_PASSWD_ALGO; const char *filename; char *myname; char *name; @@ -104,13 +111,9 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) //argc -= optind; argv += optind; - if (strcasecmp(opt_a, "des") != 0) /* -a */ - opt |= STATE_ALGO_md5; - //else - // opt |= STATE_ALGO_des; myuid = getuid(); /* -l, -u, -d require root priv and username argument */ - if ((opt & OPT_lud) && (myuid || !argv[0])) + if ((opt & OPT_lud) && (myuid != 0 || !argv[0])) bb_show_usage(); /* Will complain and die if username not found */ @@ -118,7 +121,7 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) name = argv[0] ? argv[0] : myname; pw = xgetpwnam(name); - if (myuid && pw->pw_uid != myuid) { + if (myuid != 0 && pw->pw_uid != myuid) { /* LOGMODE_BOTH */ bb_error_msg_and_die("%s can't change password for %s", myname, name); } @@ -152,27 +155,28 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) newp = NULL; c = pw->pw_passwd[0] - '!'; if (!(opt & OPT_lud)) { - if (myuid && !c) { /* passwd starts with '!' */ + if (myuid != 0 && !c) { /* passwd starts with '!' */ /* LOGMODE_BOTH */ bb_error_msg_and_die("can't change " "locked password for %s", name); } printf("Changing password for %s\n", name); - newp = new_password(pw, myuid, opt & STATE_ALGO_md5); + newp = new_password(pw, myuid, opt_a); if (!newp) { logmode = LOGMODE_STDIO; bb_error_msg_and_die("password for %s is unchanged", name); } } else if (opt & OPT_lock) { - if (!c) goto skip; /* passwd starts with '!' */ + if (!c) + goto skip; /* passwd starts with '!' */ newp = xasprintf("!%s", pw->pw_passwd); } else if (opt & OPT_unlock) { - if (c) goto skip; /* not '!' */ + if (c) + goto skip; /* not '!' */ /* pw->pw_passwd points to static storage, * strdup'ing to avoid nasty surprizes */ newp = xstrdup(&pw->pw_passwd[1]); } else if (opt & OPT_delete) { - //newp = xstrdup(""); newp = (char*)""; } @@ -189,7 +193,11 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_SHADOWPASSWDS filename = bb_path_shadow_file; rc = update_passwd(bb_path_shadow_file, name, newp, NULL); - if (rc == 0) /* no lines updated, no errors detected */ + if (rc > 0) + /* password in /etc/shadow was updated */ + newp = (char*) "x"; + if (rc >= 0) + /* 0 = /etc/shadow missing (not an error), >0 = passwd changed in /etc/shadow */ #endif { filename = bb_path_passwd_file; @@ -197,16 +205,17 @@ int passwd_main(int argc UNUSED_PARAM, char **argv) } /* LOGMODE_BOTH */ if (rc < 0) - bb_error_msg_and_die("can't update password file %s", - filename); + bb_error_msg_and_die("can't update password file %s", filename); bb_info_msg("Password for %s changed by %s", name, myname); - //if (ENABLE_FEATURE_CLEAN_UP) free(newp); + /*if (ENABLE_FEATURE_CLEAN_UP) free(newp); - can't, it may be non-malloced */ skip: if (!newp) { bb_error_msg_and_die("password for %s is already %slocked", name, (opt & OPT_unlock) ? "un" : ""); } - if (ENABLE_FEATURE_CLEAN_UP) free(myname); + + if (ENABLE_FEATURE_CLEAN_UP) + free(myname); return 0; } diff --git a/loginutils/su.c b/loginutils/su.c index 9bae375..c51f26f 100644 --- a/loginutils/su.c +++ b/loginutils/su.c @@ -1,13 +1,22 @@ /* vi: set sw=4 ts=4: */ /* - * Mini su implementation for busybox + * Mini su implementation for busybox * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include +//usage:#define su_trivial_usage +//usage: "[OPTIONS] [-] [USER]" +//usage:#define su_full_usage "\n\n" +//usage: "Run shell under USER (by default, root)\n" +//usage: "\n -,-l Clear environment, run shell as login shell" +//usage: "\n -p,-m Do not set new $HOME, $SHELL, $USER, $LOGNAME" +//usage: "\n -c CMD Command to pass to 'sh -c'" +//usage: "\n -s SH Shell to use instead of user's default" + #if ENABLE_FEATURE_SU_CHECKS_SHELLS /* Return 1 if SHELL is a restricted shell (one not returned by * getusershell), else 0, meaning it is a standard shell. */ @@ -42,7 +51,9 @@ int su_main(int argc UNUSED_PARAM, char **argv) struct passwd *pw; uid_t cur_uid = getuid(); const char *tty; +#if ENABLE_FEATURE_UTMP char user_buf[64]; +#endif const char *old_user; flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); @@ -82,7 +93,7 @@ int su_main(int argc UNUSED_PARAM, char **argv) pw = xgetpwnam(opt_username); - if (cur_uid == 0 || correct_password(pw)) { + if (cur_uid == 0 || ask_and_check_password(pw) > 0) { if (ENABLE_FEATURE_SU_SYSLOG) syslog(LOG_NOTICE, "%c %s %s:%s", '+', tty, old_user, opt_username); @@ -102,20 +113,14 @@ int su_main(int argc UNUSED_PARAM, char **argv) opt_shell = getenv("SHELL"); } - /* Make sure pw->pw_shell is non-NULL. It may be NULL when NEW_USER - * is a username that is retrieved via NIS (YP), that doesn't have - * a default shell listed. */ - if (!pw->pw_shell || !pw->pw_shell[0]) - pw->pw_shell = (char *)DEFAULT_SHELL; - #if ENABLE_FEATURE_SU_CHECKS_SHELLS - if (opt_shell && cur_uid != 0 && restricted_shell(pw->pw_shell)) { + if (opt_shell && cur_uid != 0 && pw->pw_shell && restricted_shell(pw->pw_shell)) { /* The user being su'd to has a nonstandard shell, and so is * probably a uucp account or has restricted access. Don't * compromise the account by allowing access with a standard * shell. */ bb_error_msg("using restricted shell"); - opt_shell = NULL; + opt_shell = NULL; /* ignore -s PROG */ } /* else: user can run whatever he wants via "su -s PROG USER". * This is safe since PROG is run under user's uid/gid. */ @@ -126,7 +131,8 @@ int su_main(int argc UNUSED_PARAM, char **argv) change_identity(pw); setup_environment(opt_shell, ((flags & SU_OPT_l) / SU_OPT_l * SETUP_ENV_CLEARENV) - + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV), + + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV) + + (!(flags & SU_OPT_l) * SETUP_ENV_NO_CHDIR), pw); IF_SELINUX(set_current_security_context(NULL);) diff --git a/loginutils/sulogin.c b/loginutils/sulogin.c index 3516013..2a29099 100644 --- a/loginutils/sulogin.c +++ b/loginutils/sulogin.c @@ -2,30 +2,24 @@ /* * Mini sulogin implementation for busybox * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define sulogin_trivial_usage +//usage: "[-t N] [TTY]" +//usage:#define sulogin_full_usage "\n\n" +//usage: "Single user login\n" +//usage: "\n -t N Timeout" + #include "libbb.h" #include -//static void catchalarm(int UNUSED_PARAM junk) -//{ -// exit(EXIT_FAILURE); -//} - - int sulogin_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sulogin_main(int argc UNUSED_PARAM, char **argv) { - char *cp; int timeout = 0; struct passwd *pwd; const char *shell; -#if ENABLE_FEATURE_SHADOWPASSWDS - /* Using _r function to avoid pulling in static buffers */ - char buffer[256]; - struct spwd spw; -#endif logmode = LOGMODE_BOTH; openlog(applet_name, 0, LOG_AUTH); @@ -56,43 +50,24 @@ int sulogin_main(int argc UNUSED_PARAM, char **argv) goto auth_error; } -#if ENABLE_FEATURE_SHADOWPASSWDS - { - /* getspnam_r may return 0 yet set result to NULL. - * At least glibc 2.4 does this. Be extra paranoid here. */ - struct spwd *result = NULL; - int r = getspnam_r(pwd->pw_name, &spw, buffer, sizeof(buffer), &result); - if (r || !result) { - goto auth_error; - } - pwd->pw_passwd = result->sp_pwdp; - } -#endif - while (1) { - char *encrypted; int r; - /* cp points to a static buffer that is zeroed every time */ - cp = bb_ask(STDIN_FILENO, timeout, - "Give root password for system maintenance\n" - "(or type Control-D for normal startup):"); - - if (!cp || !*cp) { + r = ask_and_check_password_extended(pwd, timeout, + "Give root password for system maintenance\n" + "(or type Control-D for normal startup):" + ); + if (r < 0) { + /* ^D, ^C, timeout, or read error */ bb_info_msg("Normal startup"); return 0; } - encrypted = pw_encrypt(cp, pwd->pw_passwd, 1); - r = strcmp(encrypted, pwd->pw_passwd); - free(encrypted); - if (r == 0) { + if (r > 0) { break; } - bb_do_delay(FAIL_DELAY); - bb_error_msg("login incorrect"); + bb_do_delay(LOGIN_FAIL_DELAY); + bb_info_msg("Login incorrect"); } - memset(cp, 0, strlen(cp)); -// signal(SIGALRM, SIG_DFL); bb_info_msg("System Maintenance Mode"); diff --git a/loginutils/vlock.c b/loginutils/vlock.c index 85f489c..44b14e6 100644 --- a/loginutils/vlock.c +++ b/loginutils/vlock.c @@ -5,7 +5,7 @@ * Copyright (C) 2000 by spoon * Written by spoon * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Shoutz to Michael K. Johnson , author of the @@ -15,9 +15,17 @@ /* Fixed by Erik Andersen to do passwords the tinylogin way... * It now works with md5, sha1, etc passwords. */ -#include +//usage:#define vlock_trivial_usage +//usage: "[-a]" +//usage:#define vlock_full_usage "\n\n" +//usage: "Lock a virtual terminal. A password is required to unlock.\n" +//usage: "\n -a Lock all VTs" + #include "libbb.h" +#ifdef __linux__ +#include + static void release_vt(int signo UNUSED_PARAM) { /* If -a, param is 0, which means: @@ -30,14 +38,17 @@ static void acquire_vt(int signo UNUSED_PARAM) /* ACK to kernel that switch to console is successful */ ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); } +#endif int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vlock_main(int argc UNUSED_PARAM, char **argv) { +#ifdef __linux__ struct vt_mode vtm; + struct vt_mode ovtm; +#endif struct termios term; struct termios oterm; - struct vt_mode ovtm; struct passwd *pw; pw = xgetpwuid(getuid()); @@ -55,6 +66,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) + (1 << SIGINT ) , SIG_IGN); +#ifdef __linux__ /* We will use SIGUSRx for console switch control: */ /* 1: set handlers */ signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); @@ -62,12 +74,14 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) /* 2: unmask them */ sig_unblock(SIGUSR1); sig_unblock(SIGUSR2); +#endif /* Revert stdin/out to our controlling tty * (or die if we have none) */ xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); +#ifdef __linux__ xioctl(STDIN_FILENO, VT_GETMODE, &vtm); ovtm = vtm; /* "console switches are controlled by us, not kernel!" */ @@ -75,6 +89,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) vtm.relsig = SIGUSR1; vtm.acqsig = SIGUSR2; ioctl(STDIN_FILENO, VT_SETMODE, &vtm); +#endif tcgetattr(STDIN_FILENO, &oterm); term = oterm; @@ -84,18 +99,21 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) term.c_lflag &= ~(ECHO | ECHOCTL); tcsetattr_stdin_TCSANOW(&term); - do { + while (1) { printf("Virtual console%s locked by %s.\n", - option_mask32 /*o_lock_all*/ ? "s" : "", - pw->pw_name); - if (correct_password(pw)) { + /* "s" if -a, else "": */ "s" + !option_mask32, + pw->pw_name + ); + if (ask_and_check_password(pw) > 0) { break; } - bb_do_delay(FAIL_DELAY); - puts("Password incorrect"); - } while (1); + bb_do_delay(LOGIN_FAIL_DELAY); + puts("Incorrect password"); + } +#ifdef __linux__ ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); +#endif tcsetattr_stdin_TCSANOW(&oterm); fflush_stdout_and_exit(EXIT_SUCCESS); } diff --git a/mailutils/Kbuild.src b/mailutils/Kbuild.src index b2fb735..6b4fb74 100644 --- a/mailutils/Kbuild.src +++ b/mailutils/Kbuild.src @@ -2,12 +2,8 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= INSERT -lib-$(CONFIG_MAKEMIME) += mime.o mail.o -lib-$(CONFIG_POPMAILDIR) += popmaildir.o mail.o -lib-$(CONFIG_REFORMIME) += mime.o mail.o -lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o diff --git a/mailutils/mail.c b/mailutils/mail.c index bcd3583..199f644 100644 --- a/mailutils/mail.c +++ b/mailutils/mail.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include "mail.h" @@ -57,10 +57,13 @@ void FAST_FUNC launch_helper(const char **argv) G.helper_pid = xvfork(); i = (!G.helper_pid) * 2; // for parent:0, for child:2 - close(pipes[i + 1]); // 1 or 3 - closing one write end - close(pipes[2 - i]); // 2 or 0 - closing one read end - xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end - xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - other write end + close(pipes[i + 1]); // 1 or 3 - closing one write end + close(pipes[2 - i]); // 2 or 0 - closing one read end + xmove_fd(pipes[i], STDIN_FILENO); // 0 or 2 - using other read end + xmove_fd(pipes[3 - i], STDOUT_FILENO); // 3 or 1 - using other write end + // End result: + // parent stdout [3] -> child stdin [2] + // child stdout [1] -> parent stdin [0] if (!G.helper_pid) { // child: try to execute connection helper @@ -75,13 +78,16 @@ void FAST_FUNC launch_helper(const char **argv) atexit(kill_helper); } -const FAST_FUNC char *command(const char *fmt, const char *param) +char* FAST_FUNC send_mail_command(const char *fmt, const char *param) { - const char *msg = fmt; + char *msg; if (timeout) alarm(timeout); - if (msg) { + msg = (char*)fmt; + if (fmt) { msg = xasprintf(fmt, param); + if (verbose) + bb_error_msg("send:'%s'", msg); printf("%s\r\n", msg); } fflush_all(); @@ -90,7 +96,7 @@ const FAST_FUNC char *command(const char *fmt, const char *param) // NB: parse_url can modify url[] (despite const), but only if '@' is there /* -static char FAST_FUNC *parse_url(char *url, char **user, char **pass) +static char* FAST_FUNC parse_url(char *url, char **user, char **pass) { // parse [user[:pass]@]host // return host @@ -113,19 +119,18 @@ static char FAST_FUNC *parse_url(char *url, char **user, char **pass) void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) { enum { - SRC_BUF_SIZE = 45, /* This *MUST* be a multiple of 3 */ + SRC_BUF_SIZE = 57, /* This *MUST* be a multiple of 3 */ DST_BUF_SIZE = 4 * ((SRC_BUF_SIZE + 2) / 3), }; - #define src_buf text + char src[SRC_BUF_SIZE]; FILE *fp = fp; ssize_t len = len; char dst_buf[DST_BUF_SIZE + 1]; if (fname) { fp = (NOT_LONE_DASH(fname)) ? xfopen_for_read(fname) : (FILE *)text; - src_buf = bb_common_bufsiz1; - // N.B. strlen(NULL) segfaults! + src_buf = src; } else if (text) { // though we do not call uuencode(NULL, NULL) explicitly // still we do not want to break things suddenly @@ -161,73 +166,6 @@ void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol) #undef src_buf } -void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream) -{ - int term_count = 1; - - while (1) { - char translated[4]; - int count = 0; - - while (count < 4) { - char *table_ptr; - int ch; - - /* Get next _valid_ character. - * global vector bb_uuenc_tbl_base64[] contains this string: - * "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n" - */ - do { - ch = fgetc(src_stream); - if (ch == EOF) { - bb_error_msg_and_die(bb_msg_read_error); - } - // - means end of MIME section - if ('-' == ch) { - // push it back - ungetc(ch, src_stream); - return; - } - table_ptr = strchr(bb_uuenc_tbl_base64, ch); - } while (table_ptr == NULL); - - /* Convert encoded character to decimal */ - ch = table_ptr - bb_uuenc_tbl_base64; - - if (*table_ptr == '=') { - if (term_count == 0) { - translated[count] = '\0'; - break; - } - term_count++; - } else if (*table_ptr == '\n') { - /* Check for terminating line */ - if (term_count == 5) { - return; - } - term_count = 1; - continue; - } else { - translated[count] = ch; - count++; - term_count = 0; - } - } - - /* Merge 6 bit chars to 8 bit */ - if (count > 1) { - fputc(translated[0] << 2 | translated[1] >> 4, dst_stream); - } - if (count > 2) { - fputc(translated[1] << 4 | translated[2] >> 2, dst_stream); - } - if (count > 3) { - fputc(translated[2] << 6 | translated[3], dst_stream); - } - } -} - - /* * get username and password from a file descriptor */ @@ -237,8 +175,8 @@ void FAST_FUNC get_cred_or_die(int fd) G.user = xstrdup(bb_ask(fd, /* timeout: */ 0, "User: ")); G.pass = xstrdup(bb_ask(fd, /* timeout: */ 0, "Password: ")); } else { - G.user = xmalloc_reads(fd, /* pfx: */ NULL, /* maxsize: */ NULL); - G.pass = xmalloc_reads(fd, /* pfx: */ NULL, /* maxsize: */ NULL); + G.user = xmalloc_reads(fd, /* maxsize: */ NULL); + G.pass = xmalloc_reads(fd, /* maxsize: */ NULL); } if (!G.user || !*G.user || !G.pass) bb_error_msg_and_die("no username or password"); diff --git a/mailutils/mail.h b/mailutils/mail.h index bb747c4..fa0c5b3 100644 --- a/mailutils/mail.h +++ b/mailutils/mail.h @@ -1,35 +1,37 @@ +/* vi: set sw=4 ts=4: */ +/* + * helper routines + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ struct globals { pid_t helper_pid; unsigned timeout; + unsigned verbose; unsigned opts; char *user; char *pass; FILE *fp0; // initial stdin char *opt_charset; - char *content_type; }; #define G (*ptr_to_globals) #define timeout (G.timeout ) +#define verbose (G.verbose ) #define opts (G.opts ) -//#define user (G.user ) -//#define pass (G.pass ) -//#define fp0 (G.fp0 ) -//#define opt_charset (G.opt_charset) -//#define content_type (G.content_type) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ G.opt_charset = (char *)CONFIG_FEATURE_MIME_CHARSET; \ - G.content_type = (char *)"text/plain"; \ } while (0) //char FAST_FUNC *parse_url(char *url, char **user, char **pass); -void FAST_FUNC launch_helper(const char **argv); -void FAST_FUNC get_cred_or_die(int fd); +void launch_helper(const char **argv) FAST_FUNC; +void get_cred_or_die(int fd) FAST_FUNC; -const FAST_FUNC char *command(const char *fmt, const char *param); +char *send_mail_command(const char *fmt, const char *param) FAST_FUNC; -void FAST_FUNC encode_base64(char *fname, const char *text, const char *eol); -void FAST_FUNC decode_base64(FILE *src_stream, FILE *dst_stream); +void encode_base64(char *fname, const char *text, const char *eol) FAST_FUNC; diff --git a/mailutils/makemime.c b/mailutils/makemime.c new file mode 100644 index 0000000..1dadd71 --- /dev/null +++ b/mailutils/makemime.c @@ -0,0 +1,239 @@ +/* vi: set sw=4 ts=4: */ +/* + * makemime: create MIME-encoded message + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-$(CONFIG_MAKEMIME) += makemime.o mail.o + +#include "libbb.h" +#include "mail.h" + +#if 0 +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg_error_msg(...) ((void)0) +#endif + +/* + makemime -c type [-o file] [-e encoding] [-C charset] [-N name] \ + [-a "Header: Contents"] file + -m [ type ] [-o file] [-e encoding] [-a "Header: Contents"] file + -j [-o file] file1 file2 + @file + + file: filename - read or write from filename + - - read or write from stdin or stdout + &n - read or write from file descriptor n + \( opts \) - read from child process, that generates [ opts ] + +Options: + -c type - create a new MIME section from "file" with this + Content-Type: (default is application/octet-stream). + -C charset - MIME charset of a new text/plain section. + -N name - MIME content name of the new mime section. + -m [ type ] - create a multipart mime section from "file" of this + Content-Type: (default is multipart/mixed). + -e encoding - use the given encoding (7bit, 8bit, quoted-printable, + or base64), instead of guessing. Omit "-e" and use + -c auto to set Content-Type: to text/plain or + application/octet-stream based on picked encoding. + -j file1 file2 - join mime section file2 to multipart section file1. + -o file - write the result to file, instead of stdout (not + allowed in child processes). + -a header - prepend an additional header to the output. + + @file - read all of the above options from file, one option or + value on each line. + {which version of makemime is this? What do we support?} +*/ +/* man makemime: + + * -c TYPE: create a (non-multipart) MIME section with Content-Type: TYPE + * makemime -c TYPE [-e ENCODING] [-o OUTFILE] [-C CHARSET] [-N NAME] [-a HEADER...] FILE + * The -C option sets the MIME charset attribute for text/plain content. + * The -N option sets the name attribute for Content-Type: + * Encoding must be one of the following: 7bit, 8bit, quoted-printable, or base64. + + * -m multipart/TYPE: create a multipart MIME collection with Content-Type: multipart/TYPE + * makemime -m multipart/TYPE [-e ENCODING] [-o OUTFILE] [-a HEADER...] FILE + * Type must be either "multipart/mixed", "multipart/alternative", or some other MIME multipart content type. + * Additionally, encoding can only be "7bit" or "8bit", and will default to "8bit" if not specified. + * Finally, filename must be a MIME-formatted section, NOT a regular file. + * The -m option creates an initial multipart MIME collection, that contains only one MIME section, taken from filename. + * The collection is written to standard output, or the pipe or to outputfile. + + * -j FILE1: add a section to a multipart MIME collection + * makemime -j FILE1 [-o OUTFILE] FILE2 + * FILE1 must be a MIME collection that was previously created by the -m option. + * FILE2 must be a MIME section that was previously created by the -c option. + * The -j options adds the MIME section in FILE2 to the MIME collection in FILE1. + */ + + +/* In busybox 1.15.0.svn, makemime generates output like this + * (empty lines are shown exactly!): +{headers added with -a HDR} +Mime-Version: 1.0 +Content-Type: multipart/mixed; boundary="24269534-2145583448-1655890676" + +--24269534-2145583448-1655890676 +Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} +Content-Disposition: inline; filename="A" +Content-Transfer-Encoding: base64 + +...file A contents... +--24269534-2145583448-1655890676 +Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} +Content-Disposition: inline; filename="B" +Content-Transfer-Encoding: base64 + +...file B contents... +--24269534-2145583448-1655890676-- + + * + * For reference: here is an example email to LKML which has + * 1st unnamed part (so it serves as an email body) + * and one attached file: +...other headers... +Content-Type: multipart/mixed; boundary="=-tOfTf3byOS0vZgxEWcX+" +...other headers... +Mime-Version: 1.0 +...other headers... + + +--=-tOfTf3byOS0vZgxEWcX+ +Content-Type: text/plain +Content-Transfer-Encoding: 7bit + +...email text... +...email text... + + +--=-tOfTf3byOS0vZgxEWcX+ +Content-Disposition: attachment; filename="xyz" +Content-Type: text/plain; name="xyz"; charset="UTF-8" +Content-Transfer-Encoding: 7bit + +...file contents... +...file contents... + +--=-tOfTf3byOS0vZgxEWcX+-- + +...random junk added by mailing list robots and such... +*/ + +//usage:#define makemime_trivial_usage +//usage: "[OPTIONS] [FILE]..." +//usage:#define makemime_full_usage "\n\n" +//usage: "Create multipart MIME-encoded message from FILEs\n" +/* //usage: "Transfer encoding is base64, disposition is inline (not attachment)\n" */ +//usage: "\n -o FILE Output. Default: stdout" +//usage: "\n -a HDR Add header(s). Examples:" +//usage: "\n \"From: user@host.org\", \"Date: `date -R`\"" +//usage: "\n -c CT Content type. Default: application/octet-stream" +//usage: "\n -C CS Charset. Default: " CONFIG_FEATURE_MIME_CHARSET +/* //usage: "\n -e ENC Transfer encoding. Ignored. base64 is assumed" */ +//usage: "\n" +//usage: "\nOther options are silently ignored" + +/* + * -c [Content-Type] should create just one MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR". + * NB: without "Content-Disposition:" auto-added, unlike we do now + * NB2: -c has *optional* param which nevertheless _can_ be specified after a space :( + * + * -m [multipart/mixed] should create multipart MIME section + * with "Content-Type:", "Content-Transfer-Encoding:", and HDRs from "-a HDR", + * and add FILE to it _verbatim_: + * HEADERS + * + * --=_1_1321709112_1605 + * FILE_CONTENTS + * --=_1_1321709112_1605 + * without any encoding of FILE_CONTENTS. (Basically, it expects that FILE + * is the result of "makemime -c"). + * + * -j MULTIPART_FILE1 SINGLE_FILE2 should output MULTIPART_FILE1 + SINGLE_FILE2 + * + * Our current behavior is a mutant "-m + -c + -j" one: we create multipart MIME + * and we put "-c" encoded FILEs into many multipart sections. + */ + +int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int makemime_main(int argc UNUSED_PARAM, char **argv) +{ + llist_t *opt_headers = NULL, *l; + const char *opt_output; + const char *content_type = "application/octet-stream"; +#define boundary opt_output + enum { + OPT_c = 1 << 0, // create (non-multipart) section + OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 + OPT_o = 1 << 2, // output to + OPT_C = 1 << 3, // charset + OPT_N = 1 << 4, // COMPAT + OPT_a = 1 << 5, // additional headers + //OPT_m = 1 << 6, // create mutipart section + //OPT_j = 1 << 7, // join section to multipart section + }; + + INIT_G(); + + // parse options + opt_complementary = "a::"; + opts = getopt32(argv, + "c:e:o:C:N:a:", // "m:j:", + &content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers //, NULL, NULL + ); + //argc -= optind; + argv += optind; + + // respect -o output + if (opts & OPT_o) + freopen(opt_output, "w", stdout); + + // no files given on command line? -> use stdin + if (!*argv) + *--argv = (char *)"-"; + + // put additional headers + for (l = opt_headers; l; l = l->link) + puts(l->data); + + // make a random string -- it will delimit message parts + srand(monotonic_us()); + boundary = xasprintf("%u-%u-%u", + (unsigned)rand(), (unsigned)rand(), (unsigned)rand()); + + // put multipart header + printf( + "Mime-Version: 1.0\n" + "Content-Type: multipart/mixed; boundary=\"%s\"\n" + , boundary + ); + + // put attachments + while (*argv) { + printf( + "\n--%s\n" + "Content-Type: %s; charset=%s\n" + "Content-Disposition: inline; filename=\"%s\"\n" + "Content-Transfer-Encoding: base64\n" + , boundary + , content_type + , G.opt_charset + , bb_get_last_path_component_strip(*argv) + ); + encode_base64(*argv++, (const char *)stdin, ""); + } + + // put multipart footer + printf("\n--%s--\n" "\n", boundary); + + return EXIT_SUCCESS; +#undef boundary +} diff --git a/mailutils/mime.c b/mailutils/mime.c deleted file mode 100644 index 5eb8ef6..0000000 --- a/mailutils/mime.c +++ /dev/null @@ -1,416 +0,0 @@ -/* vi: set sw=4 ts=4: */ -/* - * makemime: create MIME-encoded message - * reformime: parse MIME-encoded message - * - * Copyright (C) 2008 by Vladimir Dronnikov - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ -#include "libbb.h" -#include "mail.h" - -/* - makemime -c type [-o file] [-e encoding] [-C charset] [-N name] \ - [-a "Header: Contents"] file - -m [ type ] [-o file] [-e encoding] [-a "Header: Contents"] file - -j [-o file] file1 file2 - @file - - file: filename - read or write from filename - - - read or write from stdin or stdout - &n - read or write from file descriptor n - \( opts \) - read from child process, that generates [ opts ] - -Options: - - -c type - create a new MIME section from "file" with this - Content-Type: (default is application/octet-stream). - -C charset - MIME charset of a new text/plain section. - -N name - MIME content name of the new mime section. - -m [ type ] - create a multipart mime section from "file" of this - Content-Type: (default is multipart/mixed). - -e encoding - use the given encoding (7bit, 8bit, quoted-printable, - or base64), instead of guessing. Omit "-e" and use - -c auto to set Content-Type: to text/plain or - application/octet-stream based on picked encoding. - -j file1 file2 - join mime section file2 to multipart section file1. - -o file - write the result to file, instead of stdout (not - allowed in child processes). - -a header - prepend an additional header to the output. - - @file - read all of the above options from file, one option or - value on each line. - {which version of makemime is this? What do we support?} -*/ - - -/* In busybox 1.15.0.svn, makemime generates output like this - * (empty lines are shown exactly!): -{headers added with -a HDR} -Mime-Version: 1.0 -Content-Type: multipart/mixed; boundary="24269534-2145583448-1655890676" - ---24269534-2145583448-1655890676 -Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} -Content-Disposition: inline; filename="A" -Content-Transfer-Encoding: base64 - -...file A contents... ---24269534-2145583448-1655890676 -Content-Type: {set by -c, e.g. text/plain}; charset={set by -C, e.g. us-ascii} -Content-Disposition: inline; filename="B" -Content-Transfer-Encoding: base64 - -...file B contents... ---24269534-2145583448-1655890676-- - -*/ - - -/* For reference: here is an example email to LKML which has - * 1st unnamed part (so it serves as an email body) - * and one attached file: -...other headers... -Content-Type: multipart/mixed; boundary="=-tOfTf3byOS0vZgxEWcX+" -...other headers... -Mime-Version: 1.0 -...other headers... - - ---=-tOfTf3byOS0vZgxEWcX+ -Content-Type: text/plain -Content-Transfer-Encoding: 7bit - -...email text... -...email text... - - ---=-tOfTf3byOS0vZgxEWcX+ -Content-Disposition: attachment; filename="xyz" -Content-Type: text/plain; name="xyz"; charset="UTF-8" -Content-Transfer-Encoding: 7bit - -...file contents... -...file contents... - ---=-tOfTf3byOS0vZgxEWcX+-- - -...random junk added by mailing list robots and such... -*/ - -int makemime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int makemime_main(int argc UNUSED_PARAM, char **argv) -{ - llist_t *opt_headers = NULL, *l; - const char *opt_output; -#define boundary opt_output - - enum { - OPT_c = 1 << 0, // Content-Type: - OPT_e = 1 << 1, // Content-Transfer-Encoding. Ignored. Assumed base64 - OPT_o = 1 << 2, // output to - OPT_C = 1 << 3, // charset - OPT_N = 1 << 4, // COMPAT - OPT_a = 1 << 5, // additional headers - OPT_m = 1 << 6, // COMPAT - OPT_j = 1 << 7, // COMPAT - }; - - INIT_G(); - - // parse options - opt_complementary = "a::"; - opts = getopt32(argv, - "c:e:o:C:N:a:m:j:", - &G.content_type, NULL, &opt_output, &G.opt_charset, NULL, &opt_headers, NULL, NULL - ); - //argc -= optind; - argv += optind; - - // respect -o output - if (opts & OPT_o) - freopen(opt_output, "w", stdout); - - // no files given on command line? -> use stdin - if (!*argv) - *--argv = (char *)"-"; - - // put additional headers - for (l = opt_headers; l; l = l->link) - puts(l->data); - - // make a random string -- it will delimit message parts - srand(monotonic_us()); - boundary = xasprintf("%u-%u-%u", - (unsigned)rand(), (unsigned)rand(), (unsigned)rand()); - - // put multipart header - printf( - "Mime-Version: 1.0\n" - "Content-Type: multipart/mixed; boundary=\"%s\"\n" - , boundary - ); - - // put attachments - while (*argv) { - printf( - "\n--%s\n" - "Content-Type: %s; charset=%s\n" - "Content-Disposition: inline; filename=\"%s\"\n" - "Content-Transfer-Encoding: base64\n" - , boundary - , G.content_type - , G.opt_charset - , bb_get_last_path_component_strip(*argv) - ); - encode_base64(*argv++, (const char *)stdin, ""); - } - - // put multipart footer - printf("\n--%s--\n" "\n", boundary); - - return EXIT_SUCCESS; -#undef boundary -} - -static const char *find_token(const char *const string_array[], const char *key, const char *defvalue) -{ - const char *r = NULL; - int i; - for (i = 0; string_array[i] != NULL; i++) { - if (strcasecmp(string_array[i], key) == 0) { - r = (char *)string_array[i+1]; - break; - } - } - return (r) ? r : defvalue; -} - -static const char *xfind_token(const char *const string_array[], const char *key) -{ - const char *r = find_token(string_array, key, NULL); - if (r) - return r; - bb_error_msg_and_die("header: %s", key); -} - -enum { - OPT_x = 1 << 0, - OPT_X = 1 << 1, -#if ENABLE_FEATURE_REFORMIME_COMPAT - OPT_d = 1 << 2, - OPT_e = 1 << 3, - OPT_i = 1 << 4, - OPT_s = 1 << 5, - OPT_r = 1 << 6, - OPT_c = 1 << 7, - OPT_m = 1 << 8, - OPT_h = 1 << 9, - OPT_o = 1 << 10, - OPT_O = 1 << 11, -#endif -}; - -static int parse(const char *boundary, char **argv) -{ - char *line, *s, *p; - const char *type; - int boundary_len = strlen(boundary); - const char *delims = " ;\"\t\r\n"; - const char *uniq; - int ntokens; - const char *tokens[32]; // 32 is enough - - // prepare unique string pattern - uniq = xasprintf("%%llu.%u.%s", (unsigned)getpid(), safe_gethostname()); - -//bb_info_msg("PARSE[%s]", terminator); - - while ((line = xmalloc_fgets_str(stdin, "\r\n\r\n")) != NULL) { - - // seek to start of MIME section - // N.B. to avoid false positives let us seek to the _last_ occurance - p = NULL; - s = line; - while ((s = strcasestr(s, "Content-Type:")) != NULL) - p = s++; - if (!p) - goto next; -//bb_info_msg("L[%s]", p); - - // split to tokens - // TODO: strip of comments which are of form: (comment-text) - ntokens = 0; - tokens[ntokens] = NULL; - for (s = strtok(p, delims); s; s = strtok(NULL, delims)) { - tokens[ntokens] = s; - if (ntokens < ARRAY_SIZE(tokens) - 1) - ntokens++; -//bb_info_msg("L[%d][%s]", ntokens, s); - } - tokens[ntokens] = NULL; -//bb_info_msg("N[%d]", ntokens); - - // analyse tokens - type = find_token(tokens, "Content-Type:", "text/plain"); -//bb_info_msg("T[%s]", type); - if (0 == strncasecmp(type, "multipart/", 10)) { - if (0 == strcasecmp(type+10, "mixed")) { - parse(xfind_token(tokens, "boundary="), argv); - } else - bb_error_msg_and_die("no support of content type '%s'", type); - } else { - pid_t pid = pid; - int rc; - FILE *fp; - // fetch charset - const char *charset = find_token(tokens, "charset=", CONFIG_FEATURE_MIME_CHARSET); - // fetch encoding - const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit"); - // compose target filename - char *filename = (char *)find_token(tokens, "filename=", NULL); - if (!filename) - filename = xasprintf(uniq, monotonic_us()); - else - filename = bb_get_last_path_component_strip(xstrdup(filename)); - - // start external helper, if any - if (opts & OPT_X) { - int fd[2]; - xpipe(fd); - pid = vfork(); - if (0 == pid) { - // child reads from fd[0] - close(fd[1]); - xmove_fd(fd[0], STDIN_FILENO); - xsetenv("CONTENT_TYPE", type); - xsetenv("CHARSET", charset); - xsetenv("ENCODING", encoding); - xsetenv("FILENAME", filename); - BB_EXECVP_or_die(argv); - } - // parent dumps to fd[1] - close(fd[0]); - fp = xfdopen_for_write(fd[1]); - signal(SIGPIPE, SIG_IGN); // ignore EPIPE - // or create a file for dump - } else { - char *fname = xasprintf("%s%s", *argv, filename); - fp = xfopen_for_write(fname); - free(fname); - } - - // housekeeping - free(filename); - - // dump to fp - if (0 == strcasecmp(encoding, "base64")) { - decode_base64(stdin, fp); - } else if (0 != strcasecmp(encoding, "7bit") - && 0 != strcasecmp(encoding, "8bit") - ) { - // quoted-printable, binary, user-defined are unsupported so far - bb_error_msg_and_die("no support of encoding '%s'", encoding); - } else { - // N.B. we have written redundant \n. so truncate the file - // The following weird 2-tacts reading technique is due to - // we have to not write extra \n at the end of the file - // In case of -x option we could truncate the resulting file as - // fseek(fp, -1, SEEK_END); - // if (ftruncate(fileno(fp), ftell(fp))) - // bb_perror_msg("ftruncate"); - // But in case of -X we have to be much more careful. There is - // no means to truncate what we already have sent to the helper. - p = xmalloc_fgets_str(stdin, "\r\n"); - while (p) { - s = xmalloc_fgets_str(stdin, "\r\n"); - if (s == NULL) - break; - if ('-' == s[0] - && '-' == s[1] - && 0 == strncmp(s+2, boundary, boundary_len) - ) { - break; - } - fputs(p, fp); - p = s; - } - -/* - while ((s = xmalloc_fgetline_str(stdin, "\r\n")) != NULL) { - if ('-' == s[0] && '-' == s[1] - && 0 == strncmp(s+2, boundary, boundary_len)) - break; - fprintf(fp, "%s\n", s); - } - // N.B. we have written redundant \n. so truncate the file - fseek(fp, -1, SEEK_END); - if (ftruncate(fileno(fp), ftell(fp))) - bb_perror_msg("ftruncate"); -*/ - } - fclose(fp); - - // finalize helper - if (opts & OPT_X) { - signal(SIGPIPE, SIG_DFL); - // exit if helper exited >0 - rc = (wait4pid(pid) & 0xff); - if (rc) - return rc+20; - } - - // check multipart finalized - if (s && '-' == s[2+boundary_len] && '-' == s[2+boundary_len+1]) { - free(line); - break; - } - } - next: - free(line); - } - -//bb_info_msg("ENDPARSE[%s]", boundary); - - return EXIT_SUCCESS; -} - -/* -Usage: reformime [options] - -d - parse a delivery status notification. - -e - extract contents of MIME section. - -x - extract MIME section to a file. - -X - pipe MIME section to a program. - -i - show MIME info. - -s n.n.n.n - specify MIME section. - -r - rewrite message, filling in missing MIME headers. - -r7 - also convert 8bit/raw encoding to quoted-printable, if possible. - -r8 - also convert quoted-printable encoding to 8bit, if possible. - -c charset - default charset for rewriting, -o, and -O. - -m [file] [file]... - create a MIME message digest. - -h "header" - decode RFC 2047-encoded header. - -o "header" - encode unstructured header using RFC 2047. - -O "header" - encode address list header using RFC 2047. -*/ - -int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int reformime_main(int argc UNUSED_PARAM, char **argv) -{ - const char *opt_prefix = ""; - - INIT_G(); - - // parse options - // N.B. only -x and -X are supported so far - opt_complementary = "x--X:X--x" IF_FEATURE_REFORMIME_COMPAT(":m::"); - opts = getopt32(argv, - "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"), - &opt_prefix - IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) - ); - //argc -= optind; - argv += optind; - - return parse("", (opts & OPT_X) ? argv : (char **)&opt_prefix); -} diff --git a/mailutils/popmaildir.c b/mailutils/popmaildir.c index ab9ddba..6203033 100644 --- a/mailutils/popmaildir.c +++ b/mailutils/popmaildir.c @@ -7,16 +7,52 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//kbuild:lib-$(CONFIG_POPMAILDIR) += popmaildir.o mail.o + +//usage:#define popmaildir_trivial_usage +//usage: "[OPTIONS] MAILDIR [CONN_HELPER ARGS]" +//usage:#define popmaildir_full_usage "\n\n" +//usage: "Fetch content of remote mailbox to local maildir\n" +/* //usage: "\n -b Binary mode. Ignored" */ +/* //usage: "\n -d Debug. Ignored" */ +/* //usage: "\n -m Show used memory. Ignored" */ +/* //usage: "\n -V Show version. Ignored" */ +/* //usage: "\n -c Use tcpclient. Ignored" */ +/* //usage: "\n -a Use APOP protocol. Implied. If server supports APOP -> use it" */ +//usage: "\n -s Skip authorization" +//usage: "\n -T Get messages with TOP instead of RETR" +//usage: "\n -k Keep retrieved messages on the server" +//usage: "\n -t SEC Network timeout" +//usage: IF_FEATURE_POPMAILDIR_DELIVERY( +//usage: "\n -F \"PROG ARGS\" Filter program (may be repeated)" +//usage: "\n -M \"PROG ARGS\" Delivery program" +//usage: ) +//usage: "\n" +//usage: "\nFetch from plain POP3 server:" +//usage: "\npopmaildir -k DIR nc pop3.server.com 110 = BYTES. Ignored" */ +/* //usage: "\n -Z N1-N2 Remove messages from N1 to N2 (dangerous). Ignored" */ +/* //usage: "\n -L BYTES Don't retrieve new messages >= BYTES. Ignored" */ +/* //usage: "\n -H LINES Type first LINES of a message. Ignored" */ +//usage: +//usage:#define popmaildir_example_usage +//usage: "$ popmaildir -k ~/Maildir -- nc pop.drvv.ru 110 [password" string md5_begin(&md5.ctx); - md5_hash(buf, strlen(buf), &md5.ctx); - md5_hash(G.pass, strlen(G.pass), &md5.ctx); - md5_end(res, &md5.ctx); + md5_hash(&md5.ctx, buf, strlen(buf)); + md5_hash(&md5.ctx, G.pass, strlen(G.pass)); + md5_end(&md5.ctx, res); *bin2hex(md5.hex, (char*)res, 16) = '\0'; // APOP s = xasprintf("%s %s", G.user, md5.hex); diff --git a/mailutils/reformime.c b/mailutils/reformime.c new file mode 100644 index 0000000..8e7d455 --- /dev/null +++ b/mailutils/reformime.c @@ -0,0 +1,278 @@ +/* vi: set sw=4 ts=4: */ +/* + * reformime: parse MIME-encoded message + * + * Copyright (C) 2008 by Vladimir Dronnikov + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//kbuild:lib-$(CONFIG_REFORMIME) += reformime.o mail.o + +#include "libbb.h" +#include "mail.h" + +#if 0 +# define dbg_error_msg(...) bb_error_msg(__VA_ARGS__) +#else +# define dbg_error_msg(...) ((void)0) +#endif + +static const char *find_token(const char *const string_array[], const char *key, const char *defvalue) +{ + const char *r = NULL; + int i; + for (i = 0; string_array[i] != NULL; i++) { + if (strcasecmp(string_array[i], key) == 0) { + r = (char *)string_array[i+1]; + break; + } + } + return (r) ? r : defvalue; +} + +static const char *xfind_token(const char *const string_array[], const char *key) +{ + const char *r = find_token(string_array, key, NULL); + if (r) + return r; + bb_error_msg_and_die("not found: '%s'", key); +} + +enum { + OPT_x = 1 << 0, + OPT_X = 1 << 1, +#if ENABLE_FEATURE_REFORMIME_COMPAT + OPT_d = 1 << 2, + OPT_e = 1 << 3, + OPT_i = 1 << 4, + OPT_s = 1 << 5, + OPT_r = 1 << 6, + OPT_c = 1 << 7, + OPT_m = 1 << 8, + OPT_h = 1 << 9, + OPT_o = 1 << 10, + OPT_O = 1 << 11, +#endif +}; + +static int parse(const char *boundary, char **argv) +{ + int boundary_len = strlen(boundary); + char uniq[sizeof("%%llu.%u") + sizeof(int)*3]; + + dbg_error_msg("BOUNDARY[%s]", boundary); + + // prepare unique string pattern + sprintf(uniq, "%%llu.%u", (unsigned)getpid()); + dbg_error_msg("UNIQ[%s]", uniq); + + while (1) { + char *header; + const char *tokens[32]; /* 32 is enough */ + const char *type; + + /* Read the header (everything up to two \n) */ + { + unsigned header_idx = 0; + int last_ch = 0; + header = NULL; + while (1) { + int ch = fgetc(stdin); + if (ch == '\r') /* Support both line endings */ + continue; + if (ch == EOF) + break; + if (ch == '\n' && last_ch == ch) + break; + if (!(header_idx & 0xff)) + header = xrealloc(header, header_idx + 0x101); + header[header_idx++] = last_ch = ch; + } + if (!header) { + dbg_error_msg("EOF"); + break; + } + header[header_idx] = '\0'; + dbg_error_msg("H:'%s'", p); + } + + /* Split to tokens */ + { + char *s, *p; + unsigned ntokens; + const char *delims = ";=\" \t\n"; + + /* Skip to last Content-Type: */ + s = p = header; + while ((p = strchr(p, '\n')) != NULL) { + p++; + if (strncasecmp(p, "Content-Type:", sizeof("Content-Type:")-1) == 0) + s = p; + } + dbg_error_msg("L:'%s'", p); + ntokens = 0; + s = strtok(s, delims); + while (s) { + tokens[ntokens] = s; + if (ntokens < ARRAY_SIZE(tokens) - 1) + ntokens++; + dbg_error_msg("L[%d]='%s'", ntokens, s); + s = strtok(NULL, delims); + } + tokens[ntokens] = NULL; + dbg_error_msg("EMPTYLINE, ntokens:%d", ntokens); + if (ntokens == 0) + break; + } + + /* Is it multipart? */ + type = find_token(tokens, "Content-Type:", "text/plain"); + dbg_error_msg("TYPE:'%s'", type); + if (0 == strncasecmp(type, "multipart/", 10)) { + /* Yes, recurse */ + if (strcasecmp(type + 10, "mixed") != 0) + bb_error_msg_and_die("no support of content type '%s'", type); + parse(xfind_token(tokens, "boundary"), argv); + + } else { + /* No, process one non-multipart section */ + char *end; + pid_t pid = pid; + FILE *fp; + + const char *charset = find_token(tokens, "charset", CONFIG_FEATURE_MIME_CHARSET); + const char *encoding = find_token(tokens, "Content-Transfer-Encoding:", "7bit"); + + /* Compose target filename */ + char *filename = (char *)find_token(tokens, "filename", NULL); + if (!filename) + filename = xasprintf(uniq, monotonic_us()); + else + filename = bb_get_last_path_component_strip(xstrdup(filename)); + + if (opts & OPT_X) { + int fd[2]; + + /* start external helper */ + xpipe(fd); + pid = vfork(); + if (0 == pid) { + /* child reads from fd[0] */ + close(fd[1]); + xmove_fd(fd[0], STDIN_FILENO); + xsetenv("CONTENT_TYPE", type); + xsetenv("CHARSET", charset); + xsetenv("ENCODING", encoding); + xsetenv("FILENAME", filename); + BB_EXECVP_or_die(argv); + } + /* parent will write to fd[1] */ + close(fd[0]); + fp = xfdopen_for_write(fd[1]); + signal(SIGPIPE, SIG_IGN); + } else { + /* write to file */ + char *fname = xasprintf("%s%s", *argv, filename); + fp = xfopen_for_write(fname); + free(fname); + } + free(filename); + + /* write to fp */ + end = NULL; + if (0 == strcasecmp(encoding, "base64")) { + read_base64(stdin, fp, '-'); + } else + if (0 != strcasecmp(encoding, "7bit") + && 0 != strcasecmp(encoding, "8bit") + ) { + /* quoted-printable, binary, user-defined are unsupported so far */ + bb_error_msg_and_die("encoding '%s' not supported", encoding); + } else { + /* plain 7bit or 8bit */ + while ((end = xmalloc_fgets(stdin)) != NULL) { + if ('-' == end[0] + && '-' == end[1] + && strncmp(end + 2, boundary, boundary_len) == 0 + ) { + break; + } + fputs(end, fp); + } + } + fclose(fp); + + /* Wait for child */ + if (opts & OPT_X) { + int rc; + signal(SIGPIPE, SIG_DFL); + rc = (wait4pid(pid) & 0xff); + if (rc != 0) + return rc + 20; + } + + /* Multipart ended? */ + if (end && '-' == end[2 + boundary_len] && '-' == end[2 + boundary_len + 1]) { + dbg_error_msg("FINISHED MPART:'%s'", end); + break; + } + dbg_error_msg("FINISHED:'%s'", end); + free(end); + } /* end of "handle one non-multipart block" */ + + free(header); + } /* while (1) */ + + dbg_error_msg("ENDPARSE[%s]", boundary); + + return EXIT_SUCCESS; +} + +//usage:#define reformime_trivial_usage +//usage: "[OPTIONS]" +//usage:#define reformime_full_usage "\n\n" +//usage: "Parse MIME-encoded message on stdin\n" +//usage: "\n -x PREFIX Extract content of MIME sections to files" +//usage: "\n -X PROG ARGS Filter content of MIME sections through PROG" +//usage: "\n Must be the last option" +//usage: "\n" +//usage: "\nOther options are silently ignored" + +/* +Usage: reformime [options] + -d - parse a delivery status notification. + -e - extract contents of MIME section. + -x - extract MIME section to a file. + -X - pipe MIME section to a program. + -i - show MIME info. + -s n.n.n.n - specify MIME section. + -r - rewrite message, filling in missing MIME headers. + -r7 - also convert 8bit/raw encoding to quoted-printable, if possible. + -r8 - also convert quoted-printable encoding to 8bit, if possible. + -c charset - default charset for rewriting, -o, and -O. + -m [file] [file]... - create a MIME message digest. + -h "header" - decode RFC 2047-encoded header. + -o "header" - encode unstructured header using RFC 2047. + -O "header" - encode address list header using RFC 2047. +*/ + +int reformime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int reformime_main(int argc UNUSED_PARAM, char **argv) +{ + const char *opt_prefix = ""; + + INIT_G(); + + // parse options + // N.B. only -x and -X are supported so far + opt_complementary = "x--X:X--x" IF_FEATURE_REFORMIME_COMPAT(":m::"); + opts = getopt32(argv, + "x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"), + &opt_prefix + IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL) + ); + argv += optind; + + return parse("", (opts & OPT_X) ? argv : (char **)&opt_prefix); +} diff --git a/mailutils/sendmail.c b/mailutils/sendmail.c index 4b58a78..b5aa1d1 100644 --- a/mailutils/sendmail.c +++ b/mailutils/sendmail.c @@ -4,8 +4,42 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//kbuild:lib-$(CONFIG_SENDMAIL) += sendmail.o mail.o + +//usage:#define sendmail_trivial_usage +//usage: "[OPTIONS] [RECIPIENT_EMAIL]..." +//usage:#define sendmail_full_usage "\n\n" +//usage: "Read email from stdin and send it\n" +//usage: "\nStandard options:" +//usage: "\n -t Read additional recipients from message body" +//usage: "\n -f SENDER Sender (required)" +//usage: "\n -o OPTIONS Various options. -oi implied, others are ignored" +//usage: "\n -i -oi synonym. implied and ignored" +//usage: "\n" +//usage: "\nBusybox specific options:" +//usage: "\n -v Verbose" +//usage: "\n -w SECS Network timeout" +//usage: "\n -H 'PROG ARGS' Run connection helper" +//usage: "\n Examples:" +//usage: "\n -H 'exec openssl s_client -quiet -tls1 -starttls smtp" +//usage: "\n -connect smtp.gmail.com:25' die saying msg - while ((answer = xmalloc_fgetline(stdin)) != NULL) + while ((answer = xmalloc_fgetline(stdin)) != NULL) { + if (verbose) + bb_error_msg("recv:'%.*s'", (int)(strchrnul(answer, '\r') - answer), answer); if (strlen(answer) <= 3 || '-' != answer[3]) break; + free(answer); + } if (answer) { int n = atoi(answer); if (timeout) alarm(0); free(answer); - if (-1 == code || n == code) + if (-1 == code || n == code) { + free(msg); return n; + } } bb_error_msg_and_die("%s failed", msg); } @@ -45,25 +92,73 @@ static int smtp_check(const char *fmt, int code) // strip argument of bad chars static char *sane_address(char *str) { - char *s = str; - char *p = s; + char *s; + + trim(str); + s = str; while (*s) { - if (isalnum(*s) || '_' == *s || '-' == *s || '.' == *s || '@' == *s) { - *p++ = *s; + if (!isalnum(*s) && !strchr("_-.@", *s)) { + bb_error_msg("bad address '%s'", str); + /* returning "": */ + str[0] = '\0'; + return str; } s++; } - *p = '\0'; return str; } +// check for an address inside angle brackets, if not found fall back to normal +static char *angle_address(char *str) +{ + char *s, *e; + + trim(str); + e = last_char_is(str, '>'); + if (e) { + s = strrchr(str, '<'); + if (s) { + *e = '\0'; + str = s + 1; + } + } + return sane_address(str); +} + static void rcptto(const char *s) { + if (!*s) + return; // N.B. we don't die if recipient is rejected, for the other recipients may be accepted if (250 != smtp_checkp("RCPT TO:<%s>", s, -1)) bb_error_msg("Bad recipient: <%s>", s); } +// send to a list of comma separated addresses +static void rcptto_list(const char *list) +{ + char *str = xstrdup(list); + char *s = str; + char prev = 0; + int in_quote = 0; + + while (*s) { + char ch = *s++; + + if (ch == '"' && prev != '\\') { + in_quote = !in_quote; + } else if (!in_quote && ch == ',') { + s[-1] = '\0'; + rcptto(angle_address(str)); + str = s; + } + prev = ch; + } + if (prev != ',') + rcptto(angle_address(str)); + free(str); +} + int sendmail_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sendmail_main(int argc UNUSED_PARAM, char **argv) { @@ -71,9 +166,16 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) char *opt_from; char *s; llist_t *list = NULL; - char *domain = sane_address(safe_getdomainname()); + char *host = sane_address(safe_gethostname()); unsigned nheaders = 0; int code; + enum { + HDR_OTHER = 0, + HDR_TOCC, + HDR_BCC, + } last_hdr = 0; + int check_hdr; + int has_to = 0; enum { //--- standard options @@ -86,6 +188,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) OPT_H = 1 << 5, // use external connection helper OPT_S = 1 << 6, // specify connection string OPT_a = 1 << 7, // authentication tokens + OPT_v = 1 << 8, // verbosity }; // init global variables @@ -96,12 +199,13 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) G.fp0 = xfdopen_for_read(3); // parse options - // -f is required. -H and -S are mutually exclusive - opt_complementary = "f:w+:H--S:S--H:a::"; + // -v is a counter, -f is required. -H and -S are mutually exclusive, -a is a list + opt_complementary = "vv:f:w+:H--S:S--H:a::"; // N.B. since -H and -S are mutually exclusive they do not interfere in opt_connect // -a is for ssmtp (http://downloads.openwrt.org/people/nico/man/man8/ssmtp.8.html) compatibility, // it is still under development. - opts = getopt32(argv, "tf:o:iw:H:S:a::", &opt_from, NULL, &timeout, &opt_connect, &opt_connect, &list); + opts = getopt32(argv, "tf:o:iw:H:S:a::v", &opt_from, NULL, + &timeout, &opt_connect, &opt_connect, &list, &verbose); //argc -= optind; argv += optind; @@ -128,11 +232,35 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) const char *args[] = { "sh", "-c", opt_connect, NULL }; // plug it in launch_helper(args); - // vanilla connection + // Now: + // our stdout will go to helper's stdin, + // helper's stdout will be available on our stdin. + + // Wait for initial server message. + // If helper (such as openssl) invokes STARTTLS, the initial 220 + // is swallowed by helper (and not repeated after TLS is initiated). + // We will send NOOP cmd to server and check the response. + // We should get 220+250 on plain connection, 250 on STARTTLSed session. + // + // The problem here is some servers delay initial 220 message, + // and consider client to be a spammer if it starts sending cmds + // before 220 reached it. The code below is unsafe in this regard: + // in non-STARTTLSed case, we potentially send NOOP before 220 + // is sent by server. + // Ideas? (--delay SECS opt? --assume-starttls-helper opt?) + code = smtp_check("NOOP", -1); + if (code == 220) + // we got 220 - this is not STARTTLSed connection, + // eat 250 response to our NOOP + smtp_check(NULL, 250); + else + if (code != 250) + bb_error_msg_and_die("SMTP init failed"); } else { + // vanilla connection int fd; // host[:port] not explicitly specified? -> use $SMTPHOST - // no $SMTPHOST ? -> use localhost + // no $SMTPHOST? -> use localhost if (!(opts & OPT_S)) { opt_connect = getenv("SMTPHOST"); if (!opt_connect) @@ -143,25 +271,15 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // and make ourselves a simple IO filter xmove_fd(fd, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); + + // Wait for initial server 220 message + smtp_check(NULL, 220); } - // N.B. from now we know nothing about network :) - - // wait for initial server OK - // N.B. if we used openssl the initial 220 answer is already swallowed during openssl TLS init procedure - // so we need to kick the server to see whether we are ok - code = smtp_check("NOOP", -1); - // 220 on plain connection, 250 on openssl-helped TLS session - if (220 == code) - smtp_check(NULL, 250); // reread the code to stay in sync - else if (250 != code) - bb_error_msg_and_die("INIT failed"); // we should start with modern EHLO - if (250 != smtp_checkp("EHLO %s", domain, -1)) { - smtp_checkp("HELO %s", domain, 250); - } - if (ENABLE_FEATURE_CLEAN_UP) - free(domain); + if (250 != smtp_checkp("EHLO %s", host, -1)) + smtp_checkp("HELO %s", host, 250); + free(host); // perform authentication if (opts & OPT_a) { @@ -176,7 +294,7 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) } // set sender - // N.B. we have here a very loosely defined algotythm + // N.B. we have here a very loosely defined algorythm // since sendmail historically offers no means to specify secrets on cmdline. // 1) server can require no authentication -> // we must just provide a (possibly fake) reply address. @@ -193,8 +311,6 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) // G.user = xuid2uname(getuid()); // opt_from = xasprintf("%s@%s", G.user, domain); //} - //if (ENABLE_FEATURE_CLEAN_UP) - // free(domain); smtp_checkp("MAIL FROM:<%s>", opt_from, 250); // process message @@ -214,44 +330,74 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) if ('.' == s[0] /*&& '\0' == s[1] */) printf("."); // dump read line - printf("%s\r\n", s); + send_r_n(s); free(s); continue; } // analyze headers // To: or Cc: headers add recipients - if (0 == strncasecmp("To: ", s, 4) || 0 == strncasecmp("Bcc: " + 1, s, 4)) { - rcptto(sane_address(s+4)); - goto addheader; - // Bcc: header adds blind copy (hidden) recipient - } else if (0 == strncasecmp("Bcc: ", s, 5)) { - rcptto(sane_address(s+5)); - free(s); - // N.B. Bcc: vanishes from headers! - - // other headers go verbatim - - // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. - // Continuation is denoted by prefixing additional lines with whitespace(s). - // Thanks (stefan.seyfried at googlemail.com) for pointing this out. - } else if (strchr(s, ':') || (list && skip_whitespace(s) != s)) { + check_hdr = (0 == strncasecmp("To:", s, 3)); + has_to |= check_hdr; + if (opts & OPT_t) { + if (check_hdr || 0 == strncasecmp("Bcc:" + 1, s, 3)) { + rcptto_list(s+3); + last_hdr = HDR_TOCC; + goto addheader; + } + // Bcc: header adds blind copy (hidden) recipient + if (0 == strncasecmp("Bcc:", s, 4)) { + rcptto_list(s+4); + free(s); + last_hdr = HDR_BCC; + continue; // N.B. Bcc: vanishes from headers! + } + } + check_hdr = (list && isspace(s[0])); + if (strchr(s, ':') || check_hdr) { + // other headers go verbatim + // N.B. RFC2822 2.2.3 "Long Header Fields" allows for headers to occupy several lines. + // Continuation is denoted by prefixing additional lines with whitespace(s). + // Thanks (stefan.seyfried at googlemail.com) for pointing this out. + if (check_hdr && last_hdr != HDR_OTHER) { + rcptto_list(s+1); + if (last_hdr == HDR_BCC) + continue; + // N.B. Bcc: vanishes from headers! + } else { + last_hdr = HDR_OTHER; + } addheader: // N.B. we allow MAX_HEADERS generic headers at most to prevent attacks if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) goto bail; llist_add_to_end(&list, s); - // a line without ":" (an empty line too, by definition) doesn't look like a valid header - // so stop "analyze headers" mode } else { + // a line without ":" (an empty line too, by definition) doesn't look like a valid header + // so stop "analyze headers" mode reenter: // put recipients specified on cmdline + check_hdr = 1; while (*argv) { char *t = sane_address(*argv); rcptto(t); //if (MAX_HEADERS && ++nheaders >= MAX_HEADERS) // goto bail; - llist_add_to_end(&list, xasprintf("To: %s", t)); + if (!has_to) { + const char *hdr; + + if (check_hdr && argv[1]) + hdr = "To: %s,"; + else if (check_hdr) + hdr = "To: %s"; + else if (argv[1]) + hdr = "To: %s," + 3; + else + hdr = "To: %s" + 3; + llist_add_to_end(&list, + xasprintf(hdr, t)); + check_hdr = 0; + } argv++; } // enter "put message" mode @@ -261,14 +407,14 @@ int sendmail_main(int argc UNUSED_PARAM, char **argv) goto bail; // dump the headers while (list) { - printf("%s\r\n", (char *) llist_pop(&list)); + send_r_n((char *) llist_pop(&list)); } // stop analyzing headers code++; // N.B. !s means: we read nothing, and nothing to be read in the future. // just dump empty line and break the loop if (!s) { - puts("\r"); + send_r_n(""); break; } // go dump message body diff --git a/miscutils/Config.src b/miscutils/Config.src index 2f7c502..1da9800 100644 --- a/miscutils/Config.src +++ b/miscutils/Config.src @@ -10,6 +10,7 @@ INSERT config ADJTIMEX bool "adjtimex" default y + select PLATFORM_LINUX help Adjtimex reads and optionally sets adjustment parameters for the Linux clock adjustment algorithm. @@ -21,9 +22,24 @@ config BBCONFIG The bbconfig applet will print the config file with which busybox was built. +config FEATURE_COMPRESS_BBCONFIG + bool "Compress bbconfig data" + default y + depends on BBCONFIG + help + Store bbconfig data in compressed form, uncompress them on-the-fly + before output. + + If you have a really tiny busybox with few applets enabled (and + bunzip2 isn't one of them), the overhead of the decompressor might + be noticeable. Also, if you run executables directly from ROM + and have very little memory, this might not be a win. Otherwise, + you probably want this. + config BEEP bool "beep" default y + select PLATFORM_LINUX help The beep applets beeps in a given freq/Hz. @@ -120,7 +136,6 @@ config CHRT config CROND bool "crond" default y - select FEATURE_SUID select FEATURE_SYSLOG help Crond is a background daemon that parses individual crontab @@ -155,7 +170,6 @@ config FEATURE_CROND_DIR config CRONTAB bool "crontab" default y - select FEATURE_SUID help Crontab manipulates the crontab for a particular user. Only the superuser may specify a different user and/or crontab directory. @@ -180,6 +194,7 @@ config FEATURE_DC_LIBM config DEVFSD bool "devfsd (obsolete)" default n + select PLATFORM_LINUX select FEATURE_SYSLOG help This is deprecated and should NOT be used anymore. @@ -223,6 +238,7 @@ config DEVFSD_VERBOSE config FEATURE_DEVFS bool "Use devfs names for all devices (obsolete)" default n + select PLATFORM_LINUX help This is obsolete and should NOT be used anymore. Use linux >= 2.6 (optionally with hotplug) and mdev instead! @@ -242,6 +258,7 @@ config DEVMEM config EJECT bool "eject" default y + select PLATFORM_LINUX help Used to eject cdroms. (defaults to /dev/cdrom) @@ -256,6 +273,7 @@ config FEATURE_EJECT_SCSI config FBSPLASH bool "fbsplash" default y + select PLATFORM_LINUX help Shows splash image and progress bar on framebuffer device. Can be used during boot phase of an embedded device. ~2kb. @@ -305,6 +323,7 @@ config FLASH_ERASEALL config IONICE bool "ionice" default y + select PLATFORM_LINUX help Set/set program io scheduling class and priority Requires kernel >= 2.6.13 @@ -341,75 +360,10 @@ config FEATURE_LAST_FANCY logged into the system (mimics sysvinit last). +900 bytes. endchoice -config LESS - bool "less" - default y - help - 'less' is a pager, meaning that it displays text files. It possesses - a wide array of features, and is an improvement over 'more'. - -config FEATURE_LESS_MAXLINES - int "Max number of input lines less will try to eat" - default 9999999 - depends on LESS - -config FEATURE_LESS_BRACKETS - bool "Enable bracket searching" - default y - depends on LESS - help - This option adds the capability to search for matching left and right - brackets, facilitating programming. - -config FEATURE_LESS_FLAGS - bool "Enable extra flags" - default y - depends on LESS - help - The extra flags provided do the following: - - The -M flag enables a more sophisticated status line. - The -m flag enables a simpler status line with a percentage. - -config FEATURE_LESS_MARKS - bool "Enable marks" - default y - depends on LESS - help - Marks enable positions in a file to be stored for easy reference. - -config FEATURE_LESS_REGEXP - bool "Enable regular expressions" - default y - depends on LESS - help - Enable regular expressions, allowing complex file searches. - -config FEATURE_LESS_WINCH - bool "Enable automatic resizing on window size changes" - default y - depends on LESS - help - Makes less track window size changes. - -config FEATURE_LESS_DASHCMD - bool "Enable flag changes ('-' command)" - default y - depends on LESS - help - This enables the ability to change command-line flags within - less itself ('-' keyboard command). - -config FEATURE_LESS_LINENUMS - bool "Enable dynamic switching of line numbers" - default y - depends on FEATURE_LESS_DASHCMD - help - Enable "-N" command. - config HDPARM bool "hdparm" default y + select PLATFORM_LINUX help Get/Set hard drive parameters. Primarily intended for ATA drives. Adds about 13k (or around 30k if you enable the @@ -471,15 +425,15 @@ config MAKEDEVS help 'makedevs' is a utility used to create a batch of devices with one command. - . + There are two choices for command line behaviour, the interface as used by LEAF/Linux Router Project, or a device table file. - . + 'leaf' is traditionally what busybox follows, it allows multiple devices of a particluar type to be created per command. e.g. /dev/hda[0-9] Device properties are passed as command line arguments. - . + 'table' reads device properties from a file or stdin, allowing a batch of unrelated devices to be made with one command. User/group names are allowed as an alternative to uid/gid. @@ -526,6 +480,7 @@ config MT config RAIDAUTORUN bool "raidautorun" default y + select PLATFORM_LINUX help raidautorun tells the kernel md driver to search and start RAID arrays. @@ -534,6 +489,7 @@ config READAHEAD bool "readahead" default y depends on LFS + select PLATFORM_LINUX help Preload the files listed on the command line into RAM cache so that subsequent reads on these files will not block on disk I/O. @@ -547,20 +503,10 @@ config READAHEAD As readahead(2) blocks until each file has been read, it is best to run this applet as a background job. -config RFKILL - bool "rfkill" - default n # doesn't build on Ubuntu 9.04 - help - Enable/disable wireless devices. - - rfkill list : list all wireless devices - rfkill list bluetooth : list all bluetooth devices - rfkill list 1 : list device corresponding to the given index - rfkill block|unblock wlan : block/unblock all wlan(wifi) devices - config RUNLEVEL bool "runlevel" default y + depends on FEATURE_UTMP help find the current and previous system runlevel. @@ -570,6 +516,7 @@ config RUNLEVEL config RX bool "rx" default y + select PLATFORM_LINUX help Receive files using the Xmodem protocol. @@ -632,15 +579,10 @@ config VOLNAME help Prints a CD-ROM volume name. -config WALL - bool "wall" - default y - help - Write a message to all users that are logged in. - config WATCHDOG bool "watchdog" default y + select PLATFORM_LINUX help The watchdog utility is used with hardware or software watchdog device drivers. It opens the specified watchdog device special file diff --git a/miscutils/Kbuild.src b/miscutils/Kbuild.src index d9bf143..9e164f1 100644 --- a/miscutils/Kbuild.src +++ b/miscutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= @@ -36,7 +36,6 @@ lib-$(CONFIG_MOUNTPOINT) += mountpoint.o lib-$(CONFIG_MT) += mt.o lib-$(CONFIG_RAIDAUTORUN) += raidautorun.o lib-$(CONFIG_READAHEAD) += readahead.o -lib-$(CONFIG_RFKILL) += rfkill.o lib-$(CONFIG_RUNLEVEL) += runlevel.o lib-$(CONFIG_RX) += rx.o lib-$(CONFIG_SETSID) += setsid.o @@ -46,5 +45,4 @@ lib-$(CONFIG_TIME) += time.o lib-$(CONFIG_TIMEOUT) += timeout.o lib-$(CONFIG_TTYSIZE) += ttysize.o lib-$(CONFIG_VOLNAME) += volname.o -lib-$(CONFIG_WALL) += wall.o lib-$(CONFIG_WATCHDOG) += watchdog.o diff --git a/miscutils/adjtimex.c b/miscutils/adjtimex.c index c12a10b..c8816e9 100644 --- a/miscutils/adjtimex.c +++ b/miscutils/adjtimex.c @@ -8,11 +8,26 @@ * * busyboxed 20 March 2001, Larry Doolittle * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define adjtimex_trivial_usage +//usage: "[-q] [-o OFF] [-f FREQ] [-p TCONST] [-t TICK]" +//usage:#define adjtimex_full_usage "\n\n" +//usage: "Read and optionally set system timebase parameters. See adjtimex(2)\n" +//usage: "\n -q Quiet" +//usage: "\n -o OFF Time offset, microseconds" +//usage: "\n -f FREQ Frequency adjust, integer kernel units (65536 is 1ppm)" +//usage: "\n (positive values make clock run faster)" +//usage: "\n -t TICK Microseconds per tick, usually 10000" +//usage: "\n -p TCONST" + #include "libbb.h" -#include +#ifdef __BIONIC__ +# include +#else +# include +#endif static const uint16_t statlist_bit[] = { STA_PLL, diff --git a/miscutils/bbconfig.c b/miscutils/bbconfig.c index 0d649b4..e5f4eb3 100644 --- a/miscutils/bbconfig.c +++ b/miscutils/bbconfig.c @@ -1,12 +1,40 @@ /* vi: set sw=4 ts=4: */ /* This file was released into the public domain by Paul Fox. */ + +//usage:#define bbconfig_trivial_usage +//usage: "" +//usage:#define bbconfig_full_usage "\n\n" +//usage: "Print the config file used by busybox build" + #include "libbb.h" #include "bbconfigopts.h" +#if ENABLE_FEATURE_COMPRESS_BBCONFIG +# include "bb_archive.h" +# include "bbconfigopts_bz2.h" +#endif int bbconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int bbconfig_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { +#if ENABLE_FEATURE_COMPRESS_BBCONFIG + bunzip_data *bd; + int i = start_bunzip(&bd, + /* src_fd: */ -1, + /* inbuf: */ bbconfig_config_bz2, + /* len: */ sizeof(bbconfig_config_bz2)); + /* read_bunzip can longjmp to start_bunzip, and ultimately + * end up here with i != 0 on read data errors! Not trivial */ + if (!i) { + /* Cannot use xmalloc: will leak bd in NOFORK case! */ + char *outbuf = malloc_or_warn(sizeof(bbconfig_config)); + if (outbuf) { + read_bunzip(bd, outbuf, sizeof(bbconfig_config)); + full_write1_str(outbuf); + } + } +#else full_write1_str(bbconfig_config); +#endif return 0; } diff --git a/miscutils/beep.c b/miscutils/beep.c index b0ee7ea..910e03e 100644 --- a/miscutils/beep.c +++ b/miscutils/beep.c @@ -4,9 +4,19 @@ * * Copyright (C) 2009 Bernhard Reutner-Fischer * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * */ + +//usage:#define beep_trivial_usage +//usage: "-f FREQ -l LEN -d DELAY -r COUNT -n" +//usage:#define beep_full_usage "\n\n" +//usage: " -f Frequency in Hz" +//usage: "\n -l Length in ms" +//usage: "\n -d Delay in ms" +//usage: "\n -r Repetitions" +//usage: "\n -n Start new tone" + #include "libbb.h" #include diff --git a/miscutils/chat.c b/miscutils/chat.c index 3ffd7b2..bd2abc2 100644 --- a/miscutils/chat.c +++ b/miscutils/chat.c @@ -5,12 +5,21 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define chat_trivial_usage +//usage: "EXPECT [SEND [EXPECT [SEND...]]]" +//usage:#define chat_full_usage "\n\n" +//usage: "Useful for interacting with a modem connected to stdin/stdout.\n" +//usage: "A script consists of one or more \"expect-send\" pairs of strings,\n" +//usage: "each pair is a pair of arguments. Example:\n" +//usage: "chat '' ATZ OK ATD123456 CONNECT '' ogin: pppuser word: ppppass '~'" + #include "libbb.h" // default timeout: 45 sec -#define DEFAULT_CHAT_TIMEOUT 45*1000 +#define DEFAULT_CHAT_TIMEOUT 45*1000 // max length of "abort string", // i.e. device reply which causes termination #define MAX_ABORT_LEN 50 @@ -175,23 +184,24 @@ int chat_main(int argc UNUSED_PARAM, char **argv) llist_add_to_end(&aborts, arg); #if ENABLE_FEATURE_CHAT_CLR_ABORT } else if (DIR_CLR_ABORT == key) { + llist_t *l; // remove the string from abort conditions // N.B. gotta refresh maximum length too... -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN max_abort_len = 0; -#endif - for (llist_t *l = aborts; l; l = l->link) { -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# endif + for (l = aborts; l; l = l->link) { +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN size_t len = strlen(l->data); -#endif - if (!strcmp(arg, l->data)) { +# endif + if (strcmp(arg, l->data) == 0) { llist_unlink(&aborts, l); continue; } -#if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN +# if ENABLE_FEATURE_CHAT_VAR_ABORT_LEN if (len > max_abort_len) max_abort_len = len; -#endif +# endif } #endif } else if (DIR_TIMEOUT == key) { @@ -286,7 +296,7 @@ int chat_main(int argc UNUSED_PARAM, char **argv) full_write(record_fd, buf+buf_len, 1); } // dump device input if ECHO ON - if (echo > 0) { + if (echo) { // if (buf[buf_len] < ' ') { // full_write(STDERR_FILENO, "^", 1); // buf[buf_len] += '@'; diff --git a/miscutils/chrt.c b/miscutils/chrt.c index d5f87c4..f2f559f 100644 --- a/miscutils/chrt.c +++ b/miscutils/chrt.c @@ -3,13 +3,26 @@ * chrt - manipulate real-time attributes of a process * Copyright (c) 2006-2007 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define chrt_trivial_usage +//usage: "[-prfom] [PRIO] [PID | PROG ARGS]" +//usage:#define chrt_full_usage "\n\n" +//usage: "Change scheduling priority and class for a process\n" +//usage: "\n -p Operate on PID" +//usage: "\n -r Set SCHED_RR class" +//usage: "\n -f Set SCHED_FIFO class" +//usage: "\n -o Set SCHED_OTHER class" +//usage: "\n -m Show min/max priorities" +//usage: +//usage:#define chrt_example_usage +//usage: "$ chrt -r 4 sleep 900; x=$!\n" +//usage: "$ chrt -f -p 3 $x\n" +//usage: "You need CAP_SYS_NICE privileges to set scheduling attributes of a process" + #include #include "libbb.h" -#ifndef _POSIX_PRIORITY_SCHEDULING -#warning your system may be foobared -#endif static const struct { int policy; @@ -53,23 +66,25 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) const char *current_new; int policy = SCHED_RR; - /* at least 1 arg; only one policy accepted */ - opt_complementary = "-1:r--fo:f--ro:r--fo"; + /* only one policy accepted */ + opt_complementary = "r--fo:f--ro:o--rf"; opt = getopt32(argv, "+mprfo"); + if (opt & OPT_m) { /* print min/max and exit */ + show_min_max(SCHED_FIFO); + show_min_max(SCHED_RR); + show_min_max(SCHED_OTHER); + fflush_stdout_and_exit(EXIT_SUCCESS); + } if (opt & OPT_r) policy = SCHED_RR; if (opt & OPT_f) policy = SCHED_FIFO; if (opt & OPT_o) policy = SCHED_OTHER; - if (opt & OPT_m) { /* print min/max */ - show_min_max(SCHED_FIFO); - show_min_max(SCHED_RR); - show_min_max(SCHED_OTHER); - fflush_stdout_and_exit(EXIT_SUCCESS); - } argv += optind; + if (!argv[0]) + bb_show_usage(); if (opt & OPT_p) { pid_str = *argv++; if (*argv) { /* "-p [...]" */ @@ -90,13 +105,13 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) print_rt_info: pol = sched_getscheduler(pid); if (pol < 0) - bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', pid); + bb_perror_msg_and_die("can't %cet pid %d's policy", 'g', (int)pid); printf("pid %d's %s scheduling policy: %s\n", pid, current_new, policies[pol].name); if (sched_getparam(pid, &sp)) - bb_perror_msg_and_die("can't get pid %d's attributes", pid); + bb_perror_msg_and_die("can't get pid %d's attributes", (int)pid); printf("pid %d's %s scheduling priority: %d\n", - pid, current_new, sp.sched_priority); + (int)pid, current_new, sp.sched_priority); if (!*argv) { /* Either it was just "-p ", * or it was "-p " and we came here @@ -115,7 +130,7 @@ int chrt_main(int argc UNUSED_PARAM, char **argv) sp.sched_priority = xstrtou_range(priority, 0, policy != SCHED_OTHER ? 1 : 0, 99); if (sched_setscheduler(pid, policy, &sp) < 0) - bb_perror_msg_and_die("can't %cet pid %d's policy", 's', pid); + bb_perror_msg_and_die("can't %cet pid %d's policy", 's', (int)pid); if (!argv[0]) /* "-p [...]" */ goto print_rt_info; diff --git a/miscutils/conspy.c b/miscutils/conspy.c index 509a0f2..1a46a43 100644 --- a/miscutils/conspy.c +++ b/miscutils/conspy.c @@ -7,16 +7,17 @@ * Based on Russell Stuart's conspy.c * http://ace-host.stuart.id.au/russell/files/conspy.c * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_CONSPY(APPLET(conspy, _BB_DIR_BIN, _BB_SUID_DROP)) +//applet:IF_CONSPY(APPLET(conspy, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_CONSPY) += conspy.o //config:config CONSPY //config: bool "conspy" -//config: default n +//config: default y +//config: select PLATFORM_LINUX //config: help //config: A text-mode VNC like program for Linux virtual terminals. //config: example: conspy NUM shared access to console num @@ -24,24 +25,32 @@ //config: or conspy -cs NUM poor man's GNU screen like //usage:#define conspy_trivial_usage -//usage: "[-vcsndf] [-x COL] [-y LINE] [CONSOLE_NO]" +//usage: "[-vcsndfFQ] [-x COL] [-y LINE] [CONSOLE_NO]" //usage:#define conspy_full_usage "\n\n" //usage: "A text-mode VNC like program for Linux virtual consoles." //usage: "\nTo exit, quickly press ESC 3 times." //usage: "\n" -//usage: "\nOptions:" //usage: "\n -v Don't send keystrokes to the console" -//usage: "\n -c Create missing devices in /dev" +//usage: "\n -c Create missing /dev/{tty,vcsa}N" //usage: "\n -s Open a SHELL session" //usage: "\n -n Black & white" //usage: "\n -d Dump console to stdout" //usage: "\n -f Follow cursor" +//usage: "\n -F Assume console is on a framebuffer device" +//usage: "\n -Q Disable exit on ESC-ESC-ESC" //usage: "\n -x COL Starting column" //usage: "\n -y LINE Starting line" #include "libbb.h" #include +#define ESC "\033" +#define CURSOR_ON -1 +#define CURSOR_OFF 1 + +#define DEV_TTY "/dev/tty" +#define DEV_VCSA "/dev/vcsa" + struct screen_info { unsigned char lines, cols, cursor_x, cursor_y; }; @@ -69,19 +78,17 @@ struct globals { unsigned col; unsigned line; smallint curoff; // unknown:0 cursor on:-1 cursor off:1 - char attrbuf[sizeof("\033[0;1;5;30;40m")]; + char attrbuf[sizeof("0;1;5;30;40m")]; // remote console struct screen_info remote; // saved local tty terminfo struct termios term_orig; - char vcsa_name[sizeof("/dev/vcsaNN")]; + char vcsa_name[sizeof(DEV_VCSA "NN")]; }; #define G (*ptr_to_globals) #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ - G.attrbuf[0] = '\033'; \ - G.attrbuf[1] = '['; \ G.width = G.height = UINT_MAX; \ G.last_attr--; \ } while (0) @@ -89,18 +96,26 @@ struct globals { enum { FLAG_v, // view only FLAG_c, // create device if need + FLAG_Q, // never exit FLAG_s, // session FLAG_n, // no colors FLAG_d, // dump screen FLAG_f, // follow cursor + FLAG_F, // framebuffer }; #define FLAG(x) (1 << FLAG_##x) #define BW (option_mask32 & FLAG(n)) +static void putcsi(const char *s) +{ + fputs(ESC"[", stdout); + fputs(s, stdout); +} + static void clrscr(void) { // Home, clear till end of screen - fputs("\033[1;1H" "\033[J", stdout); + putcsi("1;1H" ESC"[J"); G.col = G.line = 0; } @@ -108,7 +123,7 @@ static void set_cursor(int state) { if (G.curoff != state) { G.curoff = state; - fputs("\033[?25", stdout); + putcsi("?25"); bb_putchar("h?l"[1 + state]); } } @@ -118,22 +133,23 @@ static void gotoxy(int col, int line) if (G.col != col || G.line != line) { G.col = col; G.line = line; - printf("\033[%u;%uH", line + 1, col + 1); + printf(ESC"[%u;%uH", line + 1, col + 1); } } +static void cleanup(int code) NORETURN; static void cleanup(int code) { - set_cursor(-1); // cursor on + set_cursor(CURSOR_ON); tcsetattr(G.kbd_fd, TCSANOW, &G.term_orig); if (ENABLE_FEATURE_CLEAN_UP) { close(G.kbd_fd); } // Reset attributes if (!BW) - fputs("\033[0m", stdout); + putcsi("0m"); bb_putchar('\n'); - if (code > 1) + if (code > EXIT_FAILURE) kill_myself_with_sig(code); exit(code); } @@ -154,8 +170,8 @@ static void screen_read_close(void) G.size = i; G.data = xzalloc(2 * i); } - else if (G.size != i) { - cleanup(1); + if (G.size != i) { + cleanup(EXIT_FAILURE); } data = G.data + G.current; xread(vcsa_fd, data, G.size); @@ -165,10 +181,15 @@ static void screen_read_close(void) unsigned x = j - G.x; // if will catch j < G.x too unsigned y = i - G.y; // if will catch i < G.y too - if (CHAR(data) < ' ') - CHAR(data) = ' '; if (y >= G.height || x >= G.width) DATA(data) = 0; + else { + uint8_t ch = CHAR(data); + if (ch < ' ') + CHAR(data) = ch | 0x40; + else if (ch > 0x7e) + CHAR(data) = '?'; + } } } } @@ -176,10 +197,13 @@ static void screen_read_close(void) static void screen_char(char *data) { if (!BW) { + uint8_t attr_diff; uint8_t attr = ATTR(data); - //uint8_t attr = ATTR(data) >> 1; // for framebuffer console - uint8_t attr_diff = G.last_attr ^ attr; + if (option_mask32 & FLAG(F)) { + attr >>= 1; + } + attr_diff = G.last_attr ^ attr; if (attr_diff) { // Attribute layout for VGA compatible text videobuffer: // blinking text @@ -210,7 +234,7 @@ static void screen_char(char *data) const uint8_t bg_mask = 0x70, blink_mask = 0x80; char *ptr; - ptr = G.attrbuf + 2; // skip "ESC [" + ptr = G.attrbuf; // (G.last_attr & ~attr) has 1 only where // G.last_attr has 1 but attr has 0. @@ -241,12 +265,12 @@ static void screen_char(char *data) if (attr_diff & bg_mask) { *ptr++ = '4'; *ptr++ = color[(attr & bg_mask) >> 4]; - *ptr++ = ';'; + ptr++; // last attribute } - if (ptr != G.attrbuf + 2) { + if (ptr != G.attrbuf) { ptr[-1] = 'm'; *ptr = '\0'; - fputs(G.attrbuf, stdout); + putcsi(G.attrbuf); } } } @@ -289,11 +313,11 @@ static void curmove(void) { unsigned cx = G.remote.cursor_x - G.x; unsigned cy = G.remote.cursor_y - G.y; - int cursor = 1; + int cursor = CURSOR_OFF; if (cx < G.width && cy < G.height) { gotoxy(cx, cy); - cursor = -1; + cursor = CURSOR_ON; } set_cursor(cursor); } @@ -312,10 +336,8 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int pid = xvfork(); if (pid == 0) { struct termios termchild; - char *shell = getenv("SHELL"); + const char *shell = get_shell_name(); - if (!shell) - shell = (char *) DEFAULT_SHELL; signal(SIGHUP, SIG_IGN); // set tty as a controlling tty setsid(); @@ -340,7 +362,7 @@ static NOINLINE void start_shell_in_child(const char* tty_name) int conspy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int conspy_main(int argc UNUSED_PARAM, char **argv) { - char tty_name[sizeof("/dev/ttyNN")]; + char tty_name[sizeof(DEV_TTY "NN")]; #define keybuf bb_common_bufsiz1 struct termios termbuf; unsigned opts; @@ -350,26 +372,28 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) static const char getopt_longopts[] ALIGN1 = "viewonly\0" No_argument "v" "createdevice\0" No_argument "c" + "neverquit\0" No_argument "Q" "session\0" No_argument "s" "nocolors\0" No_argument "n" "dump\0" No_argument "d" "follow\0" No_argument "f" + "framebuffer\0" No_argument "F" ; applet_long_options = getopt_longopts; #endif INIT_G(); - strcpy(G.vcsa_name, "/dev/vcsa"); + strcpy(G.vcsa_name, DEV_VCSA); opt_complementary = "x+:y+"; // numeric params - opts = getopt32(argv, "vcsndfx:y:", &G.x, &G.y); + opts = getopt32(argv, "vcQsndfFx:y:", &G.x, &G.y); argv += optind; ttynum = 0; if (argv[0]) { ttynum = xatou_range(argv[0], 0, 63); - sprintf(G.vcsa_name + sizeof("/dev/vcsa")-1, "%u", ttynum); + sprintf(G.vcsa_name + sizeof(DEV_VCSA)-1, "%u", ttynum); } - sprintf(tty_name, "%s%u", "/dev/tty", ttynum); + sprintf(tty_name, "%s%u", DEV_TTY, ttynum); if (opts & FLAG(c)) { if ((opts & (FLAG(s)|FLAG(v))) != FLAG(v)) create_cdev_if_doesnt_exist(tty_name, makedev(4, ttynum)); @@ -416,19 +440,19 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) if (G.remote.cursor_x < G.x) { G.x = G.remote.cursor_x; - i = 0; // force refresh + i = 0; // force refresh } if (nx > G.x) { G.x = nx; - i = 0; // force refresh + i = 0; // force refresh } if (G.remote.cursor_y < G.y) { G.y = G.remote.cursor_y; - i = 0; // force refresh + i = 0; // force refresh } if (ny > G.y) { G.y = ny; - i = 0; // force refresh + i = 0; // force refresh } } @@ -480,7 +504,7 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) char *k; case -1: if (errno != EINTR) - cleanup(1); + goto abort; break; case 0: if (++G.nokeys >= 4) @@ -491,32 +515,36 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) k = keybuf + G.key_count; bytes_read = read(G.kbd_fd, k, sizeof(keybuf) - G.key_count); if (bytes_read < 0) - cleanup(1); + goto abort; // Do exit processing - for (i = 0; i < bytes_read; i++) { - if (k[i] != '\033') - G.escape_count = 0; - else if (++G.escape_count >= 3) - cleanup(0); + if (!(option_mask32 & FLAG(Q))) { + for (i = 0; i < bytes_read; i++) { + if (k[i] != '\033') + G.escape_count = -1; + if (++G.escape_count >= 3) + cleanup(EXIT_SUCCESS); + } } } poll_timeout_ms = 250; + if (option_mask32 & FLAG(v)) continue; // Insert all keys pressed into the virtual console's input // buffer. Don't do this if the virtual console is in scan // code mode - giving ASCII characters to a program expecting // scan codes will confuse it. - if (!(option_mask32 & FLAG(v)) && G.escape_count == 0) { + G.key_count += bytes_read; + if (G.escape_count == 0) { int handle, result; long kbd_mode; - G.key_count += bytes_read; handle = xopen(tty_name, O_WRONLY); result = ioctl(handle, KDGKBMODE, &kbd_mode); if (result >= 0) { char *p = keybuf; + G.ioerror_count = 0; if (kbd_mode != K_XLATE && kbd_mode != K_UNICODE) { G.key_count = 0; // scan code mode } @@ -532,16 +560,18 @@ int conspy_main(int argc UNUSED_PARAM, char **argv) poll_timeout_ms = 20; } } + // We sometimes get spurious IO errors on the TTY + // as programs close and re-open it + else if (errno != EIO || ++G.ioerror_count > 4) { + if (ENABLE_FEATURE_CLEAN_UP) + close(handle); + goto abort; + } // Close & re-open tty in case they have // swapped virtual consoles close(handle); - - // We sometimes get spurious IO errors on the TTY - // as programs close and re-open it - if (result >= 0) - G.ioerror_count = 0; - else if (errno != EIO || ++G.ioerror_count > 4) - cleanup(1); } } /* while (1) */ + abort: + cleanup(EXIT_FAILURE); } diff --git a/miscutils/crond.c b/miscutils/crond.c index 4a3103c..582dc99 100644 --- a/miscutils/crond.c +++ b/miscutils/crond.c @@ -8,65 +8,77 @@ * (version 2.3.2) * Vladimir Oleynik (C) 2002 * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define crond_trivial_usage +//usage: "-fbS -l N " IF_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR" +//usage:#define crond_full_usage "\n\n" +//usage: " -f Foreground" +//usage: "\n -b Background (default)" +//usage: "\n -S Log to syslog (default)" +//usage: "\n -l Set log level. 0 is the most verbose, default 8" +//usage: IF_FEATURE_CROND_D( +//usage: "\n -d Set log level, log to stderr" +//usage: ) +//usage: "\n -L Log to file" +//usage: "\n -c Working dir" + #include "libbb.h" #include /* glibc frees previous setenv'ed value when we do next setenv() * of the same variable. uclibc does not do this! */ #if (defined(__GLIBC__) && !defined(__UCLIBC__)) /* || OTHER_SAFE_LIBC... */ -#define SETENV_LEAKS 0 +# define SETENV_LEAKS 0 #else -#define SETENV_LEAKS 1 +# define SETENV_LEAKS 1 #endif #define TMPDIR CONFIG_FEATURE_CROND_DIR #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" #ifndef SENDMAIL -#define SENDMAIL "sendmail" +# define SENDMAIL "sendmail" #endif #ifndef SENDMAIL_ARGS -#define SENDMAIL_ARGS "-ti", NULL +# define SENDMAIL_ARGS "-ti" #endif #ifndef CRONUPDATE -#define CRONUPDATE "cron.update" +# define CRONUPDATE "cron.update" #endif #ifndef MAXLINES -#define MAXLINES 256 /* max lines in non-root crontabs */ +# define MAXLINES 256 /* max lines in non-root crontabs */ #endif typedef struct CronFile { - struct CronFile *cf_Next; - struct CronLine *cf_LineBase; - char *cf_User; /* username */ - smallint cf_Ready; /* bool: one or more jobs ready */ - smallint cf_Running; /* bool: one or more jobs running */ - smallint cf_Deleted; /* marked for deletion, ignore */ + struct CronFile *cf_next; + struct CronLine *cf_lines; + char *cf_username; + smallint cf_wants_starting; /* bool: one or more jobs ready */ + smallint cf_has_running; /* bool: one or more jobs running */ + smallint cf_deleted; /* marked for deletion (but still has running jobs) */ } CronFile; typedef struct CronLine { - struct CronLine *cl_Next; - char *cl_Shell; /* shell command */ - pid_t cl_Pid; /* running pid, 0, or armed (-1) */ + struct CronLine *cl_next; + char *cl_cmd; /* shell command */ + pid_t cl_pid; /* >0:running, <0:needs to be started in this minute, 0:dormant */ #if ENABLE_FEATURE_CROND_CALL_SENDMAIL - int cl_MailPos; /* 'empty file' size */ - smallint cl_MailFlag; /* running pid is for mail */ - char *cl_MailTo; /* whom to mail results */ + int cl_empty_mail_size; /* size of mail header only, 0 if no mailfile */ + char *cl_mailto; /* whom to mail results, may be NULL */ #endif /* ordered by size, not in natural order. makes code smaller: */ - char cl_Dow[7]; /* 0-6, beginning sunday */ - char cl_Mons[12]; /* 0-11 */ - char cl_Hrs[24]; /* 0-23 */ - char cl_Days[32]; /* 1-31 */ - char cl_Mins[60]; /* 0-59 */ + char cl_Dow[7]; /* 0-6, beginning sunday */ + char cl_Mons[12]; /* 0-11 */ + char cl_Hrs[24]; /* 0-23 */ + char cl_Days[32]; /* 1-31 */ + char cl_Mins[60]; /* 0-59 */ } CronLine; -#define DaemonUid 0 +#define DAEMON_UID 0 enum { @@ -79,49 +91,30 @@ enum { OPT_d = (1 << 6) * ENABLE_FEATURE_CROND_D, }; #if ENABLE_FEATURE_CROND_D -#define DebugOpt (option_mask32 & OPT_d) +# define DebugOpt (option_mask32 & OPT_d) #else -#define DebugOpt 0 +# define DebugOpt 0 #endif struct globals { - unsigned LogLevel; /* = 8; */ - const char *LogFile; - const char *CDir; /* = CRONTABS; */ - CronFile *FileBase; + unsigned log_level; /* = 8; */ + time_t crontab_dir_mtime; + const char *log_filename; + const char *crontab_dir_name; /* = CRONTABS; */ + CronFile *cron_files; #if SETENV_LEAKS char *env_var_user; char *env_var_home; #endif } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define LogLevel (G.LogLevel ) -#define LogFile (G.LogFile ) -#define CDir (G.CDir ) -#define FileBase (G.FileBase ) -#define env_var_user (G.env_var_user ) -#define env_var_home (G.env_var_home ) #define INIT_G() do { \ - LogLevel = 8; \ - CDir = CRONTABS; \ + G.log_level = 8; \ + G.crontab_dir_name = CRONTABS; \ } while (0) -static void CheckUpdates(void); -static void SynchronizeDir(void); -static int TestJobs(time_t t1, time_t t2); -static void RunJobs(void); -static int CheckJobs(void); -static void RunJob(const char *user, CronLine *line); -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL -static void EndJob(const char *user, CronLine *line); -#else -#define EndJob(user, line) ((line)->cl_Pid = 0) -#endif -static void DeleteFile(const char *userName); - - /* 0 is the most verbose, default 8 */ #define LVL5 "\x05" #define LVL7 "\x07" @@ -138,12 +131,12 @@ static void crondlog(const char *ctl, ...) int level = (ctl[0] & 0x1f); va_start(va, ctl); - if (level >= (int)LogLevel) { + if (level >= (int)G.log_level) { /* Debug mode: all to (non-redirected) stderr, */ /* Syslog mode: all to syslog (logmode = LOGMODE_SYSLOG), */ - if (!DebugOpt && LogFile) { + if (!DebugOpt && G.log_filename) { /* Otherwise (log to file): we reopen log file at every write: */ - int logfd = open3_or_warn(LogFile, O_WRONLY | O_CREAT | O_APPEND, 0666); + int logfd = open_or_warn(G.log_filename, O_WRONLY | O_CREAT | O_APPEND); if (logfd >= 0) xmove_fd(logfd, STDERR_FILENO); } @@ -163,141 +156,6 @@ static void crondlog(const char *ctl, ...) exit(20); } -int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int crond_main(int argc UNUSED_PARAM, char **argv) -{ - unsigned opts; - - INIT_G(); - - /* "-b after -f is ignored", and so on for every pair a-b */ - opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") - ":l+:d+"; /* -l and -d have numeric param */ - opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), - &LogLevel, &LogFile, &CDir - IF_FEATURE_CROND_D(,&LogLevel)); - /* both -d N and -l N set the same variable: LogLevel */ - - if (!(opts & OPT_f)) { - /* close stdin, stdout, stderr. - * close unused descriptors - don't need them. */ - bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); - } - - if (!(opts & OPT_d) && LogFile == NULL) { - /* logging to syslog */ - openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); - logmode = LOGMODE_SYSLOG; - } - - xchdir(CDir); - //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ - xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ - crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", LogLevel); - SynchronizeDir(); - - /* main loop - synchronize to 1 second after the minute, minimum sleep - * of 1 second. */ - { - time_t t1 = time(NULL); - int rescan = 60; - int sleep_time = 60; - - write_pidfile("/var/run/crond.pid"); - for (;;) { - time_t t2; - long dt; - - sleep((sleep_time + 1) - (time(NULL) % sleep_time)); - - t2 = time(NULL); - dt = (long)t2 - (long)t1; - - /* - * The file 'cron.update' is checked to determine new cron - * jobs. The directory is rescanned once an hour to deal - * with any screwups. - * - * check for disparity. Disparities over an hour either way - * result in resynchronization. A reverse-indexed disparity - * less then an hour causes us to effectively sleep until we - * match the original time (i.e. no re-execution of jobs that - * have just been run). A forward-indexed disparity less then - * an hour causes intermediate jobs to be run, but only once - * in the worst case. - * - * when running jobs, the inequality used is greater but not - * equal to t1, and less then or equal to t2. - */ - if (--rescan == 0) { - rescan = 60; - SynchronizeDir(); - } - CheckUpdates(); - if (DebugOpt) - crondlog(LVL5 "wakeup dt=%ld", dt); - if (dt < -60 * 60 || dt > 60 * 60) { - crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); - } else if (dt > 0) { - TestJobs(t1, t2); - RunJobs(); - sleep(5); - if (CheckJobs() > 0) { - sleep_time = 10; - } else { - sleep_time = 60; - } - } - t1 = t2; - } /* for (;;) */ - } - - return 0; /* not reached */ -} - -#if SETENV_LEAKS -/* We set environment *before* vfork (because we want to use vfork), - * so we cannot use setenv() - repeated calls to setenv() may leak memory! - * Using putenv(), and freeing memory after unsetenv() won't leak */ -static void safe_setenv(char **pvar_val, const char *var, const char *val) -{ - char *var_val = *pvar_val; - - if (var_val) { - bb_unsetenv_and_free(var_val); - } - *pvar_val = xasprintf("%s=%s", var, val); - putenv(*pvar_val); -} -#endif - -static void SetEnv(struct passwd *pas) -{ -#if SETENV_LEAKS - safe_setenv(&env_var_user, "USER", pas->pw_name); - safe_setenv(&env_var_home, "HOME", pas->pw_dir); - /* if we want to set user's shell instead: */ - /*safe_setenv(env_var_user, "SHELL", pas->pw_shell);*/ -#else - xsetenv("USER", pas->pw_name); - xsetenv("HOME", pas->pw_dir); -#endif - /* currently, we use constant one: */ - /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ -} - -static void ChangeUser(struct passwd *pas) -{ - /* careful: we're after vfork! */ - change_identity(pas); /* - initgroups, setgid, setuid */ - if (chdir(pas->pw_dir) < 0) { - crondlog(WARN9 "chdir(%s)", pas->pw_dir); - if (chdir(TMPDIR) < 0) { - crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ - } - } -} - static const char DowAry[] ALIGN1 = "sun""mon""tue""wed""thu""fri""sat" /* "Sun""Mon""Tue""Wed""Thu""Fri""Sat" */ @@ -325,7 +183,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, /* Handle numeric digit or symbol or '*' */ if (*ptr == '*') { - n1 = 0; /* everything will be filled */ + n1 = 0; /* everything will be filled */ n2 = modvalue - 1; skip = 1; ++ptr; @@ -398,7 +256,6 @@ static void ParseField(char *user, char *ary, int modvalue, int off, goto err; } } while (n1 != n2); - } if (*ptr != ',') { break; @@ -414,7 +271,7 @@ static void ParseField(char *user, char *ary, int modvalue, int off, return; } - if (DebugOpt && (LogLevel <= 5)) { /* like LVL5 */ + if (DebugOpt && (G.log_level <= 5)) { /* like LVL5 */ /* can't use crondlog, it inserts '\n' */ int i; for (i = 0; i < modvalue; ++i) @@ -449,7 +306,60 @@ static void FixDayDow(CronLine *line) } } -static void SynchronizeFile(const char *fileName) +/* + * delete_cronfile() - delete user database + * + * Note: multiple entries for same user may exist if we were unable to + * completely delete a database due to running processes. + */ +//FIXME: we will start a new job even if the old job is running +//if crontab was reloaded: crond thinks that "new" job is different from "old" +//even if they are in fact completely the same. Example +//Crontab was: +// 0-59 * * * * job1 +// 0-59 * * * * long_running_job2 +//User edits crontab to: +// 0-59 * * * * job1_updated +// 0-59 * * * * long_running_job2 +//Bug: crond can now start another long_running_job2 even if old one +//is still running. +//OTOH most other versions of cron do not wait for job termination anyway, +//they end up with multiple copies of jobs if they don't terminate soon enough. +static void delete_cronfile(const char *userName) +{ + CronFile **pfile = &G.cron_files; + CronFile *file; + + while ((file = *pfile) != NULL) { + if (strcmp(userName, file->cf_username) == 0) { + CronLine **pline = &file->cf_lines; + CronLine *line; + + file->cf_has_running = 0; + file->cf_deleted = 1; + + while ((line = *pline) != NULL) { + if (line->cl_pid > 0) { + file->cf_has_running = 1; + pline = &line->cl_next; + } else { + *pline = line->cl_next; + free(line->cl_cmd); + free(line); + } + } + if (file->cf_has_running == 0) { + *pfile = file->cf_next; + free(file->cf_username); + free(file); + continue; + } + } + pfile = &file->cf_next; + } +} + +static void load_crontab(const char *fileName) { struct parser_t *parser; struct stat sbuf; @@ -459,23 +369,26 @@ static void SynchronizeFile(const char *fileName) char *mailTo = NULL; #endif - if (!fileName) + delete_cronfile(fileName); + + if (!getpwnam(fileName)) { + crondlog(LVL7 "ignoring file '%s' (no such user)", fileName); return; + } - DeleteFile(fileName); parser = config_open(fileName); if (!parser) return; maxLines = (strcmp(fileName, "root") == 0) ? 65535 : MAXLINES; - if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DaemonUid) { + if (fstat(fileno(parser->fp), &sbuf) == 0 && sbuf.st_uid == DAEMON_UID) { CronFile *file = xzalloc(sizeof(CronFile)); CronLine **pline; int n; - file->cf_User = xstrdup(fileName); - pline = &file->cf_LineBase; + file->cf_username = xstrdup(fileName); + pline = &file->cf_lines; while (1) { CronLine *line; @@ -502,11 +415,11 @@ static void SynchronizeFile(const char *fileName) continue; *pline = line = xzalloc(sizeof(*line)); /* parse date ranges */ - ParseField(file->cf_User, line->cl_Mins, 60, 0, NULL, tokens[0]); - ParseField(file->cf_User, line->cl_Hrs, 24, 0, NULL, tokens[1]); - ParseField(file->cf_User, line->cl_Days, 32, 0, NULL, tokens[2]); - ParseField(file->cf_User, line->cl_Mons, 12, -1, MonAry, tokens[3]); - ParseField(file->cf_User, line->cl_Dow, 7, 0, DowAry, tokens[4]); + ParseField(file->cf_username, line->cl_Mins, 60, 0, NULL, tokens[0]); + ParseField(file->cf_username, line->cl_Hrs, 24, 0, NULL, tokens[1]); + ParseField(file->cf_username, line->cl_Days, 32, 0, NULL, tokens[2]); + ParseField(file->cf_username, line->cl_Mons, 12, -1, MonAry, tokens[3]); + ParseField(file->cf_username, line->cl_Dow, 7, 0, DowAry, tokens[4]); /* * fix days and dow - if one is not "*" and the other * is "*", the other is set to 0, and vise-versa @@ -514,20 +427,20 @@ static void SynchronizeFile(const char *fileName) FixDayDow(line); #if ENABLE_FEATURE_CROND_CALL_SENDMAIL /* copy mailto (can be NULL) */ - line->cl_MailTo = xstrdup(mailTo); + line->cl_mailto = xstrdup(mailTo); #endif /* copy command */ - line->cl_Shell = xstrdup(tokens[5]); + line->cl_cmd = xstrdup(tokens[5]); if (DebugOpt) { crondlog(LVL5 " command:%s", tokens[5]); } - pline = &line->cl_Next; + pline = &line->cl_next; //bb_error_msg("M[%s]F[%s][%s][%s][%s][%s][%s]", mailTo, tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5]); } *pline = NULL; - file->cf_Next = FileBase; - FileBase = file; + file->cf_next = G.cron_files; + G.cron_files = file; if (maxLines == 0) { crondlog(WARN9 "user %s: too many lines", fileName); @@ -536,7 +449,7 @@ static void SynchronizeFile(const char *fileName) config_close(parser); } -static void CheckUpdates(void) +static void process_cron_update_file(void) { FILE *fi; char buf[256]; @@ -546,36 +459,34 @@ static void CheckUpdates(void) unlink(CRONUPDATE); while (fgets(buf, sizeof(buf), fi) != NULL) { /* use first word only */ - SynchronizeFile(strtok(buf, " \t\r\n")); + skip_non_whitespace(buf)[0] = '\0'; + load_crontab(buf); } fclose(fi); } } -static void SynchronizeDir(void) +static void rescan_crontab_dir(void) { CronFile *file; - /* Attempt to delete the database. */ + + /* Delete all files until we only have ones with running jobs (or none) */ again: - for (file = FileBase; file; file = file->cf_Next) { - if (!file->cf_Deleted) { - DeleteFile(file->cf_User); + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_deleted) { + delete_cronfile(file->cf_username); goto again; } } - /* - * Remove cron update file - * - * Re-chdir, in case directory was renamed & deleted, or otherwise - * screwed up. - * - * scan directory and add associated users - */ + /* Remove cron update file */ unlink(CRONUPDATE); - if (chdir(CDir) < 0) { - crondlog(DIE9 "chdir(%s)", CDir); + /* Re-chdir, in case directory was renamed & deleted */ + if (chdir(G.crontab_dir_name) < 0) { + crondlog(DIE9 "chdir(%s)", G.crontab_dir_name); } + + /* Scan directory and add associated users */ { DIR *dir = opendir("."); struct dirent *den; @@ -586,184 +497,63 @@ static void SynchronizeDir(void) if (strchr(den->d_name, '.') != NULL) { continue; } - if (getpwnam(den->d_name)) { - SynchronizeFile(den->d_name); - } else { - crondlog(LVL7 "ignoring %s", den->d_name); - } + load_crontab(den->d_name); } closedir(dir); } } -/* - * DeleteFile() - delete user database - * - * Note: multiple entries for same user may exist if we were unable to - * completely delete a database due to running processes. - */ -static void DeleteFile(const char *userName) -{ - CronFile **pfile = &FileBase; - CronFile *file; - - while ((file = *pfile) != NULL) { - if (strcmp(userName, file->cf_User) == 0) { - CronLine **pline = &file->cf_LineBase; - CronLine *line; - - file->cf_Running = 0; - file->cf_Deleted = 1; - - while ((line = *pline) != NULL) { - if (line->cl_Pid > 0) { - file->cf_Running = 1; - pline = &line->cl_Next; - } else { - *pline = line->cl_Next; - free(line->cl_Shell); - free(line); - } - } - if (file->cf_Running == 0) { - *pfile = file->cf_Next; - free(file->cf_User); - free(file); - } else { - pfile = &file->cf_Next; - } - } else { - pfile = &file->cf_Next; - } - } -} - -/* - * TestJobs() - * - * determine which jobs need to be run. Under normal conditions, the - * period is about a minute (one scan). Worst case it will be one - * hour (60 scans). - */ -static int TestJobs(time_t t1, time_t t2) +#if SETENV_LEAKS +/* We set environment *before* vfork (because we want to use vfork), + * so we cannot use setenv() - repeated calls to setenv() may leak memory! + * Using putenv(), and freeing memory after unsetenv() won't leak */ +static void safe_setenv(char **pvar_val, const char *var, const char *val) { - int nJobs = 0; - time_t t; - - /* Find jobs > t1 and <= t2 */ - - for (t = t1 - t1 % 60; t <= t2; t += 60) { - struct tm *ptm; - CronFile *file; - CronLine *line; - - if (t <= t1) - continue; + char *var_val = *pvar_val; - ptm = localtime(&t); - for (file = FileBase; file; file = file->cf_Next) { - if (DebugOpt) - crondlog(LVL5 "file %s:", file->cf_User); - if (file->cf_Deleted) - continue; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (DebugOpt) - crondlog(LVL5 " line %s", line->cl_Shell); - if (line->cl_Mins[ptm->tm_min] && line->cl_Hrs[ptm->tm_hour] - && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) - && line->cl_Mons[ptm->tm_mon] - ) { - if (DebugOpt) { - crondlog(LVL5 " job: %d %s", - (int)line->cl_Pid, line->cl_Shell); - } - if (line->cl_Pid > 0) { - crondlog(LVL8 "user %s: process already running: %s", - file->cf_User, line->cl_Shell); - } else if (line->cl_Pid == 0) { - line->cl_Pid = -1; - file->cf_Ready = 1; - ++nJobs; - } - } - } - } + if (var_val) { + bb_unsetenv_and_free(var_val); } - return nJobs; + *pvar_val = xasprintf("%s=%s", var, val); + putenv(*pvar_val); } +#endif -static void RunJobs(void) +static void set_env_vars(struct passwd *pas) { - CronFile *file; - CronLine *line; - - for (file = FileBase; file; file = file->cf_Next) { - if (!file->cf_Ready) - continue; - - file->cf_Ready = 0; - for (line = file->cf_LineBase; line; line = line->cl_Next) { - if (line->cl_Pid >= 0) - continue; - - RunJob(file->cf_User, line); - crondlog(LVL8 "USER %s pid %3d cmd %s", - file->cf_User, (int)line->cl_Pid, line->cl_Shell); - if (line->cl_Pid < 0) { - file->cf_Ready = 1; - } else if (line->cl_Pid > 0) { - file->cf_Running = 1; - } - } - } +#if SETENV_LEAKS + safe_setenv(&G.env_var_user, "USER", pas->pw_name); + safe_setenv(&G.env_var_home, "HOME", pas->pw_dir); + /* if we want to set user's shell instead: */ + /*safe_setenv(G.env_var_shell, "SHELL", pas->pw_shell);*/ +#else + xsetenv("USER", pas->pw_name); + xsetenv("HOME", pas->pw_dir); +#endif + /* currently, we use constant one: */ + /*setenv("SHELL", DEFAULT_SHELL, 1); - done earlier */ } -/* - * CheckJobs() - check for job completion - * - * Check for job completion, return number of jobs still running after - * all done. - */ -static int CheckJobs(void) +static void change_user(struct passwd *pas) { - CronFile *file; - CronLine *line; - int nStillRunning = 0; - - for (file = FileBase; file; file = file->cf_Next) { - if (file->cf_Running) { - file->cf_Running = 0; - - for (line = file->cf_LineBase; line; line = line->cl_Next) { - int status, r; - if (line->cl_Pid <= 0) - continue; - - r = waitpid(line->cl_Pid, &status, WNOHANG); - if (r < 0 || r == line->cl_Pid) { - EndJob(file->cf_User, line); - if (line->cl_Pid) { - file->cf_Running = 1; - } - } else if (r == 0) { - file->cf_Running = 1; - } - } + /* careful: we're after vfork! */ + change_identity(pas); /* - initgroups, setgid, setuid */ + if (chdir(pas->pw_dir) < 0) { + crondlog(WARN9 "chdir(%s)", pas->pw_dir); + if (chdir(TMPDIR) < 0) { + crondlog(DIE9 "chdir(%s)", TMPDIR); /* exits */ } - nStillRunning += file->cf_Running; } - return nStillRunning; } -#if ENABLE_FEATURE_CROND_CALL_SENDMAIL - // TODO: sendmail should be _run-time_ option, not compile-time! +#if ENABLE_FEATURE_CROND_CALL_SENDMAIL -static void -ForkJob(const char *user, CronLine *line, int mailFd, - const char *prog, const char *cmd, const char *arg, - const char *mail_filename) -{ +static pid_t +fork_job(const char *user, int mailFd, + const char *prog, + const char *shell_cmd /* if NULL, we run sendmail */ +) { struct passwd *pas; pid_t pid; @@ -773,48 +563,36 @@ ForkJob(const char *user, CronLine *line, int mailFd, crondlog(WARN9 "can't get uid for %s", user); goto err; } - SetEnv(pas); + set_env_vars(pas); pid = vfork(); if (pid == 0) { /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); + /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ + change_user(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", prog); } if (mailFd >= 0) { - xmove_fd(mailFd, mail_filename ? 1 : 0); + xmove_fd(mailFd, shell_cmd ? 1 : 0); dup2(1, 2); } /* crond 3.0pl1-100 puts tasks in separate process groups */ bb_setpgrp(); - execlp(prog, prog, cmd, arg, (char *) NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, prog, cmd, arg); - if (mail_filename) { - fdprintf(1, "Exec failed: %s -c %s\n", prog, arg); + execlp(prog, prog, (shell_cmd ? "-c" : SENDMAIL_ARGS), shell_cmd, (char *) NULL); + crondlog(ERR20 "can't execute '%s' for user %s", prog, user); + if (shell_cmd) { + fdprintf(1, "Exec failed: %s -c %s\n", prog, shell_cmd); } _exit(EXIT_SUCCESS); } - line->cl_Pid = pid; if (pid < 0) { /* FORK FAILED */ crondlog(ERR20 "can't vfork"); err: - line->cl_Pid = 0; - if (mail_filename) { - unlink(mail_filename); - } - } else if (mail_filename) { - /* PARENT, FORK SUCCESS - * rename mail-file based on pid of process - */ - char mailFile2[128]; - - snprintf(mailFile2, sizeof(mailFile2), "%s/cron.%s.%d", TMPDIR, user, pid); - rename(mail_filename, mailFile2); // TODO: xrename? - } + pid = 0; + } /* else: PARENT, FORK SUCCESS */ /* * Close the mail file descriptor.. we can't just leave it open in @@ -823,112 +601,120 @@ ForkJob(const char *user, CronLine *line, int mailFd, if (mailFd >= 0) { close(mailFd); } + return pid; } -static void RunJob(const char *user, CronLine *line) +static void start_one_job(const char *user, CronLine *line) { char mailFile[128]; int mailFd = -1; - line->cl_Pid = 0; - line->cl_MailFlag = 0; + line->cl_pid = 0; + line->cl_empty_mail_size = 0; - if (line->cl_MailTo) { - /* open mail file - owner root so nobody can screw with it. */ + if (line->cl_mailto) { + /* Open mail file (owner is root so nobody can screw with it) */ snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, getpid()); mailFd = open(mailFile, O_CREAT | O_TRUNC | O_WRONLY | O_EXCL | O_APPEND, 0600); if (mailFd >= 0) { - line->cl_MailFlag = 1; - fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_MailTo, - line->cl_Shell); - line->cl_MailPos = lseek(mailFd, 0, SEEK_CUR); + fdprintf(mailFd, "To: %s\nSubject: cron: %s\n\n", line->cl_mailto, + line->cl_cmd); + line->cl_empty_mail_size = lseek(mailFd, 0, SEEK_CUR); } else { crondlog(ERR20 "can't create mail file %s for user %s, " "discarding output", mailFile, user); } } - ForkJob(user, line, mailFd, DEFAULT_SHELL, "-c", line->cl_Shell, mailFile); + line->cl_pid = fork_job(user, mailFd, DEFAULT_SHELL, line->cl_cmd); + if (mailFd >= 0) { + if (line->cl_pid <= 0) { + unlink(mailFile); + } else { + /* rename mail-file based on pid of process */ + char *mailFile2 = xasprintf("%s/cron.%s.%d", TMPDIR, user, (int)line->cl_pid); + rename(mailFile, mailFile2); // TODO: xrename? + free(mailFile2); + } + } } /* - * EndJob - called when job terminates and when mail terminates + * process_finished_job - called when job terminates and when mail terminates */ -static void EndJob(const char *user, CronLine *line) +static void process_finished_job(const char *user, CronLine *line) { + pid_t pid; int mailFd; char mailFile[128]; struct stat sbuf; - /* No job */ - if (line->cl_Pid <= 0) { - line->cl_Pid = 0; + pid = line->cl_pid; + line->cl_pid = 0; + if (pid <= 0) { + /* No job */ return; } - - /* - * End of job and no mail file - * End of sendmail job - */ - snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, line->cl_Pid); - line->cl_Pid = 0; - - if (line->cl_MailFlag == 0) { + if (line->cl_empty_mail_size <= 0) { + /* End of job and no mail file, or end of sendmail job */ return; } - line->cl_MailFlag = 0; /* - * End of primary job - check for mail file. If size has increased and - * the file is still valid, we sendmail it. + * End of primary job - check for mail file. + * If size has changed and the file is still valid, we send it. */ + snprintf(mailFile, sizeof(mailFile), "%s/cron.%s.%d", TMPDIR, user, (int)pid); mailFd = open(mailFile, O_RDONLY); unlink(mailFile); if (mailFd < 0) { return; } - if (fstat(mailFd, &sbuf) < 0 || sbuf.st_uid != DaemonUid - || sbuf.st_nlink != 0 || sbuf.st_size == line->cl_MailPos + if (fstat(mailFd, &sbuf) < 0 + || sbuf.st_uid != DAEMON_UID + || sbuf.st_nlink != 0 + || sbuf.st_size == line->cl_empty_mail_size || !S_ISREG(sbuf.st_mode) ) { close(mailFd); return; } - if (line->cl_MailTo) - ForkJob(user, line, mailFd, SENDMAIL, SENDMAIL_ARGS, NULL); + line->cl_empty_mail_size = 0; + /* if (line->cl_mailto) - always true if cl_empty_mail_size was nonzero */ + line->cl_pid = fork_job(user, mailFd, SENDMAIL, NULL); } -#else /* crond without sendmail */ +#else /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ -static void RunJob(const char *user, CronLine *line) +static void start_one_job(const char *user, CronLine *line) { struct passwd *pas; pid_t pid; - /* prepare things before vfork */ pas = getpwnam(user); if (!pas) { crondlog(WARN9 "can't get uid for %s", user); goto err; } - SetEnv(pas); - /* fork as the user in question and run program */ + /* Prepare things before vfork */ + set_env_vars(pas); + + /* Fork as the user in question and run program */ pid = vfork(); if (pid == 0) { /* CHILD */ - /* change running state to the user in question */ - ChangeUser(pas); + /* initgroups, setgid, setuid, and chdir to home or TMPDIR */ + change_user(pas); if (DebugOpt) { crondlog(LVL5 "child running %s", DEFAULT_SHELL); } /* crond 3.0pl1-100 puts tasks in separate process groups */ bb_setpgrp(); - execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_Shell, (char *) NULL); - crondlog(ERR20 "can't exec, user %s cmd %s %s %s", user, - DEFAULT_SHELL, "-c", line->cl_Shell); + execl(DEFAULT_SHELL, DEFAULT_SHELL, "-c", line->cl_cmd, (char *) NULL); + crondlog(ERR20 "can't execute '%s' for user %s", DEFAULT_SHELL, user); _exit(EXIT_SUCCESS); } if (pid < 0) { @@ -937,7 +723,232 @@ static void RunJob(const char *user, CronLine *line) err: pid = 0; } - line->cl_Pid = pid; + line->cl_pid = pid; +} + +#define process_finished_job(user, line) ((line)->cl_pid = 0) + +#endif /* !ENABLE_FEATURE_CROND_CALL_SENDMAIL */ + +/* + * Determine which jobs need to be run. Under normal conditions, the + * period is about a minute (one scan). Worst case it will be one + * hour (60 scans). + */ +static void flag_starting_jobs(time_t t1, time_t t2) +{ + time_t t; + + /* Find jobs > t1 and <= t2 */ + + for (t = t1 - t1 % 60; t <= t2; t += 60) { + struct tm *ptm; + CronFile *file; + CronLine *line; + + if (t <= t1) + continue; + + ptm = localtime(&t); + for (file = G.cron_files; file; file = file->cf_next) { + if (DebugOpt) + crondlog(LVL5 "file %s:", file->cf_username); + if (file->cf_deleted) + continue; + for (line = file->cf_lines; line; line = line->cl_next) { + if (DebugOpt) + crondlog(LVL5 " line %s", line->cl_cmd); + if (line->cl_Mins[ptm->tm_min] + && line->cl_Hrs[ptm->tm_hour] + && (line->cl_Days[ptm->tm_mday] || line->cl_Dow[ptm->tm_wday]) + && line->cl_Mons[ptm->tm_mon] + ) { + if (DebugOpt) { + crondlog(LVL5 " job: %d %s", + (int)line->cl_pid, line->cl_cmd); + } + if (line->cl_pid > 0) { + crondlog(LVL8 "user %s: process already running: %s", + file->cf_username, line->cl_cmd); + } else if (line->cl_pid == 0) { + line->cl_pid = -1; + file->cf_wants_starting = 1; + } + } + } + } + } +} + +static void start_jobs(void) +{ + CronFile *file; + CronLine *line; + + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_wants_starting) + continue; + + file->cf_wants_starting = 0; + for (line = file->cf_lines; line; line = line->cl_next) { + pid_t pid; + if (line->cl_pid >= 0) + continue; + + start_one_job(file->cf_username, line); + pid = line->cl_pid; + crondlog(LVL8 "USER %s pid %3d cmd %s", + file->cf_username, (int)pid, line->cl_cmd); + if (pid < 0) { + file->cf_wants_starting = 1; + } + if (pid > 0) { + file->cf_has_running = 1; + } + } + } +} + +/* + * Check for job completion, return number of jobs still running after + * all done. + */ +static int check_completions(void) +{ + CronFile *file; + CronLine *line; + int num_still_running = 0; + + for (file = G.cron_files; file; file = file->cf_next) { + if (!file->cf_has_running) + continue; + + file->cf_has_running = 0; + for (line = file->cf_lines; line; line = line->cl_next) { + int r; + + if (line->cl_pid <= 0) + continue; + + r = waitpid(line->cl_pid, NULL, WNOHANG); + if (r < 0 || r == line->cl_pid) { + process_finished_job(file->cf_username, line); + if (line->cl_pid == 0) { + /* sendmail was not started for it */ + continue; + } + /* else: sendmail was started, job is still running, fall thru */ + } + /* else: r == 0: "process is still running" */ + file->cf_has_running = 1; + } +//FIXME: if !file->cf_has_running && file->deleted: delete it! +//otherwise deleted entries will stay forever, right? + num_still_running += file->cf_has_running; + } + return num_still_running; } -#endif /* ENABLE_FEATURE_CROND_CALL_SENDMAIL */ +int crond_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int crond_main(int argc UNUSED_PARAM, char **argv) +{ + time_t t2; + int rescan; + int sleep_time; + unsigned opts; + + INIT_G(); + + /* "-b after -f is ignored", and so on for every pair a-b */ + opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l") + /* -l and -d have numeric param */ + ":l+" IF_FEATURE_CROND_D(":d+"); + opts = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"), + &G.log_level, &G.log_filename, &G.crontab_dir_name + IF_FEATURE_CROND_D(,&G.log_level)); + /* both -d N and -l N set the same variable: G.log_level */ + + if (!(opts & OPT_f)) { + /* close stdin, stdout, stderr. + * close unused descriptors - don't need them. */ + bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); + } + + if (!(opts & OPT_d) && G.log_filename == NULL) { + /* logging to syslog */ + openlog(applet_name, LOG_CONS | LOG_PID, LOG_CRON); + logmode = LOGMODE_SYSLOG; + } + + xchdir(G.crontab_dir_name); + //signal(SIGHUP, SIG_IGN); /* ? original crond dies on HUP... */ + xsetenv("SHELL", DEFAULT_SHELL); /* once, for all future children */ + crondlog(LVL8 "crond (busybox "BB_VER") started, log level %d", G.log_level); + rescan_crontab_dir(); + write_pidfile(CONFIG_PID_FILE_PATH "/crond.pid"); + + /* Main loop */ + t2 = time(NULL); + rescan = 60; + sleep_time = 60; + for (;;) { + struct stat sbuf; + time_t t1; + long dt; + + t1 = t2; + + /* Synchronize to 1 minute, minimum 1 second */ + sleep(sleep_time - (time(NULL) % sleep_time) + 1); + + t2 = time(NULL); + dt = (long)t2 - (long)t1; + + /* + * The file 'cron.update' is checked to determine new cron + * jobs. The directory is rescanned once an hour to deal + * with any screwups. + * + * Check for time jump. Disparities over an hour either way + * result in resynchronization. A negative disparity + * less than an hour causes us to effectively sleep until we + * match the original time (i.e. no re-execution of jobs that + * have just been run). A positive disparity less than + * an hour causes intermediate jobs to be run, but only once + * in the worst case. + * + * When running jobs, the inequality used is greater but not + * equal to t1, and less then or equal to t2. + */ + if (stat(G.crontab_dir_name, &sbuf) != 0) + sbuf.st_mtime = 0; /* force update (once) if dir was deleted */ + if (G.crontab_dir_mtime != sbuf.st_mtime) { + G.crontab_dir_mtime = sbuf.st_mtime; + rescan = 1; + } + if (--rescan == 0) { + rescan = 60; + rescan_crontab_dir(); + } + process_cron_update_file(); + if (DebugOpt) + crondlog(LVL5 "wakeup dt=%ld", dt); + if (dt < -60 * 60 || dt > 60 * 60) { + crondlog(WARN9 "time disparity of %ld minutes detected", dt / 60); + /* and we do not run any jobs in this case */ + } else if (dt > 0) { + /* Usual case: time advances forward, as expected */ + flag_starting_jobs(t1, t2); + start_jobs(); + if (check_completions() > 0) { + /* some jobs are still running */ + sleep_time = 10; + } else { + sleep_time = 60; + } + } + /* else: time jumped back, do not run any jobs */ + } /* for (;;) */ + + return 0; /* not reached */ +} diff --git a/miscutils/crontab.c b/miscutils/crontab.c index b8a5abc..aad242f 100644 --- a/miscutils/crontab.c +++ b/miscutils/crontab.c @@ -7,9 +7,19 @@ * Copyright 1994 Matthew Dillon (dillon@apollo.west.oic.com) * Vladimir Oleynik (C) 2002 * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define crontab_trivial_usage +//usage: "[-c DIR] [-u USER] [-ler]|[FILE]" +//usage:#define crontab_full_usage "\n\n" +//usage: " -c Crontab directory" +//usage: "\n -u User" +//usage: "\n -l List crontab" +//usage: "\n -e Edit crontab" +//usage: "\n -r Delete crontab" +//usage: "\n FILE Replace crontab by FILE ('-': stdin)" + #include "libbb.h" #define CRONTABS CONFIG_FEATURE_CROND_DIR "/crontabs" @@ -20,8 +30,9 @@ static void edit_file(const struct passwd *pas, const char *file) { const char *ptr; - int pid = xvfork(); + pid_t pid; + pid = xvfork(); if (pid) { /* parent */ wait4pid(pid); return; @@ -30,7 +41,7 @@ static void edit_file(const struct passwd *pas, const char *file) /* CHILD - change user and run editor */ /* initgroups, setgid, setuid */ change_identity(pas); - setup_environment(DEFAULT_SHELL, + setup_environment(pas->pw_shell, SETUP_ENV_CHANGEENV | SETUP_ENV_TO_TMP, pas); ptr = getenv("VISUAL"); @@ -41,29 +52,7 @@ static void edit_file(const struct passwd *pas, const char *file) } BB_EXECLP(ptr, ptr, file, NULL); - bb_perror_msg_and_die("exec %s", ptr); -} - -static int open_as_user(const struct passwd *pas, const char *file) -{ - pid_t pid; - char c; - - pid = xvfork(); - if (pid) { /* PARENT */ - if (wait4pid(pid) == 0) { - /* exitcode 0: child says it can read */ - return open(file, O_RDONLY); - } - return -1; - } - - /* CHILD */ - /* initgroups, setgid, setuid */ - change_identity(pas); - /* We just try to read one byte. If it works, file is readable - * under this user. We signal that by exiting with 0. */ - _exit(safe_read(xopen(file, O_RDONLY), &c, 1) < 0); + bb_perror_msg_and_die("can't execute '%s'", ptr); } int crontab_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -126,10 +115,7 @@ int crontab_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) bb_show_usage(); if (NOT_LONE_DASH(argv[0])) { - src_fd = open_as_user(pas, argv[0]); - if (src_fd < 0) - bb_error_msg_and_die("user %s cannot read %s", - pas->pw_name, argv[0]); + src_fd = xopen_as_uid_gid(argv[0], O_RDONLY, pas->pw_uid, pas->pw_gid); } } diff --git a/miscutils/dc.c b/miscutils/dc.c index cb4b1e9..6bcfbe2 100644 --- a/miscutils/dc.c +++ b/miscutils/dc.c @@ -1,12 +1,44 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include -/* Tiny RPN calculator, because "expr" didn't give me bitwise operations. */ +//usage:#define dc_trivial_usage +//usage: "EXPRESSION..." +//usage: +//usage:#define dc_full_usage "\n\n" +//usage: "Tiny RPN calculator. Operations:\n" +//usage: "+, add, -, sub, *, mul, /, div, %, mod, "IF_FEATURE_DC_LIBM("**, exp, ")"and, or, not, xor,\n" +//usage: "p - print top of the stack (without popping),\n" +//usage: "f - print entire stack,\n" +//usage: "o - pop the value and set output radix (must be 10, 16, 8 or 2).\n" +//usage: "Examples: 'dc 2 2 add p' -> 4, 'dc 8 8 mul 2 2 + / p' -> 16" +//usage: +//usage:#define dc_example_usage +//usage: "$ dc 2 2 + p\n" +//usage: "4\n" +//usage: "$ dc 8 8 \\* 2 2 + / p\n" +//usage: "16\n" +//usage: "$ dc 0 1 and p\n" +//usage: "0\n" +//usage: "$ dc 0 1 or p\n" +//usage: "1\n" +//usage: "$ echo 72 9 div 8 mul p | dc\n" +//usage: "64\n" + +#if 0 +typedef unsigned data_t; +#define DATA_FMT "" +#elif 0 +typedef unsigned long data_t; +#define DATA_FMT "l" +#else +typedef unsigned long long data_t; +#define DATA_FMT "ll" +#endif struct globals { @@ -73,29 +105,29 @@ static void divide(void) static void mod(void) { - unsigned d = pop(); + data_t d = pop(); - push((unsigned) pop() % d); + push((data_t) pop() % d); } static void and(void) { - push((unsigned) pop() & (unsigned) pop()); + push((data_t) pop() & (data_t) pop()); } static void or(void) { - push((unsigned) pop() | (unsigned) pop()); + push((data_t) pop() | (data_t) pop()); } static void eor(void) { - push((unsigned) pop() ^ (unsigned) pop()); + push((data_t) pop() ^ (data_t) pop()); } static void not(void) { - push(~(unsigned) pop()); + push(~(data_t) pop()); } static void set_output_base(void) @@ -112,25 +144,30 @@ static void set_output_base(void) static void print_base(double print) { - unsigned x, i; + data_t x, i; + x = (data_t) print; if (base == 10) { - printf("%g\n", print); + if (x == print) /* exactly representable as unsigned integer */ + printf("%"DATA_FMT"u\n", x); + else + printf("%g\n", print); return; } - x = (unsigned)print; switch (base) { case 16: - printf("%x\n", x); + printf("%"DATA_FMT"x\n", x); break; case 8: - printf("%o\n", x); + printf("%"DATA_FMT"o\n", x); break; default: /* base 2 */ - i = (unsigned)INT_MAX + 1; + i = MAXINT(data_t) - (MAXINT(data_t) >> 1); + /* i is 100000...00000 */ do { - if (x & i) break; + if (x & i) + break; i >>= 1; } while (i > 1); do { @@ -182,43 +219,30 @@ static const struct op operators[] = { {"p", print_no_pop}, {"f", print_stack_no_pop}, {"o", set_output_base}, - { "", NULL } }; static void stack_machine(const char *argument) { - char *endPointer; + char *end; double d; - const struct op *o = operators; - - d = strtod(argument, &endPointer); + const struct op *o; - if (endPointer != argument && *endPointer == '\0') { + d = strtod(argument, &end); + if (end != argument && *end == '\0') { push(d); return; } - while (o->function) { + o = operators; + do { if (strcmp(o->name, argument) == 0) { o->function(); return; } o++; - } - bb_error_msg_and_die("syntax error at '%s'", argument); -} + } while (o != operators + ARRAY_SIZE(operators)); -/* return pointer to next token in buffer and set *buffer to one char - * past the end of the above mentioned token - */ -static char *get_token(char **buffer) -{ - char *current = skip_whitespace(*buffer); - if (*current != '\0') { - *buffer = skip_non_whitespace(current); - return current; - } - return NULL; + bb_error_msg_and_die("syntax error at '%s'", argument); } int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -235,16 +259,18 @@ int dc_main(int argc UNUSED_PARAM, char **argv) while ((line = xmalloc_fgetline(stdin)) != NULL) { cursor = line; while (1) { - token = get_token(&cursor); - if (!token) + token = skip_whitespace(cursor); + if (*token == '\0') break; - *cursor++ = '\0'; + cursor = skip_non_whitespace(token); + if (*cursor != '\0') + *cursor++ = '\0'; stack_machine(token); } free(line); } } else { - // why? it breaks "dc -2 2 * p" + // why? it breaks "dc -2 2 + p" //if (argv[0][0] == '-') // bb_show_usage(); do { diff --git a/miscutils/devfsd.c b/miscutils/devfsd.c index 4ccb76d..96ffe07 100644 --- a/miscutils/devfsd.c +++ b/miscutils/devfsd.c @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -53,6 +53,21 @@ The postal address is: Richard Gooch, c/o ATNF, P. O. Box 76, Epping, N.S.W., 2121, Australia. */ + +//usage:#define devfsd_trivial_usage +//usage: "mntpnt [-v]" IF_DEVFSD_FG_NP("[-fg][-np]") +//usage:#define devfsd_full_usage "\n\n" +//usage: "Manage devfs permissions and old device name symlinks\n" +//usage: "\n mntpnt The mount point where devfs is mounted" +//usage: "\n -v Print the protocol version numbers for devfsd" +//usage: "\n and the kernel-side protocol version and exit" +//usage: IF_DEVFSD_FG_NP( +//usage: "\n -fg Run in foreground" +//usage: "\n -np Exit after parsing the configuration file" +//usage: "\n and processing synthetic REGISTER events," +//usage: "\n don't poll for events" +//usage: ) + #include "libbb.h" #include "xregex.h" #include @@ -75,7 +90,7 @@ /* Various defines taken from linux/devfs_fs.h */ #define DEVFSD_PROTOCOL_REVISION_KERNEL 5 -#define DEVFSD_IOCTL_BASE 'd' +#define DEVFSD_IOCTL_BASE 'd' /* These are the various ioctls */ #define DEVFSDIOC_GET_PROTO_REV _IOR(DEVFSD_IOCTL_BASE, 0, int) #define DEVFSDIOC_SET_EVENT_MASK _IOW(DEVFSD_IOCTL_BASE, 2, int) @@ -204,7 +219,7 @@ static void action_execute(const struct devfsd_notify_struct *, const struct con const regmatch_t *, unsigned); static void action_modload(const struct devfsd_notify_struct *info, const struct config_entry_struct *entry); static void action_copy(const struct devfsd_notify_struct *, const struct config_entry_struct *, - const regmatch_t *, unsigned); + const regmatch_t *, unsigned); static void action_compat(const struct devfsd_notify_struct *, unsigned); static void free_config(void); static void restore(char *spath, struct stat source_stat, int rootlen); @@ -214,12 +229,12 @@ static void signal_handler(int); static const char *get_variable(const char *, void *); static int make_dir_tree(const char *); static int expand_expression(char *, unsigned, const char *, const char *(*)(const char *, void *), void *, - const char *, const regmatch_t *, unsigned); + const char *, const regmatch_t *, unsigned); static void expand_regexp(char *, size_t, const char *, const char *, const regmatch_t *, unsigned); static const char *expand_variable( char *, unsigned, unsigned *, const char *, const char *(*)(const char *, void *), void *); static const char *get_variable_v2(const char *, const char *(*)(const char *, void *), void *); -static char get_old_ide_name(unsigned , unsigned); +static char get_old_ide_name(unsigned, unsigned); static char *write_old_sd_name(char *, unsigned, unsigned, const char *); /* busybox functions */ @@ -565,9 +580,9 @@ static void process_config_line(const char *line, unsigned long *event_mask) /*This action will pass "/dev/$devname"(i.e. "/dev/" prefixed to the device name) to the module loading facility. In addition, the /etc/modules.devfs configuration file is used.*/ - if (ENABLE_DEVFSD_MODLOAD) + if (ENABLE_DEVFSD_MODLOAD) new->action.what = AC_MODLOAD; - break; + break; case 6: /* EXECUTE */ new->action.what = AC_EXECUTE; num_args -= 3; @@ -735,7 +750,7 @@ static void action_permissions(const struct devfsd_notify_struct *info, } /* End Function action_permissions */ static void action_modload(const struct devfsd_notify_struct *info, - const struct config_entry_struct *entry UNUSED_PARAM) + const struct config_entry_struct *entry UNUSED_PARAM) /* [SUMMARY] Load a module. The devfs change. The config file entry. @@ -756,8 +771,8 @@ static void action_modload(const struct devfsd_notify_struct *info, } /* End Function action_modload */ static void action_execute(const struct devfsd_notify_struct *info, - const struct config_entry_struct *entry, - const regmatch_t *regexpr, unsigned int numexpr) + const struct config_entry_struct *entry, + const regmatch_t *regexpr, unsigned int numexpr) /* [SUMMARY] Execute a programme. The devfs change. The config file entry. @@ -788,8 +803,8 @@ static void action_execute(const struct devfsd_notify_struct *info, static void action_copy(const struct devfsd_notify_struct *info, - const struct config_entry_struct *entry, - const regmatch_t *regexpr, unsigned int numexpr) + const struct config_entry_struct *entry, + const regmatch_t *regexpr, unsigned int numexpr) /* [SUMMARY] Copy permissions. The devfs change. The config file entry. @@ -1068,21 +1083,23 @@ static int get_uid_gid(int flag, const char *string) { struct passwd *pw_ent; struct group *grp_ent; - static const char *msg; - - if (ENABLE_DEVFSD_VERBOSE) - msg = "user"; + const char *msg; - if (isdigit(string[0]) ||((string[0] == '-') && isdigit(string[1]))) + if (isdigit(string[0]) || ((string[0] == '-') && isdigit(string[1]))) return atoi(string); if (flag == UID && (pw_ent = getpwnam(string)) != NULL) return pw_ent->pw_uid; - if (flag == GID && (grp_ent = getgrnam(string)) != NULL) - return grp_ent->gr_gid; - else if (ENABLE_DEVFSD_VERBOSE) - msg = "group"; + if (ENABLE_DEVFSD_VERBOSE) + msg = "user"; + + if (flag == GID) { + if ((grp_ent = getgrnam(string)) != NULL) + return grp_ent->gr_gid; + if (ENABLE_DEVFSD_VERBOSE) + msg = "group"; + } if (ENABLE_DEVFSD_VERBOSE) msg_logger(LOG_ERR, "unknown %s: %s, defaulting to %cid=0", msg, string, msg[0]); @@ -1244,11 +1261,11 @@ static int make_dir_tree(const char *path) } /* End Function make_dir_tree */ static int expand_expression(char *output, unsigned int outsize, - const char *input, - const char *(*get_variable_func)(const char *variable, void *info), - void *info, - const char *devname, - const regmatch_t *ex, unsigned int numexp) + const char *input, + const char *(*get_variable_func)(const char *variable, void *info), + void *info, + const char *devname, + const regmatch_t *ex, unsigned int numexp) /* [SUMMARY] Expand environment variables and regular subexpressions in string. The output expanded expression is written here. The size of the output buffer. @@ -1273,8 +1290,8 @@ static int expand_expression(char *output, unsigned int outsize, } /* End Function expand_expression */ static void expand_regexp(char *output, size_t outsize, const char *input, - const char *devname, - const regmatch_t *ex, unsigned int numex) + const char *devname, + const regmatch_t *ex, unsigned int numex) /* [SUMMARY] Expand all occurrences of the regular subexpressions \0 to \9. The output expanded expression is written here. The size of the output buffer. @@ -1370,7 +1387,7 @@ static struct translate_struct translate_table[] = }; const char *get_old_name(const char *devname, unsigned int namelen, - char *buffer, unsigned int major, unsigned int minor) + char *buffer, unsigned int major, unsigned int minor) /* [SUMMARY] Translate a kernel-supplied name into an old name. The device name provided by the kernel. The length of the name. @@ -1408,7 +1425,7 @@ const char *get_old_name(const char *devname, unsigned int namelen, }; for (trans = translate_table; trans->match != NULL; ++trans) { - len = strlen(trans->match); + len = strlen(trans->match); if (strncmp(devname, trans->match, len) == 0) { if (trans->format == NULL) @@ -1534,9 +1551,9 @@ static char *write_old_sd_name(char *buffer, /*EXPERIMENTAL_FUNCTION*/ int st_expr_expand(char *output, unsigned int length, const char *input, - const char *(*get_variable_func)(const char *variable, - void *info), - void *info) + const char *(*get_variable_func)(const char *variable, + void *info), + void *info) /* [SUMMARY] Expand an expression using Borne Shell-like unquoted rules. The output expanded expression is written here. The size of the output buffer. @@ -1626,10 +1643,10 @@ st_expr_expand_out: /* Private functions follow */ static const char *expand_variable(char *buffer, unsigned int length, - unsigned int *out_pos, const char *input, - const char *(*func)(const char *variable, - void *info), - void *info) + unsigned int *out_pos, const char *input, + const char *(*func)(const char *variable, + void *info), + void *info) /* [SUMMARY] Expand a variable. The buffer to write to. The length of the output buffer. @@ -1771,8 +1788,8 @@ expand_variable_out: static const char *get_variable_v2(const char *variable, - const char *(*func)(const char *variable, void *info), - void *info) + const char *(*func)(const char *variable, void *info), + void *info) /* [SUMMARY] Get a variable from the environment or . The variable name. A function which will be used to get the variable. If this returns diff --git a/miscutils/devmem.c b/miscutils/devmem.c index 39b5808..786a21b 100644 --- a/miscutils/devmem.c +++ b/miscutils/devmem.c @@ -1,9 +1,17 @@ /* - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * Copyright (C) 2000, Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl) * Copyright (C) 2008, BusyBox Team. -solar 4/26/08 */ +//usage:#define devmem_trivial_usage +//usage: "ADDRESS [WIDTH [VALUE]]" +//usage:#define devmem_full_usage "\n\n" +//usage: "Read/write from physical address\n" +//usage: "\n ADDRESS Address to act upon" +//usage: "\n WIDTH Width (8/16/...)" +//usage: "\n VALUE Data to be written" + #include "libbb.h" int devmem_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/miscutils/eject.c b/miscutils/eject.c index a869c63..a20e04b 100644 --- a/miscutils/eject.c +++ b/miscutils/eject.c @@ -5,7 +5,7 @@ * Copyright (C) 2004 Peter Willis * Copyright (C) 2005 Tito Ragusa * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -13,6 +13,16 @@ * Most of the dirty work blatantly ripped off from cat.c =) */ +//usage:#define eject_trivial_usage +//usage: "[-t] [-T] [DEVICE]" +//usage:#define eject_full_usage "\n\n" +//usage: "Eject DEVICE or default /dev/cdrom\n" +//usage: IF_FEATURE_EJECT_SCSI( +//usage: "\n -s SCSI device" +//usage: ) +//usage: "\n -t Close tray" +//usage: "\n -T Open/close tray (toggle)" + #include #include "libbb.h" /* Must be after libbb.h: they need size_t */ diff --git a/miscutils/fbsplash.c b/miscutils/fbsplash.c index e370d20..12a77b7 100644 --- a/miscutils/fbsplash.c +++ b/miscutils/fbsplash.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2008 Michele Sanges * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Usage: * - use kernel option 'vga=xxx' or otherwise enable framebuffer device. @@ -21,16 +21,24 @@ * "exit" (or just close fifo) - well you guessed it. */ +//usage:#define fbsplash_trivial_usage +//usage: "-s IMGFILE [-c] [-d DEV] [-i INIFILE] [-f CMD]" +//usage:#define fbsplash_full_usage "\n\n" +//usage: " -s Image" +//usage: "\n -c Hide cursor" +//usage: "\n -d Framebuffer device (default /dev/fb0)" +//usage: "\n -i Config file (var=value):" +//usage: "\n BAR_LEFT,BAR_TOP,BAR_WIDTH,BAR_HEIGHT" +//usage: "\n BAR_R,BAR_G,BAR_B" +//usage: "\n -f Control pipe (else exit after drawing image)" +//usage: "\n commands: 'NN' (% for progress bar) or 'exit'" + #include "libbb.h" #include /* If you want logging messages on /tmp/fbsplash.log... */ #define DEBUG 0 -#define BYTES_PER_PIXEL 2 - -typedef unsigned short DATA; - struct globals { #if DEBUG bool bdebug_messages; // enable/disable logging @@ -41,6 +49,11 @@ struct globals { const char *image_filename; struct fb_var_screeninfo scr_var; struct fb_fix_screeninfo scr_fix; + unsigned bytes_per_pixel; + // cached (8 - scr_var.COLOR.length): + unsigned red_shift; + unsigned green_shift; + unsigned blue_shift; }; #define G (*ptr_to_globals) #define INIT_G() do { \ @@ -65,9 +78,46 @@ struct globals { #define DEBUG_MESSAGE(...) ((void)0) #endif +/** + * Configure palette for RGB:332 + */ +static void fb_setpal(int fd) +{ + struct fb_cmap cmap; + /* fb colors are 16 bit */ + unsigned short red[256], green[256], blue[256]; + unsigned i; + + /* RGB:332 */ + for (i = 0; i < 256; i++) { + /* Color is encoded in pixel value as rrrgggbb. + * 3-bit color is mapped to 16-bit one as: + * 000 -> 00000000 00000000 + * 001 -> 00100100 10010010 + * ... + * 011 -> 01101101 10110110 + * 100 -> 10010010 01001001 + * ... + * 111 -> 11111111 11111111 + */ + red[i] = (( i >> 5 ) * 0x9249) >> 2; // rrr * 00 10010010 01001001 >> 2 + green[i] = (((i >> 2) & 0x7) * 0x9249) >> 2; // ggg * 00 10010010 01001001 >> 2 + /* 2-bit color is easier: */ + blue[i] = ( i & 0x3) * 0x5555; // bb * 01010101 01010101 + } + + cmap.start = 0; + cmap.len = 256; + cmap.red = red; + cmap.green = green; + cmap.blue = blue; + cmap.transp = 0; + + xioctl(fd, FBIOPUTCMAP, &cmap); +} /** - * Open and initialize the framebuffer device + * Open and initialize the framebuffer device * \param *strfb_device pointer to framebuffer device */ static void fb_open(const char *strfb_device) @@ -78,59 +128,133 @@ static void fb_open(const char *strfb_device) xioctl(fbfd, FBIOGET_VSCREENINFO, &G.scr_var); xioctl(fbfd, FBIOGET_FSCREENINFO, &G.scr_fix); - if (G.scr_var.bits_per_pixel != 16) - bb_error_msg_and_die("only 16 bpp is supported"); + switch (G.scr_var.bits_per_pixel) { + case 8: + fb_setpal(fbfd); + break; + + case 16: + case 24: + case 32: + break; + + default: + bb_error_msg_and_die("unsupported %u bpp", (int)G.scr_var.bits_per_pixel); + break; + } + + G.red_shift = 8 - G.scr_var.red.length; + G.green_shift = 8 - G.scr_var.green.length; + G.blue_shift = 8 - G.scr_var.blue.length; + G.bytes_per_pixel = (G.scr_var.bits_per_pixel + 7) >> 3; // map the device in memory G.addr = mmap(NULL, - G.scr_var.xres * G.scr_var.yres - * BYTES_PER_PIXEL /*(G.scr_var.bits_per_pixel / 8)*/, + G.scr_var.yres * G.scr_fix.line_length, PROT_WRITE, MAP_SHARED, fbfd, 0); if (G.addr == MAP_FAILED) bb_perror_msg_and_die("mmap"); + + // point to the start of the visible screen + G.addr += G.scr_var.yoffset * G.scr_fix.line_length + G.scr_var.xoffset * G.bytes_per_pixel; close(fbfd); } /** - * Draw hollow rectangle on framebuffer + * Return pixel value of the passed RGB color. + * This is performance critical fn. + */ +static unsigned fb_pixel_value(unsigned r, unsigned g, unsigned b) +{ + /* We assume that the r,g,b values are <= 255 */ + + if (G.bytes_per_pixel == 1) { + r = r & 0xe0; // 3-bit red + g = (g >> 3) & 0x1c; // 3-bit green + b = b >> 6; // 2-bit blue + return r + g + b; + } + if (G.bytes_per_pixel == 2) { + // ARM PL110 on Integrator/CP has RGBA5551 bit arrangement. + // We want to support bit locations like that. + // + // First shift out unused bits + r = r >> G.red_shift; + g = g >> G.green_shift; + b = b >> G.blue_shift; + // Then shift the remaining bits to their offset + return (r << G.scr_var.red.offset) + + (g << G.scr_var.green.offset) + + (b << G.scr_var.blue.offset); + } + // RGB 888 + return b + (g << 8) + (r << 16); +} + +/** + * Draw pixel on framebuffer + */ +static void fb_write_pixel(unsigned char *addr, unsigned pixel) +{ + switch (G.bytes_per_pixel) { + case 1: + *addr = pixel; + break; + case 2: + *(uint16_t *)addr = pixel; + break; + case 4: + *(uint32_t *)addr = pixel; + break; + default: // 24 bits per pixel + addr[0] = pixel; + addr[1] = pixel >> 8; + addr[2] = pixel >> 16; + } +} + + +/** + * Draw hollow rectangle on framebuffer */ static void fb_drawrectangle(void) { int cnt; - DATA thispix; - DATA *ptr1, *ptr2; + unsigned thispix; + unsigned char *ptr1, *ptr2; unsigned char nred = G.nbar_colr/2; unsigned char ngreen = G.nbar_colg/2; unsigned char nblue = G.nbar_colb/2; - nred >>= 3; // 5-bit red - ngreen >>= 2; // 6-bit green - nblue >>= 3; // 5-bit blue - thispix = nblue + (ngreen << 5) + (nred << (5+6)); + thispix = fb_pixel_value(nred, ngreen, nblue); // horizontal lines - ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); - ptr2 = (DATA*)(G.addr + ((G.nbar_posy + G.nbar_height - 1) * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + (G.nbar_posy + G.nbar_height - 1) * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; cnt = G.nbar_width - 1; do { - *ptr1++ = thispix; - *ptr2++ = thispix; + fb_write_pixel(ptr1, thispix); + fb_write_pixel(ptr2, thispix); + ptr1 += G.bytes_per_pixel; + ptr2 += G.bytes_per_pixel; } while (--cnt >= 0); // vertical lines - ptr1 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx) * BYTES_PER_PIXEL); - ptr2 = (DATA*)(G.addr + (G.nbar_posy * G.scr_var.xres + G.nbar_posx + G.nbar_width - 1) * BYTES_PER_PIXEL); + ptr1 = G.addr + G.nbar_posy * G.scr_fix.line_length + G.nbar_posx * G.bytes_per_pixel; + ptr2 = G.addr + G.nbar_posy * G.scr_fix.line_length + (G.nbar_posx + G.nbar_width - 1) * G.bytes_per_pixel; cnt = G.nbar_height - 1; do { - *ptr1 = thispix; ptr1 += G.scr_var.xres; - *ptr2 = thispix; ptr2 += G.scr_var.xres; + fb_write_pixel(ptr1, thispix); + fb_write_pixel(ptr2, thispix); + ptr1 += G.scr_fix.line_length; + ptr2 += G.scr_fix.line_length; } while (--cnt >= 0); } /** - * Draw filled rectangle on framebuffer + * Draw filled rectangle on framebuffer * \param nx1pos,ny1pos upper left position * \param nx2pos,ny2pos down right position * \param nred,ngreen,nblue rgb color @@ -139,21 +263,19 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, unsigned char nred, unsigned char ngreen, unsigned char nblue) { int cnt1, cnt2, nypos; - DATA thispix; - DATA *ptr; + unsigned thispix; + unsigned char *ptr; - nred >>= 3; // 5-bit red - ngreen >>= 2; // 6-bit green - nblue >>= 3; // 5-bit blue - thispix = nblue + (ngreen << 5) + (nred << (5+6)); + thispix = fb_pixel_value(nred, ngreen, nblue); cnt1 = ny2pos - ny1pos; nypos = ny1pos; do { - ptr = (DATA*)(G.addr + (nypos * G.scr_var.xres + nx1pos) * BYTES_PER_PIXEL); + ptr = G.addr + nypos * G.scr_fix.line_length + nx1pos * G.bytes_per_pixel; cnt2 = nx2pos - nx1pos; do { - *ptr++ = thispix; + fb_write_pixel(ptr, thispix); + ptr += G.bytes_per_pixel; } while (--cnt2 >= 0); nypos++; @@ -162,19 +284,20 @@ static void fb_drawfullrectangle(int nx1pos, int ny1pos, int nx2pos, int ny2pos, /** - * Draw a progress bar on framebuffer + * Draw a progress bar on framebuffer * \param percent percentage of loading */ static void fb_drawprogressbar(unsigned percent) { - int i, left_x, top_y, width, height; + int left_x, top_y, pos_x; + unsigned width, height; // outer box left_x = G.nbar_posx; top_y = G.nbar_posy; width = G.nbar_width - 1; height = G.nbar_height - 1; - if ((height | width) < 0) + if ((int)(height | width) < 0) return; // NB: "width" of 1 actually makes rect with width of 2! fb_drawrectangle(); @@ -184,35 +307,41 @@ static void fb_drawprogressbar(unsigned percent) top_y++; width -= 2; height -= 2; - if ((height | width) < 0) + if ((int)(height | width) < 0) return; - fb_drawfullrectangle( - left_x, top_y, - left_x + width, top_y + height, - G.nbar_colr, G.nbar_colg, G.nbar_colb); + pos_x = left_x; if (percent > 0) { + int i, y; + // actual progress bar - width = width * percent / 100; + pos_x += (unsigned)(width * percent) / 100; + + y = top_y; i = height; if (height == 0) height++; // divide by 0 is bad while (i >= 0) { // draw one-line thick "rectangle" // top line will have gray lvl 200, bottom one 100 - unsigned gray_level = 100 + i*100/height; + unsigned gray_level = 100 + (unsigned)i*100 / height; fb_drawfullrectangle( - left_x, top_y, left_x + width, top_y, + left_x, y, pos_x, y, gray_level, gray_level, gray_level); - top_y++; + y++; i--; } } + + fb_drawfullrectangle( + pos_x, top_y, + left_x + width, top_y + height, + G.nbar_colr, G.nbar_colg, G.nbar_colb); } /** - * Draw image from PPM file + * Draw image from PPM file */ static void fb_drawimage(void) { @@ -273,18 +402,16 @@ static void fb_drawimage(void) height = G.scr_var.yres; for (j = 0; j < height; j++) { unsigned char *pixel; - DATA *src; + unsigned char *src; if (fread(pixline, 1, line_size, theme_file) != line_size) bb_error_msg_and_die("bad PPM file '%s'", G.image_filename); pixel = pixline; - src = (DATA *)(G.addr + j * G.scr_fix.line_length); + src = G.addr + j * G.scr_fix.line_length; for (i = 0; i < width; i++) { - unsigned thispix; - thispix = (((unsigned)pixel[0] << 8) & 0xf800) - | (((unsigned)pixel[1] << 3) & 0x07e0) - | (((unsigned)pixel[2] >> 3)); - *src++ = thispix; + unsigned thispix = fb_pixel_value(pixel[0], pixel[1], pixel[2]); + fb_write_pixel(src, thispix); + src += G.bytes_per_pixel; pixel += 3; } } @@ -294,7 +421,7 @@ static void fb_drawimage(void) /** - * Parse configuration file + * Parse configuration file * \param *cfg_filename name of the configuration file */ static void init(const char *cfg_filename) @@ -311,7 +438,7 @@ static void init(const char *cfg_filename) parser_t *parser = config_open2(cfg_filename, xfopen_stdin); while (config_read(parser, token, 2, 2, "#=", (PARSE_NORMAL | PARSE_MIN_DIE) & ~(PARSE_TRIM | PARSE_COLLAPSE))) { - unsigned val = xatoi_u(token[1]); + unsigned val = xatoi_positive(token[1]); int i = index_in_strings(param_names, token[0]); if (i < 0) bb_error_msg_and_die("syntax error: %s", token[0]); diff --git a/miscutils/flash_eraseall.c b/miscutils/flash_eraseall.c index ca00a13..bf9b739 100644 --- a/miscutils/flash_eraseall.c +++ b/miscutils/flash_eraseall.c @@ -7,17 +7,25 @@ * * Renamed to flash_eraseall.c * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define flash_eraseall_trivial_usage +//usage: "[-jNq] MTD_DEVICE" +//usage:#define flash_eraseall_full_usage "\n\n" +//usage: "Erase an MTD device\n" +//usage: "\n -j Format the device for jffs2" +//usage: "\n -N Don't skip bad blocks" +//usage: "\n -q Don't display progress messages" + #include "libbb.h" #include #include -#define OPTION_J (1 << 0) -#define OPTION_Q (1 << 1) -#define IS_NAND (1 << 2) -#define BBTEST (1 << 3) +#define OPTION_J (1 << 0) +#define OPTION_N (1 << 1) +#define OPTION_Q (1 << 2) +#define IS_NAND (1 << 3) /* mtd/jffs2-user.h used to have this atrocity: extern int target_endian; @@ -42,15 +50,6 @@ but mtd/jffs2-user.h is gone now (at least 2.6.31.6 does not have it anymore) #define cpu_to_je16(v) ((jint16_t){(v)}) #define cpu_to_je32(v) ((jint32_t){(v)}) -static uint32_t crc32(uint32_t val, const void *ss, int len, - uint32_t *crc32_table) -{ - const unsigned char *s = ss; - while (--len >= 0) - val = crc32_table[(val ^ *s++) & 0xff] ^ (val >> 8); - return val; -} - static void show_progress(mtd_info_t *meminfo, erase_info_t *erase) { printf("\rErasing %u Kibyte @ %x - %2u%% complete.", @@ -73,7 +72,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) char *mtd_name; opt_complementary = "=1"; - flags = BBTEST | getopt32(argv, "jq"); + flags = getopt32(argv, "jNq"); mtd_name = argv[optind]; fd = xopen(mtd_name, O_RDWR); @@ -131,8 +130,9 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) cleanmarker.totlen = cpu_to_je32(8); } - cleanmarker.hdr_crc = cpu_to_je32(crc32(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, - crc32_table)); + cleanmarker.hdr_crc = cpu_to_je32( + crc32_block_endian0(0, &cleanmarker, sizeof(struct jffs2_unknown_node) - 4, crc32_table) + ); } /* Don't want to destroy progress indicator by bb_error_msg's */ @@ -140,7 +140,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) for (erase.start = 0; erase.start < meminfo.size; erase.start += meminfo.erasesize) { - if (flags & BBTEST) { + if (!(flags & OPTION_N)) { int ret; loff_t offset = erase.start; @@ -155,7 +155,7 @@ int flash_eraseall_main(int argc UNUSED_PARAM, char **argv) * types e.g. NOR */ if (errno == EOPNOTSUPP) { - flags &= ~BBTEST; + flags |= OPTION_N; if (flags & IS_NAND) bb_error_msg_and_die("bad block check not available"); } else { diff --git a/miscutils/flash_lock_unlock.c b/miscutils/flash_lock_unlock.c index f4e2f73..1fefd95 100644 --- a/miscutils/flash_lock_unlock.c +++ b/miscutils/flash_lock_unlock.c @@ -1,8 +1,20 @@ /* vi: set sw=4 ts=4: */ /* Ported to busybox from mtd-utils. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define flash_lock_trivial_usage +//usage: "MTD_DEVICE OFFSET SECTORS" +//usage:#define flash_lock_full_usage "\n\n" +//usage: "Lock part or all of an MTD device. If SECTORS is -1, then all sectors\n" +//usage: "will be locked, regardless of the value of OFFSET" +//usage: +//usage:#define flash_unlock_trivial_usage +//usage: "MTD_DEVICE" +//usage:#define flash_unlock_full_usage "\n\n" +//usage: "Unlock an MTD device" + #include "libbb.h" #include diff --git a/miscutils/flashcp.c b/miscutils/flashcp.c index 9472c75..b526566 100644 --- a/miscutils/flashcp.c +++ b/miscutils/flashcp.c @@ -4,12 +4,19 @@ * * (C) 2009 Stefan Seyfried * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define flashcp_trivial_usage +//usage: "-v FILE MTD_DEVICE" +//usage:#define flashcp_full_usage "\n\n" +//usage: "Copy an image to MTD device\n" +//usage: "\n -v Verbose" + #include "libbb.h" #include +/* If 1, simulates "flashing" by writing to existing regular file */ #define MTD_DEBUG 0 #define OPT_v (1 << 0) @@ -26,7 +33,7 @@ static void progress(int mode, uoff_t count, uoff_t total) if (total) percent = (unsigned) (percent / total); printf("\r%s: %"OFF_FMT"u/%"OFF_FMT"u (%u%%) ", - (mode == 0) ? "Erasing block" : ((mode == 1) ? "Writing kb" : "Verifying kb"), + (mode < 0) ? "Erasing block" : ((mode == 0) ? "Writing kb" : "Verifying kb"), count, total, (unsigned)percent); fflush_all(); } @@ -44,7 +51,6 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) int fd_f, fd_d; /* input file and mtd device file descriptors */ int i; uoff_t erase_count; - unsigned opts; struct mtd_info_user mtd; struct erase_info_user e; struct stat statb; @@ -53,7 +59,7 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) RESERVE_CONFIG_UBUFFER(buf2, BUFSIZE); opt_complementary = "=2"; /* exactly 2 non-option args: file, dev */ - opts = getopt32(argv, "v"); + /*opts =*/ getopt32(argv, "v"); argv += optind; // filename = *argv++; // devicename = *argv; @@ -92,8 +98,7 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) #endif e.start = 0; for (i = 1; i <= erase_count; i++) { - progress(0, i, erase_count); - errno = 0; + progress(-1, i, erase_count); #if !MTD_DEBUG if (ioctl(fd_d, MEMERASE, &e) < 0) { bb_perror_msg_and_die("erase error at 0x%llx on %s", @@ -108,7 +113,7 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) /* doing this outer loop gives significantly smaller code * than doing two separate loops for writing and verifying */ - for (i = 1; i <= 2; i++) { + for (i = 0; i <= 1; i++) { uoff_t done; unsigned count; @@ -117,25 +122,29 @@ int flashcp_main(int argc UNUSED_PARAM, char **argv) done = 0; count = BUFSIZE; while (1) { - uoff_t rem = statb.st_size - done; + uoff_t rem; + + progress(i, done / 1024, (uoff_t)statb.st_size / 1024); + rem = statb.st_size - done; if (rem == 0) break; if (rem < BUFSIZE) count = rem; - progress(i, done / 1024, (uoff_t)statb.st_size / 1024); xread(fd_f, buf, count); - if (i == 1) { + if (i == 0) { int ret; + if (count < BUFSIZE) + memset((char*)buf + count, 0, BUFSIZE - count); errno = 0; - ret = full_write(fd_d, buf, count); - if (ret != count) { + ret = full_write(fd_d, buf, BUFSIZE); + if (ret != BUFSIZE) { bb_perror_msg_and_die("write error at 0x%"OFF_FMT"x on %s, " "write returned %d", done, devicename, ret); } - } else { /* i == 2 */ + } else { /* i == 1 */ xread(fd_d, buf2, count); - if (memcmp(buf, buf2, count)) { + if (memcmp(buf, buf2, count) != 0) { bb_error_msg_and_die("verification mismatch at 0x%"OFF_FMT"x", done); } } diff --git a/miscutils/hdparm.c b/miscutils/hdparm.c index 9738620..f0e9c9d 100644 --- a/miscutils/hdparm.c +++ b/miscutils/hdparm.c @@ -5,12 +5,63 @@ * Copyright (C) [2003] by [Matteo Croce] <3297627799@wind.it> * Hacked by Tito for size optimization. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * This program is based on the source code of hdparm: see below... * hdparm.c - Command line interface to get/set hard disk parameters * - by Mark Lord (C) 1994-2002 -- freely distributable */ + +//usage:#define hdparm_trivial_usage +//usage: "[OPTIONS] [DEVICE]" +//usage:#define hdparm_full_usage "\n\n" +//usage: " -a Get/set fs readahead" +//usage: "\n -A Set drive read-lookahead flag (0/1)" +//usage: "\n -b Get/set bus state (0 == off, 1 == on, 2 == tristate)" +//usage: "\n -B Set Advanced Power Management setting (1-255)" +//usage: "\n -c Get/set IDE 32-bit IO setting" +//usage: "\n -C Check IDE power mode status" +//usage: IF_FEATURE_HDPARM_HDIO_GETSET_DMA( +//usage: "\n -d Get/set using_dma flag") +//usage: "\n -D Enable/disable drive defect-mgmt" +//usage: "\n -f Flush buffer cache for device on exit" +//usage: "\n -g Display drive geometry" +//usage: "\n -h Display terse usage information" +//usage: IF_FEATURE_HDPARM_GET_IDENTITY( +//usage: "\n -i Display drive identification") +//usage: IF_FEATURE_HDPARM_GET_IDENTITY( +//usage: "\n -I Detailed/current information directly from drive") +//usage: "\n -k Get/set keep_settings_over_reset flag (0/1)" +//usage: "\n -K Set drive keep_features_over_reset flag (0/1)" +//usage: "\n -L Set drive doorlock (0/1) (removable harddisks only)" +//usage: "\n -m Get/set multiple sector count" +//usage: "\n -n Get/set ignore-write-errors flag (0/1)" +//usage: "\n -p Set PIO mode on IDE interface chipset (0,1,2,3,4,...)" +//usage: "\n -P Set drive prefetch count" +/* //usage: "\n -q Change next setting quietly" - not supported ib bbox */ +//usage: "\n -Q Get/set DMA tagged-queuing depth (if supported)" +//usage: "\n -r Get/set readonly flag (DANGEROUS to set)" +//usage: IF_FEATURE_HDPARM_HDIO_SCAN_HWIF( +//usage: "\n -R Register an IDE interface (DANGEROUS)") +//usage: "\n -S Set standby (spindown) timeout" +//usage: "\n -t Perform device read timings" +//usage: "\n -T Perform cache read timings" +//usage: "\n -u Get/set unmaskirq flag (0/1)" +//usage: IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( +//usage: "\n -U Unregister an IDE interface (DANGEROUS)") +//usage: "\n -v Defaults; same as -mcudkrag for IDE drives" +//usage: "\n -V Display program version and exit immediately" +//usage: IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( +//usage: "\n -w Perform device reset (DANGEROUS)") +//usage: "\n -W Set drive write-caching flag (0/1) (DANGEROUS)" +//usage: IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( +//usage: "\n -x Tristate device for hotswap (0/1) (DANGEROUS)") +//usage: "\n -X Set IDE xfer mode (DANGEROUS)" +//usage: "\n -y Put IDE drive in standby mode" +//usage: "\n -Y Put IDE drive to sleep" +//usage: "\n -Z Disable Seagate auto-powersaving mode" +//usage: "\n -z Reread partition table" + #include "libbb.h" /* must be _after_ libbb.h: */ #include @@ -382,6 +433,7 @@ struct BUG_G_too_big { #define hwif_data (G.hwif_data ) #define hwif_ctrl (G.hwif_ctrl ) #define hwif_irq (G.hwif_irq ) +#define INIT_G() do { } while (0) /* Busybox messages and functions */ @@ -413,14 +465,14 @@ static void on_off(int value) static void print_flag_on_off(int get_arg, const char *s, unsigned long arg) { if (get_arg) { - printf(" setting %s to %ld", s, arg); + printf(" setting %s to %lu", s, arg); on_off(arg); } } static void print_value_on_off(const char *str, unsigned long argp) { - printf(" %s\t= %2ld", str, argp); + printf(" %s\t= %2lu", str, argp); on_off(argp != 0); } @@ -730,8 +782,8 @@ static void identify(uint16_t *val) if (val[MINOR] && (val[MINOR] <= MINOR_MAX)) { if (like_std < 3) like_std = 3; std = actual_ver[val[MINOR]]; - if (std) printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR])); - + if (std) + printf("\n\tUsed: %s ", nth_string(minor_str, val[MINOR])); } /* looks like when they up-issue the std, they obsolete one; * thus, only the newest 4 issues need be supported. (That's @@ -970,8 +1022,8 @@ static void identify(uint16_t *val) } if ((like_std > 3) && (val[CMDS_SUPP_1] & 0x0008)) { /* We print out elsewhere whether the APM feature is enabled or - not. If it's not enabled, let's not repeat the info; just print - nothing here. */ + * not. If it's not enabled, let's not repeat the info; just print + * nothing here. */ printf("\tAdvancedPM level: "); if ((val[ADV_PWR] & 0xFF00) == 0x4000) { uint8_t apm_level = val[ADV_PWR] & 0x00FF; @@ -986,7 +1038,7 @@ static void identify(uint16_t *val) val[ACOUSTIC] & 0x00ff); } } else { - /* ATAPI */ + /* ATAPI */ if (eqpt != CDROM && (val[CAPAB_0] & SWRST_REQ)) printf("\tATA sw reset required\n"); @@ -1457,7 +1509,7 @@ static void bus_state_value(unsigned value) else if (value == BUSSTATE_TRISTATE) printf(" (tristate)\n"); else - printf(" (unknown: %d)\n", value); + printf(" (unknown: %u)\n", value); } #endif @@ -1537,7 +1589,7 @@ static void interpret_xfermode(unsigned xfermode) static void print_flag(int flag, const char *s, unsigned long value) { if (flag) - printf(" setting %s to %ld\n", s, value); + printf(" setting %s to %lu\n", s, value); } static void process_dev(char *devname) @@ -1745,7 +1797,7 @@ static void process_dev(char *devname) if (-1 == read(fd, buf, sizeof(buf))) bb_perror_msg("read of 512 bytes failed"); } -#endif /* HDIO_DRIVE_CMD */ +#endif /* HDIO_DRIVE_CMD */ if (getset_mult || get_identity) { multcount = -1; if (ioctl(fd, HDIO_GET_MULTCOUNT, &multcount)) { @@ -2008,6 +2060,8 @@ int hdparm_main(int argc, char **argv) int c; int flagcount = 0; + INIT_G(); + while ((c = getopt(argc, argv, hdparm_options)) >= 0) { flagcount++; IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I')); @@ -2055,8 +2109,8 @@ int hdparm_main(int argc, char **argv) #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF if (c == 'R') { scan_hwif = parse_opts_0_INTMAX(&hwif_data); - hwif_ctrl = xatoi_u((argv[optind]) ? argv[optind] : ""); - hwif_irq = xatoi_u((argv[optind+1]) ? argv[optind+1] : ""); + hwif_ctrl = xatoi_positive((argv[optind]) ? argv[optind] : ""); + hwif_irq = xatoi_positive((argv[optind+1]) ? argv[optind+1] : ""); /* Move past the 2 additional arguments */ argv += 2; argc -= 2; diff --git a/miscutils/inotifyd.c b/miscutils/inotifyd.c index 271f3ad..7a1a6a2 100644 --- a/miscutils/inotifyd.c +++ b/miscutils/inotifyd.c @@ -5,7 +5,7 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* @@ -27,6 +27,34 @@ * See below for mask names explanation. */ +//usage:#define inotifyd_trivial_usage +//usage: "PROG FILE1[:MASK]..." +//usage:#define inotifyd_full_usage "\n\n" +//usage: "Run PROG on filesystem changes." +//usage: "\nWhen a filesystem event matching MASK occurs on FILEn," +//usage: "\nPROG ACTUAL_EVENTS FILEn [SUBFILE] is run." +//usage: "\nIf PROG is -, events are sent to stdout." +//usage: "\nEvents:" +//usage: "\n a File is accessed" +//usage: "\n c File is modified" +//usage: "\n e Metadata changed" +//usage: "\n w Writable file is closed" +//usage: "\n 0 Unwritable file is closed" +//usage: "\n r File is opened" +//usage: "\n D File is deleted" +//usage: "\n M File is moved" +//usage: "\n u Backing fs is unmounted" +//usage: "\n o Event queue overflowed" +//usage: "\n x File can't be watched anymore" +//usage: "\nIf watching a directory:" +//usage: "\n m Subfile is moved into dir" +//usage: "\n y Subfile is moved out of dir" +//usage: "\n n Subfile is created" +//usage: "\n d Subfile is deleted" +//usage: "\n" +//usage: "\ninotifyd waits for PROG to exit." +//usage: "\nWhen x event happens for all FILEs, inotifyd exits." + #include "libbb.h" #include @@ -150,12 +178,20 @@ int inotifyd_main(int argc, char **argv) *s++ = mask_names[i]; } *s = '\0'; -// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], -// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); - args[1] = events; - args[2] = watches[ie->wd]; - args[3] = ie->len ? ie->name : NULL; - spawn_and_wait((char **)args); + if (LONE_CHAR(args[0], '-')) { + /* "inotifyd - FILE": built-in echo */ + printf(ie->len ? "%s\t%s\t%s\n" : "%s\t%s\n", events, + watches[ie->wd], + ie->name); + fflush(stdout); + } else { +// bb_error_msg("exec %s %08X\t%s\t%s\t%s", args[0], +// ie->mask, events, watches[ie->wd], ie->len ? ie->name : ""); + args[1] = events; + args[2] = watches[ie->wd]; + args[3] = ie->len ? ie->name : NULL; + spawn_and_wait((char **)args); + } // we are done if all files got final x event if (ie->mask & 0x8000) { if (--argc <= 0) diff --git a/miscutils/ionice.c b/miscutils/ionice.c index 52e51b9..bd30060 100644 --- a/miscutils/ionice.c +++ b/miscutils/ionice.c @@ -4,9 +4,16 @@ * * Copyright (C) 2008 by * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ionice_trivial_usage +//usage: "[-c 1-3] [-n 0-7] [-p PID] [PROG]" +//usage:#define ionice_full_usage "\n\n" +//usage: "Change I/O priority and class\n" +//usage: "\n -c Class. 1:realtime 2:best-effort 3:idle" +//usage: "\n -n Priority" + #include #include #include "libbb.h" @@ -73,7 +80,7 @@ int ionice_main(int argc UNUSED_PARAM, char **argv) if (!(opt & (OPT_n|OPT_c))) { if (!(opt & OPT_p) && *argv) - pid = xatoi_u(*argv); + pid = xatoi_positive(*argv); pri = ioprio_get(IOPRIO_WHO_PROCESS, pid); if (pri == -1) diff --git a/miscutils/last.c b/miscutils/last.c index 55c03ae..24f6e1c 100644 --- a/miscutils/last.c +++ b/miscutils/last.c @@ -4,11 +4,20 @@ * * Copyright (C) 2003-2004 by Erik Andersen * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define last_trivial_usage +//usage: ""IF_FEATURE_LAST_FANCY("[-HW] [-f FILE]") +//usage:#define last_full_usage "\n\n" +//usage: "Show listing of the last users that logged into the system" +//usage: IF_FEATURE_LAST_FANCY( "\n" +/* //usage: "\n -H Show header line" */ +//usage: "\n -W Display with no host column truncation" +//usage: "\n -f FILE Read from FILE instead of /var/log/wtmp" +//usage: ) + #include "libbb.h" -#include /* NB: ut_name and ut_user are the same field, use only one name (ut_user) * to reduce confusion */ @@ -46,14 +55,14 @@ int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) static const char _ut_lin[] ALIGN1 = "~\0" "{\0" "|\0" /* "LOGIN\0" "date\0" */; enum { - TYPE_RUN_LVL = RUN_LVL, /* 1 */ - TYPE_BOOT_TIME = BOOT_TIME, /* 2 */ + TYPE_RUN_LVL = RUN_LVL, /* 1 */ + TYPE_BOOT_TIME = BOOT_TIME, /* 2 */ TYPE_SHUTDOWN_TIME = SHUTDOWN_TIME }; enum { - _TILDE = EMPTY, /* 0 */ - TYPE_NEW_TIME, /* NEW_TIME, 3 */ - TYPE_OLD_TIME /* OLD_TIME, 4 */ + _TILDE = EMPTY, /* 0 */ + TYPE_NEW_TIME, /* NEW_TIME, 3 */ + TYPE_OLD_TIME /* OLD_TIME, 4 */ }; if (argv[1]) { @@ -62,7 +71,7 @@ int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) file = xopen(bb_path_wtmp_file, O_RDONLY); printf("%-10s %-14s %-18s %-12.12s %s\n", - "USER", "TTY", "HOST", "LOGIN", "TIME"); + "USER", "TTY", "HOST", "LOGIN", "TIME"); /* yikes. We reverse over the file and that is a not too elegant way */ pos = xlseek(file, 0, SEEK_END); pos = lseek(file, pos - sizeof(ut), SEEK_SET); @@ -122,7 +131,7 @@ int last_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) * but some systems have it wrong */ t_tmp = (time_t)ut.ut_tv.tv_sec; printf("%-10s %-14s %-18s %-12.12s\n", - ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4); + ut.ut_user, ut.ut_line, ut.ut_host, ctime(&t_tmp) + 4); next: pos -= sizeof(ut); if (pos <= 0) diff --git a/miscutils/last_fancy.c b/miscutils/last_fancy.c index f3ea037..f687d7e 100644 --- a/miscutils/last_fancy.c +++ b/miscutils/last_fancy.c @@ -4,11 +4,10 @@ * * Copyright (C) 2008 by Patricia Muscalu * - * Licensed under the GPLv2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" -#include /* NB: ut_name and ut_user are the same field, use only one name (ut_user) * to reduce confusion */ @@ -94,14 +93,14 @@ static void show_entry(struct utmp *ut, int state, time_t dur_secs) } printf(HEADER_FORMAT, - ut->ut_user, - ut->ut_line, - show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, - show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, - ut->ut_host, - login_time, - logout_str, - duration_str); + ut->ut_user, + ut->ut_line, + show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, + show_wide ? INET6_ADDRSTRLEN : INET_ADDRSTRLEN, + ut->ut_host, + login_time, + logout_str, + duration_str); } static int get_ut_type(struct utmp *ut) @@ -162,11 +161,10 @@ int last_main(int argc UNUSED_PARAM, char **argv) time_t boot_time; time_t down_time; int file; - unsigned opt; smallint going_down; smallint boot_down; - opt = getopt32(argv, "Wf:" /* "H" */, &filename); + /*opt =*/ getopt32(argv, "Wf:" /* "H" */, &filename); #ifdef BUT_UTIL_LINUX_LAST_HAS_NO_SUCH_OPT if (opt & LAST_OPT_H) { /* Print header line */ diff --git a/miscutils/less.c b/miscutils/less.c index da2cd07..60105f4 100644 --- a/miscutils/less.c +++ b/miscutils/less.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005 by Rob Sullivan * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -21,20 +21,111 @@ * redirected input has been read from stdin */ -#include /* sched_yield() */ +//config:config LESS +//config: bool "less" +//config: default y +//config: help +//config: 'less' is a pager, meaning that it displays text files. It possesses +//config: a wide array of features, and is an improvement over 'more'. +//config: +//config:config FEATURE_LESS_MAXLINES +//config: int "Max number of input lines less will try to eat" +//config: default 9999999 +//config: depends on LESS +//config: +//config:config FEATURE_LESS_BRACKETS +//config: bool "Enable bracket searching" +//config: default y +//config: depends on LESS +//config: help +//config: This option adds the capability to search for matching left and right +//config: brackets, facilitating programming. +//config: +//config:config FEATURE_LESS_FLAGS +//config: bool "Enable -m/-M" +//config: default y +//config: depends on LESS +//config: help +//config: The -M/-m flag enables a more sophisticated status line. +//config: +//config:config FEATURE_LESS_MARKS +//config: bool "Enable marks" +//config: default y +//config: depends on LESS +//config: help +//config: Marks enable positions in a file to be stored for easy reference. +//config: +//config:config FEATURE_LESS_REGEXP +//config: bool "Enable regular expressions" +//config: default y +//config: depends on LESS +//config: help +//config: Enable regular expressions, allowing complex file searches. +//config: +//config:config FEATURE_LESS_WINCH +//config: bool "Enable automatic resizing on window size changes" +//config: default y +//config: depends on LESS +//config: help +//config: Makes less track window size changes. +//config: +//config:config FEATURE_LESS_ASK_TERMINAL +//config: bool "Use 'tell me cursor position' ESC sequence to measure window" +//config: default y +//config: depends on FEATURE_LESS_WINCH +//config: help +//config: Makes less track window size changes. +//config: If terminal size can't be retrieved and $LINES/$COLUMNS are not set, +//config: this option makes less perform a last-ditch effort to find it: +//config: position cursor to 999,999 and ask terminal to report real +//config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. +//config: +//config: This is not clean but helps a lot on serial lines and such. +//config: +//config:config FEATURE_LESS_DASHCMD +//config: bool "Enable flag changes ('-' command)" +//config: default y +//config: depends on LESS +//config: help +//config: This enables the ability to change command-line flags within +//config: less itself ('-' keyboard command). +//config: +//config:config FEATURE_LESS_LINENUMS +//config: bool "Enable dynamic switching of line numbers" +//config: default y +//config: depends on FEATURE_LESS_DASHCMD +//config: help +//config: Enables "-N" command. + +//usage:#define less_trivial_usage +//usage: "[-E" IF_FEATURE_LESS_FLAGS("Mm") "Nh~I?] [FILE]..." +//usage:#define less_full_usage "\n\n" +//usage: "View FILE (or stdin) one screenful at a time\n" +//usage: "\n -E Quit once the end of a file is reached" +//usage: IF_FEATURE_LESS_FLAGS( +//usage: "\n -M,-m Display status line with line numbers" +//usage: "\n and percentage through the file" +//usage: ) +//usage: "\n -N Prefix line number to each line" +//usage: "\n -I Ignore case in all searches" +//usage: "\n -~ Suppress ~s displayed past EOF" + +#include /* sched_yield() */ #include "libbb.h" #if ENABLE_FEATURE_LESS_REGEXP #include "xregex.h" #endif + +#define ESC "\033" /* The escape codes for highlighted and normal text */ -#define HIGHLIGHT "\033[7m" -#define NORMAL "\033[0m" +#define HIGHLIGHT ESC"[7m" +#define NORMAL ESC"[0m" /* The escape code to home and clear to the end of screen */ -#define CLEAR "\033[H\033[J" +#define CLEAR ESC"[H\033[J" /* The escape code to clear to the end of line */ -#define CLEAR_2_EOL "\033[K" +#define CLEAR_2_EOL ESC"[K" enum { /* Absolute max of lines eaten */ @@ -95,6 +186,9 @@ struct globals { regex_t pattern; smallint pattern_valid; #endif +#if ENABLE_FEATURE_LESS_ASK_TERMINAL + smallint winsize_err; +#endif smallint terminated; struct termios term_orig, term_less; char kbd_input[KEYCODE_BUFFER_SIZE]; @@ -165,12 +259,12 @@ static void set_tty_cooked(void) top-left corner of the console */ static void move_cursor(int line, int row) { - printf("\033[%u;%uH", line, row); + printf(ESC"[%u;%uH", line, row); } static void clear_line(void) { - printf("\033[%u;0H" CLEAR_2_EOL, max_displayed_line + 2); + printf(ESC"[%u;0H" CLEAR_2_EOL, max_displayed_line + 2); } static void print_hilite(const char *str) @@ -477,7 +571,7 @@ static void m_status_print(void) { int percentage; - if (less_gets_pos >= 0) /* don't touch statusline while input is done! */ + if (less_gets_pos >= 0) /* don't touch statusline while input is done! */ return; clear_line(); @@ -503,7 +597,7 @@ static void status_print(void) { const char *p; - if (less_gets_pos >= 0) /* don't touch statusline while input is done! */ + if (less_gets_pos >= 0) /* don't touch statusline while input is done! */ return; /* Change the status if flags have been set */ @@ -615,9 +709,9 @@ static void print_found(const char *line) /* buf[] holds quarantined version of str */ /* Each part of the line that matches has the HIGHLIGHT - and NORMAL escape sequences placed around it. - NB: we regex against line, but insert text - from quarantined copy (buf[]) */ + * and NORMAL escape sequences placed around it. + * NB: we regex against line, but insert text + * from quarantined copy (buf[]) */ str = buf; growline = NULL; eflags = 0; @@ -626,8 +720,8 @@ static void print_found(const char *line) while (match_status == 0) { char *new = xasprintf("%s%.*s"HIGHLIGHT"%.*s"NORMAL, growline ? growline : "", - match_structs.rm_so, str, - match_structs.rm_eo - match_structs.rm_so, + (int)match_structs.rm_so, str, + (int)(match_structs.rm_eo - match_structs.rm_so), str + match_structs.rm_so); free(growline); growline = new; @@ -802,12 +896,17 @@ static void reinitialize(void) cur_fline = 0; max_lineno = 0; open_file_and_read_lines(); +#if ENABLE_FEATURE_LESS_ASK_TERMINAL + if (G.winsize_err) + printf("\033[999;999H" "\033[6n"); +#endif buffer_fill_and_print(); } -static int getch_nowait(void) +static int64_t getch_nowait(void) { int rd; + int64_t key64; struct pollfd pfd[2]; pfd[0].fd = STDIN_FILENO; @@ -855,8 +954,8 @@ static int getch_nowait(void) /* We have kbd_fd in O_NONBLOCK mode, read inside read_key() * would not block even if there is no input available */ - rd = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); - if (rd == -1) { + key64 = read_key(kbd_fd, kbd_input, /*timeout off:*/ -2); + if ((int)key64 == -1) { if (errno == EAGAIN) { /* No keyboard input available. Since poll() did return, * we should have input on stdin */ @@ -868,25 +967,30 @@ static int getch_nowait(void) less_exit(0); } set_tty_cooked(); - return rd; + return key64; } /* Grab a character from input without requiring the return key. * May return KEYCODE_xxx values. * Note that this function works best with raw input. */ -static int less_getch(int pos) +static int64_t less_getch(int pos) { - int i; + int64_t key64; + int key; again: less_gets_pos = pos; - i = getch_nowait(); + key = key64 = getch_nowait(); less_gets_pos = -1; - /* Discard Ctrl-something chars */ - if (i >= 0 && i < ' ' && i != 0x0d && i != 8) + /* Discard Ctrl-something chars. + * (checking only lower 32 bits is a size optimization: + * upper 32 bits are used only by KEYCODE_CURSOR_POS) + */ + if (key >= 0 && key < ' ' && key != 0x0d && key != 8) goto again; - return i; + + return key64; } static char* less_gets(int sz) @@ -1426,6 +1530,9 @@ static void keypress_process(int keypress) break; #endif case 'r': case 'R': + /* TODO: (1) also bind ^R, ^L to this? + * (2) re-measure window size? + */ buffer_print(); break; /*case 'R': @@ -1501,7 +1608,8 @@ static void sigwinch_handler(int sig UNUSED_PARAM) int less_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int less_main(int argc, char **argv) { - int keypress; + char *tty_name; + int tty_fd; INIT_G(); @@ -1532,10 +1640,28 @@ int less_main(int argc, char **argv) if (option_mask32 & FLAG_TILDE) empty_line_marker = ""; - kbd_fd = open(CURRENT_TTY, O_RDONLY); - if (kbd_fd < 0) - return bb_cat(argv); - ndelay_on(kbd_fd); + /* Some versions of less can survive w/o controlling tty, + * try to do the same. This also allows to specify an alternative + * tty via "less 1<>TTY". + * We don't try to use STDOUT_FILENO directly, + * since we want to set this fd to non-blocking mode, + * and not bother with restoring it on exit. + */ + tty_name = xmalloc_ttyname(STDOUT_FILENO); + if (tty_name) { + tty_fd = open(tty_name, O_RDONLY); + free(tty_name); + if (tty_fd < 0) + goto try_ctty; + } else { + /* Try controlling tty */ + try_ctty: + tty_fd = open(CURRENT_TTY, O_RDONLY); + if (tty_fd < 0) + return bb_cat(argv); + } + ndelay_on(tty_fd); + kbd_fd = tty_fd; /* save in a global */ tcgetattr(kbd_fd, &term_orig); term_less = term_orig; @@ -1545,7 +1671,7 @@ int less_main(int argc, char **argv) term_less.c_cc[VMIN] = 1; term_less.c_cc[VTIME] = 0; - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(kbd_fd, &width, &max_displayed_line); /* 20: two tabstops + 4 */ if (width < 20 || max_displayed_line < 3) return bb_cat(argv); @@ -1560,11 +1686,14 @@ int less_main(int argc, char **argv) buffer = xmalloc((max_displayed_line+1) * sizeof(char *)); reinitialize(); while (1) { + int64_t keypress; + #if ENABLE_FEATURE_LESS_WINCH while (WINCH_COUNTER) { again: winch_counter--; - get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(G.winsize_err =) get_terminal_width_height(kbd_fd, &width, &max_displayed_line); + IF_FEATURE_LESS_ASK_TERMINAL(got_size:) /* 20: two tabstops + 4 */ if (width < 20) width = 20; @@ -1584,8 +1713,18 @@ int less_main(int argc, char **argv) /* This took some time. Loop back and check, * were there another SIGWINCH? */ } -#endif keypress = less_getch(-1); /* -1: do not position cursor */ +# if ENABLE_FEATURE_LESS_ASK_TERMINAL + if ((int32_t)keypress == KEYCODE_CURSOR_POS) { + uint32_t rc = (keypress >> 32); + width = (rc & 0x7fff); + max_displayed_line = ((rc >> 16) & 0x7fff); + goto got_size; + } +# endif +#else + keypress = less_getch(-1); /* -1: do not position cursor */ +#endif keypress_process(keypress); } } diff --git a/miscutils/makedevs.c b/miscutils/makedevs.c index abf5057..c945a13 100644 --- a/miscutils/makedevs.c +++ b/miscutils/makedevs.c @@ -7,6 +7,66 @@ * known bugs: can't deal with alpha ranges */ +//usage:#if ENABLE_FEATURE_MAKEDEVS_LEAF +//usage:#define makedevs_trivial_usage +//usage: "NAME TYPE MAJOR MINOR FIRST LAST [s]" +//usage:#define makedevs_full_usage "\n\n" +//usage: "Create a range of block or character special files" +//usage: "\n" +//usage: "\nTYPE is:" +//usage: "\n b Block device" +//usage: "\n c Character device" +//usage: "\n f FIFO, MAJOR and MINOR are ignored" +//usage: "\n" +//usage: "\nFIRST..LAST specify numbers appended to NAME." +//usage: "\nIf 's' is the last argument, the base device is created as well." +//usage: "\n" +//usage: "\nExamples:" +//usage: "\n makedevs /dev/ttyS c 4 66 2 63 -> ttyS2-ttyS63" +//usage: "\n makedevs /dev/hda b 3 0 0 8 s -> hda,hda1-hda8" +//usage: +//usage:#define makedevs_example_usage +//usage: "# makedevs /dev/ttyS c 4 66 2 63\n" +//usage: "[creates ttyS2-ttyS63]\n" +//usage: "# makedevs /dev/hda b 3 0 0 8 s\n" +//usage: "[creates hda,hda1-hda8]\n" +//usage:#endif +//usage: +//usage:#if ENABLE_FEATURE_MAKEDEVS_TABLE +//usage:#define makedevs_trivial_usage +//usage: "[-d device_table] rootdir" +//usage:#define makedevs_full_usage "\n\n" +//usage: "Create a range of special files as specified in a device table.\n" +//usage: "Device table entries take the form of:\n" +//usage: " \n" +//usage: "Where name is the file name, type can be one of:\n" +//usage: " f Regular file\n" +//usage: " d Directory\n" +//usage: " c Character device\n" +//usage: " b Block device\n" +//usage: " p Fifo (named pipe)\n" +//usage: "uid is the user id for the target file, gid is the group id for the\n" +//usage: "target file. The rest of the entries (major, minor, etc) apply to\n" +//usage: "to device special files. A '-' may be used for blank entries." +//usage: +//usage:#define makedevs_example_usage +//usage: "For example:\n" +//usage: " \n" +//usage: "/dev d 755 0 0 - - - - -\n" +//usage: "/dev/console c 666 0 0 5 1 - - -\n" +//usage: "/dev/null c 666 0 0 1 3 0 0 -\n" +//usage: "/dev/zero c 666 0 0 1 5 0 0 -\n" +//usage: "/dev/hda b 640 0 0 3 0 0 0 -\n" +//usage: "/dev/hda b 640 0 0 3 1 1 1 15\n\n" +//usage: "Will Produce:\n" +//usage: "/dev\n" +//usage: "/dev/console\n" +//usage: "/dev/null\n" +//usage: "/dev/zero\n" +//usage: "/dev/hda\n" +//usage: "/dev/hda[0-15]\n" +//usage:#endif + #include "libbb.h" #if ENABLE_FEATURE_MAKEDEVS_LEAF @@ -36,10 +96,10 @@ int makedevs_main(int argc, char **argv) basedev = argv[1]; buf = xasprintf("%s%u", argv[1], (unsigned)-1); type = argv[2]; - Smajor = xatoi_u(argv[3]); - Sminor = xatoi_u(argv[4]); - S = xatoi_u(argv[5]); - E = xatoi_u(argv[6]); + Smajor = xatoi_positive(argv[3]); + Sminor = xatoi_positive(argv[4]); + S = xatoi_positive(argv[5]); + E = xatoi_positive(argv[6]); nodname = argv[7] ? basedev : buf; mode = 0660; @@ -76,7 +136,7 @@ int makedevs_main(int argc, char **argv) #elif ENABLE_FEATURE_MAKEDEVS_TABLE -/* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ +/* Licensed under GPLv2 or later, see file LICENSE in this source tree. */ int makedevs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int makedevs_main(int argc UNUSED_PARAM, char **argv) @@ -121,7 +181,7 @@ int makedevs_main(int argc UNUSED_PARAM, char **argv) if ((2 > sscanf(line, "%40s %c %o %40s %40s %u %u %u %u %u", name, &type, &mode, user, group, - &major, &minor, &start, &increment, &count)) + &major, &minor, &start, &increment, &count)) || ((unsigned)(major | minor | start | count | increment) > 255) ) { bb_error_msg("invalid line %d: '%s'", linenum, line); diff --git a/miscutils/man.c b/miscutils/man.c index a4ff274..d3e832b 100644 --- a/miscutils/man.c +++ b/miscutils/man.c @@ -1,8 +1,15 @@ /* mini man implementation for busybox * Copyright (C) 2008 Denys Vlasenko - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define man_trivial_usage +//usage: "[-aw] [MANPAGE]..." +//usage:#define man_full_usage "\n\n" +//usage: "Format and display manual page\n" +//usage: "\n -a Display all pages" +//usage: "\n -w Show page locations" + #include "libbb.h" enum { @@ -23,16 +30,6 @@ echo ".pl \n(nlu+10" */ -#if ENABLE_FEATURE_SEAMLESS_LZMA -#define Z_SUFFIX ".lzma" -#elif ENABLE_FEATURE_SEAMLESS_BZ2 -#define Z_SUFFIX ".bz2" -#elif ENABLE_FEATURE_SEAMLESS_GZ -#define Z_SUFFIX ".gz" -#else -#define Z_SUFFIX "" -#endif - static int show_manpage(const char *pager, char *man_filename, int man, int level); static int run_pipe(const char *pager, char *man_filename, int man, int level) @@ -95,7 +92,7 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) /* Links do not have .gz extensions, even if manpage * is compressed */ - man_filename = xasprintf("%s/%s" Z_SUFFIX, man_filename, linkname); + man_filename = xasprintf("%s/%s", man_filename, linkname); free(line); /* Note: we leak "new" man_filename string as well... */ if (show_manpage(pager, man_filename, man, level + 1)) @@ -117,37 +114,36 @@ static int run_pipe(const char *pager, char *man_filename, int man, int level) return 1; } -/* man_filename is of the form "/dir/dir/dir/name.s" Z_SUFFIX */ +/* man_filename is of the form "/dir/dir/dir/name.s" */ static int show_manpage(const char *pager, char *man_filename, int man, int level) { -#if ENABLE_FEATURE_SEAMLESS_LZMA - if (run_pipe(pager, man_filename, man, level)) - return 1; +#if SEAMLESS_COMPRESSION + /* We leak this allocation... */ + char *filename_with_zext = xasprintf("%s.lzma", man_filename); + char *ext = strrchr(filename_with_zext, '.') + 1; #endif -#if ENABLE_FEATURE_SEAMLESS_BZ2 #if ENABLE_FEATURE_SEAMLESS_LZMA - strcpy(strrchr(man_filename, '.') + 1, "bz2"); -#endif - if (run_pipe(pager, man_filename, man, level)) + if (run_pipe(pager, filename_with_zext, man, level)) return 1; #endif - -#if ENABLE_FEATURE_SEAMLESS_GZ -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 - strcpy(strrchr(man_filename, '.') + 1, "gz"); -#endif - if (run_pipe(pager, man_filename, man, level)) +#if ENABLE_FEATURE_SEAMLESS_XZ + strcpy(ext, "xz"); + if (run_pipe(pager, filename_with_zext, man, level)) return 1; #endif - -#if ENABLE_FEATURE_SEAMLESS_LZMA || ENABLE_FEATURE_SEAMLESS_BZ2 || ENABLE_FEATURE_SEAMLESS_GZ - *strrchr(man_filename, '.') = '\0'; +#if ENABLE_FEATURE_SEAMLESS_BZ2 + strcpy(ext, "bz2"); + if (run_pipe(pager, filename_with_zext, man, level)) + return 1; #endif - if (run_pipe(pager, man_filename, man, level)) +#if ENABLE_FEATURE_SEAMLESS_GZ + strcpy(ext, "gz"); + if (run_pipe(pager, filename_with_zext, man, level)) return 1; +#endif - return 0; + return run_pipe(pager, man_filename, man, level); } int man_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -166,7 +162,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) opt = getopt32(argv, "+aw"); argv += optind; - sec_list = xstrdup("1:2:3:4:5:6:7:8:9"); + sec_list = xstrdup("0p:1:1p:2:3:3p:4:5:6:7:8:9"); /* Last valid man_path_list[] is [0x10] */ count_mp = 0; man_path_list = xzalloc(0x11 * sizeof(man_path_list[0])); @@ -182,16 +178,21 @@ int man_main(int argc UNUSED_PARAM, char **argv) pager = "more"; } - /* Parse man.conf[ig] */ + /* Parse man.conf[ig] or man_db.conf */ /* man version 1.6f uses man.config */ + /* man-db implementation of man uses man_db.conf */ parser = config_open2("/etc/man.config", fopen_for_read); if (!parser) parser = config_open2("/etc/man.conf", fopen_for_read); + if (!parser) + parser = config_open2("/etc/man_db.conf", fopen_for_read); while (config_read(parser, token, 2, 0, "# \t", PARSE_NORMAL)) { if (!token[1]) continue; - if (strcmp("MANPATH", token[0]) == 0) { + if (strcmp("MANDATORY_MANPATH"+10, token[0]) == 0 /* "MANPATH"? */ + || strcmp("MANDATORY_MANPATH", token[0]) == 0 + ) { char *path = token[1]; while (*path) { char *next_path; @@ -250,7 +251,7 @@ int man_main(int argc UNUSED_PARAM, char **argv) /* Search for cat, then man page */ while (cat0man1 < 2) { int found_here; - man_filename = xasprintf("%s/%s%.*s/%s.%.*s" Z_SUFFIX, + man_filename = xasprintf("%s/%s%.*s/%s.%.*s", cur_path, "cat\0man" + (cat0man1 * 4), sect_len, cur_sect, diff --git a/miscutils/microcom.c b/miscutils/microcom.c index 78863d4..5e29a1a 100644 --- a/miscutils/microcom.c +++ b/miscutils/microcom.c @@ -5,8 +5,19 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define microcom_trivial_usage +//usage: "[-d DELAY] [-t TIMEOUT] [-s SPEED] [-X] TTY" +//usage:#define microcom_full_usage "\n\n" +//usage: "Copy bytes for stdin to TTY and from TTY to stdout\n" +//usage: "\n -d Wait up to DELAY ms for TTY output before sending every" +//usage: "\n next byte to it" +//usage: "\n -t Exit if both stdin and TTY are silent for TIMEOUT ms" +//usage: "\n -s Set serial line to SPEED" +//usage: "\n -X Disable special meaning of NUL and Ctrl-X from stdin" + #include "libbb.h" // set raw tty mode diff --git a/miscutils/mountpoint.c b/miscutils/mountpoint.c index a35c389..7041f7c 100644 --- a/miscutils/mountpoint.c +++ b/miscutils/mountpoint.c @@ -4,11 +4,26 @@ * * Copyright (C) 2005 Bernhard Reutner-Fischer * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Based on sysvinit's mountpoint */ +//usage:#define mountpoint_trivial_usage +//usage: "[-q] <[-dn] DIR | -x DEVICE>" +//usage:#define mountpoint_full_usage "\n\n" +//usage: "Check if the directory is a mountpoint\n" +//usage: "\n -q Quiet" +//usage: "\n -d Print major/minor device number of the filesystem" +//usage: "\n -n Print device name of the filesystem" +//usage: "\n -x Print major/minor device number of the blockdevice" +//usage: +//usage:#define mountpoint_example_usage +//usage: "$ mountpoint /proc\n" +//usage: "/proc is not a mountpoint\n" +//usage: "$ mountpoint /sys\n" +//usage: "/sys is a mountpoint\n" + #include "libbb.h" int mountpoint_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/miscutils/mt.c b/miscutils/mt.c index 586373d..20afd3a 100644 --- a/miscutils/mt.c +++ b/miscutils/mt.c @@ -1,8 +1,20 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define mt_trivial_usage +//usage: "[-f device] opcode value" +//usage:#define mt_full_usage "\n\n" +//usage: "Control magnetic tape drive operation\n" +//usage: "\n" +//usage: "Available Opcodes:\n" +//usage: "\n" +//usage: "bsf bsfm bsr bss datacompression drvbuffer eof eom erase\n" +//usage: "fsf fsfm fsr fss load lock mkpart nop offline ras1 ras2\n" +//usage: "ras3 reset retension rewind rewoffline seek setblk setdensity\n" +//usage: "setpart tell unload unlock weof wset" + #include "libbb.h" #include @@ -106,9 +118,9 @@ int mt_main(int argc UNUSED_PARAM, char **argv) op.mt_op = opcode_value[idx]; if (argv[2]) - op.mt_count = xatoi_u(argv[2]); + op.mt_count = xatoi_positive(argv[2]); else - op.mt_count = 1; /* One, not zero, right? */ + op.mt_count = 1; /* One, not zero, right? */ switch (opcode_value[idx]) { case MTWEOF: diff --git a/miscutils/nandwrite.c b/miscutils/nandwrite.c new file mode 100644 index 0000000..e3f9b56 --- /dev/null +++ b/miscutils/nandwrite.c @@ -0,0 +1,239 @@ +/* + * nandwrite and nanddump ported to busybox from mtd-utils + * + * Author: Baruch Siach , Orex Computed Radiography + * + * Licensed under GPLv2, see file LICENSE in this source tree. + * + * TODO: add support for large (>4GB) MTD devices + */ + +//config:config NANDWRITE +//config: bool "nandwrite" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Write to the specified MTD device, with bad blocks awareness +//config: +//config:config NANDDUMP +//config: bool "nanddump" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Dump the content of raw NAND chip + +//applet:IF_NANDWRITE(APPLET(nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP)) +//applet:IF_NANDDUMP(APPLET_ODDNAME(nanddump, nandwrite, BB_DIR_USR_SBIN, BB_SUID_DROP, nanddump)) + +//kbuild:lib-$(CONFIG_NANDWRITE) += nandwrite.o +//kbuild:lib-$(CONFIG_NANDDUMP) += nandwrite.o + +//usage:#define nandwrite_trivial_usage +//usage: "[-p] [-s ADDR] MTD_DEVICE [FILE]" +//usage:#define nandwrite_full_usage "\n\n" +//usage: "Write to MTD_DEVICE\n" +//usage: "\n -p Pad to page size" +//usage: "\n -s ADDR Start address" + +//usage:#define nanddump_trivial_usage +//usage: "[-o] [-b] [-s ADDR] [-l LEN] [-f FILE] MTD_DEVICE" +//usage:#define nanddump_full_usage "\n\n" +//usage: "Dump MTD_DEVICE\n" +//usage: "\n -o Dump oob data" +//usage: "\n -b Omit bad block from the dump" +//usage: "\n -s ADDR Start address" +//usage: "\n -l LEN Length" +//usage: "\n -f FILE Dump to file ('-' for stdout)" + +#include "libbb.h" +#include + +#define IS_NANDDUMP (ENABLE_NANDDUMP && (!ENABLE_NANDWRITE || (applet_name[4] == 'd'))) +#define IS_NANDWRITE (ENABLE_NANDWRITE && (!ENABLE_NANDDUMP || (applet_name[4] != 'd'))) + +#define OPT_p (1 << 0) /* nandwrite only */ +#define OPT_o (1 << 0) /* nanddump only */ +#define OPT_s (1 << 1) +#define OPT_b (1 << 2) +#define OPT_f (1 << 3) +#define OPT_l (1 << 4) + +/* helper for writing out 0xff for bad blocks pad */ +static void dump_bad(struct mtd_info_user *meminfo, unsigned len, int oob) +{ + unsigned char buf[meminfo->writesize]; + unsigned count; + + /* round len to the next page */ + len = (len | ~(meminfo->writesize - 1)) + 1; + + memset(buf, 0xff, sizeof(buf)); + for (count = 0; count < len; count += meminfo->writesize) { + xwrite(STDOUT_FILENO, buf, meminfo->writesize); + if (oob) + xwrite(STDOUT_FILENO, buf, meminfo->oobsize); + } +} + +static unsigned next_good_eraseblock(int fd, struct mtd_info_user *meminfo, + unsigned block_offset) +{ + while (1) { + loff_t offs; + + if (block_offset >= meminfo->size) { + if (IS_NANDWRITE) + bb_error_msg_and_die("not enough space in MTD device"); + return block_offset; /* let the caller exit */ + } + offs = block_offset; + if (xioctl(fd, MEMGETBADBLOCK, &offs) == 0) + return block_offset; + /* ioctl returned 1 => "bad block" */ + if (IS_NANDWRITE) + printf("Skipping bad block at 0x%08x\n", block_offset); + block_offset += meminfo->erasesize; + } +} + +int nandwrite_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nandwrite_main(int argc UNUSED_PARAM, char **argv) +{ + /* Buffer for OOB data */ + unsigned char *oobbuf; + unsigned opts; + int fd; + ssize_t cnt; + unsigned mtdoffset, meminfo_writesize, blockstart, limit; + unsigned end_addr = ~0; + struct mtd_info_user meminfo; + struct mtd_oob_buf oob; + unsigned char *filebuf; + const char *opt_s = "0", *opt_f = "-", *opt_l; + + if (IS_NANDDUMP) { + opt_complementary = "=1"; + opts = getopt32(argv, "os:bf:l:", &opt_s, &opt_f, &opt_l); + } else { /* nandwrite */ + opt_complementary = "-1:?2"; + opts = getopt32(argv, "ps:", &opt_s); + } + argv += optind; + + if (IS_NANDWRITE && argv[1]) + opt_f = argv[1]; + if (!LONE_DASH(opt_f)) { + int tmp_fd = xopen(opt_f, + IS_NANDDUMP ? O_WRONLY | O_TRUNC | O_CREAT : O_RDONLY + ); + xmove_fd(tmp_fd, IS_NANDDUMP ? STDOUT_FILENO : STDIN_FILENO); + } + + fd = xopen(argv[0], IS_NANDWRITE ? O_RDWR : O_RDONLY); + xioctl(fd, MEMGETINFO, &meminfo); + + mtdoffset = xstrtou(opt_s, 0); + if (IS_NANDDUMP && (opts & OPT_l)) { + unsigned length = xstrtou(opt_l, 0); + if (length < meminfo.size - mtdoffset) + end_addr = mtdoffset + length; + } + + /* Pull it into a CPU register (hopefully) - smaller code that way */ + meminfo_writesize = meminfo.writesize; + + if (mtdoffset & (meminfo_writesize - 1)) + bb_error_msg_and_die("start address is not page aligned"); + + filebuf = xmalloc(meminfo_writesize); + oobbuf = xmalloc(meminfo.oobsize); + + oob.start = 0; + oob.length = meminfo.oobsize; + oob.ptr = oobbuf; + + blockstart = mtdoffset & ~(meminfo.erasesize - 1); + if (blockstart != mtdoffset) { + unsigned tmp; + /* mtdoffset is in the middle of an erase block, verify that + * this block is OK. Advance mtdoffset only if this block is + * bad. + */ + tmp = next_good_eraseblock(fd, &meminfo, blockstart); + if (tmp != blockstart) { + /* bad block(s), advance mtdoffset */ + if (IS_NANDDUMP && !(opts & OPT_b)) { + int bad_len = MIN(tmp, end_addr) - mtdoffset; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } + mtdoffset = tmp; + } + } + + cnt = -1; + limit = MIN(meminfo.size, end_addr); + while (mtdoffset < limit) { + int input_fd = IS_NANDWRITE ? STDIN_FILENO : fd; + int output_fd = IS_NANDWRITE ? fd : STDOUT_FILENO; + + blockstart = mtdoffset & ~(meminfo.erasesize - 1); + if (blockstart == mtdoffset) { + /* starting a new eraseblock */ + mtdoffset = next_good_eraseblock(fd, &meminfo, blockstart); + if (IS_NANDWRITE) + printf("Writing at 0x%08x\n", mtdoffset); + else if (mtdoffset > blockstart && !(opts & OPT_b)) { + int bad_len = MIN(mtdoffset, limit) - blockstart; + dump_bad(&meminfo, bad_len, opts & OPT_o); + } + if (mtdoffset >= limit) + break; + } + xlseek(fd, mtdoffset, SEEK_SET); + + /* get some more data from input */ + cnt = full_read(input_fd, filebuf, meminfo_writesize); + if (cnt == 0) { + /* even with -p, we do not pad past the end of input + * (-p only zero-pads last incomplete page) + */ + break; + } + if (cnt < meminfo_writesize) { + if (IS_NANDDUMP) + bb_error_msg_and_die("short read"); + if (!(opts & OPT_p)) + bb_error_msg_and_die("input size is not rounded up to page size, " + "use -p to zero pad"); + /* zero pad to end of write block */ + memset(filebuf + cnt, 0, meminfo_writesize - cnt); + } + xwrite(output_fd, filebuf, meminfo_writesize); + + if (IS_NANDDUMP && (opts & OPT_o)) { + /* Dump OOB data */ + oob.start = mtdoffset; + xioctl(fd, MEMREADOOB, &oob); + xwrite(output_fd, oobbuf, meminfo.oobsize); + } + + mtdoffset += meminfo_writesize; + if (cnt < meminfo_writesize) + break; + } + + if (IS_NANDWRITE && cnt != 0) { + /* We filled entire MTD, but did we reach EOF on input? */ + if (full_read(STDIN_FILENO, filebuf, meminfo_writesize) != 0) { + /* no */ + bb_error_msg_and_die("not enough space in MTD device"); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + free(filebuf); + close(fd); + } + + return EXIT_SUCCESS; +} diff --git a/miscutils/raidautorun.c b/miscutils/raidautorun.c index 113e49f..b72d890 100644 --- a/miscutils/raidautorun.c +++ b/miscutils/raidautorun.c @@ -4,10 +4,18 @@ * * Copyright (C) 2006 Bernhard Reutner-Fischer * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * */ +//usage:#define raidautorun_trivial_usage +//usage: "DEVICE" +//usage:#define raidautorun_full_usage "\n\n" +//usage: "Tell the kernel to automatically search and start RAID arrays" +//usage: +//usage:#define raidautorun_example_usage +//usage: "$ raidautorun /dev/md0" + #include "libbb.h" #include diff --git a/miscutils/readahead.c b/miscutils/readahead.c index f3b21a2..e22aaa4 100644 --- a/miscutils/readahead.c +++ b/miscutils/readahead.c @@ -7,9 +7,14 @@ * * Copyright (C) 2006 Michael Opdenacker * - * Licensed under GPLv2 or later, see file License in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define readahead_trivial_usage +//usage: "[FILE]..." +//usage:#define readahead_full_usage "\n\n" +//usage: "Preload FILEs to RAM" + #include "libbb.h" int readahead_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/miscutils/rfkill.c b/miscutils/rfkill.c index 0f5817b..7411b6f 100644 --- a/miscutils/rfkill.c +++ b/miscutils/rfkill.c @@ -4,8 +4,38 @@ * * Copyright (C) 2010 Malek Degachi * -* Licensed under the GPL v2 or later, see the file LICENSE in this tarball. +* Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//config:config RFKILL +//config: bool "rfkill" +//config: default n # doesn't build on Ubuntu 9.04 +//config: select PLATFORM_LINUX +//config: help +//config: Enable/disable wireless devices. +//config: +//config: rfkill list : list all wireless devices +//config: rfkill list bluetooth : list all bluetooth devices +//config: rfkill list 1 : list device corresponding to the given index +//config: rfkill block|unblock wlan : block/unblock all wlan(wifi) devices +//config: + +//applet:IF_RFKILL(APPLET(rfkill, BB_DIR_USR_SBIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_RFKILL) += rfkill.o + +//usage:#define rfkill_trivial_usage +//usage: "COMMAND [INDEX|TYPE]" +//usage:#define rfkill_full_usage "\n\n" +//usage: "Enable/disable wireless devices\n" +//usage: "\nCommands:" +//usage: "\n list [INDEX|TYPE] List current state" +//usage: "\n block INDEX|TYPE Disable device" +//usage: "\n unblock INDEX|TYPE Enable device" +//usage: "\n" +//usage: "\n TYPE: all, wlan(wifi), bluetooth, uwb(ultrawideband)," +//usage: "\n wimax, wwan, gps, fm" + #include "libbb.h" #include @@ -53,7 +83,7 @@ int rfkill_main(int argc UNUSED_PARAM, char **argv) rf_name = "uwb"; rf_type = index_in_strings(rfkill_types, rf_name); if (rf_type < 0) { - rf_idx = xatoi_u(rf_name); + rf_idx = xatoi_positive(rf_name); } } diff --git a/miscutils/runlevel.c b/miscutils/runlevel.c index 83b5a77..76231df 100644 --- a/miscutils/runlevel.c +++ b/miscutils/runlevel.c @@ -1,18 +1,30 @@ /* vi: set sw=4 ts=4: */ /* - * runlevel Prints out the previous and the current runlevel. + * Prints out the previous and the current runlevel. * - * Version: @(#)runlevel 1.20 16-Apr-1997 MvS + * Version: @(#)runlevel 1.20 16-Apr-1997 MvS * - * This file is part of the sysvinit suite, - * Copyright 1991-1997 Miquel van Smoorenburg. + * This file is part of the sysvinit suite, + * Copyright 1991-1997 Miquel van Smoorenburg. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * initially busyboxified by Bernhard Reutner-Fischer */ + +//usage:#define runlevel_trivial_usage +//usage: "[FILE]" +//usage:#define runlevel_full_usage "\n\n" +//usage: "Find the current and previous system runlevel\n" +//usage: "\n" +//usage: "If no utmp FILE exists or if no runlevel record can be found,\n" +//usage: "print \"unknown\"" +//usage: +//usage:#define runlevel_example_usage +//usage: "$ runlevel /var/run/utmp\n" +//usage: "N 2" + #include "libbb.h" -#include int runlevel_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int runlevel_main(int argc UNUSED_PARAM, char **argv) diff --git a/miscutils/rx.c b/miscutils/rx.c index 4c5d5a1..1dffb59 100644 --- a/miscutils/rx.c +++ b/miscutils/rx.c @@ -10,11 +10,19 @@ * * Copyright (C) 2001 Hewlett-Packard Laboratories * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * This was originally written for blob and then adapted for busybox. */ +//usage:#define rx_trivial_usage +//usage: "FILE" +//usage:#define rx_full_usage "\n\n" +//usage: "Receive a file using the xmodem protocol" +//usage: +//usage:#define rx_example_usage +//usage: "$ rx /tmp/foo\n" + #include "libbb.h" #define SOH 0x01 @@ -100,12 +108,10 @@ static int receive(/*int read_fd, */int file_fd) } } /* Write previously received block */ - if (blockLength) { - errno = 0; - if (full_write(file_fd, blockBuf, blockLength) != blockLength) { - bb_perror_msg("can't write to file"); - goto fatal; - } + errno = 0; + if (full_write(file_fd, blockBuf, blockLength) != blockLength) { + bb_perror_msg(bb_msg_write_error); + goto fatal; } timeout = TIMEOUT; @@ -147,23 +153,20 @@ static int receive(/*int read_fd, */int file_fd) blockBuf[i] = cc; } + cksum_or_crc = read_byte(TIMEOUT); + if (cksum_or_crc < 0) + goto timeout; if (do_crc) { - cksum_or_crc = read_byte(TIMEOUT); - if (cksum_or_crc < 0) - goto timeout; cksum_or_crc = (cksum_or_crc << 8) | read_byte(TIMEOUT); if (cksum_or_crc < 0) goto timeout; - } else { - cksum_or_crc = read_byte(TIMEOUT); - if (cksum_or_crc < 0) - goto timeout; } if (blockNo == ((wantBlockNo - 1) & 0xff)) { /* a repeat of the last block is ok, just ignore it. */ /* this also ignores the initial block 0 which is */ /* meta data. */ + blockLength = 0; goto next; } if (blockNo != (wantBlockNo & 0xff)) { @@ -190,8 +193,8 @@ static int receive(/*int read_fd, */int file_fd) } if (cksum_or_crc != expected) { bb_error_msg(do_crc ? "crc error, expected 0x%04x, got 0x%04x" - : "checksum error, expected 0x%02x, got 0x%02x", - expected, cksum_or_crc); + : "checksum error, expected 0x%02x, got 0x%02x", + expected, cksum_or_crc); goto error; } @@ -204,6 +207,7 @@ static int receive(/*int read_fd, */int file_fd) continue; error: timeout: + blockLength = 0; errors++; if (errors == MAXERRORS) { /* Abort */ diff --git a/miscutils/setserial.c b/miscutils/setserial.c new file mode 100644 index 0000000..dfed330 --- /dev/null +++ b/miscutils/setserial.c @@ -0,0 +1,763 @@ +/* vi: set sw=4 ts=4: */ +/* + * setserial implementation for busybox + * + * + * Copyright (C) 2011 Marek Bečka + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ + +//config:config SETSERIAL +//config: bool "setserial" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Retrieve or set Linux serial port. + +//applet:IF_SETSERIAL(APPLET(setserial, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_SETSERIAL) += setserial.o + +#include "libbb.h" +#include + +#ifndef PORT_UNKNOWN +# define PORT_UNKNOWN 0 +#endif +#ifndef PORT_8250 +# define PORT_8250 1 +#endif +#ifndef PORT_16450 +# define PORT_16450 2 +#endif +#ifndef PORT_16550 +# define PORT_16550 3 +#endif +#ifndef PORT_16550A +# define PORT_16550A 4 +#endif +#ifndef PORT_CIRRUS +# define PORT_CIRRUS 5 +#endif +#ifndef PORT_16650 +# define PORT_16650 6 +#endif +#ifndef PORT_16650V2 +# define PORT_16650V2 7 +#endif +#ifndef PORT_16750 +# define PORT_16750 8 +#endif +#ifndef PORT_STARTECH +# define PORT_STARTECH 9 +#endif +#ifndef PORT_16C950 +# define PORT_16C950 10 +#endif +#ifndef PORT_16654 +# define PORT_16654 11 +#endif +#ifndef PORT_16850 +# define PORT_16850 12 +#endif +#ifndef PORT_RSA +# define PORT_RSA 13 +#endif +#ifndef PORT_NS16550A +# define PORT_NS16550A 14 +#endif +#ifndef PORT_XSCALE +# define PORT_XSCALE 15 +#endif +#ifndef PORT_RM9000 +# define PORT_RM9000 16 +#endif +#ifndef PORT_OCTEON +# define PORT_OCTEON 17 +#endif +#ifndef PORT_AR7 +# define PORT_AR7 18 +#endif +#ifndef PORT_U6_16550A +# define PORT_U6_16550A 19 +#endif + +#ifndef ASYNCB_HUP_NOTIFY +# define ASYNCB_HUP_NOTIFY 0 +#endif +#ifndef ASYNCB_FOURPORT +# define ASYNCB_FOURPORT 1 +#endif +#ifndef ASYNCB_SAK +# define ASYNCB_SAK 2 +#endif +#ifndef ASYNCB_SPLIT_TERMIOS +# define ASYNCB_SPLIT_TERMIOS 3 +#endif +#ifndef ASYNCB_SPD_HI +# define ASYNCB_SPD_HI 4 +#endif +#ifndef ASYNCB_SPD_VHI +# define ASYNCB_SPD_VHI 5 +#endif +#ifndef ASYNCB_SKIP_TEST +# define ASYNCB_SKIP_TEST 6 +#endif +#ifndef ASYNCB_AUTO_IRQ +# define ASYNCB_AUTO_IRQ 7 +#endif +#ifndef ASYNCB_SESSION_LOCKOUT +# define ASYNCB_SESSION_LOCKOUT 8 +#endif +#ifndef ASYNCB_PGRP_LOCKOUT +# define ASYNCB_PGRP_LOCKOUT 9 +#endif +#ifndef ASYNCB_CALLOUT_NOHUP +# define ASYNCB_CALLOUT_NOHUP 10 +#endif +#ifndef ASYNCB_SPD_SHI +# define ASYNCB_SPD_SHI 12 +#endif +#ifndef ASYNCB_LOW_LATENCY +# define ASYNCB_LOW_LATENCY 13 +#endif +#ifndef ASYNCB_BUGGY_UART +# define ASYNCB_BUGGY_UART 14 +#endif + +#ifndef ASYNC_HUP_NOTIFY +# define ASYNC_HUP_NOTIFY (1U << ASYNCB_HUP_NOTIFY) +#endif +#ifndef ASYNC_FOURPORT +# define ASYNC_FOURPORT (1U << ASYNCB_FOURPORT) +#endif +#ifndef ASYNC_SAK +# define ASYNC_SAK (1U << ASYNCB_SAK) +#endif +#ifndef ASYNC_SPLIT_TERMIOS +# define ASYNC_SPLIT_TERMIOS (1U << ASYNCB_SPLIT_TERMIOS) +#endif +#ifndef ASYNC_SPD_HI +# define ASYNC_SPD_HI (1U << ASYNCB_SPD_HI) +#endif +#ifndef ASYNC_SPD_VHI +# define ASYNC_SPD_VHI (1U << ASYNCB_SPD_VHI) +#endif +#ifndef ASYNC_SKIP_TEST +# define ASYNC_SKIP_TEST (1U << ASYNCB_SKIP_TEST) +#endif +#ifndef ASYNC_AUTO_IRQ +# define ASYNC_AUTO_IRQ (1U << ASYNCB_AUTO_IRQ) +#endif +#ifndef ASYNC_SESSION_LOCKOUT +# define ASYNC_SESSION_LOCKOUT (1U << ASYNCB_SESSION_LOCKOUT) +#endif +#ifndef ASYNC_PGRP_LOCKOUT +# define ASYNC_PGRP_LOCKOUT (1U << ASYNCB_PGRP_LOCKOUT) +#endif +#ifndef ASYNC_CALLOUT_NOHUP +# define ASYNC_CALLOUT_NOHUP (1U << ASYNCB_CALLOUT_NOHUP) +#endif +#ifndef ASYNC_SPD_SHI +# define ASYNC_SPD_SHI (1U << ASYNCB_SPD_SHI) +#endif +#ifndef ASYNC_LOW_LATENCY +# define ASYNC_LOW_LATENCY (1U << ASYNCB_LOW_LATENCY) +#endif +#ifndef ASYNC_BUGGY_UART +# define ASYNC_BUGGY_UART (1U << ASYNCB_BUGGY_UART) +#endif + +#ifndef ASYNC_SPD_CUST +# define ASYNC_SPD_CUST (ASYNC_SPD_HI|ASYNC_SPD_VHI) +#endif +#ifndef ASYNC_SPD_WARP +# define ASYNC_SPD_WARP (ASYNC_SPD_HI|ASYNC_SPD_SHI) +#endif +#ifndef ASYNC_SPD_MASK +# define ASYNC_SPD_MASK (ASYNC_SPD_HI|ASYNC_SPD_VHI|ASYNC_SPD_SHI) +#endif + +#ifndef ASYNC_CLOSING_WAIT_INF +# define ASYNC_CLOSING_WAIT_INF 0 +#endif +#ifndef ASYNC_CLOSING_WAIT_NONE +# define ASYNC_CLOSING_WAIT_NONE 65535 +#endif + +#ifndef _LINUX_SERIAL_H +struct serial_struct { + int type; + int line; + unsigned int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char io_type; + char reserved_char[1]; + int hub6; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + unsigned char *iomem_base; + unsigned short iomem_reg_shift; + unsigned int port_high; + unsigned long iomap_base; /* cookie passed into ioremap */ +}; +#endif + +//usage:#define setserial_trivial_usage +//usage: "[-gabGvzV] DEVICE [PARAMETER [ARG]]..." +//usage:#define setserial_full_usage "\n\n" +//usage: "Request or set Linux serial port information\n" +//usage: "\n" +//usage: " -g Interpret parameters as list of devices for reporting\n" +//usage: " -a Print all available information\n" +//usage: " -b Print summary information\n" +//usage: " -G Print in form which can be fed back\n" +//usage: " to setserial as command line parameters\n" +//usage: " -z Zero out serial flags before setting\n" +//usage: " -v Verbose\n" +//usage: "\n" +//usage: "Parameters: (* = takes an argument, ^ = can be turned off by preceding ^)\n" +//usage: " *port, *irq, *divisor, *uart, *baud_base, *close_delay, *closing_wait,\n" +//usage: " ^fourport, ^auto_irq, ^skip_test, ^sak, ^session_lockout, ^pgrp_lockout,\n" +//usage: " ^callout_nohup, ^split_termios, ^hup_notify, ^low_latency, autoconfig,\n" +//usage: " spd_normal, spd_hi, spd_vhi, spd_shi, spd_warp, spd_cust\n" +//usage: "\n" +//usage: "UART types:\n" +//usage: " unknown, 8250, 16450, 16550, 16550A, Cirrus, 16650, 16650V2, 16750,\n" +//usage: " 16950, 16954, 16654, 16850, RSA, NS16550A, XSCALE, RM9000, OCTEON, AR7,\n" +//usage: " U6_16550A" + +#define OPT_PRINT_SUMMARY (1 << 0) +#define OPT_PRINT_FEDBACK (1 << 1) +#define OPT_PRINT_ALL (1 << 2) +#define OPT_VERBOSE (1 << 3) +#define OPT_ZERO (1 << 4) +#define OPT_GET (1 << 5) + +#define OPT_MODE_MASK \ + (OPT_PRINT_ALL | OPT_PRINT_SUMMARY | OPT_PRINT_FEDBACK) + +enum print_mode +{ + PRINT_NORMAL = 0, + PRINT_SUMMARY = (1 << 0), + PRINT_FEDBACK = (1 << 1), + PRINT_ALL = (1 << 2), +}; + +#define CTL_SET (1 << 0) +#define CTL_CONFIG (1 << 1) +#define CTL_GET (1 << 2) +#define CTL_CLOSE (1 << 3) +#define CTL_NODIE (1 << 4) + +static const char serial_types[] = + "unknown\0" /* 0 */ + "8250\0" /* 1 */ + "16450\0" /* 2 */ + "16550\0" /* 3 */ + "16550A\0" /* 4 */ + "Cirrus\0" /* 5 */ + "16650\0" /* 6 */ + "16650V2\0" /* 7 */ + "16750\0" /* 8 */ + "16950\0" /* 9 UNIMPLEMENTED: also know as "16950/954" */ + "16954\0" /* 10 */ + "16654\0" /* 11 */ + "16850\0" /* 12 */ + "RSA\0" /* 13 */ +#ifndef SETSERIAL_BASE + "NS16550A\0" /* 14 */ + "XSCALE\0" /* 15 */ + "RM9000\0" /* 16 */ + "OCTEON\0" /* 17 */ + "AR7\0" /* 18 */ + "U6_16550A\0" /* 19 */ +#endif +; + +#ifndef SETSERIAL_BASE +# define MAX_SERIAL_TYPE 19 +#else +# define MAX_SERIAL_TYPE 13 +#endif + +static const char commands[] = + "spd_normal\0" + "spd_hi\0" + "spd_vhi\0" + "spd_shi\0" + "spd_warp\0" + "spd_cust\0" + + "sak\0" + "fourport\0" + "hup_notify\0" + "skip_test\0" + "auto_irq\0" + "split_termios\0" + "session_lockout\0" + "pgrp_lockout\0" + "callout_nohup\0" + "low_latency\0" + + "port\0" + "irq\0" + "divisor\0" + "uart\0" + "baud_base\0" + "close_delay\0" + "closing_wait\0" + + "autoconfig\0" +; + +enum +{ + CMD_SPD_NORMAL = 0, + CMD_SPD_HI, + CMD_SPD_VHI, + CMD_SPD_SHI, + CMD_SPD_WARP, + CMD_SPD_CUST, + + CMD_FLAG_SAK, + CMD_FLAG_FOURPORT, + CMD_FLAG_NUP_NOTIFY, + CMD_FLAG_SKIP_TEST, + CMD_FLAG_AUTO_IRQ, + CMD_FLAG_SPLIT_TERMIOS, + CMD_FLAG_SESSION_LOCKOUT, + CMD_FLAG_PGRP_LOCKOUT, + CMD_FLAG_CALLOUT_NOHUP, + CMD_FLAG_LOW_LATENCY, + + CMD_PORT, + CMD_IRQ, + CMD_DIVISOR, + CMD_UART, + CMD_BASE, + CMD_DELAY, + CMD_WAIT, + + CMD_AUTOCONFIG, + + CMD_FLAG_FIRST = CMD_FLAG_SAK, + CMD_FLAG_LAST = CMD_FLAG_LOW_LATENCY, +}; + +static bool cmd_noprint(int cmd) +{ + return (cmd >= CMD_FLAG_SKIP_TEST && cmd <= CMD_FLAG_CALLOUT_NOHUP); +} + +static bool cmd_is_flag(int cmd) +{ + return (cmd >= CMD_FLAG_FIRST && cmd <= CMD_FLAG_LAST); +} + +static bool cmd_need_arg(int cmd) +{ + return (cmd >= CMD_PORT && cmd <= CMD_WAIT); +} + +#define ALL_SPD ( \ + ASYNC_SPD_HI | ASYNC_SPD_VHI | ASYNC_SPD_SHI | \ + ASYNC_SPD_WARP | ASYNC_SPD_CUST \ + ) + +#define ALL_FLAGS ( \ + ASYNC_SAK | ASYNC_FOURPORT | ASYNC_HUP_NOTIFY | \ + ASYNC_SKIP_TEST | ASYNC_AUTO_IRQ | ASYNC_SPLIT_TERMIOS | \ + ASYNC_SESSION_LOCKOUT | ASYNC_PGRP_LOCKOUT | ASYNC_CALLOUT_NOHUP | \ + ASYNC_LOW_LATENCY \ + ) + +#if (ALL_SPD | ALL_FLAGS) > 0xffff +# error "Unexpected flags size" +#endif + +static const uint16_t setbits[CMD_FLAG_LAST + 1] = +{ + 0, + ASYNC_SPD_HI, + ASYNC_SPD_VHI, + ASYNC_SPD_SHI, + ASYNC_SPD_WARP, + ASYNC_SPD_CUST, + + ASYNC_SAK, + ASYNC_FOURPORT, + ASYNC_HUP_NOTIFY, + ASYNC_SKIP_TEST, + ASYNC_AUTO_IRQ, + ASYNC_SPLIT_TERMIOS, + ASYNC_SESSION_LOCKOUT, + ASYNC_PGRP_LOCKOUT, + ASYNC_CALLOUT_NOHUP, + ASYNC_LOW_LATENCY +}; + +static const char STR_INFINITE[] = "infinite"; +static const char STR_NONE[] = "none"; + +static const char *uart_type(int type) +{ + if (type > MAX_SERIAL_TYPE) + return "undefined"; + + return nth_string(serial_types, type); +} + +/* libbb candidate */ +static int index_in_strings_case_insensitive(const char *strings, const char *key) +{ + int idx = 0; + + while (*strings) { + if (strcasecmp(strings, key) == 0) { + return idx; + } + strings += strlen(strings) + 1; /* skip NUL */ + idx++; + } + return -1; +} + +static int uart_id(const char *name) +{ + return index_in_strings_case_insensitive(serial_types, name); +} + +static const char *get_spd(int flags, enum print_mode mode) +{ + int idx; + + switch (flags & ASYNC_SPD_MASK) { + case ASYNC_SPD_HI: + idx = CMD_SPD_HI; + break; + case ASYNC_SPD_VHI: + idx = CMD_SPD_VHI; + break; + case ASYNC_SPD_SHI: + idx = CMD_SPD_SHI; + break; + case ASYNC_SPD_WARP: + idx = CMD_SPD_WARP; + break; + case ASYNC_SPD_CUST: + idx = CMD_SPD_CUST; + break; + default: + if (mode < PRINT_FEDBACK) + return NULL; + idx = CMD_SPD_NORMAL; + } + + return nth_string(commands, idx); +} + +static int get_numeric(const char *arg) +{ + return bb_strtol(arg, NULL, 0); +} + +static int get_wait(const char *arg) +{ + if (strcasecmp(arg, STR_NONE) == 0) + return ASYNC_CLOSING_WAIT_NONE; + + if (strcasecmp(arg, STR_INFINITE) == 0) + return ASYNC_CLOSING_WAIT_INF; + + return get_numeric(arg); +} + +static int get_uart(const char *arg) +{ + int uart = uart_id(arg); + + if (uart < 0) + bb_error_msg_and_die("illegal UART type: %s", arg); + + return uart; +} + +static int serial_open(const char *dev, bool quiet) +{ + int fd; + + fd = device_open(dev, O_RDWR | O_NONBLOCK); + if (fd < 0 && !quiet) + bb_simple_perror_msg(dev); + + return fd; +} + +static int serial_ctl(int fd, int ops, struct serial_struct *serinfo) +{ + int ret = 0; + const char *err; + + if (ops & CTL_SET) { + ret = ioctl(fd, TIOCSSERIAL, serinfo); + if (ret < 0) { + err = "can't set serial info"; + goto fail; + } + } + + if (ops & CTL_CONFIG) { + ret = ioctl(fd, TIOCSERCONFIG); + if (ret < 0) { + err = "can't autoconfigure port"; + goto fail; + } + } + + if (ops & CTL_GET) { + ret = ioctl(fd, TIOCGSERIAL, serinfo); + if (ret < 0) { + err = "can't get serial info"; + goto fail; + } + } + nodie: + if (ops & CTL_CLOSE) + close(fd); + + return ret; + fail: + bb_simple_perror_msg(err); + if (ops & CTL_NODIE) + goto nodie; + exit(EXIT_FAILURE); +} + +static void print_flag(const char **prefix, const char *flag) +{ + printf("%s%s", *prefix, flag); + *prefix = " "; +} + +static void print_serial_flags(int serial_flags, enum print_mode mode, + const char *prefix, const char *postfix) +{ + int i; + const char *spd, *pr; + + pr = prefix; + + spd = get_spd(serial_flags, mode); + if (spd) + print_flag(&pr, spd); + + for (i = CMD_FLAG_FIRST; i <= CMD_FLAG_LAST; i++) { + if ((serial_flags & setbits[i]) + && (mode > PRINT_SUMMARY || !cmd_noprint(i)) + ) { + print_flag(&pr, nth_string(commands, i)); + } + } + + puts(pr == prefix ? "" : postfix); +} + +static void print_closing_wait(unsigned int closing_wait) +{ + switch (closing_wait) { + case ASYNC_CLOSING_WAIT_NONE: + puts(STR_NONE); + break; + case ASYNC_CLOSING_WAIT_INF: + puts(STR_INFINITE); + break; + default: + printf("%u\n", closing_wait); + } +} + +static void serial_get(const char *device, enum print_mode mode) +{ + int fd, ret; + const char *uart, *prefix, *postfix; + struct serial_struct serinfo; + + fd = serial_open(device, /*quiet:*/ mode == PRINT_SUMMARY); + if (fd < 0) + return; + + ret = serial_ctl(fd, CTL_GET | CTL_CLOSE | CTL_NODIE, &serinfo); + if (ret < 0) + return; + + uart = uart_type(serinfo.type); + prefix = ", Flags: "; + postfix = ""; + + switch (mode) { + case PRINT_NORMAL: + printf("%s, UART: %s, Port: 0x%.4x, IRQ: %d", + device, uart, serinfo.port, serinfo.irq); + break; + case PRINT_SUMMARY: + if (!serinfo.type) + return; + printf("%s at 0x%.4x (irq = %d) is a %s", + device, serinfo.port, serinfo.irq, uart); + prefix = " ("; + postfix = ")"; + break; + case PRINT_FEDBACK: + printf("%s uart %s port 0x%.4x irq %d baud_base %d", device, + uart, serinfo.port, serinfo.irq, serinfo.baud_base); + prefix = " "; + break; + case PRINT_ALL: + printf("%s, Line %d, UART: %s, Port: 0x%.4x, IRQ: %d\n", + device, serinfo.line, uart, serinfo.port, serinfo.irq); + printf("\tBaud_base: %d, close_delay: %u, divisor: %d\n", + serinfo.baud_base, serinfo.close_delay, + serinfo.custom_divisor); + printf("\tclosing_wait: "); + print_closing_wait(serinfo.closing_wait); + prefix = "\tFlags: "; + postfix = "\n"; + break; + default: + assert(0); + } + + print_serial_flags(serinfo.flags, mode, prefix, postfix); +} + +static int find_cmd(const char *cmd) +{ + int idx; + + idx = index_in_strings_case_insensitive(commands, cmd); + if (idx < 0) + bb_error_msg_and_die("invalid flag: %s", cmd); + + return idx; +} + +static void serial_set(char **arg, int opts) +{ + struct serial_struct serinfo; + int cmd; + const char *word; + int fd; + + fd = serial_open(*arg++, /*quiet:*/ false); + if (fd < 0) + exit(201); + + serial_ctl(fd, CTL_GET, &serinfo); + + if (opts & OPT_ZERO) + serinfo.flags = 0; + + while (*arg) { + int invert; + + word = *arg++; + invert = (*word == '^'); + word += invert; + + cmd = find_cmd(word); + + if (*arg == NULL && cmd_need_arg(cmd)) + bb_error_msg_and_die(bb_msg_requires_arg, word); + + if (invert && !cmd_is_flag(cmd)) + bb_error_msg_and_die("can't invert %s", word); + + switch (cmd) { + case CMD_SPD_NORMAL: + case CMD_SPD_HI: + case CMD_SPD_VHI: + case CMD_SPD_SHI: + case CMD_SPD_WARP: + case CMD_SPD_CUST: + serinfo.flags &= ~ASYNC_SPD_MASK; + /* fallthrough */ + case CMD_FLAG_SAK: + case CMD_FLAG_FOURPORT: + case CMD_FLAG_NUP_NOTIFY: + case CMD_FLAG_SKIP_TEST: + case CMD_FLAG_AUTO_IRQ: + case CMD_FLAG_SPLIT_TERMIOS: + case CMD_FLAG_SESSION_LOCKOUT: + case CMD_FLAG_PGRP_LOCKOUT: + case CMD_FLAG_CALLOUT_NOHUP: + case CMD_FLAG_LOW_LATENCY: + if (invert) + serinfo.flags &= ~setbits[cmd]; + else + serinfo.flags |= setbits[cmd]; + break; + case CMD_PORT: + serinfo.port = get_numeric(*arg++); + break; + case CMD_IRQ: + serinfo.irq = get_numeric(*arg++); + break; + case CMD_DIVISOR: + serinfo.custom_divisor = get_numeric(*arg++); + break; + case CMD_UART: + serinfo.type = get_uart(*arg++); + break; + case CMD_BASE: + serinfo.baud_base = get_numeric(*arg++); + break; + case CMD_DELAY: + serinfo.close_delay = get_numeric(*arg++); + break; + case CMD_WAIT: + serinfo.closing_wait = get_wait(*arg++); + break; + case CMD_AUTOCONFIG: + serial_ctl(fd, CTL_SET | CTL_CONFIG | CTL_GET, &serinfo); + break; + default: + assert(0); + } + } + + serial_ctl(fd, CTL_SET | CTL_CLOSE, &serinfo); +} + +int setserial_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setserial_main(int argc UNUSED_PARAM, char **argv) +{ + int opts; + + opt_complementary = "-1:b-aG:G-ab:a-bG"; + opts = getopt32(argv, "bGavzg"); + argv += optind; + + if (!argv[1]) /* one arg only? */ + opts |= OPT_GET; + + if (!(opts & OPT_GET)) { + serial_set(argv, opts); + argv[1] = NULL; + } + + if (opts & (OPT_VERBOSE | OPT_GET)) { + do { + serial_get(*argv++, opts & OPT_MODE_MASK); + } while (*argv); + } + + return EXIT_SUCCESS; +} diff --git a/miscutils/setsid.c b/miscutils/setsid.c index c573fae..637081b 100644 --- a/miscutils/setsid.c +++ b/miscutils/setsid.c @@ -14,6 +14,13 @@ * - busyboxed */ +//usage:#define setsid_trivial_usage +//usage: "PROG ARGS" +//usage:#define setsid_full_usage "\n\n" +//usage: "Run PROG in a new session. PROG will have no controlling terminal\n" +//usage: "and will not be affected by keyboard signals (Ctrl-C etc).\n" +//usage: "See setsid(2) for details." + #include "libbb.h" int setsid_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -24,7 +31,17 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) /* setsid() is allowed only when we are not a process group leader. * Otherwise our PID serves as PGID of some existing process group - * and cannot be used as PGID of a new process group. */ + * and cannot be used as PGID of a new process group. + * + * Example: setsid() below fails when run alone in interactive shell: + * $ setsid PROG + * because shell's child (setsid) is put in a new process group. + * But doesn't fail if shell is not interactive + * (and therefore doesn't create process groups for pipes), + * or if setsid is not the first process in the process group: + * $ true | setsid PROG + * or if setsid is executed in backquotes (`setsid PROG`)... + */ if (setsid() < 0) { pid_t pid = fork_or_rexec(argv); if (pid != 0) { @@ -36,7 +53,7 @@ int setsid_main(int argc UNUSED_PARAM, char **argv) * However, the code is larger and upstream * does not do such trick. */ - exit(EXIT_SUCCESS); + return EXIT_SUCCESS; } /* child */ diff --git a/miscutils/strings.c b/miscutils/strings.c index b4c5854..9f50182 100644 --- a/miscutils/strings.c +++ b/miscutils/strings.c @@ -4,15 +4,24 @@ * * Copyright 2003 Tito Ragusa * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define strings_trivial_usage +//usage: "[-afo] [-n LEN] [FILE]..." +//usage:#define strings_full_usage "\n\n" +//usage: "Display printable strings in a binary file\n" +//usage: "\n -a Scan whole file (default)" +//usage: "\n -f Precede strings with filenames" +//usage: "\n -n LEN At least LEN characters form a string (default 4)" +//usage: "\n -o Precede strings with decimal offsets" + #include "libbb.h" -#define WHOLE_FILE 1 -#define PRINT_NAME 2 -#define PRINT_OFFSET 4 -#define SIZE 8 +#define WHOLE_FILE 1 +#define PRINT_NAME 2 +#define PRINT_OFFSET 4 +#define SIZE 8 int strings_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int strings_main(int argc UNUSED_PARAM, char **argv) diff --git a/miscutils/taskset.c b/miscutils/taskset.c index 08198d5..4a9e323 100644 --- a/miscutils/taskset.c +++ b/miscutils/taskset.c @@ -3,9 +3,26 @@ * taskset - retrieve or set a processes' CPU affinity * Copyright (c) 2006 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define taskset_trivial_usage +//usage: "[-p] [MASK] [PID | PROG ARGS]" +//usage:#define taskset_full_usage "\n\n" +//usage: "Set or get CPU affinity\n" +//usage: "\n -p Operate on an existing PID" +//usage: +//usage:#define taskset_example_usage +//usage: "$ taskset 0x7 ./dgemm_test&\n" +//usage: "$ taskset -p 0x1 $!\n" +//usage: "pid 4790's current affinity mask: 7\n" +//usage: "pid 4790's new affinity mask: 1\n" +//usage: "$ taskset 0x7 /bin/sh -c './taskset -p 0x1 $$'\n" +//usage: "pid 6671's current affinity mask: 1\n" +//usage: "pid 6671's new affinity mask: 1\n" +//usage: "$ taskset -p 1\n" +//usage: "pid 1's current affinity mask: 3\n" + #include #include "libbb.h" diff --git a/miscutils/time.c b/miscutils/time.c index 9facc36..19b0b44 100644 --- a/miscutils/time.c +++ b/miscutils/time.c @@ -2,14 +2,21 @@ /* 'time' utility to display resource usage of processes. Copyright (C) 1990, 91, 92, 93, 96 Free Software Foundation, Inc. - Licensed under GPL version 2, see file LICENSE in this tarball for details. + Licensed under GPLv2, see file LICENSE in this source tree. */ /* Originally written by David Keppel . Heavily modified by David MacKenzie . Heavily modified for busybox by Erik Andersen */ +//usage:#define time_trivial_usage +//usage: "[-v] PROG ARGS" +//usage:#define time_full_usage "\n\n" +//usage: "Run PROG, display resource usage when it exits\n" +//usage: "\n -v Verbose" + #include "libbb.h" +#include /* getrusage */ /* Information on the resources used by a child process. */ typedef struct { @@ -63,7 +70,7 @@ static void resuse_end(pid_t pid, resource_t *resp) pid_t caught; /* Ignore signals, but don't ignore the children. When wait3 - returns the child process, set the time the command finished. */ + * returns the child process, set the time the command finished. */ while ((caught = wait3(&resp->waitstatus, 0, &resp->ru)) != pid) { if (caught == -1 && errno != EINTR) { bb_perror_msg("wait"); diff --git a/miscutils/timeout.c b/miscutils/timeout.c index 48b8d8f..9d56593 100644 --- a/miscutils/timeout.c +++ b/miscutils/timeout.c @@ -28,6 +28,12 @@ * rewrite 14-11-2008 vda */ +//usage:#define timeout_trivial_usage +//usage: "[-t SECS] [-s SIG] PROG ARGS" +//usage:#define timeout_full_usage "\n\n" +//usage: "Runs PROG. Sends SIG to it if it is not gone in SECS seconds.\n" +//usage: "Defaults: SECS: 10, SIG: TERM." + #include "libbb.h" int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -83,7 +89,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) bb_daemonize_or_rexec(0, argv); /* Here we are grandchild. Sleep, then kill grandparent */ grandchild: - /* Just sleep(NUGE_NUM); kill(parent) may kill wrong process! */ + /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ while (1) { sleep(1); if (--timeout <= 0) diff --git a/miscutils/ttysize.c b/miscutils/ttysize.c index ca9a2ec..d2d48d0 100644 --- a/miscutils/ttysize.c +++ b/miscutils/ttysize.c @@ -7,8 +7,14 @@ * * Copyright (C) 2007 by Denys Vlasenko * - * Licensed under the GPL v2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define ttysize_trivial_usage +//usage: "[w] [h]" +//usage:#define ttysize_full_usage "\n\n" +//usage: "Print dimension(s) of stdin's terminal, on error return 80x25" + #include "libbb.h" int ttysize_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/miscutils/ubi_attach_detach.c b/miscutils/ubi_attach_detach.c deleted file mode 100644 index 7b92a8a..0000000 --- a/miscutils/ubi_attach_detach.c +++ /dev/null @@ -1,88 +0,0 @@ -/* Ported to busybox from mtd-utils. - * - * Licensed under GPLv2, see file LICENSE in this tarball for details. - */ - -//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_attach_detach, _BB_DIR_USR_SBIN, _BB_SUID_DROP, ubiattach)) -//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_attach_detach, _BB_DIR_USR_SBIN, _BB_SUID_DROP, ubidetach)) - -//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_attach_detach.o -//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_attach_detach.o - -//config:config UBIATTACH -//config: bool "ubiattach" -//config: default n -//config: help -//config: Attach MTD device to an UBI device. -//config: -//config:config UBIDETACH -//config: bool "ubidetach" -//config: default n -//config: help -//config: Detach MTD device from an UBI device. - -#include "libbb.h" -#include - -#define OPTION_M (1 << 0) -#define OPTION_D (1 << 1) - -#define do_attach (ENABLE_UBIATTACH && \ - (!ENABLE_UBIDETACH || (applet_name[3] == 'a'))) - -//usage:#define ubiattach_trivial_usage -//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" -//usage:#define ubiattach_full_usage "\n\n" -//usage: "Attach MTD device to UBI\n" -//usage: "\nOptions:" -//usage: "\n -m MTD_NUM MTD device number to attach" -//usage: "\n -d UBI_NUM UBI device number to assign" -//usage: -//usage:#define ubidetach_trivial_usage -//usage: "-d UBI_NUM UBI_CTRL_DEV" -//usage:#define ubidetach_full_usage "\n\n" -//usage: "Detach MTD device from UBI\n" -//usage: "\nOptions:" -//usage: "\n -d UBI_NUM UBI device number" - -int ubi_attach_detach_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int ubi_attach_detach_main(int argc UNUSED_PARAM, char **argv) -{ - unsigned opts; - char *ubi_ctrl; - //struct stat st; - struct ubi_attach_req req; - int fd; - int mtd_num; - int dev_num = UBI_DEV_NUM_AUTO; - - opt_complementary = "=1:m+:d+"; - opts = getopt32(argv, "m:d:", &mtd_num, &dev_num); - ubi_ctrl = argv[optind]; - - fd = xopen(ubi_ctrl, O_RDWR); - //fstat(fd, &st); - //if (!S_ISCHR(st.st_mode)) - // bb_error_msg_and_die("'%s' is not a char device", ubi_ctrl); - - if (do_attach) { - if (!(opts & OPTION_M)) - bb_error_msg_and_die("%s device not specified", "MTD"); - - memset(&req, 0, sizeof(req)); - req.mtd_num = mtd_num; - req.ubi_num = dev_num; - - xioctl(fd, UBI_IOCATT, &req); - } else { /* detach */ - if (!(opts & OPTION_D)) - bb_error_msg_and_die("%s device not specified", "UBI"); - - xioctl(fd, UBI_IOCDET, &dev_num); - } - - if (ENABLE_FEATURE_CLEAN_UP) - close(fd); - - return EXIT_SUCCESS; -} diff --git a/miscutils/ubi_tools.c b/miscutils/ubi_tools.c new file mode 100644 index 0000000..b713935 --- /dev/null +++ b/miscutils/ubi_tools.c @@ -0,0 +1,327 @@ +/* Ported to busybox from mtd-utils. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UBIATTACH +//config: bool "ubiattach" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Attach MTD device to an UBI device. +//config: +//config:config UBIDETACH +//config: bool "ubidetach" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Detach MTD device from an UBI device. +//config: +//config:config UBIMKVOL +//config: bool "ubimkvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Create a UBI volume. +//config: +//config:config UBIRMVOL +//config: bool "ubirmvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Delete a UBI volume. +//config: +//config:config UBIRSVOL +//config: bool "ubirsvol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Resize a UBI volume. +//config: +//config:config UBIUPDATEVOL +//config: bool "ubiupdatevol" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: Update a UBI volume. + +//applet:IF_UBIATTACH(APPLET_ODDNAME(ubiattach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiattach)) +//applet:IF_UBIDETACH(APPLET_ODDNAME(ubidetach, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubidetach)) +//applet:IF_UBIMKVOL(APPLET_ODDNAME(ubimkvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubimkvol)) +//applet:IF_UBIRMVOL(APPLET_ODDNAME(ubirmvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirmvol)) +//applet:IF_UBIRSVOL(APPLET_ODDNAME(ubirsvol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubirsvol)) +//applet:IF_UBIUPDATEVOL(APPLET_ODDNAME(ubiupdatevol, ubi_tools, BB_DIR_USR_SBIN, BB_SUID_DROP, ubiupdatevol)) + +//kbuild:lib-$(CONFIG_UBIATTACH) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIDETACH) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIMKVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIRMVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIRSVOL) += ubi_tools.o +//kbuild:lib-$(CONFIG_UBIUPDATEVOL) += ubi_tools.o + +#include "libbb.h" +/* Some versions of kernel have broken headers, need this hack */ +#ifndef __packed +# define __packed __attribute__((packed)) +#endif +#include + +#define do_attach (ENABLE_UBIATTACH && applet_name[3] == 'a') +#define do_detach (ENABLE_UBIDETACH && applet_name[3] == 'd') +#define do_mkvol (ENABLE_UBIMKVOL && applet_name[3] == 'm') +#define do_rmvol (ENABLE_UBIRMVOL && applet_name[4] == 'm') +#define do_rsvol (ENABLE_UBIRSVOL && applet_name[4] == 's') +#define do_update (ENABLE_UBIUPDATEVOL && applet_name[3] == 'u') + +static unsigned get_num_from_file(const char *path, unsigned max, const char *errmsg) +{ + char buf[sizeof(long long)*3]; + unsigned long long num; + + if (open_read_close(path, buf, sizeof(buf)) < 0) + bb_perror_msg_and_die(errmsg, path); + /* It can be \n terminated, xatoull won't work well */ + if (sscanf(buf, "%llu", &num) != 1 || num > max) + bb_error_msg_and_die(errmsg, path); + return num; +} + +/* To prevent malloc(1G) accidents */ +#define MAX_SANE_ERASEBLOCK (16*1024*1024) + +int ubi_tools_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int ubi_tools_main(int argc UNUSED_PARAM, char **argv) +{ + static const struct suffix_mult size_suffixes[] = { + { "KiB", 1024 }, + { "MiB", 1024*1024 }, + { "GiB", 1024*1024*1024 }, + { "", 0 } + }; + + unsigned opts; + char *ubi_ctrl; + int fd; + int mtd_num; + int dev_num = UBI_DEV_NUM_AUTO; + int vol_id = UBI_VOL_NUM_AUTO; + char *vol_name; + unsigned long long size_bytes = size_bytes; /* for compiler */ + char *size_bytes_str; + int alignment = 1; + char *type; + union { + struct ubi_attach_req attach_req; + struct ubi_mkvol_req mkvol_req; + struct ubi_rsvol_req rsvol_req; + } req_structs; +#define attach_req req_structs.attach_req +#define mkvol_req req_structs.mkvol_req +#define rsvol_req req_structs.rsvol_req + char path[sizeof("/sys/class/ubi/ubi%d_%d/usable_eb_size") + + 2 * sizeof(int)*3 + /*just in case:*/ 16]; +#define path_sys_class_ubi_ubi (path + sizeof("/sys/class/ubi/ubi")-1) + + strcpy(path, "/sys/class/ubi/ubi"); + memset(&req_structs, 0, sizeof(req_structs)); + + if (do_mkvol) { + opt_complementary = "-1:d+:n+:a+"; + opts = getopt32(argv, "md:n:N:s:a:t:", + &dev_num, &vol_id, + &vol_name, &size_bytes_str, &alignment, &type + ); + } else { + opt_complementary = "-1:m+:d+:n+:a+"; + opts = getopt32(argv, "m:d:n:N:s:a:t:", + &mtd_num, &dev_num, &vol_id, + &vol_name, &size_bytes_str, &alignment, &type + ); + } +#define OPTION_m (1 << 0) +#define OPTION_d (1 << 1) +#define OPTION_n (1 << 2) +#define OPTION_N (1 << 3) +#define OPTION_s (1 << 4) +#define OPTION_a (1 << 5) +#define OPTION_t (1 << 6) + + if (opts & OPTION_s) + size_bytes = xatoull_sfx(size_bytes_str, size_suffixes); + argv += optind; + ubi_ctrl = *argv++; + + fd = xopen(ubi_ctrl, O_RDWR); + //xfstat(fd, &st, ubi_ctrl); + //if (!S_ISCHR(st.st_mode)) + // bb_error_msg_and_die("%s: not a char device", ubi_ctrl); + +//usage:#define ubiattach_trivial_usage +//usage: "-m MTD_NUM [-d UBI_NUM] UBI_CTRL_DEV" +//usage:#define ubiattach_full_usage "\n\n" +//usage: "Attach MTD device to UBI\n" +//usage: "\n -m MTD_NUM MTD device number to attach" +//usage: "\n -d UBI_NUM UBI device number to assign" + if (do_attach) { + if (!(opts & OPTION_m)) + bb_error_msg_and_die("%s device not specified", "MTD"); + + attach_req.mtd_num = mtd_num; + attach_req.ubi_num = dev_num; + + xioctl(fd, UBI_IOCATT, &attach_req); + } else + +//usage:#define ubidetach_trivial_usage +//usage: "-d UBI_NUM UBI_CTRL_DEV" +//usage:#define ubidetach_full_usage "\n\n" +//usage: "Detach MTD device from UBI\n" +//usage: "\n -d UBI_NUM UBI device number" + if (do_detach) { + if (!(opts & OPTION_d)) + bb_error_msg_and_die("%s device not specified", "UBI"); + + /* FIXME? kernel expects int32_t* here: */ + xioctl(fd, UBI_IOCDET, &dev_num); + } else + +//usage:#define ubimkvol_trivial_usage +//usage: "UBI_DEVICE -N NAME [-s SIZE | -m]" +//usage:#define ubimkvol_full_usage "\n\n" +//usage: "Create UBI volume\n" +//usage: "\n -a ALIGNMENT Volume alignment (default 1)" +//usage: "\n -m Set volume size to maximum available" +//usage: "\n -n VOLID Volume ID. If not specified," +//usage: "\n assigned automatically" +//usage: "\n -N NAME Volume name" +//usage: "\n -s SIZE Size in bytes" +//usage: "\n -t TYPE Volume type (static|dynamic)" + if (do_mkvol) { + if (opts & OPTION_m) { + unsigned leb_avail; + unsigned leb_size; + unsigned num; + char *p; + + if (sscanf(ubi_ctrl, "/dev/ubi%u", &num) != 1) + bb_error_msg_and_die("wrong format of UBI device name"); + + p = path_sys_class_ubi_ubi + sprintf(path_sys_class_ubi_ubi, "%u/", num); + + strcpy(p, "avail_eraseblocks"); + leb_avail = get_num_from_file(path, UINT_MAX, "Can't get available eraseblocks from '%s'"); + + strcpy(p, "eraseblock_size"); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get eraseblock size from '%s'"); + + size_bytes = leb_avail * (unsigned long long)leb_size; + //if (size_bytes <= 0) + // bb_error_msg_and_die("%s invalid maximum size calculated", "UBI"); + } else + if (!(opts & OPTION_s)) + bb_error_msg_and_die("size not specified"); + + if (!(opts & OPTION_N)) + bb_error_msg_and_die("name not specified"); + + mkvol_req.vol_id = vol_id; + mkvol_req.vol_type = UBI_DYNAMIC_VOLUME; + if ((opts & OPTION_t) && type[0] == 's') + mkvol_req.vol_type = UBI_STATIC_VOLUME; + mkvol_req.alignment = alignment; + mkvol_req.bytes = size_bytes; /* signed int64_t */ + strncpy(mkvol_req.name, vol_name, UBI_MAX_VOLUME_NAME); + mkvol_req.name_len = strlen(vol_name); + if (mkvol_req.name_len > UBI_MAX_VOLUME_NAME) + bb_error_msg_and_die("volume name too long: '%s'", vol_name); + + xioctl(fd, UBI_IOCMKVOL, &mkvol_req); + } else + +//usage:#define ubirmvol_trivial_usage +//usage: "UBI_DEVICE -n VOLID" +//usage:#define ubirmvol_full_usage "\n\n" +//usage: "Remove UBI volume\n" +//usage: "\n -n VOLID Volume ID" + if (do_rmvol) { + if (!(opts & OPTION_n)) + bb_error_msg_and_die("volume id not specified"); + + /* FIXME? kernel expects int32_t* here: */ + xioctl(fd, UBI_IOCRMVOL, &vol_id); + } else + +//usage:#define ubirsvol_trivial_usage +//usage: "UBI_DEVICE -n VOLID -s SIZE" +//usage:#define ubirsvol_full_usage "\n\n" +//usage: "Resize UBI volume\n" +//usage: "\n -n VOLID Volume ID" +//usage: "\n -s SIZE Size in bytes" + if (do_rsvol) { + if (!(opts & OPTION_s)) + bb_error_msg_and_die("size not specified"); + if (!(opts & OPTION_n)) + bb_error_msg_and_die("volume id not specified"); + + rsvol_req.bytes = size_bytes; /* signed int64_t */ + rsvol_req.vol_id = vol_id; + + xioctl(fd, UBI_IOCRSVOL, &rsvol_req); + } else + +//usage:#define ubiupdatevol_trivial_usage +//usage: "UBI_DEVICE [-t | [-s SIZE] IMG_FILE]" +//usage:#define ubiupdatevol_full_usage "\n\n" +//usage: "Update UBI volume\n" +//usage: "\n -t Truncate to zero size" +//usage: "\n -s SIZE Size in bytes to resize to" + if (do_update) { + int64_t bytes64; + + if (opts & OPTION_t) { + /* truncate the volume by starting an update for size 0 */ + bytes64 = 0; + /* this ioctl expects int64_t* parameter */ + xioctl(fd, UBI_IOCVOLUP, &bytes64); + } + else { + struct stat st; + unsigned ubinum, volnum; + unsigned leb_size; + ssize_t len; + char *input_data; + + /* Assume that device is in normal format. */ + /* Removes need for scanning sysfs tree as full libubi does. */ + if (sscanf(ubi_ctrl, "/dev/ubi%u_%u", &ubinum, &volnum) != 2) + bb_error_msg_and_die("wrong format of UBI device name"); + + sprintf(path_sys_class_ubi_ubi, "%u_%u/usable_eb_size", ubinum, volnum); + leb_size = get_num_from_file(path, MAX_SANE_ERASEBLOCK, "Can't get usable eraseblock size from '%s'"); + + if (!(opts & OPTION_s)) { + if (!*argv) + bb_show_usage(); + xstat(*argv, &st); + size_bytes = st.st_size; + xmove_fd(xopen(*argv, O_RDONLY), STDIN_FILENO); + } + + bytes64 = size_bytes; + /* this ioctl expects signed int64_t* parameter */ + xioctl(fd, UBI_IOCVOLUP, &bytes64); + + input_data = xmalloc(leb_size); + while ((len = full_read(STDIN_FILENO, input_data, leb_size)) > 0) { + xwrite(fd, input_data, len); + } + if (len < 0) + bb_perror_msg_and_die("UBI volume update failed"); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) + close(fd); + + return EXIT_SUCCESS; +} diff --git a/miscutils/volname.c b/miscutils/volname.c index 6e86156..b50e795 100644 --- a/miscutils/volname.c +++ b/miscutils/volname.c @@ -27,6 +27,12 @@ * mods from distributed source (eject-2.0.13) are by * Matthew Stoltenberg */ + +//usage:#define volname_trivial_usage +//usage: "[DEVICE]" +//usage:#define volname_full_usage "\n\n" +//usage: "Show CD volume name of the DEVICE (default /dev/cdrom)" + #include "libbb.h" int volname_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/miscutils/wall.c b/miscutils/wall.c index 2dbab60..bb709ee 100644 --- a/miscutils/wall.c +++ b/miscutils/wall.c @@ -3,19 +3,46 @@ * wall - write a message to all logged-in users * Copyright (c) 2009 Bernhard Reutner-Fischer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config WALL +//config: bool "wall" +//config: default y +//config: depends on FEATURE_UTMP +//config: help +//config: Write a message to all users that are logged in. + +/* Needs to be run by root or be suid root - needs to write to /dev/TTY: */ +//applet:IF_WALL(APPLET(wall, BB_DIR_USR_BIN, BB_SUID_REQUIRE)) + +//kbuild:lib-$(CONFIG_WALL) += wall.o + +//usage:#define wall_trivial_usage +//usage: "[FILE]" +//usage:#define wall_full_usage "\n\n" +//usage: "Write content of FILE or stdin to all logged-in users" +//usage: +//usage:#define wall_sample_usage +//usage: "echo foo | wall\n" +//usage: "wall ./mymessage" + #include "libbb.h" -#include int wall_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int wall_main(int argc UNUSED_PARAM, char **argv) { struct utmp *ut; char *msg; - int fd = argv[1] ? xopen(argv[1], O_RDONLY) : STDIN_FILENO; + int fd; + fd = STDIN_FILENO; + if (argv[1]) { + /* The applet is setuid. + * Access to the file must be under user's uid/gid. + */ + fd = xopen_as_uid_gid(argv[1], O_RDONLY, getuid(), getgid()); + } msg = xmalloc_read(fd, NULL); if (ENABLE_FEATURE_CLEAN_UP && argv[1]) close(fd); diff --git a/miscutils/watchdog.c b/miscutils/watchdog.c index 8e961f0..d3a76ed 100644 --- a/miscutils/watchdog.c +++ b/miscutils/watchdog.c @@ -6,9 +6,19 @@ * Copyright (C) 2006 Bernhard Reutner-Fischer * Copyright (C) 2008 Darius Augulis * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define watchdog_trivial_usage +//usage: "[-t N[ms]] [-T N[ms]] [-F] DEV" +//usage:#define watchdog_full_usage "\n\n" +//usage: "Periodically write to watchdog device DEV\n" +//usage: "\n -T N Reboot after N seconds if not reset (default 60)" +//usage: "\n -t N Reset every N seconds (default 30)" +//usage: "\n -F Run in foreground" +//usage: "\n" +//usage: "\nUse 500ms to specify period in milliseconds" + #include "libbb.h" #include "linux/types.h" /* for __u32 */ #include "linux/watchdog.h" @@ -21,10 +31,11 @@ static void watchdog_shutdown(int sig UNUSED_PARAM) { static const char V = 'V'; - write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ + remove_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); + write(3, &V, 1); /* Magic, see watchdog-api.txt in kernel */ if (ENABLE_FEATURE_CLEAN_UP) close(3); - exit(EXIT_SUCCESS); + _exit(EXIT_SUCCESS); } int watchdog_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -85,6 +96,8 @@ int watchdog_main(int argc, char **argv) stimer_duration, htimer_duration * 1000); #endif + write_pidfile(CONFIG_PID_FILE_PATH "/watchdog.pid"); + while (1) { /* * Make sure we clear the counter before sleeping, diff --git a/modutils/Config.src b/modutils/Config.src index a7dcb3a..449ac65 100644 --- a/modutils/Config.src +++ b/modutils/Config.src @@ -10,6 +10,7 @@ INSERT config MODPROBE_SMALL bool "Simplified modutils" default y + select PLATFORM_LINUX help Simplified modutils. @@ -44,6 +45,7 @@ config FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE bool "Accept module options on modprobe command line" default y depends on MODPROBE_SMALL + select PLATFORM_LINUX help Allow insmod and modprobe take module options from command line. @@ -58,6 +60,7 @@ config INSMOD bool "insmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help insmod is used to load specified modules in the running kernel. @@ -65,6 +68,7 @@ config RMMOD bool "rmmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help rmmod is used to unload specified modules from the kernel. @@ -72,6 +76,7 @@ config LSMOD bool "lsmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help lsmod is used to display a list of loaded modules. @@ -79,6 +84,7 @@ config FEATURE_LSMOD_PRETTY_2_6_OUTPUT bool "Pretty output" default n depends on LSMOD + select PLATFORM_LINUX help This option makes output format of lsmod adjusted to the format of module-init-tools for Linux kernel 2.6. @@ -88,6 +94,7 @@ config MODPROBE bool "modprobe" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help Handle the loading of modules, and their dependencies on a high level. @@ -96,6 +103,7 @@ config FEATURE_MODPROBE_BLACKLIST bool "Blacklist support" default n depends on MODPROBE + select PLATFORM_LINUX help Say 'y' here to enable support for the 'blacklist' command in modprobe.conf. This prevents the alias resolver to resolve @@ -107,6 +115,7 @@ config DEPMOD bool "depmod" default n depends on !MODPROBE_SMALL + select PLATFORM_LINUX help depmod generates modules.dep (and potentially modules.alias and modules.symbols) that contain dependency information @@ -118,6 +127,7 @@ config FEATURE_2_4_MODULES bool "Support version 2.2/2.4 Linux kernels" default n depends on INSMOD || RMMOD || LSMOD + select PLATFORM_LINUX help Support module loading for 2.2.x and 2.4.x Linux kernels. This increases size considerably. Say N unless you plan @@ -127,6 +137,7 @@ config FEATURE_INSMOD_TRY_MMAP bool "Try to load module from a mmap'ed area" default n depends on INSMOD || MODPROBE_SMALL + select PLATFORM_LINUX help This option causes module loading code to try to mmap module first. If it does not work (for example, @@ -143,6 +154,7 @@ config FEATURE_INSMOD_VERSION_CHECKING bool "Enable module version checking" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help Support checking of versions for modules. This is used to ensure that the kernel and module are made for each other. @@ -151,6 +163,7 @@ config FEATURE_INSMOD_KSYMOOPS_SYMBOLS bool "Add module symbols to kernel symbol table" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help By adding module symbols to the kernel symbol table, Oops messages occuring within kernel modules can be properly debugged. By enabling @@ -162,6 +175,7 @@ config FEATURE_INSMOD_LOADINKMEM bool "In kernel memory optimization (uClinux only)" default n depends on FEATURE_2_4_MODULES && (INSMOD || MODPROBE) + select PLATFORM_LINUX help This is a special uClinux only memory optimization that lets insmod load the specified kernel module directly into kernel space, reducing @@ -172,6 +186,7 @@ config FEATURE_INSMOD_LOAD_MAP bool "Enable insmod load map (-m) option" default n depends on FEATURE_2_4_MODULES && INSMOD + select PLATFORM_LINUX help Enabling this, one would be able to get a load map output on stdout. This makes kernel module debugging @@ -183,6 +198,7 @@ config FEATURE_INSMOD_LOAD_MAP_FULL bool "Symbols in load map" default y depends on FEATURE_INSMOD_LOAD_MAP && !MODPROBE_SMALL + select PLATFORM_LINUX help Without this option, -m will only output section load map. With this option, -m will also output @@ -192,6 +208,7 @@ config FEATURE_CHECK_TAINTED_MODULE bool "Support tainted module checking with new kernels" default y depends on (LSMOD || FEATURE_2_4_MODULES) && !MODPROBE_SMALL + select PLATFORM_LINUX help Support checking for tainted modules. These are usually binary only modules that will make the linux-kernel list ignore your @@ -202,6 +219,7 @@ config FEATURE_MODUTILS_ALIAS bool "Support for module.aliases file" default y depends on DEPMOD || MODPROBE + select PLATFORM_LINUX help Generate and parse modules.alias containing aliases for bus identifiers: @@ -218,6 +236,7 @@ config FEATURE_MODUTILS_SYMBOLS bool "Support for module.symbols file" default y depends on DEPMOD || MODPROBE + select PLATFORM_LINUX help Generate and parse modules.symbols containing aliases for symbol_request() kernel calls, such as: diff --git a/modutils/Kbuild.src b/modutils/Kbuild.src index a512f60..1a7ac87 100644 --- a/modutils/Kbuild.src +++ b/modutils/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/modutils/depmod.c b/modutils/depmod.c index 694f9ea..aa228ec 100644 --- a/modutils/depmod.c +++ b/modutils/depmod.c @@ -5,9 +5,11 @@ * Copyrihgt (c) 2008 Timo Teras * Copyright (c) 2008 Vladimir Dronnikov * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//applet:IF_DEPMOD(APPLET(depmod, BB_DIR_SBIN, BB_SUID_DROP)) + #include "libbb.h" #include "modutils.h" #include /* uname() */ @@ -29,7 +31,7 @@ typedef struct module_info { } module_info; static int FAST_FUNC parse_module(const char *fname, struct stat *sb UNUSED_PARAM, - void *data, int depth UNUSED_PARAM) + void *data, int depth UNUSED_PARAM) { char modname[MODULE_NAME_LEN]; module_info **first = (module_info **) data; @@ -93,7 +95,7 @@ static module_info *find_module(module_info *modules, const char *modname) } static void order_dep_list(module_info *modules, module_info *start, - llist_t *add) + llist_t *add) { module_info *m; llist_t *n; @@ -124,7 +126,16 @@ static void xfreopen_write(const char *file, FILE *f) bb_perror_msg_and_die("can't open '%s'", file); } -/* Usage: +//usage:#if !ENABLE_MODPROBE_SMALL +//usage:#define depmod_trivial_usage "[-n] [-b BASE] [VERSION] [MODFILES]..." +//usage:#define depmod_full_usage "\n\n" +//usage: "Generate modules.dep, alias, and symbols files" +//usage: "\n" +//usage: "\n -b BASE Use BASE/lib/modules/VERSION" +//usage: "\n -n Dry run: print files to stdout" +//usage:#endif + +/* Upstream usage: * [-aAenv] [-C FILE or DIR] [-b BASE] [-F System.map] [VERSION] [MODFILES]... * -a --all * Probe all modules. Default if no MODFILES. @@ -135,7 +146,7 @@ static void xfreopen_write(const char *file, FILE *f) * -C --config FILE or DIR * Path to /etc/depmod.conf or /etc/depmod.d/ * -e --errsyms - * When combined with the -F option, this reports any symbols which + * When combined with the -F option, this reports any symbols * which are not supplied by other modules or kernel. * -F --filesyms System.map * -n --dry-run @@ -144,9 +155,16 @@ static void xfreopen_write(const char *file, FILE *f) * Print to stdout all the symbols each module depends on * and the module's file name which provides that symbol. * -r No-op + * -u No-op + * -q No-op + * + * So far we only support: [-n] [-b BASE] [VERSION] [MODFILES]... + * Accepted but ignored: + * -aAe + * -F System.map + * -C FILE/DIR * - * So far we only support: [-rn] [-b BASE] [VERSION] [MODFILES]... - * -aAeF are accepted but ignored. -vC are not accepted. + * Not accepted: -v */ enum { //OPT_a = (1 << 0), /* All modules, ignore mods in argv */ @@ -155,7 +173,10 @@ enum { //OPT_e = (1 << 3), /* with -F, print unresolved symbols */ //OPT_F = (1 << 4), /* System.map that contains the symbols */ OPT_n = (1 << 5), /* dry-run, print to stdout only */ - OPT_r = (1 << 6) /* Compat dummy. Linux Makefile uses it */ + OPT_r = (1 << 6), /* Compat dummy. Linux Makefile uses it */ + OPT_u = (1 << 7), /* -u,--unresolved-error: ignored */ + OPT_q = (1 << 8), /* -q,--quiet: ignored */ + OPT_C = (1 << 9), /* -C,--config etc_modules_conf: ignored */ }; int depmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -167,7 +188,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) struct utsname uts; int tmp; - getopt32(argv, "aAb:eF:nr", &moddir_base, NULL); + getopt32(argv, "aAb:eF:nruqC:", &moddir_base, NULL, NULL); argv += optind; /* goto modules location */ @@ -195,7 +216,7 @@ int depmod_main(int argc UNUSED_PARAM, char **argv) } while (*++argv); } else { recursive_action(".", ACTION_RECURSE, - parse_module, NULL, &modules, 0); + parse_module, NULL, &modules, 0); } /* Generate dependency and alias files */ diff --git a/modutils/insmod.c b/modutils/insmod.c index b88446c..887d9f2 100644 --- a/modutils/insmod.c +++ b/modutils/insmod.c @@ -4,23 +4,25 @@ * * Copyright (C) 2008 Timo Teras * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//applet:IF_INSMOD(APPLET(insmod, BB_DIR_SBIN, BB_SUID_DROP)) + #include "libbb.h" #include "modutils.h" /* 2.6 style insmod has no options and required filename * (not module name - .ko can't be omitted) */ +//usage:#if !ENABLE_MODPROBE_SMALL //usage:#define insmod_trivial_usage //usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ") //usage: IF_NOT_FEATURE_2_4_MODULES("FILE ") -//usage: "[symbol=value]..." +//usage: "[SYMBOL=VALUE]..." //usage:#define insmod_full_usage "\n\n" //usage: "Load the specified kernel modules into the kernel" //usage: IF_FEATURE_2_4_MODULES( "\n" -//usage: "\nOptions:" //usage: "\n -f Force module to load into the wrong kernel version" //usage: "\n -k Make module autoclean-able" //usage: "\n -v Verbose" @@ -31,6 +33,7 @@ //usage: ) //usage: "\n -x Don't export externs" //usage: ) +//usage:#endif int insmod_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int insmod_main(int argc UNUSED_PARAM, char **argv) @@ -55,7 +58,7 @@ int insmod_main(int argc UNUSED_PARAM, char **argv) if (!filename) bb_show_usage(); - rc = bb_init_module(filename, parse_cmdline_module_options(argv)); + rc = bb_init_module(filename, parse_cmdline_module_options(argv, /*quote_spaces:*/ 0)); if (rc) bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); diff --git a/modutils/lsmod.c b/modutils/lsmod.c index 97954c7..3b3c166 100644 --- a/modutils/lsmod.c +++ b/modutils/lsmod.c @@ -5,8 +5,18 @@ * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//applet:IF_LSMOD(APPLET(lsmod, BB_DIR_SBIN, BB_SUID_DROP)) + +//usage:#if !ENABLE_MODPROBE_SMALL +//usage:#define lsmod_trivial_usage +//usage: "" +//usage:#define lsmod_full_usage "\n\n" +//usage: "List the currently loaded kernel modules" +//usage:#endif + #include "libbb.h" #include "unicode.h" @@ -77,7 +87,8 @@ int lsmod_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) // N.B. token[3] is either '-' (module is not used by others) // or comma-separated list ended by comma // so trimming the trailing char is just what we need! - token[3][strlen(token[3])-1] = '\0'; + if (token[3][0]) + token[3][strlen(token[3]) - 1] = '\0'; # if ENABLE_UNICODE_SUPPORT { uni_stat_t uni_stat; diff --git a/modutils/modinfo.c b/modutils/modinfo.c index 454a1b3..7c978d1 100644 --- a/modutils/modinfo.c +++ b/modutils/modinfo.c @@ -3,16 +3,17 @@ * modinfo - retrieve module info * Copyright (c) 2008 Pascal Bellard * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -//applet:IF_MODINFO(APPLET(modinfo, _BB_DIR_SBIN, _BB_SUID_DROP)) +//applet:IF_MODINFO(APPLET(modinfo, BB_DIR_SBIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_MODINFO) += modinfo.o modutils.o //config:config MODINFO //config: bool "modinfo" //config: default y +//config: select PLATFORM_LINUX //config: help //config: Show information about a Linux Kernel module @@ -23,9 +24,9 @@ enum { - OPT_TAGS = (1 << 6) - 1, - OPT_F = (1 << 6), /* field name */ - OPT_0 = (1 << 7), /* \0 as separator */ + OPT_TAGS = (1 << 12) - 1, /* shortcut count */ + OPT_F = (1 << 12), /* field name */ + OPT_0 = (1 << 13), /* \0 as separator */ }; struct modinfo_env { @@ -44,15 +45,21 @@ static int display(const char *data, const char *pattern, int flag) } static void modinfo(const char *path, const char *version, - struct modinfo_env *env) + const struct modinfo_env *env) { static const char *const shortcuts[] = { "filename", - "description", - "author", "license", + "author", + "description", + "version", + "alias", + "srcversion", + "depends", + "uts_release", "vermagic", "parm", + "firmware", }; size_t len; int j, length; @@ -80,11 +87,13 @@ static void modinfo(const char *path, const char *version, if (field) tags |= OPT_F; for (j = 1; (1< /* uname() */ @@ -18,10 +24,13 @@ extern int delete_module(const char *module, unsigned flags); extern int query_module(const char *name, int which, void *buf, size_t bufsize, size_t *ret); -#define dbg1_error_msg(...) ((void)0) -#define dbg2_error_msg(...) ((void)0) -//#define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__) -//#define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__) +#if 1 +# define dbg1_error_msg(...) ((void)0) +# define dbg2_error_msg(...) ((void)0) +#else +# define dbg1_error_msg(...) bb_error_msg(__VA_ARGS__) +# define dbg2_error_msg(...) bb_error_msg(__VA_ARGS__) +#endif #define DEPFILE_BB CONFIG_DEFAULT_DEPMOD_FILE".bb" @@ -196,6 +205,7 @@ static void parse_module(module_info *info, const char *pathname) /* Read (possibly compressed) module */ len = 64 * 1024 * 1024; /* 64 Mb at most */ module_image = xmalloc_open_zipped_read_close(pathname, &len); + /* module_image == NULL is ok here, find_keyword handles it */ //TODO: optimize redundant module body reads /* "alias1 symbol:sym1 alias2 symbol:sym2" */ @@ -579,24 +589,30 @@ static void process_module(char *name, const char *cmdline_options) /* rmmod? unload it by name */ if (is_rmmod) { - if (delete_module(name, O_NONBLOCK | O_EXCL) != 0 - && !(option_mask32 & OPT_q) - ) { - bb_perror_msg("remove '%s'", name); + if (delete_module(name, O_NONBLOCK | O_EXCL) != 0) { + if (!(option_mask32 & OPT_q)) + bb_perror_msg("remove '%s'", name); goto ret; } - /* N.B. we do not stop here - + + if (applet_name[0] == 'r') { + /* rmmod: do not remove dependencies, exit */ + goto ret; + } + + /* modprobe -r: we do not stop here - * continue to unload modules on which the module depends: * "-r --remove: option causes modprobe to remove a module. * If the modules it depends on are also unused, modprobe - * will try to remove them, too." */ + * will try to remove them, too." + */ } if (!info) { /* both dirscan and find_alias found nothing */ - if (applet_name[0] != 'd') /* it wasn't depmod */ + if (!is_rmmod && applet_name[0] != 'd') /* it wasn't rmmod or depmod */ bb_error_msg("module '%s' not found", name); -//TODO: _and_die()? +//TODO: _and_die()? or should we continue (un)loading modules listed on cmdline? goto ret; } @@ -686,17 +702,59 @@ The following options are useful for people managing distributions: */ //usage:#if ENABLE_MODPROBE_SMALL + +//// Note: currently, help system shows modprobe --help text for all aliased cmds +//// (see APPLET_ODDNAME macro definition). +//// All other help texts defined below are not used. FIXME? + +//usage:#define depmod_trivial_usage NOUSAGE_STR +//usage:#define depmod_full_usage "" + +//usage:#define lsmod_trivial_usage +//usage: "" +//usage:#define lsmod_full_usage "\n\n" +//usage: "List the currently loaded kernel modules" + +//usage:#define insmod_trivial_usage +//usage: IF_FEATURE_2_4_MODULES("[OPTIONS] MODULE ") +//usage: IF_NOT_FEATURE_2_4_MODULES("FILE ") +//usage: "[SYMBOL=VALUE]..." +//usage:#define insmod_full_usage "\n\n" +//usage: "Load the specified kernel modules into the kernel" +//usage: IF_FEATURE_2_4_MODULES( "\n" +//usage: "\n -f Force module to load into the wrong kernel version" +//usage: "\n -k Make module autoclean-able" +//usage: "\n -v Verbose" +//usage: "\n -q Quiet" +//usage: "\n -L Lock: prevent simultaneous loads" +//usage: IF_FEATURE_INSMOD_LOAD_MAP( +//usage: "\n -m Output load map to stdout" +//usage: ) +//usage: "\n -x Don't export externs" +//usage: ) + +//usage:#define rmmod_trivial_usage +//usage: "[-wfa] [MODULE]..." +//usage:#define rmmod_full_usage "\n\n" +//usage: "Unload kernel modules\n" +//usage: "\n -w Wait until the module is no longer used" +//usage: "\n -f Force unload" +//usage: "\n -a Remove all unused modules (recursively)" +//usage: +//usage:#define rmmod_example_usage +//usage: "$ rmmod tulip\n" + //usage:#define modprobe_trivial_usage //usage: "[-qfwrsv] MODULE [symbol=value]..." //usage:#define modprobe_full_usage "\n\n" -//usage: "Options:" -//usage: "\n -r Remove MODULE (stacks) or do autoclean" +//usage: " -r Remove MODULE (stacks) or do autoclean" //usage: "\n -q Quiet" //usage: "\n -v Verbose" //usage: "\n -f Force" //usage: "\n -w Wait for unload" //usage: "\n -s Report via syslog instead of stderr" -//usage:#endif /* ENABLE_MODPROBE_SMALL */ + +//usage:#endif int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int modprobe_main(int argc UNUSED_PARAM, char **argv) @@ -758,7 +816,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) opt_complementary = "-1"; /* only -q (quiet) and -r (rmmod), * the rest are accepted and ignored (compat) */ - getopt32(argv, "qrfsvw"); + getopt32(argv, "qrfsvwb"); argv += optind; /* are we rmmod? -> simulate modprobe -r */ @@ -795,13 +853,17 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) void *map; len = MAXINT(ssize_t); - map = xmalloc_xopen_read_close(*argv, &len); + map = xmalloc_open_zipped_read_close(*argv, &len); + if (!map) + bb_perror_msg_and_die("can't read '%s'", *argv); if (init_module(map, len, IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "") IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("") - ) != 0) + ) != 0 + ) { bb_error_msg_and_die("can't insert '%s': %s", *argv, moderror(errno)); + } return 0; } @@ -811,8 +873,8 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* Load/remove modules. * Only rmmod loops here, modprobe has only argv[0] */ do { - process_module(*argv++, options); - } while (*argv); + process_module(*argv, options); + } while (*++argv); if (ENABLE_FEATURE_CLEAN_UP) { IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);) diff --git a/modutils/modprobe.c b/modutils/modprobe.c index 0a94242..7f7446d 100644 --- a/modutils/modprobe.c +++ b/modutils/modprobe.c @@ -5,13 +5,11 @@ * Copyright (c) 2008 Timo Teras * Copyright (c) 2008 Vladimir Dronnikov * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ -/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), - * we expect the full dependency list to be specified in modules.dep. - * Older versions would only export the direct dependency list. - */ +//applet:IF_MODPROBE(APPLET(modprobe, BB_DIR_SBIN, BB_SUID_DROP)) + #include "libbb.h" #include "modutils.h" #include @@ -20,6 +18,12 @@ //#define DBG(fmt, ...) bb_error_msg("%s: " fmt, __func__, ## __VA_ARGS__) #define DBG(...) ((void)0) +/* Note that unlike older versions of modules.dep/depmod (busybox and m-i-t), + * we expect the full dependency list to be specified in modules.dep. + * Older versions would only export the direct dependency list. + */ + + //usage:#if !ENABLE_MODPROBE_SMALL //usage:#define modprobe_notes_usage //usage: "modprobe can (un)load a stack of modules, passing each module options (when\n" @@ -82,41 +86,60 @@ //usage: " from the command line\n" //usage: //usage:#define modprobe_trivial_usage -//usage: "[-alrqvs" -//usage: IF_FEATURE_MODPROBE_BLACKLIST("b") -//usage: "] MODULE [symbol=value]..." +//usage: "[-alrqvsD" IF_FEATURE_MODPROBE_BLACKLIST("b") "]" +//usage: " MODULE [symbol=value]..." //usage:#define modprobe_full_usage "\n\n" -//usage: "Options:" -//usage: "\n -a Load multiple MODULEs" +//usage: " -a Load multiple MODULEs" //usage: "\n -l List (MODULE is a pattern)" //usage: "\n -r Remove MODULE (stacks) or do autoclean" //usage: "\n -q Quiet" //usage: "\n -v Verbose" //usage: "\n -s Log to syslog" +//usage: "\n -D Show dependencies" //usage: IF_FEATURE_MODPROBE_BLACKLIST( //usage: "\n -b Apply blacklist to module names too" //usage: ) //usage:#endif /* !ENABLE_MODPROBE_SMALL */ -/* Note that usage text doesn't document various 2.4 options - * we pull in through INSMOD_OPTS define */ - -#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--ar:a--lr:r--al" -#define MODPROBE_OPTS "alr" IF_FEATURE_MODPROBE_BLACKLIST("b") +/* Note: usage text doesn't document various 2.4 options + * we pull in through INSMOD_OPTS define + * Note2: -b is always accepted, but if !FEATURE_MODPROBE_BLACKLIST, + * it is a no-op. + */ +#define MODPROBE_OPTS "alrDb" +/* -a and -D _are_ in fact compatible */ +#define MODPROBE_COMPLEMENTARY ("q-v:v-q:l--arD:r--alD:a--lr:D--rl") +//#define MODPROBE_OPTS "acd:lnrt:C:b" //#define MODPROBE_COMPLEMENTARY "q-v:v-q:l--acr:a--lr:r--al" -//#define MODPROBE_OPTS "acd:lnrt:C:" IF_FEATURE_MODPROBE_BLACKLIST("b") enum { - MODPROBE_OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ - //MODPROBE_OPT_DUMP_ONLY= (INSMOD_OPT_UNUSED << x), /* c */ - //MODPROBE_OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ - MODPROBE_OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ - //MODPROBE_OPT_SHOW_ONLY= (INSMOD_OPT_UNUSED << x), /* n */ - MODPROBE_OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ - //MODPROBE_OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ - //MODPROBE_OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ - //MODPROBE_OPT_CONFIGFILE=(INSMOD_OPT_UNUSED << x), /* C */ - MODPROBE_OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 3) * ENABLE_FEATURE_MODPROBE_BLACKLIST, + OPT_INSERT_ALL = (INSMOD_OPT_UNUSED << 0), /* a */ + //OPT_DUMP_ONLY = (INSMOD_OPT_UNUSED << x), /* c */ + //OPT_DIRNAME = (INSMOD_OPT_UNUSED << x), /* d */ + OPT_LIST_ONLY = (INSMOD_OPT_UNUSED << 1), /* l */ + //OPT_SHOW_ONLY = (INSMOD_OPT_UNUSED << x), /* n */ + OPT_REMOVE = (INSMOD_OPT_UNUSED << 2), /* r */ + //OPT_RESTRICT = (INSMOD_OPT_UNUSED << x), /* t */ + //OPT_VERONLY = (INSMOD_OPT_UNUSED << x), /* V */ + //OPT_CONFIGFILE = (INSMOD_OPT_UNUSED << x), /* C */ + OPT_SHOW_DEPS = (INSMOD_OPT_UNUSED << 3), /* D */ + OPT_BLACKLIST = (INSMOD_OPT_UNUSED << 4) * ENABLE_FEATURE_MODPROBE_BLACKLIST, }; +#if ENABLE_LONG_OPTS +static const char modprobe_longopts[] ALIGN1 = + /* nobody asked for long opts (yet) */ + // "all\0" No_argument "a" + // "list\0" No_argument "l" + // "remove\0" No_argument "r" + // "quiet\0" No_argument "q" + // "verbose\0" No_argument "v" + // "syslog\0" No_argument "s" + /* module-init-tools 3.11.1 has only long opt --show-depends + * but no short -D, we provide long opt for scripts which + * were written for 3.11.1: */ + "show-depends\0" No_argument "D" + // "use-blacklist\0" No_argument "b" + ; +#endif #define MODULE_FLAG_LOADED 0x0001 #define MODULE_FLAG_NEED_DEPS 0x0002 @@ -135,16 +158,21 @@ struct module_entry { /* I'll call it ME. */ llist_t *deps; /* strings. modules we depend on */ }; +#define DB_HASH_SIZE 256 + struct globals { - llist_t *db; /* MEs of all modules ever seen (caching for speed) */ llist_t *probes; /* MEs of module(s) requested on cmdline */ char *cmdline_mopts; /* module options from cmdline */ int num_unresolved_deps; /* bool. "Did we have 'symbol:FOO' requested on cmdline?" */ smallint need_symbols; + struct utsname uts; + llist_t *db[DB_HASH_SIZE]; /* MEs of all modules ever seen (caching for speed) */ } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) static int read_config(const char *path); @@ -164,14 +192,26 @@ static char *gather_options_str(char *opts, const char *append) return opts; } +/* These three functions called many times, optimizing for speed. + * Users reported minute-long delays when they runn iptables repeatedly + * (iptables use modprobe to install needed kernel modules). + */ static struct module_entry *helper_get_module(const char *module, int create) { char modname[MODULE_NAME_LEN]; struct module_entry *e; llist_t *l; + unsigned i; + unsigned hash; filename2modname(module, modname); - for (l = G.db; l != NULL; l = l->link) { + + hash = 0; + for (i = 0; modname[i]; i++) + hash = ((hash << 5) + hash) + modname[i]; + hash %= DB_HASH_SIZE; + + for (l = G.db[hash]; l; l = l->link) { e = (struct module_entry *) l->data; if (strcmp(e->modname, modname) == 0) return e; @@ -181,15 +221,15 @@ static struct module_entry *helper_get_module(const char *module, int create) e = xzalloc(sizeof(*e)); e->modname = xstrdup(modname); - llist_add_to(&G.db, e); + llist_add_to(&G.db[hash], e); return e; } -static struct module_entry *get_or_add_modentry(const char *module) +static ALWAYS_INLINE struct module_entry *get_or_add_modentry(const char *module) { return helper_get_module(module, 1); } -static struct module_entry *get_modentry(const char *module) +static ALWAYS_INLINE struct module_entry *get_modentry(const char *module) { return helper_get_module(module, 0); } @@ -199,7 +239,7 @@ static void add_probe(const char *name) struct module_entry *m; m = get_or_add_modentry(name); - if (!(option_mask32 & MODPROBE_OPT_REMOVE) + if (!(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) && (m->flags & MODULE_FLAG_LOADED) ) { DBG("skipping %s, it is already loaded", name); @@ -249,7 +289,7 @@ static int FAST_FUNC config_file_action(const char *filename, continue; filename2modname(tokens[1], wildcard); - for (l = G.probes; l != NULL; l = l->link) { + for (l = G.probes; l; l = l->link) { m = (struct module_entry *) l->data; if (fnmatch(wildcard, m->modname, 0) != 0) continue; @@ -350,10 +390,7 @@ static char *parse_and_add_kcmdline_module_options(char *options, const char *mo */ static int do_modprobe(struct module_entry *m) { - struct module_entry *m2 = m2; /* for compiler */ - char *fn, *options; int rc, first; - llist_t *l; if (!(m->flags & MODULE_FLAG_FOUND_IN_MODDEP)) { if (!(option_mask32 & INSMOD_OPT_SILENT)) @@ -363,20 +400,26 @@ static int do_modprobe(struct module_entry *m) } DBG("do_modprob'ing %s", m->modname); - if (!(option_mask32 & MODPROBE_OPT_REMOVE)) + if (!(option_mask32 & OPT_REMOVE)) m->deps = llist_rev(m->deps); - for (l = m->deps; l != NULL; l = l->link) - DBG("dep: %s", l->data); + if (0) { + llist_t *l; + for (l = m->deps; l; l = l->link) + DBG("dep: %s", l->data); + } first = 1; rc = 0; while (m->deps) { + struct module_entry *m2; + char *fn, *options; + rc = 0; fn = llist_pop(&m->deps); /* we leak it */ m2 = get_or_add_modentry(fn); - if (option_mask32 & MODPROBE_OPT_REMOVE) { + if (option_mask32 & OPT_REMOVE) { /* modprobe -r */ if (m2->flags & MODULE_FLAG_LOADED) { rc = bb_delete_module(m2->modname, O_EXCL); @@ -396,16 +439,27 @@ static int do_modprobe(struct module_entry *m) continue; } - if (m2->flags & MODULE_FLAG_LOADED) { - DBG("%s is already loaded, skipping", fn); - continue; - } - options = m2->options; m2->options = NULL; options = parse_and_add_kcmdline_module_options(options, m2->modname); if (m == m2) options = gather_options_str(options, G.cmdline_mopts); + + if (option_mask32 & OPT_SHOW_DEPS) { + printf(options ? "insmod %s/%s/%s %s\n" + : "insmod %s/%s/%s\n", + CONFIG_DEFAULT_MODULES_DIR, G.uts.release, fn, + options); + free(options); + continue; + } + + if (m2->flags & MODULE_FLAG_LOADED) { + DBG("%s is already loaded, skipping", fn); + free(options); + continue; + } + rc = bb_init_module(fn, options); DBG("loaded %s '%s', rc:%d", fn, options, rc); if (rc == EEXIST) @@ -453,7 +507,7 @@ static void load_modules_dep(void) /* Optimization... */ if ((m->flags & MODULE_FLAG_LOADED) - && !(option_mask32 & MODPROBE_OPT_REMOVE) + && !(option_mask32 & (OPT_REMOVE | OPT_SHOW_DEPS)) ) { DBG("skip deps of %s, it's already loaded", tokens[0]); continue; @@ -474,25 +528,31 @@ static void load_modules_dep(void) int modprobe_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int modprobe_main(int argc UNUSED_PARAM, char **argv) { - struct utsname uts; int rc; unsigned opt; struct module_entry *me; + INIT_G(); + + IF_LONG_OPTS(applet_long_options = modprobe_longopts;) opt_complementary = MODPROBE_COMPLEMENTARY; opt = getopt32(argv, INSMOD_OPTS MODPROBE_OPTS INSMOD_ARGS); argv += optind; /* Goto modules location */ xchdir(CONFIG_DEFAULT_MODULES_DIR); - uname(&uts); - xchdir(uts.release); + uname(&G.uts); + xchdir(G.uts.release); - if (opt & MODPROBE_OPT_LIST_ONLY) { + if (opt & OPT_LIST_ONLY) { + int i; char name[MODULE_NAME_LEN]; char *colon, *tokens[2]; parser_t *p = config_open2(CONFIG_DEFAULT_DEPMOD_FILE, xfopen_for_read); + for (i = 0; argv[i]; i++) + replace(argv[i], '-', '_'); + while (config_read(p, tokens, 2, 1, "# \t", PARSE_NORMAL)) { colon = last_char_is(tokens[0], ':'); if (!colon) @@ -502,7 +562,6 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) if (!argv[0]) puts(tokens[0]); else { - int i; for (i = 0; argv[i]; i++) { if (fnmatch(argv[i], name, 0) == 0) { puts(tokens[0]); @@ -518,7 +577,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) logmode = LOGMODE_SYSLOG; if (!argv[0]) { - if (opt & MODPROBE_OPT_REMOVE) { + if (opt & OPT_REMOVE) { /* "modprobe -r" (w/o params). * "If name is NULL, all unused modules marked * autoclean will be removed". @@ -538,7 +597,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) config_close(parser); } - if (opt & (MODPROBE_OPT_INSERT_ALL | MODPROBE_OPT_REMOVE)) { + if (opt & (OPT_INSERT_ALL | OPT_REMOVE)) { /* Each argument is a module name */ do { DBG("adding module %s", *argv); @@ -548,7 +607,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* First argument is module name, rest are parameters */ DBG("probing just module %s", *argv); add_probe(argv[0]); - G.cmdline_mopts = parse_cmdline_module_options(argv); + G.cmdline_mopts = parse_cmdline_module_options(argv, /*quote_spaces:*/ 1); } /* Happens if all requested modules are already loaded */ @@ -572,7 +631,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) /* This is not an alias. Literal names are blacklisted * only if '-b' is given. */ - if (!(opt & MODPROBE_OPT_BLACKLIST) + if (!(opt & OPT_BLACKLIST) || !(me->flags & MODULE_FLAG_BLACKLISTED) ) { rc |= do_modprobe(me); @@ -589,7 +648,7 @@ int modprobe_main(int argc UNUSED_PARAM, char **argv) m2 = get_or_add_modentry(realname); if (!(m2->flags & MODULE_FLAG_BLACKLISTED) && (!(m2->flags & MODULE_FLAG_LOADED) - || (opt & MODPROBE_OPT_REMOVE)) + || (opt & (OPT_REMOVE | OPT_SHOW_DEPS))) ) { //TODO: we can pass "me" as 2nd param to do_modprobe, //and make do_modprobe emit more meaningful error messages diff --git a/modutils/modutils-24.c b/modutils/modutils-24.c index 7f39e25..12cb75c 100644 --- a/modutils/modutils-24.c +++ b/modutils/modutils-24.c @@ -55,12 +55,11 @@ * Restructured (and partly rewritten) by: * Björn Ekwall February 1999 * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include "modutils.h" -#include #include #if ENABLE_FEATURE_INSMOD_LOADINKMEM @@ -90,6 +89,27 @@ #define USE_SINGLE #endif +/* NDS32 support */ +#if defined(__nds32__) || defined(__NDS32__) +#define CONFIG_USE_GOT_ENTRIES +#define CONFIG_GOT_ENTRY_SIZE 4 +#define CONFIG_USE_SINGLE + +#if defined(__NDS32_EB__) +#define MATCH_MACHINE(x) (x == EM_NDS32) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif + +#if defined(__NDS32_EL__) +#define MATCH_MACHINE(x) (x == EM_NDS32) +#define SHT_RELM SHT_RELA +#define Elf32_RelM Elf32_Rela +#define ELFCLASSM ELFCLASS32 +#endif +#endif + /* blackfin */ #if defined(BFIN) #define MATCH_MACHINE(x) (x == EM_BLACKFIN) @@ -2423,14 +2443,12 @@ new_process_module_arguments(struct obj_file *f, const char *options) bb_error_msg_and_die("symbol for parameter %s not found", param); /* Number of parameters */ + min = max = 1; if (isdigit(*pinfo)) { - min = strtoul(pinfo, &pinfo, 10); + min = max = strtoul(pinfo, &pinfo, 10); if (*pinfo == '-') max = strtoul(pinfo + 1, &pinfo, 10); - else - max = min; - } else - min = max = 1; + } contents = f->sections[sym->secidx]->contents; loc = contents + sym->value; @@ -2452,7 +2470,8 @@ new_process_module_arguments(struct obj_file *f, const char *options) /* Parse parameter values */ n = 0; p = val; - while (*p != 0) { + while (*p) { + char sv_ch; char *endp; if (++n > max) @@ -2461,21 +2480,25 @@ new_process_module_arguments(struct obj_file *f, const char *options) switch (*pinfo) { case 's': len = strcspn(p, ","); - p[len] = 0; + sv_ch = p[len]; + p[len] = '\0'; obj_string_patch(f, sym->secidx, loc - contents, p); loc += tgt_sizeof_char_p; p += len; + *p = sv_ch; break; case 'c': len = strcspn(p, ","); - p[len] = 0; + sv_ch = p[len]; + p[len] = '\0'; if (len >= charssize) bb_error_msg_and_die("string too long for %s (max %ld)", param, charssize - 1); strcpy((char *) loc, p); loc += charssize; p += len; + *p = sv_ch; break; case 'b': *loc++ = strtoul(p, &endp, 0); @@ -3540,7 +3563,7 @@ static void check_tainted_module(struct obj_file *f, const char *m_name) else if (errno == EACCES) kernel_has_tainted = 1; else { - perror(TAINT_FILENAME); + bb_simple_perror_msg(TAINT_FILENAME); kernel_has_tainted = 0; } } diff --git a/modutils/modutils.c b/modutils/modutils.c index 850a868..6187ca7 100644 --- a/modutils/modutils.c +++ b/modutils/modutils.c @@ -3,7 +3,7 @@ * * Copyright (C) 2008 by Timo Teras * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "modutils.h" @@ -62,7 +62,7 @@ char* FAST_FUNC filename2modname(const char *filename, char *modname) return modname; } -char* FAST_FUNC parse_cmdline_module_options(char **argv) +char* FAST_FUNC parse_cmdline_module_options(char **argv, int quote_spaces) { char *options; int optlen; @@ -70,10 +70,31 @@ char* FAST_FUNC parse_cmdline_module_options(char **argv) options = xzalloc(1); optlen = 0; while (*++argv) { - options = xrealloc(options, optlen + 2 + strlen(*argv) + 2); - /* Spaces handled by "" pairs, but no way of escaping quotes */ - optlen += sprintf(options + optlen, (strchr(*argv, ' ') ? "\"%s\" " : "%s "), *argv); + const char *fmt; + const char *var; + const char *val; + + var = *argv; + options = xrealloc(options, optlen + 2 + strlen(var) + 2); + fmt = "%.*s%s "; + val = strchrnul(var, '='); + if (quote_spaces) { + /* + * modprobe (module-init-tools version 3.11.1) compat: + * quote only value: + * var="val with spaces", not "var=val with spaces" + * (note: var *name* is not checked for spaces!) + */ + if (*val) { /* has var=val format. skip '=' */ + val++; + if (strchr(val, ' ')) + fmt = "%.*s\"%s\" "; + } + } + optlen += sprintf(options + optlen, fmt, (int)(val - var), var, val); } + /* Remove trailing space. Disabled */ + /* if (optlen != 0) options[optlen-1] = '\0'; */ return options; } diff --git a/modutils/modutils.h b/modutils/modutils.h index d46870c..5f059c7 100644 --- a/modutils/modutils.h +++ b/modutils/modutils.h @@ -3,7 +3,7 @@ * * Copyright (C) 2008 by Timo Teras * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef MODUTILS_H @@ -21,7 +21,7 @@ void replace(char *s, char what, char with) FAST_FUNC; char *replace_underscores(char *s) FAST_FUNC; int string_to_llist(char *string, llist_t **llist, const char *delim) FAST_FUNC; char *filename2modname(const char *filename, char *modname) FAST_FUNC; -char *parse_cmdline_module_options(char **argv) FAST_FUNC; +char *parse_cmdline_module_options(char **argv, int quote_spaces) FAST_FUNC; /* insmod for 2.4 and modprobe's options (insmod 2.6 has no options at all): */ #define INSMOD_OPTS \ diff --git a/modutils/rmmod.c b/modutils/rmmod.c index ee32dfd..f13ff9e 100644 --- a/modutils/rmmod.c +++ b/modutils/rmmod.c @@ -5,9 +5,23 @@ * Copyright (C) 1999-2004 by Erik Andersen * Copyright (C) 2008 Timo Teras * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//applet:IF_RMMOD(APPLET(rmmod, BB_DIR_SBIN, BB_SUID_DROP)) + +//usage:#if !ENABLE_MODPROBE_SMALL +//usage:#define rmmod_trivial_usage +//usage: "[-wfa] [MODULE]..." +//usage:#define rmmod_full_usage "\n\n" +//usage: "Unload kernel modules\n" +//usage: "\n -w Wait until the module is no longer used" +//usage: "\n -f Force unload" +//usage: "\n -a Remove all unused modules (recursively)" +//usage:#define rmmod_example_usage +//usage: "$ rmmod tulip\n" +//usage:#endif + #include "libbb.h" #include "modutils.h" @@ -20,9 +34,9 @@ int rmmod_main(int argc UNUSED_PARAM, char **argv) /* Parse command line. */ n = getopt32(argv, "wfas"); // -s ignored argv += optind; - if (n & 1) // --wait + if (n & 1) // --wait flags &= ~O_NONBLOCK; - if (n & 2) // --force + if (n & 2) // --force flags |= O_TRUNC; if (n & 4) { /* Unload _all_ unused modules via NULL delete_module() call */ @@ -46,7 +60,7 @@ int rmmod_main(int argc UNUSED_PARAM, char **argv) filename2modname(bname, modname); if (bb_delete_module(modname, flags)) bb_error_msg_and_die("can't unload '%s': %s", - modname, moderror(errno)); + modname, moderror(errno)); } return EXIT_SUCCESS; diff --git a/networking/Config.src b/networking/Config.src index 4494362..ca0ddcd 100644 --- a/networking/Config.src +++ b/networking/Config.src @@ -51,18 +51,21 @@ config VERBOSE_RESOLUTION_ERRORS config ARP bool "arp" default y + select PLATFORM_LINUX help Manipulate the system ARP cache. config ARPING bool "arping" default y + select PLATFORM_LINUX help Ping hosts by ARP packets. config BRCTL bool "brctl" default y + select PLATFORM_LINUX help Manage ethernet bridges. Supports addbr/delbr and addif/delif. @@ -79,12 +82,12 @@ config FEATURE_BRCTL_FANCY This adds about 600 bytes. config FEATURE_BRCTL_SHOW - bool "Support show, showmac and showstp" + bool "Support show" default y depends on BRCTL && FEATURE_BRCTL_FANCY help Add support for option which prints the current config: - showmacs, showstp, show + show config DNSD bool "dnsd" @@ -95,6 +98,7 @@ config DNSD config ETHER_WAKE bool "ether-wake" default y + select PLATFORM_LINUX help Send a magic packet to wake up sleeping machines. @@ -195,14 +199,22 @@ config FEATURE_HTTPD_BASIC_AUTH help Utilizes password settings from /etc/httpd.conf for basic authentication on a per url basis. + Example for httpd.conf file: + /adm:toor:PaSsWd config FEATURE_HTTPD_AUTH_MD5 bool "Support MD5 crypted passwords for http Authentication" default y depends on FEATURE_HTTPD_BASIC_AUTH help - Enables basic per URL authentication from /etc/httpd.conf - using md5 passwords. + Enables encrypted passwords, and wildcard user/passwords + in httpd.conf file. + User '*' means 'any system user name is ok', + password of '*' means 'use system password for this user' + Examples: + /adm:toor:$1$P/eKnWXS$aI1aPGxT.dJD5SzqAKWrF0 + /adm:root:* + /wiki:*:* config FEATURE_HTTPD_CGI bool "Support Common Gateway Interface (CGI)" @@ -219,8 +231,8 @@ config FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR help This option enables support for running scripts through an interpreter. Turn this on if you want PHP scripts to work - properly. You need to supply an additional line in your httpd - config file: + properly. You need to supply an additional line in your + httpd.conf file: *.php:/path/to/your/php config FEATURE_HTTPD_SET_REMOTE_PORT_TO_ENV @@ -266,9 +278,18 @@ config FEATURE_HTTPD_PROXY Then a request to /url/myfile will be forwarded to http://hostname[:port]/new/path/myfile. +config FEATURE_HTTPD_GZIP + bool "Support for GZIP content encoding" + default y + depends on HTTPD + help + Makes httpd send files using GZIP content encoding if the + client supports it and a pre-compressed .gz exists. + config IFCONFIG bool "ifconfig" default y + select PLATFORM_LINUX help Ifconfig is used to configure the kernel-resident network interfaces. @@ -316,6 +337,7 @@ config FEATURE_IFCONFIG_BROADCAST_PLUS config IFENSLAVE bool "ifenslave" default y + select PLATFORM_LINUX help Userspace application to bind several interfaces to a logical interface (use with kernel bonding driver). @@ -323,6 +345,7 @@ config IFENSLAVE config IFPLUGD bool "ifplugd" default y + select PLATFORM_LINUX help Network interface plug detection daemon. @@ -365,6 +388,7 @@ config FEATURE_IFUPDOWN_IP_BUILTIN bool "Use busybox ip applet" default y depends on FEATURE_IFUPDOWN_IP + select PLATFORM_LINUX select IP select FEATURE_IP_ADDRESS select FEATURE_IP_LINK @@ -483,6 +507,7 @@ config FEATURE_INETD_RPC config IP bool "ip" default y + select PLATFORM_LINUX help The "ip" applet is a TCP/IP interface configuration and routing utility. You generally don't need "ip" to use busybox with @@ -595,37 +620,10 @@ config FEATURE_IPCALC_LONG_OPTIONS help Support long options for the ipcalc applet. -config NAMEIF - bool "nameif" - default y - select FEATURE_SYSLOG - help - nameif is used to rename network interface by its MAC address. - Renamed interfaces MUST be in the down state. - It is possible to use a file (default: /etc/mactab) - with list of new interface names and MACs. - Maximum interface name length: IFNAMSIZ = 16 - File fields are separated by space or tab. - File format: - # Comment - new_interface_name XX:XX:XX:XX:XX:XX - -config FEATURE_NAMEIF_EXTENDED - bool "Extended nameif" - default y - depends on NAMEIF - help - This extends the nameif syntax to support the bus_info and driver - checks. The syntax is compatible to the normal nameif. - File format: - new_interface_name driver=asix bus=usb-0000:00:08.2-3 - new_interface_name bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5 - new_interface_name mac=00:80:C8:38:91:B5 - new_interface_name 00:80:C8:38:91:B5 - config NETSTAT bool "netstat" default y + select PLATFORM_LINUX help netstat prints information about the Linux networking subsystem. @@ -654,6 +652,7 @@ config NSLOOKUP config NTPD bool "ntpd" default y + select PLATFORM_LINUX help The NTP client/server daemon. @@ -665,28 +664,6 @@ config FEATURE_NTPD_SERVER Make ntpd usable as a NTP server. If you disable this option ntpd will be usable only as a NTP client. -config PING - bool "ping" - default y - help - ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to - elicit an ICMP ECHO_RESPONSE from a host or gateway. - -config PING6 - bool "ping6" - default y - depends on FEATURE_IPV6 && PING - help - This will give you a ping that can talk IPv6. - -config FEATURE_FANCY_PING - bool "Enable fancy ping output" - default y - depends on PING - help - Make the output from the ping applet include statistics, and at the - same time provide full support for ICMP packets. - config PSCAN bool "pscan" default y @@ -696,12 +673,14 @@ config PSCAN config ROUTE bool "route" default y + select PLATFORM_LINUX help Route displays or manipulates the kernel's IP routing tables. config SLATTACH bool "slattach" default y + select PLATFORM_LINUX help slattach is a small utility to attach network interfaces to serial lines. @@ -782,7 +761,7 @@ config TELNETD mount -t devpts devpts /dev/pts - You need to be sure that Busybox has LOGIN and + You need to be sure that busybox has LOGIN and FEATURE_SUID enabled. And finally, you should make certain that Busybox has been installed setuid root: @@ -888,6 +867,7 @@ config TFTP_DEBUG config TRACEROUTE bool "traceroute" default y + select PLATFORM_LINUX help Utility to trace the route of IP packets. @@ -924,6 +904,7 @@ config FEATURE_TRACEROUTE_USE_ICMP config TUNCTL bool "tunctl" default y + select PLATFORM_LINUX help tunctl creates or deletes tun devices. @@ -956,6 +937,7 @@ config UDPSVD config VCONFIG bool "vconfig" default y + select PLATFORM_LINUX help Creates, removes, and configures VLAN interfaces @@ -963,8 +945,8 @@ config WGET bool "wget" default y help - wget is a utility for non-interactive download of files from HTTP, - HTTPS, and FTP servers. + wget is a utility for non-interactive download of files from HTTP + and FTP servers. config FEATURE_WGET_STATUSBAR bool "Enable a nifty process meter (+2k)" @@ -987,9 +969,24 @@ config FEATURE_WGET_LONG_OPTIONS help Support long options for the wget applet. +config FEATURE_WGET_TIMEOUT + bool "Enable timeout option -T SEC" + default y + depends on WGET + help + Supports network read and connect timeouts for wget, + so that wget will give up and timeout, through the -T + command line option. + + Currently only connect and network data read timeout are + supported (i.e., timeout is not applied to the DNS query). When + FEATURE_WGET_LONG_OPTIONS is also enabled, the --timeout option + will work in addition to -T. + config ZCIP bool "zcip" default y + select PLATFORM_LINUX select FEATURE_SYSLOG help ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. diff --git a/networking/Kbuild.src b/networking/Kbuild.src index e1a4ebc..944f27b 100644 --- a/networking/Kbuild.src +++ b/networking/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= @@ -30,8 +30,6 @@ lib-$(CONFIG_NC) += nc.o lib-$(CONFIG_NETSTAT) += netstat.o lib-$(CONFIG_NSLOOKUP) += nslookup.o lib-$(CONFIG_NTPD) += ntpd.o -lib-$(CONFIG_PING) += ping.o -lib-$(CONFIG_PING6) += ping.o lib-$(CONFIG_PSCAN) += pscan.o lib-$(CONFIG_ROUTE) += route.o lib-$(CONFIG_SLATTACH) += slattach.o diff --git a/networking/arp.c b/networking/arp.c index 0ef267a..e79b1b6 100644 --- a/networking/arp.c +++ b/networking/arp.c @@ -13,6 +13,24 @@ * modified for getopt32 by Arne Bernin */ +//usage:#define arp_trivial_usage +//usage: "\n[-vn] [-H HWTYPE] [-i IF] -a [HOSTNAME]" +//usage: "\n[-v] [-i IF] -d HOSTNAME [pub]" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [temp]" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -s HOSTNAME HWADDR [netmask MASK] pub" +//usage: "\n[-v] [-H HWTYPE] [-i IF] -Ds HOSTNAME IFACE [netmask MASK] pub" +//usage:#define arp_full_usage "\n\n" +//usage: "Manipulate ARP cache\n" +//usage: "\n -a Display (all) hosts" +//usage: "\n -d Delete ARP entry" +//usage: "\n -s Set new entry" +//usage: "\n -v Verbose" +//usage: "\n -n Don't resolve names" +//usage: "\n -i IF Network interface" +//usage: "\n -D Read HWADDR from IFACE" +//usage: "\n -A,-p AF Protocol family" +//usage: "\n -H HWTYPE Hardware address type" + #include "libbb.h" #include "inet_common.h" @@ -195,16 +213,15 @@ static int arp_del(char **args) } /* Get the hardware address to a specified interface name */ -static void arp_getdevhw(char *ifname, struct sockaddr *sa, - const struct hwtype *hwt) +static void arp_getdevhw(char *ifname, struct sockaddr *sa) { struct ifreq ifr; const struct hwtype *xhw; strcpy(ifr.ifr_name, ifname); ioctl_or_perror_and_die(sockfd, SIOCGIFHWADDR, &ifr, - "cant get HW-Address for '%s'", ifname); - if (hwt && (ifr.ifr_hwaddr.sa_family != hw->type)) { + "can't get HW-Address for '%s'", ifname); + if (hw_set && (ifr.ifr_hwaddr.sa_family != hw->type)) { bb_error_msg_and_die("protocol type mismatch"); } memcpy(sa, &(ifr.ifr_hwaddr), sizeof(struct sockaddr)); @@ -215,8 +232,8 @@ static void arp_getdevhw(char *ifname, struct sockaddr *sa, xhw = get_hwntype(-1); } bb_error_msg("device '%s' has HW address %s '%s'", - ifname, xhw->name, - xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data)); + ifname, xhw->name, + xhw->print((unsigned char *) &ifr.ifr_hwaddr.sa_data)); } } @@ -243,7 +260,7 @@ static int arp_set(char **args) bb_error_msg_and_die("need hardware address"); } if (option_mask32 & ARP_OPT_D) { - arp_getdevhw(*args++, &req.arp_ha, hw_set ? hw : NULL); + arp_getdevhw(*args++, &req.arp_ha); } else { if (hw->input(*args++, &req.arp_ha) < 0) { bb_error_msg_and_die("invalid hardware address"); @@ -327,7 +344,7 @@ static int arp_set(char **args) /* Print the contents of an ARP request block. */ static void arp_disp(const char *name, char *ip, int type, int arp_flags, - char *hwa, char *mask, char *dev) + char *hwa, char *mask, char *dev) { static const int arp_masks[] = { ATF_PERM, ATF_PUBL, @@ -410,7 +427,7 @@ static int arp_show(char *name) /* All these strings can't overflow * because fgets above reads limited amount of data */ num = sscanf(line, "%s 0x%x 0x%x %s %s %s\n", - ip, &type, &flags, hwa, mask, dev); + ip, &type, &flags, hwa, mask, dev); if (num < 4) break; @@ -442,12 +459,12 @@ static int arp_show(char *name) arp_disp(hostname, ip, type, flags, hwa, mask, dev); } if (option_mask32 & ARP_OPT_v) - printf("Entries: %d\tSkipped: %d\tFound: %d\n", - entries, entries - shown, shown); + printf("Entries: %u\tSkipped: %u\tFound: %u\n", + entries, entries - shown, shown); if (!shown) { if (hw_set || host || device[0]) - printf("No match found in %d entries\n", entries); + printf("No match found in %u entries\n", entries); } if (ENABLE_FEATURE_CLEAN_UP) { free((char*)host); @@ -459,28 +476,33 @@ static int arp_show(char *name) int arp_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int arp_main(int argc UNUSED_PARAM, char **argv) { - const char *hw_type = "ether"; + const char *hw_type; const char *protocol; unsigned opts; INIT_G(); xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), sockfd); + ap = get_aftype(DFLT_AF); - if (!ap) - bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family"); + /* Defaults are always supported */ + //if (!ap) + // bb_error_msg_and_die("%s: %s not supported", DFLT_AF, "address family"); + hw = get_hwtype(DFLT_HW); + //if (!hw) + // bb_error_msg_and_die("%s: %s not supported", DFLT_HW, "hardware type"); opts = getopt32(argv, "A:p:H:t:i:adnDsv", &protocol, &protocol, &hw_type, &hw_type, &device); argv += optind; if (opts & (ARP_OPT_A | ARP_OPT_p)) { ap = get_aftype(protocol); - if (ap == NULL) + if (!ap) bb_error_msg_and_die("%s: unknown %s", protocol, "address family"); } - if (opts & (ARP_OPT_A | ARP_OPT_p)) { + if (opts & (ARP_OPT_H | ARP_OPT_t)) { hw = get_hwtype(hw_type); - if (hw == NULL) + if (!hw) bb_error_msg_and_die("%s: unknown %s", hw_type, "hardware type"); hw_set = 1; } @@ -489,17 +511,9 @@ int arp_main(int argc UNUSED_PARAM, char **argv) if (ap->af != AF_INET) { bb_error_msg_and_die("%s: kernel only supports 'inet'", ap->name); } - - /* If no hw type specified get default */ - if (!hw) { - hw = get_hwtype(DFLT_HW); - if (!hw) - bb_error_msg_and_die("%s: %s not supported", DFLT_HW, "hardware type"); - } - if (hw->alen <= 0) { bb_error_msg_and_die("%s: %s without ARP support", - hw->name, "hardware type"); + hw->name, "hardware type"); } /* Now see what we have to do here... */ @@ -510,6 +524,7 @@ int arp_main(int argc UNUSED_PARAM, char **argv) return arp_set(argv); return arp_del(argv); } + //if (opts & ARP_OPT_a) - default return arp_show(argv[0]); } diff --git a/networking/arping.c b/networking/arping.c index effe418..a4421ed 100644 --- a/networking/arping.c +++ b/networking/arping.c @@ -1,13 +1,27 @@ /* vi: set sw=4 ts=4: */ /* - * arping.c - Ping hosts by ARP requests/replies + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * Author: Alexey Kuznetsov + * Author: Alexey Kuznetsov * Busybox port: Nick Fedchik */ +//usage:#define arping_trivial_usage +//usage: "[-fqbDUA] [-c CNT] [-w TIMEOUT] [-I IFACE] [-s SRC_IP] DST_IP" +//usage:#define arping_full_usage "\n\n" +//usage: "Send ARP requests/replies\n" +//usage: "\n -f Quit on first ARP reply" +//usage: "\n -q Quiet" +//usage: "\n -b Keep broadcasting, don't go unicast" +//usage: "\n -D Duplicated address detection mode" +//usage: "\n -U Unsolicited ARP mode, update your neighbors" +//usage: "\n -A ARP answer mode, update your neighbors" +//usage: "\n -c N Stop after sending N ARP requests" +//usage: "\n -w TIMEOUT Time to wait for ARP reply, seconds" +//usage: "\n -I IFACE Interface to use (default eth0)" +//usage: "\n -s SRC_IP Sender IP address" +//usage: "\n DST_IP Target IP address" + #include #include #include diff --git a/networking/brctl.c b/networking/brctl.c index a36ab45..207b069 100644 --- a/networking/brctl.c +++ b/networking/brctl.c @@ -7,11 +7,35 @@ * Some helper functions from bridge-utils are * Copyright (C) 2000 Lennert Buytenhek * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* This applet currently uses only the ioctl interface and no sysfs at all. * At the time of this writing this was considered a feature. */ + +//usage:#define brctl_trivial_usage +//usage: "COMMAND [BRIDGE [INTERFACE]]" +//usage:#define brctl_full_usage "\n\n" +//usage: "Manage ethernet bridges\n" +//usage: "\nCommands:" +//usage: IF_FEATURE_BRCTL_SHOW( +//usage: "\n show Show a list of bridges" +//usage: ) +//usage: "\n addbr BRIDGE Create BRIDGE" +//usage: "\n delbr BRIDGE Delete BRIDGE" +//usage: "\n addif BRIDGE IFACE Add IFACE to BRIDGE" +//usage: "\n delif BRIDGE IFACE Delete IFACE from BRIDGE" +//usage: IF_FEATURE_BRCTL_FANCY( +//usage: "\n setageing BRIDGE TIME Set ageing time" +//usage: "\n setfd BRIDGE TIME Set bridge forward delay" +//usage: "\n sethello BRIDGE TIME Set hello time" +//usage: "\n setmaxage BRIDGE TIME Set max message age" +//usage: "\n setpathcost BRIDGE COST Set path cost" +//usage: "\n setportprio BRIDGE PRIO Set port priority" +//usage: "\n setbridgeprio BRIDGE PRIO Set bridge priority" +//usage: "\n stp BRIDGE [1/yes/on|0/no/off] STP on/off" +//usage: ) + #include "libbb.h" #include #include @@ -43,7 +67,7 @@ # include /* FIXME: These 4 funcs are not really clean and could be improved */ -static ALWAYS_INLINE void strtotimeval(struct timeval *tv, +static ALWAYS_INLINE void bb_strtotimeval(struct timeval *tv, const char *time_str) { double secs; @@ -80,7 +104,7 @@ static void jiffies_to_tv(struct timeval *tv, unsigned long jiffies) static unsigned long str_to_jiffies(const char *time_str) { struct timeval tv; - strtotimeval(&tv, time_str); + bb_strtotimeval(&tv, time_str); return tv_to_jiffies(&tv); } @@ -105,15 +129,15 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) "setageing\0" "setfd\0" "sethello\0" "setmaxage\0" "setpathcost\0" "setportprio\0" "setbridgeprio\0" ) - IF_FEATURE_BRCTL_SHOW("showmacs\0" "show\0"); + IF_FEATURE_BRCTL_SHOW("show\0"); enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif IF_FEATURE_BRCTL_FANCY(, - ARG_stp, - ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, - ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio + ARG_stp, + ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage, + ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio ) - IF_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show) + IF_FEATURE_BRCTL_SHOW(, ARG_show) }; int fd; @@ -184,7 +208,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) tabs = 1; printf("\t\t%s\n", ifname); } - if (!tabs) /* bridge has no interfaces */ + if (!tabs) /* bridge has no interfaces */ bb_putchar('\n'); } goto done; @@ -261,7 +285,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die(bb_msg_invalid_arg, *argv, "port"); memset(ifidx, 0, sizeof ifidx); arm_ioctl(args, BRCTL_GET_PORT_LIST, (unsigned long)ifidx, - MAX_PORTS); + MAX_PORTS); xioctl(fd, SIOCDEVPRIVATE, &ifr); for (i = 0; i < MAX_PORTS; i++) { if (ifidx[i] == port) { @@ -271,7 +295,7 @@ int brctl_main(int argc UNUSED_PARAM, char **argv) } } arg1 = port; - arg2 = xatoi_u(*argv); + arg2 = xatoi_positive(*argv); if (key == ARG_setbridgeprio) { arg1 = arg2; arg2 = 0; diff --git a/networking/dnsd.c b/networking/dnsd.c index 1a99040..fe98400 100644 --- a/networking/dnsd.c +++ b/networking/dnsd.c @@ -6,7 +6,7 @@ * Copyright (C) 2005 Odd Arild Olsen (oao at fibula dot no) * Copyright (C) 2003 Paul Sheer * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Odd Arild Olsen started out with the sheerdns [1] of Paul Sheer and rewrote * it into a shape which I believe is both easier to understand and maintain. @@ -17,6 +17,21 @@ * the first porting of oao' scdns to busybox also. */ +//usage:#define dnsd_trivial_usage +//usage: "[-dvs] [-c CONFFILE] [-t TTL_SEC] [-p PORT] [-i ADDR]" +//usage:#define dnsd_full_usage "\n\n" +//usage: "Small static DNS server daemon\n" +//usage: "\n -c FILE Config file" +//usage: "\n -t SEC TTL" +//usage: "\n -p PORT Listen on PORT" +//usage: "\n -i ADDR Listen on ADDR" +//usage: "\n -d Daemonize" +//usage: "\n -v Verbose" +//usage: "\n -s Send successful replies only. Use this if you want" +//usage: "\n to use /etc/resolv.conf with two nameserver lines:" +//usage: "\n nameserver DNSD_SERVER" +//usage: "\n nameserver NORMAL_DNS_SERVER" + #include "libbb.h" #include @@ -388,7 +403,7 @@ static int process_packet(struct dns_entry *conf_data, query_len = strlen(query_string) + 1; /* may be unaligned! */ unaligned_type_class = (void *)(query_string + query_len); - query_len += sizeof(unaligned_type_class); + query_len += sizeof(*unaligned_type_class); /* where to append answer block */ answb = (void *)(unaligned_type_class + 1); diff --git a/networking/ether-wake.c b/networking/ether-wake.c index deeb68c..c38547d 100644 --- a/networking/ether-wake.c +++ b/networking/ether-wake.c @@ -2,7 +2,7 @@ /* * ether-wake.c - Send a magic packet to wake up sleeping machines. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Author: Donald Becker, http://www.scyld.com/"; http://www.scyld.com/wakeonlan.html * Busybox port: Christian Volkmann @@ -49,9 +49,9 @@ * Copyright 1999-2003 Donald Becker and Scyld Computing Corporation. * * The author may be reached as becker@scyld, or C/O - * Scyld Computing Corporation - * 914 Bay Ridge Road, Suite 220 - * Annapolis MD 21403 + * Scyld Computing Corporation + * 914 Bay Ridge Road, Suite 220 + * Annapolis MD 21403 * * Notes: * On some systems dropping root capability allows the process to be @@ -62,16 +62,23 @@ * An alternative to needing 'root' is using a UDP broadcast socket, however * doing so only works with adapters configured for unicast+broadcast Rx * filter. That configuration consumes more power. -*/ + */ +//usage:#define ether_wake_trivial_usage +//usage: "[-b] [-i IFACE] [-p aa:bb:cc:dd[:ee:ff]/a.b.c.d] MAC" +//usage:#define ether_wake_full_usage "\n\n" +//usage: "Send a magic packet to wake up sleeping machines.\n" +//usage: "MAC must be a station address (00:11:22:33:44:55) or\n" +//usage: "a hostname with a known 'ethers' entry.\n" +//usage: "\n -b Broadcast the packet" +//usage: "\n -i IFACE Interface to use (default eth0)" +//usage: "\n -p PASSWORD Append four or six byte PASSWORD to the packet" +#include "libbb.h" #include -#include #include #include -#include "libbb.h" - /* Note: PF_INET, SOCK_DGRAM, IPPROTO_UDP would allow SIOCGIFHWADDR to * work as non-root, but we need SOCK_PACKET to specify the Ethernet * destination address. @@ -106,7 +113,7 @@ void bb_debug_dump_packet(unsigned char *outpack, int pktsize) * Host name * IP address string * MAC address string -*/ + */ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) { struct ether_addr *eap; @@ -114,10 +121,7 @@ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) eap = ether_aton_r(hostid, eaddr); if (eap) { bb_debug_msg("The target station address is %s\n\n", ether_ntoa(eap)); -#if !defined(__UCLIBC_MAJOR__) \ - || __UCLIBC_MAJOR__ > 0 \ - || __UCLIBC_MINOR__ > 9 \ - || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ >= 30) +#if !defined(__UCLIBC__) || UCLIBC_VERSION >= KERNEL_VERSION(0, 9, 30) } else if (ether_hostton(hostid, eaddr) == 0) { bb_debug_msg("Station address for hostname %s is %s\n\n", hostid, ether_ntoa(eaddr)); #endif @@ -126,7 +130,8 @@ static void get_dest_addr(const char *hostid, struct ether_addr *eaddr) } } -static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast) +#define PKT_HEADER_SIZE (20 + 16*6) +static int fill_pkt_header(unsigned char *pkt, struct ether_addr *eaddr, int broadcast) { int i; unsigned char *station_addr = eaddr->ether_addr_octet; @@ -149,7 +154,7 @@ static int get_fill(unsigned char *pkt, struct ether_addr *eaddr, int broadcast) memcpy(pkt, station_addr, 6); /* 20,26,32,... */ } - return 20 + 16*6; /* length of packet */ + return PKT_HEADER_SIZE; /* length of packet */ } static int get_wol_pw(const char *ethoptarg, unsigned char *wol_passwd) @@ -189,12 +194,12 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) unsigned flags; unsigned char wol_passwd[6]; int wol_passwd_sz = 0; - int s; /* Raw socket */ + int s; /* Raw socket */ int pktsize; - unsigned char outpack[1000]; + unsigned char outpack[PKT_HEADER_SIZE + 6 /* max passwd size */ + 16 /* paranoia */]; struct ether_addr eaddr; - struct whereto_t whereto; /* who to wake up */ + struct whereto_t whereto; /* who to wake up */ /* handle misc user options */ opt_complementary = "=1"; @@ -213,7 +218,7 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) get_dest_addr(argv[optind], &eaddr); /* fill out the header of the packet */ - pktsize = get_fill(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */); + pktsize = fill_pkt_header(outpack, &eaddr, flags /* & 1 OPT_BROADCAST */); bb_debug_dump_packet(outpack, pktsize); @@ -231,9 +236,9 @@ int ether_wake_main(int argc UNUSED_PARAM, char **argv) { unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; printf("The hardware address (SIOCGIFHWADDR) of %s is type %d " - "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname, - if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], - hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x\n\n", ifname, + if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); } # endif } diff --git a/networking/ftpd.c b/networking/ftpd.c index e8cae0a..33db964 100644 --- a/networking/ftpd.c +++ b/networking/ftpd.c @@ -4,7 +4,7 @@ * * Author: Adam Tkac * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * * Only subset of FTP protocol is implemented but vast majority of clients * should not have any problem. @@ -12,6 +12,22 @@ * You have to run this daemon via inetd. */ +//usage:#define ftpd_trivial_usage +//usage: "[-wvS] [-t N] [-T N] [DIR]" +//usage:#define ftpd_full_usage "\n\n" +//usage: "Anonymous FTP server\n" +//usage: "\n" +//usage: "ftpd should be used as an inetd service.\n" +//usage: "ftpd's line for inetd.conf:\n" +//usage: " 21 stream tcp nowait root ftpd ftpd /files/to/serve\n" +//usage: "It also can be ran from tcpsvd:\n" +//usage: " tcpsvd -vE 0.0.0.0 21 ftpd /files/to/serve\n" +//usage: "\n -w Allow upload" +//usage: "\n -v Log errors to stderr. -vv: verbose log" +//usage: "\n -S Log errors to syslog. -SS: verbose log" +//usage: "\n -t,-T Idle and absolute timeouts" +//usage: "\n DIR Change root to this directory" + #include "libbb.h" #include #include @@ -206,7 +222,7 @@ cmdio_write_error(unsigned status) { *(uint32_t *) G.msg_err = status; xwrite(STDOUT_FILENO, G.msg_err, sizeof("NNN " MSG_ERR) - 1); - if (G.verbose > 1) + if (G.verbose > 0) verbose_log(G.msg_err); } #define WRITE_ERR(a) cmdio_write_error(STRNUM32sp(a)) @@ -416,7 +432,7 @@ bind_for_passive_mode(void) G.pasv_listen_fd = fd = xsocket(G.local_addr->u.sa.sa_family, SOCK_STREAM, 0); setsockopt_reuseaddr(fd); - set_nport(G.local_addr, 0); + set_nport(&G.local_addr->u.sa, 0); xbind(fd, &G.local_addr->u.sa, G.local_addr->len); xlisten(fd, 1); getsockname(fd, &G.local_addr->u.sa, &G.local_addr->len); @@ -525,7 +541,7 @@ handle_port(void) G.port_addr = xdotted2sockaddr(raw, port); #else G.port_addr = get_peer_lsa(STDIN_FILENO); - set_nport(G.port_addr, htons(port)); + set_nport(&G.port_addr->u.sa, htons(port)); #endif WRITE_OK(FTP_PORTOK); } @@ -534,7 +550,7 @@ static void handle_rest(void) { /* When ftp_arg == NULL simply restart from beginning */ - G.restart_pos = G.ftp_arg ? xatoi_u(G.ftp_arg) : 0; + G.restart_pos = G.ftp_arg ? xatoi_positive(G.ftp_arg) : 0; WRITE_OK(FTP_RESTOK); } @@ -805,7 +821,7 @@ handle_size_or_mdtm(int need_size) gmtime_r(&statbuf.st_mtime, &broken_out); sprintf(buf, STR(FTP_STATFILE_OK)" %04u%02u%02u%02u%02u%02u\r\n", broken_out.tm_year + 1900, - broken_out.tm_mon, + broken_out.tm_mon + 1, broken_out.tm_mday, broken_out.tm_hour, broken_out.tm_min, @@ -911,6 +927,7 @@ handle_upload_common(int is_append, int is_unique) || fstat(local_file_fd, &statbuf) != 0 || !S_ISREG(statbuf.st_mode) ) { + free(tempname); WRITE_ERR(FTP_UPLOADFAIL); if (local_file_fd >= 0) goto close_local_and_bail; @@ -1163,8 +1180,7 @@ int ftpd_main(int argc UNUSED_PARAM, char **argv) #endif if (argv[optind]) { - xchdir(argv[optind]); - chroot("."); + xchroot(argv[optind]); } //umask(077); - admin can set umask before starting us diff --git a/networking/ftpgetput.c b/networking/ftpgetput.c index 120ccff..8283366 100644 --- a/networking/ftpgetput.c +++ b/networking/ftpgetput.c @@ -10,9 +10,45 @@ * Based on wget.c by Chip Rosenthal Covad Communications * * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ftpget_trivial_usage +//usage: "[OPTIONS] HOST [LOCAL_FILE] REMOTE_FILE" +//usage:#define ftpget_full_usage "\n\n" +//usage: "Download a file via FTP\n" +//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -c,--continue Continue previous transfer" +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" +//usage: ) +//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -c Continue previous transfer" +//usage: "\n -v Verbose" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port" +//usage: ) +//usage: +//usage:#define ftpput_trivial_usage +//usage: "[OPTIONS] HOST [REMOTE_FILE] LOCAL_FILE" +//usage:#define ftpput_full_usage "\n\n" +//usage: "Upload a file to a FTP server\n" +//usage: IF_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -v,--verbose Verbose" +//usage: "\n -u,--username USER Username" +//usage: "\n -p,--password PASS Password" +//usage: "\n -P,--port NUM Port" +//usage: ) +//usage: IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( +//usage: "\n -v Verbose" +//usage: "\n -u USER Username" +//usage: "\n -p PASS Password" +//usage: "\n -P NUM Port number" +//usage: ) + #include "libbb.h" struct globals { @@ -22,7 +58,7 @@ struct globals { FILE *control_stream; int verbose_flag; int do_continue; - char buf[1]; /* actually [BUFSZ] */ + char buf[4]; /* actually [BUFSZ] */ } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) enum { BUFSZ = COMMON_BUFSIZE - offsetof(struct globals, buf) }; @@ -67,7 +103,7 @@ static int ftpcmd(const char *s1, const char *s2) } do { - strcpy(buf, "EOF"); + strcpy(buf, "EOF"); /* for ftp_die */ if (fgets(buf, BUFSZ - 2, control_stream) == NULL) { ftp_die(NULL); } @@ -151,7 +187,7 @@ TODO2: need to stop ignoring IP address in PASV response. *buf_ptr = '\0'; port_num += xatoul_range(buf_ptr + 1, 0, 255) * 256; - set_nport(lsa, htons(port_num)); + set_nport(&lsa->u.sa, htons(port_num)); return xconnect_stream(lsa); } @@ -278,7 +314,6 @@ static const char ftpgetput_longopts[] ALIGN1 = int ftpgetput_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ftpgetput_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; const char *port = "ftp"; /* socket to ftp server */ @@ -307,7 +342,7 @@ int ftpgetput_main(int argc UNUSED_PARAM, char **argv) applet_long_options = ftpgetput_longopts; #endif opt_complementary = "-2:vv:cc"; /* must have 2 to 3 params; -v and -c count */ - opt = getopt32(argv, "cvu:p:P:", &user, &password, &port, + getopt32(argv, "cvu:p:P:", &user, &password, &port, &verbose_flag, &do_continue); argv += optind; diff --git a/networking/hostname.c b/networking/hostname.c index 121ad40..b3e3522 100644 --- a/networking/hostname.c +++ b/networking/hostname.c @@ -7,8 +7,26 @@ * Adjusted by Erik Andersen to remove * use of long options and GNU getopt. Improved the usage info. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define hostname_trivial_usage +//usage: "[OPTIONS] [HOSTNAME | -F FILE]" +//usage:#define hostname_full_usage "\n\n" +//usage: "Get or set hostname or DNS domain name\n" +//usage: "\n -s Short" +//usage: "\n -i Addresses for the hostname" +//usage: "\n -d DNS domain name" +//usage: "\n -f Fully qualified domain name" +//usage: "\n -F FILE Use FILE's content as hostname" +//usage: +//usage:#define hostname_example_usage +//usage: "$ hostname\n" +//usage: "sage\n" +//usage: +//usage:#define dnsdomainname_trivial_usage NOUSAGE_STR +//usage:#define dnsdomainname_full_usage "" + #include "libbb.h" static void do_sethostname(char *s, int isfile) @@ -88,7 +106,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) OPT_i = 0x4, OPT_s = 0x8, OPT_F = 0x10, - OPT_dfis = 0xf, + OPT_dfi = 0x7, }; unsigned opts; @@ -116,7 +134,7 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) if (applet_name[0] == 'd') /* dnsdomainname? */ opts = OPT_d; - if (opts & OPT_dfis) { + if (opts & OPT_dfi) { /* Cases when we need full hostname (or its part) */ struct hostent *hp; char *p; @@ -135,12 +153,15 @@ int hostname_main(int argc UNUSED_PARAM, char **argv) if (hp->h_length == sizeof(struct in_addr)) { struct in_addr **h_addr_list = (struct in_addr **)hp->h_addr_list; while (*h_addr_list) { - printf("%s ", inet_ntoa(**h_addr_list)); + printf(h_addr_list[1] ? "%s " : "%s", inet_ntoa(**h_addr_list)); h_addr_list++; } bb_putchar('\n'); } } + } else if (opts & OPT_s) { + strchrnul(buf, '.')[0] = '\0'; + puts(buf); } else if (opts & OPT_F) { /* Set the hostname */ do_sethostname(hostname_str, 1); diff --git a/networking/httpd.c b/networking/httpd.c index 8ad7e88..621d9cd 100644 --- a/networking/httpd.c +++ b/networking/httpd.c @@ -5,32 +5,33 @@ * Copyright (C) 2002,2003 Glenn Engel * Copyright (C) 2003-2006 Vladimir Oleynik * - * simplify patch stolen from libbb without using strdup - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * ***************************************************************************** * * Typical usage: - * for non root user - * httpd -p 8080 -h $HOME/public_html - * or for daemon start from rc script with uid=0: - * httpd -u www - * This is equivalent if www user have uid=80 to - * httpd -p 80 -u 80 -h /www -c /etc/httpd.conf -r "Web Server Authentication" - * + * For non root user: + * httpd -p 8080 -h $HOME/public_html + * For daemon start from rc script with uid=0: + * httpd -u www + * which is equivalent to (assuming user www has uid 80): + * httpd -p 80 -u 80 -h $PWD -c /etc/httpd.conf -r "Web Server Authentication" * - * When an url starts by "/cgi-bin/" it is assumed to be a cgi script. The - * server changes directory to the location of the script and executes it + * When an url starts with "/cgi-bin/" it is assumed to be a cgi script. + * The server changes directory to the location of the script and executes it * after setting QUERY_STRING and other environment variables. * + * If directory URL is given, no index.html is found and CGI support is enabled, + * cgi-bin/index.cgi will be run. Directory to list is ../$QUERY_STRING. + * See httpd_indexcgi.c for an example GCI code. + * * Doc: * "CGI Environment Variables": http://hoohoo.ncsa.uiuc.edu/cgi/env.html * * The applet can also be invoked as an url arg decoder and html text encoder * as follows: - * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" - * bar=`httpd -e ""` # encode as "<Hello World>" + * foo=`httpd -d $foo` # decode "Hello%20World" as "Hello World" + * bar=`httpd -e ""` # encode as "<Hello World>" * Note that url encoding for arguments is not the same as html encoding for * presentation. -d decodes an url-encoded argument while -e encodes in html * for page display. @@ -53,6 +54,8 @@ * /cgi-bin:foo:bar # Require user foo, pwd bar on urls starting with /cgi-bin/ * /adm:admin:setup # Require user admin, pwd setup on urls starting with /adm/ * /adm:toor:PaSsWd # or user toor, pwd PaSsWd on urls starting with /adm/ + * /adm:root:* # or user root, pwd from /etc/passwd on urls starting with /adm/ + * /wiki:*:* # or any user from /etc/passwd with according pwd on urls starting with /wiki/ * .au:audio/basic # additional mime type for audio.au files * *.php:/path/php # run xxx.php through an interpreter * @@ -74,7 +77,7 @@ * D:2.3.4. # deny from 2.3.4.0 - 2.3.4.255 * A:* # (optional line added for clarity) * - * If a sub directory contains a config file it is parsed and merged with + * If a sub directory contains config file, it is parsed and merged with * any existing settings as if it was appended to the original configuration. * * subdir paths are relative to the containing subdir and thus cannot @@ -96,19 +99,51 @@ */ /* TODO: use TCP_CORK, parse_config() */ +//usage:#define httpd_trivial_usage +//usage: "[-ifv[v]]" +//usage: " [-c CONFFILE]" +//usage: " [-p [IP:]PORT]" +//usage: IF_FEATURE_HTTPD_SETUID(" [-u USER[:GRP]]") +//usage: IF_FEATURE_HTTPD_BASIC_AUTH(" [-r REALM]") +//usage: " [-h HOME]\n" +//usage: "or httpd -d/-e" IF_FEATURE_HTTPD_AUTH_MD5("/-m") " STRING" +//usage:#define httpd_full_usage "\n\n" +//usage: "Listen for incoming HTTP requests\n" +//usage: "\n -i Inetd mode" +//usage: "\n -f Don't daemonize" +//usage: "\n -v[v] Verbose" +//usage: "\n -p [IP:]PORT Bind to IP:PORT (default *:80)" +//usage: IF_FEATURE_HTTPD_SETUID( +//usage: "\n -u USER[:GRP] Set uid/gid after binding to port") +//usage: IF_FEATURE_HTTPD_BASIC_AUTH( +//usage: "\n -r REALM Authentication Realm for Basic Authentication") +//usage: "\n -h HOME Home directory (default .)" +//usage: "\n -c FILE Configuration file (default {/etc,HOME}/httpd.conf)" +//usage: IF_FEATURE_HTTPD_AUTH_MD5( +//usage: "\n -m STRING MD5 crypt STRING") +//usage: "\n -e STRING HTML encode STRING" +//usage: "\n -d STRING URL decode STRING" + #include "libbb.h" +#if ENABLE_PAM +/* PAM may include . We may need to undefine bbox's stub define: */ +# undef setlocale +/* For some obscure reason, PAM is not in pam/xxx, but in security/xxx. + * Apparently they like to confuse people. */ +# include +# include +#endif #if ENABLE_FEATURE_HTTPD_USE_SENDFILE # include #endif - -#define DEBUG 0 - -#define IOBUF_SIZE 8192 /* IO buffer */ - /* amount of buffering in a pipe */ #ifndef PIPE_BUF # define PIPE_BUF 4096 #endif + +#define DEBUG 0 + +#define IOBUF_SIZE 8192 #if PIPE_BUF >= IOBUF_SIZE # error "PIPE_BUF >= IOBUF_SIZE" #endif @@ -118,6 +153,7 @@ static const char DEFAULT_PATH_HTTPD_CONF[] ALIGN1 = "/etc"; static const char HTTPD_CONF[] ALIGN1 = "httpd.conf"; static const char HTTP_200[] ALIGN1 = "HTTP/1.0 200 OK\r\n"; +static const char index_html[] ALIGN1 = "index.html"; typedef struct has_next_ptr { struct has_next_ptr *next; @@ -170,7 +206,6 @@ enum { HTTP_PAYMENT_REQUIRED = 402, HTTP_BAD_GATEWAY = 502, HTTP_SERVICE_UNAVAILABLE = 503, /* overload, maintenance */ - HTTP_RESPONSE_SETSIZE = 0xffffffff #endif }; @@ -231,14 +266,11 @@ static const struct { #endif }; -static const char index_html[] ALIGN1 = "index.html"; - - struct globals { int verbose; /* must be int (used by getopt32) */ smallint flg_deny_all; - unsigned rmt_ip; /* used for IP-based allow/deny rules */ + unsigned rmt_ip; /* used for IP-based allow/deny rules */ time_t last_mod; char *rmt_ip_str; /* for $REMOTE_ADDR and $REMOTE_PORT */ const char *bind_addr_or_port; @@ -274,7 +306,7 @@ struct globals { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR Htaccess *script_i; /* config script interpreters */ #endif - char *iobuf; /* [IOBUF_SIZE] */ + char *iobuf; /* [IOBUF_SIZE] */ #define hdr_buf bb_common_bufsiz1 char *hdr_ptr; int hdr_cnt; @@ -284,6 +316,10 @@ struct globals { #if ENABLE_FEATURE_HTTPD_PROXY Htaccess_Proxy *proxy; #endif +#if ENABLE_FEATURE_HTTPD_GZIP + /* client can handle gzip / we are going to send gzip */ + smallint content_gzip; +#endif }; #define G (*ptr_to_globals) #define verbose (G.verbose ) @@ -312,7 +348,7 @@ struct globals { #define range_len (G.range_len ) #else enum { - range_start = 0, + range_start = -1, range_end = MAXINT(off_t) - 1, range_len = MAXINT(off_t), }; @@ -326,9 +362,15 @@ enum { #define hdr_cnt (G.hdr_cnt ) #define http_error_page (G.http_error_page ) #define proxy (G.proxy ) +#if ENABLE_FEATURE_HTTPD_GZIP +# define content_gzip (G.content_gzip ) +#else +# define content_gzip 0 +#endif #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \ + IF_FEATURE_HTTPD_RANGES(range_start = -1;) \ bind_addr_or_port = "80"; \ index_page = index_html; \ file_size = -1; \ @@ -754,9 +796,9 @@ static void parse_conf(const char *path, int flag) /* the line is not recognized */ config_error: bb_error_msg("config error '%s' in '%s'", buf, filename); - } /* while (fgets) */ + } /* while (fgets) */ - fclose(f); + fclose(f); } #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR @@ -777,7 +819,7 @@ static char *encodeString(const char *string) char *p = out; char ch; - while ((ch = *string++)) { + while ((ch = *string++) != '\0') { /* very simple check for what to encode */ if (isalnum(ch)) *p++ = ch; @@ -787,79 +829,7 @@ static char *encodeString(const char *string) *p = '\0'; return out; } -#endif /* FEATURE_HTTPD_ENCODE_URL_STR */ - -/* - * Given a URL encoded string, convert it to plain ascii. - * Since decoding always makes strings smaller, the decode is done in-place. - * Thus, callers should xstrdup() the argument if they do not want the - * argument modified. The return is the original pointer, allowing this - * function to be easily used as arguments to other functions. - * - * string The first string to decode. - * option_d 1 if called for httpd -d - * - * Returns a pointer to the decoded string (same as input). - */ -static unsigned hex_to_bin(unsigned char c) -{ - unsigned v; - - v = c - '0'; - if (v <= 9) - return v; - /* c | 0x20: letters to lower case, non-letters - * to (potentially different) non-letters */ - v = (unsigned)(c | 0x20) - 'a'; - if (v <= 5) - return v + 10; - return ~0; -} -/* For testing: -void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } -int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); -t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } -*/ -static char *decodeString(char *orig, int option_d) -{ - /* note that decoded string is always shorter than original */ - char *string = orig; - char *ptr = string; - char c; - - while ((c = *ptr++) != '\0') { - unsigned v; - - if (option_d && c == '+') { - *string++ = ' '; - continue; - } - if (c != '%') { - *string++ = c; - continue; - } - v = hex_to_bin(ptr[0]); - if (v > 15) { - bad_hex: - if (!option_d) - return NULL; - *string++ = '%'; - continue; - } - v = (v * 16) | hex_to_bin(ptr[1]); - if (v > 255) - goto bad_hex; - if (!option_d && (v == '/' || v == '\0')) { - /* caller takes it as indication of invalid - * (dangerous wrt exploits) chars */ - return orig + 1; - } - *string++ = v; - ptr += 2; - } - *string = '\0'; - return orig; -} +#endif #if ENABLE_FEATURE_HTTPD_BASIC_AUTH /* @@ -1034,10 +1004,14 @@ static void send_headers(int responseNum) #endif "Last-Modified: %s\r\n%s %"OFF_FMT"u\r\n", tmp_str, - "Content-length:", + content_gzip ? "Transfer-length:" : "Content-length:", file_size ); } + + if (content_gzip) + len += sprintf(iobuf + len, "Content-Encoding: gzip\r\n"); + iobuf[len++] = '\r'; iobuf[len++] = '\n'; if (infoString) { @@ -1059,6 +1033,7 @@ static void send_headers(int responseNum) static void send_headers_and_exit(int responseNum) NORETURN; static void send_headers_and_exit(int responseNum) { + IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) send_headers(responseNum); log_and_exit(); } @@ -1129,18 +1104,31 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post /* NB: breaking out of this loop jumps to log_and_exit() */ out_cnt = 0; + pfd[FROM_CGI].fd = fromCgi_rd; + pfd[FROM_CGI].events = POLLIN; + pfd[TO_CGI].fd = toCgi_wr; while (1) { - memset(pfd, 0, sizeof(pfd)); - - pfd[FROM_CGI].fd = fromCgi_rd; - pfd[FROM_CGI].events = POLLIN; - - if (toCgi_wr) { - pfd[TO_CGI].fd = toCgi_wr; - if (hdr_cnt > 0) { - pfd[TO_CGI].events = POLLOUT; - } else if (post_len > 0) { - pfd[0].events = POLLIN; + /* Note: even pfd[0].events == 0 won't prevent + * revents == POLLHUP|POLLERR reports from closed stdin. + * Setting fd to -1 works: */ + pfd[0].fd = -1; + pfd[0].events = POLLIN; + pfd[0].revents = 0; /* probably not needed, paranoia */ + + /* We always poll this fd, thus kernel always sets revents: */ + /*pfd[FROM_CGI].events = POLLIN; - moved out of loop */ + /*pfd[FROM_CGI].revents = 0; - not needed */ + + /* gcc-4.8.0 still doesnt fill two shorts with one insn :( */ + /* http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47059 */ + /* hopefully one day it will... */ + pfd[TO_CGI].events = POLLOUT; + pfd[TO_CGI].revents = 0; /* needed! */ + + if (toCgi_wr && hdr_cnt <= 0) { + if (post_len > 0) { + /* Expect more POST data from network */ + pfd[0].fd = 0; } else { /* post_len <= 0 && hdr_cnt <= 0: * no more POST data to CGI, @@ -1152,7 +1140,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post } /* Now wait on the set of sockets */ - count = safe_poll(pfd, toCgi_wr ? TO_CGI+1 : FROM_CGI+1, -1); + count = safe_poll(pfd, hdr_cnt > 0 ? TO_CGI+1 : FROM_CGI+1, -1); if (count <= 0) { #if 0 if (safe_waitpid(pid, &status, WNOHANG) <= 0) { @@ -1169,7 +1157,7 @@ static NOINLINE void cgi_io_loop_and_exit(int fromCgi_rd, int toCgi_wr, int post } if (pfd[TO_CGI].revents) { - /* hdr_cnt > 0 here due to the way pfd[TO_CGI].events set */ + /* hdr_cnt > 0 here due to the way poll() called */ /* Have data from peer and can write to CGI */ count = safe_write(toCgi_wr, hdr_ptr, hdr_cnt); /* Doesn't happen, we dont use nonblocking IO here @@ -1291,18 +1279,21 @@ static void setenv1(const char *name, const char *value) * * Parameters: * const char *url The requested URL (with leading /). + * const char *orig_uri The original URI before rewriting (if any) * int post_len Length of the POST body. * const char *cookie For set HTTP_COOKIE. * const char *content_type For set CONTENT_TYPE. */ static void send_cgi_and_exit( const char *url, + const char *orig_uri, const char *request, int post_len, const char *cookie, const char *content_type) NORETURN; static void send_cgi_and_exit( const char *url, + const char *orig_uri, const char *request, int post_len, const char *cookie, @@ -1310,7 +1301,7 @@ static void send_cgi_and_exit( { struct fd_pair fromCgi; /* CGI -> httpd pipe */ struct fd_pair toCgi; /* httpd -> CGI pipe */ - char *script; + char *script, *last_slash; int pid; /* Make a copy. NB: caller guarantees: @@ -1324,22 +1315,25 @@ static void send_cgi_and_exit( */ /* Check for [dirs/]script.cgi/PATH_INFO */ - script = (char*)url; + last_slash = script = (char*)url; while ((script = strchr(script + 1, '/')) != NULL) { + int dir; *script = '\0'; - if (!is_directory(url + 1, 1, NULL)) { + dir = is_directory(url + 1, /*followlinks:*/ 1); + *script = '/'; + if (!dir) { /* not directory, found script.cgi/PATH_INFO */ - *script = '/'; break; } - *script = '/'; /* is directory, find next '/' */ + /* is directory, find next '/' */ + last_slash = script; } setenv1("PATH_INFO", script); /* set to /PATH_INFO or "" */ setenv1("REQUEST_METHOD", request); if (g_query) { - putenv(xasprintf("%s=%s?%s", "REQUEST_URI", url, g_query)); + putenv(xasprintf("%s=%s?%s", "REQUEST_URI", orig_uri, g_query)); } else { - setenv1("REQUEST_URI", url); + setenv1("REQUEST_URI", orig_uri); } if (script != NULL) *script = '\0'; /* cut off /PATH_INFO */ @@ -1413,7 +1407,7 @@ static void send_cgi_and_exit( log_and_exit(); } - if (!pid) { + if (pid == 0) { /* Child process */ char *argv[3]; @@ -1429,11 +1423,11 @@ static void send_cgi_and_exit( /* dup2(1, 2); */ /* Chdiring to script's dir */ - script = strrchr(url, '/'); + script = last_slash; if (script != url) { /* paranoia */ *script = '\0'; if (chdir(url + 1) != 0) { - bb_perror_msg("chdir(%s)", url + 1); + bb_perror_msg("can't change directory to '%s'", url + 1); goto error_execing_cgi; } // not needed: *script = '/'; @@ -1507,7 +1501,23 @@ static NOINLINE void send_file_and_exit(const char *url, int what) int fd; ssize_t count; - fd = open(url, O_RDONLY); + if (content_gzip) { + /* does .gz exist? Then use it instead */ + char *gzurl = xasprintf("%s.gz", url); + fd = open(gzurl, O_RDONLY); + free(gzurl); + if (fd != -1) { + struct stat sb; + fstat(fd, &sb); + file_size = sb.st_size; + last_mod = sb.st_mtime; + } else { + IF_FEATURE_HTTPD_GZIP(content_gzip = 0;) + fd = open(url, O_RDONLY); + } + } else { + fd = open(url, O_RDONLY); + } if (fd < 0) { if (DEBUG) bb_perror_msg("can't open '%s'", url); @@ -1590,18 +1600,21 @@ static NOINLINE void send_file_and_exit(const char *url, int what) url, found_mime_type); #if ENABLE_FEATURE_HTTPD_RANGES - if (what == SEND_BODY) - range_start = 0; /* err pages and ranges don't mix */ + if (what == SEND_BODY /* err pages and ranges don't mix */ + || content_gzip /* we are sending compressed page: can't do ranges */ ///why? + ) { + range_start = -1; + } range_len = MAXINT(off_t); - if (range_start) { - if (!range_end) { + if (range_start >= 0) { + if (!range_end || range_end > file_size - 1) { range_end = file_size - 1; } if (range_end < range_start || lseek(fd, range_start, SEEK_SET) != range_start ) { lseek(fd, 0, SEEK_SET); - range_start = 0; + range_start = -1; } else { range_len = range_end - range_start + 1; send_headers(HTTP_PARTIAL_CONTENT); @@ -1624,7 +1637,7 @@ static NOINLINE void send_file_and_exit(const char *url, int what) break; /* fall back to read/write loop */ goto fin; } - IF_FEATURE_HTTPD_RANGES(range_len -= sz;) + IF_FEATURE_HTTPD_RANGES(range_len -= count;) if (count == 0 || range_len == 0) log_and_exit(); } @@ -1675,6 +1688,56 @@ static int checkPermIP(void) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH + +# if ENABLE_PAM +struct pam_userinfo { + const char *name; + const char *pw; +}; + +static int pam_talker(int num_msg, + const struct pam_message **msg, + struct pam_response **resp, + void *appdata_ptr) +{ + int i; + struct pam_userinfo *userinfo = (struct pam_userinfo *) appdata_ptr; + struct pam_response *response; + + if (!resp || !msg || !userinfo) + return PAM_CONV_ERR; + + /* allocate memory to store response */ + response = xzalloc(num_msg * sizeof(*response)); + + /* copy values */ + for (i = 0; i < num_msg; i++) { + const char *s; + + switch (msg[i]->msg_style) { + case PAM_PROMPT_ECHO_ON: + s = userinfo->name; + break; + case PAM_PROMPT_ECHO_OFF: + s = userinfo->pw; + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + s = ""; + break; + default: + free(response); + return PAM_CONV_ERR; + } + response[i].resp = xstrdup(s); + if (PAM_SUCCESS != 0) + response[i].resp_retcode = PAM_SUCCESS; + } + *resp = response; + return PAM_SUCCESS; +} +# endif + /* * Config file entries are of the form "/::". * If config file has no prefix match for path, access is allowed. @@ -1684,7 +1747,7 @@ static int checkPermIP(void) * * Returns 1 if user_and_passwd is OK. */ -static int check_user_passwd(const char *path, const char *user_and_passwd) +static int check_user_passwd(const char *path, char *user_and_passwd) { Htaccess *cur; const char *prev = NULL; @@ -1692,6 +1755,7 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) for (cur = g_auth; cur; cur = cur->next) { const char *dir_prefix; size_t len; + int r; dir_prefix = cur->before_colon; @@ -1707,7 +1771,8 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) len = strlen(dir_prefix); if (len != 1 /* dir_prefix "/" matches all, don't need to check */ && (strncmp(dir_prefix, path, len) != 0 - || (path[len] != '/' && path[len] != '\0')) + || (path[len] != '/' && path[len] != '\0') + ) ) { continue; } @@ -1716,38 +1781,105 @@ static int check_user_passwd(const char *path, const char *user_and_passwd) prev = dir_prefix; if (ENABLE_FEATURE_HTTPD_AUTH_MD5) { - char *md5_passwd; - - md5_passwd = strchr(cur->after_colon, ':'); - if (md5_passwd && md5_passwd[1] == '$' && md5_passwd[2] == '1' - && md5_passwd[3] == '$' && md5_passwd[4] + char *colon_after_user; + const char *passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS && !ENABLE_PAM + char sp_buf[256]; +# endif + + colon_after_user = strchr(user_and_passwd, ':'); + if (!colon_after_user) + goto bad_input; + + /* compare "user:" */ + if (cur->after_colon[0] != '*' + && strncmp(cur->after_colon, user_and_passwd, + colon_after_user - user_and_passwd + 1) != 0 ) { - char *encrypted; - int r, user_len_p1; - - md5_passwd++; - user_len_p1 = md5_passwd - cur->after_colon; - /* comparing "user:" */ - if (strncmp(cur->after_colon, user_and_passwd, user_len_p1) != 0) { + continue; + } + /* this cfg entry is '*' or matches username from peer */ + + passwd = strchr(cur->after_colon, ':'); + if (!passwd) + goto bad_input; + passwd++; + if (passwd[0] == '*') { +# if ENABLE_PAM + struct pam_userinfo userinfo; + struct pam_conv conv_info = { &pam_talker, (void *) &userinfo }; + pam_handle_t *pamh; + + *colon_after_user = '\0'; + userinfo.name = user_and_passwd; + userinfo.pw = colon_after_user + 1; + r = pam_start("httpd", user_and_passwd, &conv_info, &pamh) != PAM_SUCCESS; + if (r == 0) { + r = pam_authenticate(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + || pam_acct_mgmt(pamh, PAM_DISALLOW_NULL_AUTHTOK) != PAM_SUCCESS + ; + pam_end(pamh, PAM_SUCCESS); + } + *colon_after_user = ':'; + goto end_check_passwd; +# else +# if ENABLE_FEATURE_SHADOWPASSWDS + /* Using _r function to avoid pulling in static buffers */ + struct spwd spw; +# endif + struct passwd *pw; + + *colon_after_user = '\0'; + pw = getpwnam(user_and_passwd); + *colon_after_user = ':'; + if (!pw || !pw->pw_passwd) continue; + passwd = pw->pw_passwd; +# if ENABLE_FEATURE_SHADOWPASSWDS + if ((passwd[0] == 'x' || passwd[0] == '*') && !passwd[1]) { + /* getspnam_r may return 0 yet set result to NULL. + * At least glibc 2.4 does this. Be extra paranoid here. */ + struct spwd *result = NULL; + r = getspnam_r(pw->pw_name, &spw, sp_buf, sizeof(sp_buf), &result); + if (r == 0 && result) + passwd = result->sp_pwdp; } +# endif + /* In this case, passwd is ALWAYS encrypted: + * it came from /etc/passwd or /etc/shadow! + */ + goto check_encrypted; +# endif /* ENABLE_PAM */ + } + /* Else: passwd is from httpd.conf, it is either plaintext or encrypted */ + if (passwd[0] == '$' && isdigit(passwd[1])) { + char *encrypted; +# if !ENABLE_PAM + check_encrypted: +# endif + /* encrypt pwd from peer and check match with local one */ encrypted = pw_encrypt( - user_and_passwd + user_len_p1 /* cleartext pwd from user */, - md5_passwd /*salt */, 1 /* cleanup */); - r = strcmp(encrypted, md5_passwd); + /* pwd (from peer): */ colon_after_user + 1, + /* salt: */ passwd, + /* cleanup: */ 0 + ); + r = strcmp(encrypted, passwd); free(encrypted); - if (r == 0) - goto set_remoteuser_var; /* Ok */ - continue; + } else { + /* local passwd is from httpd.conf and it's plaintext */ + r = strcmp(colon_after_user + 1, passwd); } + goto end_check_passwd; } - + bad_input: /* Comparing plaintext "user:pass" in one go */ - if (strcmp(cur->after_colon, user_and_passwd) == 0) { - set_remoteuser_var: + r = strcmp(cur->after_colon, user_and_passwd); + end_check_passwd: + if (r == 0) { remoteuser = xstrndup(user_and_passwd, - strchrnul(user_and_passwd, ':') - user_and_passwd); + strchrnul(user_and_passwd, ':') - user_and_passwd + ); return 1; /* Ok */ } } /* for */ @@ -1845,7 +1977,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) send_headers_and_exit(HTTP_BAD_REQUEST); /* Determine type of request (GET/POST) */ - urlp = strpbrk(iobuf, " \t"); + // rfc2616: method and URI is separated by exactly one space + //urlp = strpbrk(iobuf, " \t"); - no, tab isn't allowed + urlp = strchr(iobuf, ' '); if (urlp == NULL) send_headers_and_exit(HTTP_BAD_REQUEST); *urlp++ = '\0'; @@ -1863,7 +1997,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (strcasecmp(iobuf, request_GET) != 0) send_headers_and_exit(HTTP_NOT_IMPLEMENTED); #endif - urlp = skip_whitespace(urlp); + // rfc2616: method and URI is separated by exactly one space + //urlp = skip_whitespace(urlp); - should not be necessary if (urlp[0] != '/') send_headers_and_exit(HTTP_BAD_REQUEST); @@ -1886,7 +2021,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* NB: urlcopy ptr is never changed after this */ /* Extract url args if present */ - g_query = NULL; + /* g_query = NULL; - already is */ tptr = strchr(urlcopy, '?'); if (tptr) { *tptr++ = '\0'; @@ -1894,7 +2029,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } /* Decode URL escape sequences */ - tptr = decodeString(urlcopy, 0); + tptr = percent_decode_in_place(urlcopy, /*strict:*/ 1); if (tptr == NULL) send_headers_and_exit(HTTP_BAD_REQUEST); if (tptr == urlcopy + 1) { @@ -1906,34 +2041,40 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* Algorithm stolen from libbb bb_simplify_path(), * but don't strdup, retain trailing slash, protect root */ urlp = tptr = urlcopy; - do { + for (;;) { if (*urlp == '/') { /* skip duplicate (or initial) slash */ if (*tptr == '/') { - continue; + goto next_char; } if (*tptr == '.') { - /* skip extra "/./" */ - if (tptr[1] == '/' || !tptr[1]) { - continue; - } - /* "..": be careful */ - if (tptr[1] == '.' && (tptr[2] == '/' || !tptr[2])) { - ++tptr; - if (urlp == urlcopy) /* protect root */ + if (tptr[1] == '.' && (tptr[2] == '/' || tptr[2] == '\0')) { + /* "..": be careful */ + /* protect root */ + if (urlp == urlcopy) send_headers_and_exit(HTTP_BAD_REQUEST); - while (*--urlp != '/') /* omit previous dir */; + /* omit previous dir */ + while (*--urlp != '/') continue; + /* skip to "./" or "." */ + tptr++; + } + if (tptr[1] == '/' || tptr[1] == '\0') { + /* skip extra "/./" */ + goto next_char; } } } *++urlp = *tptr; - } while (*++tptr); - *++urlp = '\0'; /* terminate after last character */ + if (*urlp == '\0') + break; + next_char: + tptr++; + } /* If URL is a directory, add '/' */ if (urlp[-1] != '/') { - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { found_moved_temporarily = urlcopy; } } @@ -1947,7 +2088,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) while (ip_allowed && (tptr = strchr(tptr + 1, '/')) != NULL) { /* have path1/path2 */ *tptr = '\0'; - if (is_directory(urlcopy + 1, 1, NULL)) { + if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) { /* may have subdir config */ parse_conf(urlcopy + 1, SUBDIR_PARSE); ip_allowed = checkPermIP(); @@ -1964,7 +2105,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if (http_major_version >= '0') { /* Request was with "... HTTP/nXXX", and n >= 0 */ - /* Read until blank line for HTTP version specified, else parse immediate */ + /* Read until blank line */ while (1) { if (!get_line()) break; /* EOF or error or empty line */ @@ -1991,9 +2132,9 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) if ((STRNCASECMP(iobuf, "Content-length:") == 0)) { /* extra read only for POST */ if (prequest != request_GET -#if ENABLE_FEATURE_HTTPD_CGI +# if ENABLE_FEATURE_HTTPD_CGI && prequest != request_HEAD -#endif +# endif ) { tptr = skip_whitespace(iobuf + sizeof("Content-length:") - 1); if (!tptr[0]) @@ -2046,15 +2187,32 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) s += sizeof("bytes=")-1; range_start = BB_STRTOOFF(s, &s, 10); if (s[0] != '-' || range_start < 0) { - range_start = 0; + range_start = -1; } else if (s[1]) { range_end = BB_STRTOOFF(s+1, NULL, 10); if (errno || range_end < range_start) - range_start = 0; + range_start = -1; } } } #endif +#if ENABLE_FEATURE_HTTPD_GZIP + if (STRNCASECMP(iobuf, "Accept-Encoding:") == 0) { + /* Note: we do not support "gzip;q=0" + * method of _disabling_ gzip + * delivery. No one uses that, though */ + const char *s = strstr(iobuf, "gzip"); + if (s) { + // want more thorough checks? + //if (s[-1] == ' ' + // || s[-1] == ',' + // || s[-1] == ':' + //) { + content_gzip = 1; + //} + } + } +#endif } /* while extra header reading */ } @@ -2067,10 +2225,10 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) } #if ENABLE_FEATURE_HTTPD_BASIC_AUTH - /* Case: no "Authorization:" was seen, but page does require passwd. + /* Case: no "Authorization:" was seen, but page might require passwd. * Check that with dummy user:pass */ if (authorized < 0) - authorized = check_user_passwd(urlcopy, ":"); + authorized = check_user_passwd(urlcopy, (char *) ""); if (!authorized) send_headers_and_exit(HTTP_UNAUTHORIZED); #endif @@ -2116,12 +2274,20 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* protect listing "cgi-bin/" */ send_headers_and_exit(HTTP_FORBIDDEN); } - send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } #endif - if (urlp[-1] == '/') + if (urlp[-1] == '/') { + /* When index_page string is appended to / URL, it overwrites + * the query string. If we fall back to call /cgi-bin/index.cgi, + * query string would be lost and not available to the CGI. + * Work around it by making a deep copy. + */ + if (ENABLE_FEATURE_HTTPD_CGI) + g_query = xstrdup(g_query); /* ok for NULL too */ strcpy(urlp, index_page); + } if (stat(tptr, &sb) == 0) { #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR char *suffix = strrchr(tptr, '.'); @@ -2129,7 +2295,7 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) Htaccess *cur; for (cur = script_i; cur; cur = cur->next) { if (strcmp(cur->before_colon + 1, suffix) == 0) { - send_cgi_and_exit(urlcopy, prequest, length, cookie, content_type); + send_cgi_and_exit(urlcopy, urlcopy, prequest, length, cookie, content_type); } } } @@ -2142,9 +2308,8 @@ static void handle_incoming_and_exit(const len_and_sockaddr *fromAddr) /* It's a dir URL and there is no index.html * Try cgi-bin/index.cgi */ if (access("/cgi-bin/index.cgi"+1, X_OK) == 0) { - urlp[0] = '\0'; - g_query = urlcopy; - send_cgi_and_exit("/cgi-bin/index.cgi", prequest, length, cookie, content_type); + urlp[0] = '\0'; /* remove index_page */ + send_cgi_and_exit("/cgi-bin/index.cgi", urlcopy, prequest, length, cookie, content_type); } } /* else fall through to send_file, it errors out if open fails: */ @@ -2183,9 +2348,9 @@ static void mini_httpd(int server_socket) /* Wait for connections... */ fromAddr.len = LSA_SIZEOF_SA; n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len); - if (n < 0) continue; + /* set the KEEPALIVE option to cull dead connections */ setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); @@ -2226,9 +2391,9 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) /* Wait for connections... */ fromAddr.len = LSA_SIZEOF_SA; n = accept(server_socket, &fromAddr.u.sa, &fromAddr.len); - if (n < 0) continue; + /* set the KEEPALIVE option to cull dead connections */ setsockopt(n, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); @@ -2243,6 +2408,7 @@ static void mini_httpd_nommu(int server_socket, int argc, char **argv) /* Run a copy of ourself in inetd mode */ re_exec(argv_copy); } + argv_copy[0][0] &= 0x7f; /* parent, or vfork failed */ close(n); } /* while (1) */ @@ -2336,7 +2502,7 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) , &verbose ); if (opt & OPT_DECODE_URL) { - fputs(decodeString(url_for_decode, 1), stdout); + fputs(percent_decode_in_place(url_for_decode, /*strict:*/ 0), stdout); return 0; } #if ENABLE_FEATURE_HTTPD_ENCODE_URL_STR @@ -2351,8 +2517,8 @@ int httpd_main(int argc UNUSED_PARAM, char **argv) salt[0] = '$'; salt[1] = '1'; salt[2] = '$'; - crypt_make_salt(salt + 3, 4, 0); - puts(pw_encrypt(pass, salt, 1)); + crypt_make_salt(salt + 3, 4); + puts(pw_encrypt(pass, salt, /*cleanup:*/ 0)); return 0; } #endif diff --git a/networking/httpd_indexcgi.c b/networking/httpd_indexcgi.c index af43380..562cd7f 100644 --- a/networking/httpd_indexcgi.c +++ b/networking/httpd_indexcgi.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2007 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* @@ -35,6 +35,7 @@ httpd_indexcgi.c -o index.cgi * 2576 4 2048 4628 1214 index.cgi.o */ +#define _GNU_SOURCE 1 /* for strchrnul */ #include #include #include @@ -221,20 +222,25 @@ int main(int argc, char *argv[]) unsigned long long size_total; int odd; DIR *dirp; - char *QUERY_STRING; - - QUERY_STRING = getenv("QUERY_STRING"); - if (!QUERY_STRING - || QUERY_STRING[0] != '/' - || strstr(QUERY_STRING, "//") - || strstr(QUERY_STRING, "/../") - || strcmp(strrchr(QUERY_STRING, '/'), "/..") == 0 + char *location; + + location = getenv("REQUEST_URI"); + if (!location) + return 1; + + /* drop URL arguments if any */ + strchrnul(location, '?')[0] = '\0'; + + if (location[0] != '/' + || strstr(location, "//") + || strstr(location, "/../") + || strcmp(strrchr(location, '/'), "/..") == 0 ) { return 1; } if (chdir("..") - || (QUERY_STRING[1] && chdir(QUERY_STRING + 1)) + || (location[1] && chdir(location + 1)) ) { return 1; } @@ -271,14 +277,14 @@ int main(int argc, char *argv[]) "\r\n" /* Mandatory empty line after headers */ "Index of "); /* Guard against directories with &, > etc */ - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "\n" STYLE_STR "" "\n" "" "\n" "

Index of "); - fmt_html(QUERY_STRING); + fmt_html(location); fmt_str( "

" "\n" "" "\n" diff --git a/networking/httpd_ssi.c b/networking/httpd_ssi.c index 03f2633..4bd9a6d 100644 --- a/networking/httpd_ssi.c +++ b/networking/httpd_ssi.c @@ -1,7 +1,7 @@ /* * Copyright (c) 2009 Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* @@ -52,9 +52,9 @@ httpd_ssi.c -o httpd_ssi static char* skip_whitespace(char *s) { - while (*s == ' ' || *s == '\t') ++s; + while (*s == ' ' || *s == '\t') ++s; - return s; + return s; } static char line[64 * 1024]; @@ -133,7 +133,7 @@ static void process_includes(const char *filename) process_includes(include_directive); /* Print everything after directive */ - if (end) { + if (end) { fputs(end, stdout); free(end); } diff --git a/networking/ifconfig.c b/networking/ifconfig.c index 1a56c1c..8984b02 100644 --- a/networking/ifconfig.c +++ b/networking/ifconfig.c @@ -10,7 +10,7 @@ * Authors of the original ifconfig was: * Fred N. van Kempen, * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -26,21 +26,37 @@ * IPV6 support added by Bart Visscher */ +//usage:#define ifconfig_trivial_usage +//usage: IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]" +//usage:#define ifconfig_full_usage "\n\n" +//usage: "Configure a network interface\n" +//usage: "\n" +//usage: IF_FEATURE_IPV6( +//usage: " [add ADDRESS[/PREFIXLEN]]\n") +//usage: IF_FEATURE_IPV6( +//usage: " [del ADDRESS[/PREFIXLEN]]\n") +//usage: " [[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" +//usage: " [netmask ADDRESS] [dstaddr ADDRESS]\n" +//usage: IF_FEATURE_IFCONFIG_SLIP( +//usage: " [outfill NN] [keepalive NN]\n") +//usage: " " IF_FEATURE_IFCONFIG_HW("[hw ether" IF_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu NN]\n" +//usage: " [[-]trailers] [[-]arp] [[-]allmulti]\n" +//usage: " [multicast] [[-]promisc] [txqueuelen NN] [[-]dynamic]\n" +//usage: IF_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( +//usage: " [mem_start NN] [io_addr NN] [irq NN]\n") +//usage: " [up|down] ..." + +#include "libbb.h" +#include "inet_common.h" #include #include #include -#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 -#include -#include -#else -#include -#include +#ifdef HAVE_NET_ETHERNET_H +# include #endif -#include "libbb.h" -#include "inet_common.h" #if ENABLE_FEATURE_IFCONFIG_SLIP -# include +# include #endif /* I don't know if this is needed for busybox or not. Anyone? */ @@ -158,10 +174,6 @@ struct in6_ifreq { #define ARG_ADD_DEL (A_CAST_HOST_COPY_RESOLVE | A_SET_AFTER) -/* - * Set up the tables. Warning! They must have corresponding order! - */ - struct arg1opt { const char *name; unsigned short selector; @@ -182,6 +194,10 @@ struct options { #define ifreq_offsetof(x) offsetof(struct ifreq, x) +/* + * Set up the tables. Warning! They must have corresponding order! + */ + static const struct arg1opt Arg1Opt[] = { { "SIFMETRIC", SIOCSIFMETRIC, ifreq_offsetof(ifr_metric) }, { "SIFMTU", SIOCSIFMTU, ifreq_offsetof(ifr_mtu) }, @@ -204,11 +220,11 @@ static const struct arg1opt Arg1Opt[] = { { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.base_addr) }, { "SIFMAP", SIOCSIFMAP, ifreq_offsetof(ifr_map.irq) }, #endif - /* Last entry if for unmatched (possibly hostname) arg. */ #if ENABLE_FEATURE_IPV6 { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */ { "DIFADDR", SIOCDIFADDR, ifreq_offsetof(ifr_addr) }, /* IPv6 version ignores the offset */ #endif + /* Last entry is for unmatched (assumed to be hostname/address) arg. */ { "SIFADDR", SIOCSIFADDR, ifreq_offsetof(ifr_addr) }, }; @@ -249,16 +265,6 @@ static const struct options OptArray[] = { { NULL, 0, ARG_HOSTNAME, (IFF_UP | IFF_RUNNING) } }; -/* - * A couple of prototypes. - */ -#if ENABLE_FEATURE_IFCONFIG_HW -static int in_ether(const char *bufp, struct sockaddr *sap); -#endif - -/* - * Our main function. - */ int ifconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ifconfig_main(int argc UNUSED_PARAM, char **argv) { @@ -314,7 +320,7 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) strncpy_IFNAMSIZ(ifr.ifr_name, *argv); /* Process the remaining arguments. */ - while (*++argv != (char *) NULL) { + while (*++argv != NULL) { p = *argv; mask = N_MASK; if (*p == '-') { /* If the arg starts with '-'... */ @@ -340,9 +346,9 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) FOUND_ARG: if (mask & ARG_MASK) { mask = op->arg_flags; - a1op = Arg1Opt + (op - OptArray); if (mask & A_NETMASK & did_flags) bb_show_usage(); + a1op = Arg1Opt + (op - OptArray); if (*++argv == NULL) { if (mask & A_ARG_REQ) bb_show_usage(); @@ -355,27 +361,18 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_IFCONFIG_HW if (mask & A_CAST_RESOLVE) { #endif -#if ENABLE_FEATURE_IPV6 - char *prefix; - int prefix_len = 0; -#endif - /*safe_strncpy(host, *argv, (sizeof host));*/ host = *argv; -#if ENABLE_FEATURE_IPV6 - prefix = strchr(host, '/'); - if (prefix) { - prefix_len = xatou_range(prefix + 1, 0, 128); - *prefix = '\0'; - } -#endif + if (strcmp(host, "inet") == 0) + continue; /* compat stuff */ sai.sin_family = AF_INET; sai.sin_port = 0; - if (!strcmp(host, bb_str_default)) { + if (strcmp(host, "default") == 0) { /* Default is special, meaning 0.0.0.0. */ sai.sin_addr.s_addr = INADDR_ANY; } #if ENABLE_FEATURE_IFCONFIG_BROADCAST_PLUS - else if ((host[0] == '+' && !host[1]) && (mask & A_BROADCAST) + else if ((host[0] == '+' && !host[1]) + && (mask & A_BROADCAST) && (did_flags & (A_NETMASK|A_HOSTNAME)) == (A_NETMASK|A_HOSTNAME) ) { /* + is special, meaning broadcast is derived. */ @@ -384,23 +381,36 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) #endif else { len_and_sockaddr *lsa; - if (strcmp(host, "inet") == 0) - continue; /* compat stuff */ +#if ENABLE_FEATURE_IPV6 + char *prefix; + int prefix_len = 0; + prefix = strchr(host, '/'); + if (prefix) { + prefix_len = xatou_range(prefix + 1, 0, 128); + *prefix = '\0'; + } + resolve: +#endif lsa = xhost2sockaddr(host, 0); #if ENABLE_FEATURE_IPV6 + if (lsa->u.sa.sa_family != AF_INET6 && prefix) { +/* TODO: we do not support "ifconfig eth0 up 1.2.3.4/17". + * For now, just make it fail instead of silently ignoring "/17" part: + */ + *prefix = '/'; + goto resolve; + } if (lsa->u.sa.sa_family == AF_INET6) { int sockfd6; struct in6_ifreq ifr6; - memcpy((char *) &ifr6.ifr6_addr, - (char *) &(lsa->u.sin6.sin6_addr), - sizeof(struct in6_addr)); - - /* Create a channel to the NET kernel. */ sockfd6 = xsocket(AF_INET6, SOCK_DGRAM, 0); - xioctl(sockfd6, SIOGIFINDEX, &ifr); + xioctl(sockfd6, SIOCGIFINDEX, &ifr); ifr6.ifr6_ifindex = ifr.ifr_ifindex; ifr6.ifr6_prefixlen = prefix_len; + memcpy(&ifr6.ifr6_addr, + &lsa->u.sin6.sin6_addr, + sizeof(struct in6_addr)); ioctl_or_perror_and_die(sockfd6, a1op->selector, &ifr6, "SIOC%s", a1op->name); if (ENABLE_FEATURE_CLEAN_UP) free(lsa); @@ -421,19 +431,18 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_IFCONFIG_HW } else { /* A_CAST_HOST_COPY_IN_ETHER */ /* This is the "hw" arg case. */ - smalluint hw_class= index_in_substrings("ether\0" + smalluint hw_class = index_in_substrings("ether\0" IF_FEATURE_HWIB("infiniband\0"), *argv) + 1; if (!hw_class || !*++argv) bb_show_usage(); - /*safe_strncpy(host, *argv, sizeof(host));*/ host = *argv; if (hw_class == 1 ? in_ether(host, &sa) : in_ib(host, &sa)) bb_error_msg_and_die("invalid hw-addr %s", host); p = (char *) &sa; } #endif - memcpy( (((char *)&ifr) + a1op->ifr_offset), - p, sizeof(struct sockaddr)); + memcpy( ((char *)&ifr) + a1op->ifr_offset, + p, sizeof(struct sockaddr)); } else { /* FIXME: error check?? */ unsigned long i = strtoul(*argv, NULL, 0); @@ -442,17 +451,17 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) if (mask & A_MAP_TYPE) { xioctl(sockfd, SIOCGIFMAP, &ifr); if ((mask & A_MAP_UCHAR) == A_MAP_UCHAR) - *((unsigned char *) p) = i; + *(unsigned char *) p = i; else if (mask & A_MAP_USHORT) - *((unsigned short *) p) = i; + *(unsigned short *) p = i; else - *((unsigned long *) p) = i; + *(unsigned long *) p = i; } else #endif if (mask & A_CAST_CHAR_PTR) - *((caddr_t *) p) = (caddr_t) i; + *(caddr_t *) p = (caddr_t) i; else /* A_CAST_INT */ - *((int *) p) = i; + *(int *) p = i; } ioctl_or_perror_and_die(sockfd, a1op->selector, &ifr, "SIOC%s", a1op->name); @@ -478,7 +487,7 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) if (!(mask & A_SET_AFTER)) continue; mask = N_SET; - } + } /* if (mask & ARG_MASK) */ xioctl(sockfd, SIOCGIFFLAGS, &ifr); selector = op->selector; @@ -493,46 +502,3 @@ int ifconfig_main(int argc UNUSED_PARAM, char **argv) close(sockfd); return 0; } - -#if ENABLE_FEATURE_IFCONFIG_HW -/* Input an Ethernet address and convert to binary. */ -static int in_ether(const char *bufp, struct sockaddr *sap) -{ - char *ptr; - int i, j; - unsigned char val; - unsigned char c; - - sap->sa_family = ARPHRD_ETHER; - ptr = (char *) sap->sa_data; - - i = 0; - do { - j = val = 0; - - /* We might get a semicolon here - not required. */ - if (i && (*bufp == ':')) { - bufp++; - } - - do { - c = *bufp; - if (((unsigned char)(c - '0')) <= 9) { - c -= '0'; - } else if (((unsigned char)((c|0x20) - 'a')) <= 5) { - c = (c|0x20) - ('a'-10); - } else if (j && (c == ':' || c == 0)) { - break; - } else { - return -1; - } - ++bufp; - val <<= 4; - val += c; - } while (++j < 2); - *ptr++ = val; - } while (++i < ETH_ALEN); - - return *bufp; /* Error if we don't end at end of string. */ -} -#endif diff --git a/networking/ifenslave.c b/networking/ifenslave.c index 0b3ebf7..c3be818 100644 --- a/networking/ifenslave.c +++ b/networking/ifenslave.c @@ -98,6 +98,32 @@ * set version to 1.1.0 */ +//usage:#define ifenslave_trivial_usage +//usage: "[-cdf] MASTER_IFACE SLAVE_IFACE..." +//usage:#define ifenslave_full_usage "\n\n" +//usage: "Configure network interfaces for parallel routing\n" +//usage: "\n -c,--change-active Change active slave" +//usage: "\n -d,--detach Remove slave interface from bonding device" +//usage: "\n -f,--force Force, even if interface is not Ethernet" +/* //usage: "\n -r,--receive-slave Create a receive-only slave" */ +//usage: +//usage:#define ifenslave_example_usage +//usage: "To create a bond device, simply follow these three steps:\n" +//usage: "- ensure that the required drivers are properly loaded:\n" +//usage: " # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n" +//usage: "- assign an IP address to the bond device:\n" +//usage: " # ifconfig bond0 netmask broadcast \n" +//usage: "- attach all the interfaces you need to the bond device:\n" +//usage: " # ifenslave bond0 eth0 eth1 eth2\n" +//usage: " If bond0 didn't have a MAC address, it will take eth0's. Then, all\n" +//usage: " interfaces attached AFTER this assignment will get the same MAC addr.\n\n" +//usage: " To detach a dead interface without setting the bond device down:\n" +//usage: " # ifenslave -d bond0 eth1\n\n" +//usage: " To set the bond device down and automatically release all the slaves:\n" +//usage: " # ifconfig bond0 down\n\n" +//usage: " To change active slave:\n" +//usage: " # ifenslave -c bond0 eth0\n" + #include "libbb.h" /* #include - no. linux/if_bonding.h pulls in linux/if.h */ @@ -244,7 +270,7 @@ static int set_if_addr(char *master_ifname, char *slave_ifname) if (res < 0) { ifr.ifr_addr.sa_family = AF_INET; memset(ifr.ifr_addr.sa_data, 0, - sizeof(ifr.ifr_addr.sa_data)); + sizeof(ifr.ifr_addr.sa_data)); } res = set_ifrname_and_do_ioctl(ifra[i].s_ioctl, &ifr, slave_ifname); @@ -520,7 +546,7 @@ int ifenslave_main(int argc UNUSED_PARAM, char **argv) #ifdef WHY_BOTHER /* Neither -c[hange] nor -d[etach] -> it's "enslave" then; * and -f[orce] is not there too. Check that it's ethernet. */ - if (!(opt & (OPT_d|OPT_c|OPT_f)) { + if (!(opt & (OPT_d|OPT_c|OPT_f))) { /* The family '1' is ARPHRD_ETHER for ethernet. */ if (master.hwaddr.ifr_hwaddr.sa_family != 1) { bb_error_msg_and_die( diff --git a/networking/ifplugd.c b/networking/ifplugd.c index 8cb07db..b578f4c 100644 --- a/networking/ifplugd.c +++ b/networking/ifplugd.c @@ -4,15 +4,42 @@ * * Copyright (C) 2009 Maksym Kryzhanovskyy * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define ifplugd_trivial_usage +//usage: "[OPTIONS]" +//usage:#define ifplugd_full_usage "\n\n" +//usage: "Network interface plug detection daemon\n" +//usage: "\n -n Don't daemonize" +//usage: "\n -s Don't log to syslog" +//usage: "\n -i IFACE Interface" +//usage: "\n -f/-F Treat link detection error as link down/link up" +//usage: "\n (otherwise exit on error)" +//usage: "\n -a Don't up interface at each link probe" +//usage: "\n -M Monitor creation/destruction of interface" +//usage: "\n (otherwise it must exist)" +//usage: "\n -r PROG Script to run" +//usage: "\n -x ARG Extra argument for script" +//usage: "\n -I Don't exit on nonzero exit code from script" +//usage: "\n -p Don't run \"up\" script on startup" +//usage: "\n -q Don't run \"down\" script on exit" +//usage: "\n -l Always run script on startup" +//usage: "\n -t SECS Poll time in seconds" +//usage: "\n -u SECS Delay before running script after link up" +//usage: "\n -d SECS Delay after link down" +//usage: "\n -m MODE API mode (mii, priv, ethtool, wlan, iff, auto)" +//usage: "\n -k Kill running daemon" + #include "libbb.h" #include "fix_u32.h" #include #include #include -#include +#ifdef HAVE_NET_ETHERNET_H +# include +#endif #include #include #include @@ -71,15 +98,6 @@ enum { # define OPTION_STR "+ansfFi:r:It:u:d:m:pqlx:M" #endif -enum { // api mode - API_AUTO = 'a', - API_ETHTOOL = 'e', - API_MII = 'm', - API_PRIVATE = 'p', - API_WLAN = 'w', - API_IFF = 'i', -}; - enum { // interface status IFSTATUS_ERR = -1, IFSTATUS_DOWN = 0, @@ -95,6 +113,7 @@ struct globals { smallint iface_last_status; smallint iface_prev_status; smallint iface_exists; + smallint api_method_num; /* Used in getopt32, must have sizeof == sizeof(int) */ unsigned poll_time; @@ -105,9 +124,6 @@ struct globals { const char *api_mode; const char *script_name; const char *extra_arg; - - smallint (*detect_link_func)(void); - smallint (*cached_detect_link_func)(void); }; #define G (*ptr_to_globals) #define INIT_G() do { \ @@ -122,42 +138,12 @@ struct globals { } while (0) -static const char *strstatus(int status) -{ - if (status == IFSTATUS_ERR) - return "error"; - return "down\0up" + (status * 5); -} +/* Utility routines */ -static int run_script(const char *action) +static void set_ifreq_to_ifname(struct ifreq *ifreq) { - char *env_PREVIOUS, *env_CURRENT; - char *argv[5]; - int r; - - bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action); - - argv[0] = (char*) G.script_name; - argv[1] = (char*) G.iface; - argv[2] = (char*) action; - argv[3] = (char*) G.extra_arg; - argv[4] = NULL; - - env_PREVIOUS = xasprintf("%s=%s", IFPLUGD_ENV_PREVIOUS, strstatus(G.iface_prev_status)); - putenv(env_PREVIOUS); - env_CURRENT = xasprintf("%s=%s", IFPLUGD_ENV_CURRENT, strstatus(G.iface_last_status)); - putenv(env_CURRENT); - - /* r < 0 - can't exec, 0 <= r < 0x180 - exited, >=0x180 - killed by sig (r-0x180) */ - r = spawn_and_wait(argv); - - unsetenv(IFPLUGD_ENV_PREVIOUS); - unsetenv(IFPLUGD_ENV_CURRENT); - free(env_PREVIOUS); - free(env_CURRENT); - - bb_error_msg("exit code: %d", r & 0xff); - return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r; + memset(ifreq, 0, sizeof(struct ifreq)); + strncpy_IFNAMSIZ(ifreq->ifr_name, G.iface); } static int network_ioctl(int request, void* data, const char *errmsg) @@ -168,95 +154,25 @@ static int network_ioctl(int request, void* data, const char *errmsg) return r; } -static void set_ifreq_to_ifname(struct ifreq *ifreq) -{ - memset(ifreq, 0, sizeof(struct ifreq)); - strncpy_IFNAMSIZ(ifreq->ifr_name, G.iface); -} - -static void up_iface(void) -{ - struct ifreq ifrequest; - - if (!G.iface_exists) - return; - - set_ifreq_to_ifname(&ifrequest); - if (network_ioctl(SIOCGIFFLAGS, &ifrequest, "getting interface flags") < 0) { - G.iface_exists = 0; - return; - } - - if (!(ifrequest.ifr_flags & IFF_UP)) { - ifrequest.ifr_flags |= IFF_UP; - /* Let user know we mess up with interface */ - bb_error_msg("upping interface"); - if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) - xfunc_die(); - } - -#if 0 /* why do we mess with IP addr? It's not our business */ - if (network_ioctl(SIOCGIFADDR, &ifrequest, "can't get interface address") < 0) { - } else if (ifrequest.ifr_addr.sa_family != AF_INET) { - bb_perror_msg("the interface is not IP-based"); - } else { - ((struct sockaddr_in*)(&ifrequest.ifr_addr))->sin_addr.s_addr = INADDR_ANY; - network_ioctl(SIOCSIFADDR, &ifrequest, "can't set interface address"); - } - network_ioctl(SIOCGIFFLAGS, &ifrequest, "can't get interface flags"); -#endif -} - -static void maybe_up_new_iface(void) -{ - if (!(option_mask32 & FLAG_NO_AUTO)) - up_iface(); - -#if 0 /* bloat */ - struct ifreq ifrequest; - struct ethtool_drvinfo driver_info; - - set_ifreq_to_ifname(&ifrequest); - driver_info.cmd = ETHTOOL_GDRVINFO; - ifrequest.ifr_data = &driver_info; - if (network_ioctl(SIOCETHTOOL, &ifrequest, NULL) == 0) { - char buf[sizeof("/xx:xx:xx:xx:xx:xx")]; - - /* Get MAC */ - buf[0] = '\0'; - set_ifreq_to_ifname(&ifrequest); - if (network_ioctl(SIOCGIFHWADDR, &ifrequest, NULL) == 0) { - sprintf(buf, "/%02X:%02X:%02X:%02X:%02X:%02X", - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[0]), - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[1]), - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[2]), - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[3]), - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[4]), - (uint8_t)(ifrequest.ifr_hwaddr.sa_data[5])); - } - - bb_error_msg("using interface %s%s with driver<%s> (version: %s)", - G.iface, buf, driver_info.driver, driver_info.version); - } -#endif - - G.cached_detect_link_func = NULL; -} +/* Link detection routines and table */ static smallint detect_link_mii(void) { - struct ifreq ifreq; - struct mii_ioctl_data *mii = (void *)&ifreq.ifr_data; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char buf[sizeof(struct ifreq)]; + struct ifreq *const ifreq = (void *)buf; - set_ifreq_to_ifname(&ifreq); + struct mii_ioctl_data *mii = (void *)&ifreq->ifr_data; + + set_ifreq_to_ifname(ifreq); - if (network_ioctl(SIOCGMIIPHY, &ifreq, "SIOCGMIIPHY") < 0) { + if (network_ioctl(SIOCGMIIPHY, ifreq, "SIOCGMIIPHY") < 0) { return IFSTATUS_ERR; } mii->reg_num = 1; - if (network_ioctl(SIOCGMIIREG, &ifreq, "SIOCGMIIREG") < 0) { + if (network_ioctl(SIOCGMIIREG, ifreq, "SIOCGMIIREG") < 0) { return IFSTATUS_ERR; } @@ -265,18 +181,21 @@ static smallint detect_link_mii(void) static smallint detect_link_priv(void) { - struct ifreq ifreq; - struct mii_ioctl_data *mii = (void *)&ifreq.ifr_data; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char buf[sizeof(struct ifreq)]; + struct ifreq *const ifreq = (void *)buf; - set_ifreq_to_ifname(&ifreq); + struct mii_ioctl_data *mii = (void *)&ifreq->ifr_data; - if (network_ioctl(SIOCDEVPRIVATE, &ifreq, "SIOCDEVPRIVATE") < 0) { + set_ifreq_to_ifname(ifreq); + + if (network_ioctl(SIOCDEVPRIVATE, ifreq, "SIOCDEVPRIVATE") < 0) { return IFSTATUS_ERR; } mii->reg_num = 1; - if (network_ioctl(SIOCDEVPRIVATE+1, &ifreq, "SIOCDEVPRIVATE+1") < 0) { + if (network_ioctl(SIOCDEVPRIVATE+1, ifreq, "SIOCDEVPRIVATE+1") < 0) { return IFSTATUS_ERR; } @@ -348,40 +267,135 @@ static smallint detect_link_wlan(void) return IFSTATUS_UP; } -static smallint detect_link_auto(void) +enum { // api mode + API_ETHTOOL, // 'e' + API_MII, // 'm' + API_PRIVATE, // 'p' + API_WLAN, // 'w' + API_IFF, // 'i' + API_AUTO, // 'a' +}; + +static const char api_modes[] ALIGN1 = "empwia"; + +static const struct { + const char *name; + smallint (*func)(void); +} method_table[] = { + { "SIOCETHTOOL" , &detect_link_ethtool }, + { "SIOCGMIIPHY" , &detect_link_mii }, + { "SIOCDEVPRIVATE" , &detect_link_priv }, + { "wireless extension", &detect_link_wlan }, + { "IFF_RUNNING" , &detect_link_iff }, +}; + + + +static const char *strstatus(int status) { - static const struct { - const char *name; - smallint (*func)(void); - } method[] = { - { "SIOCETHTOOL" , &detect_link_ethtool }, - { "SIOCGMIIPHY" , &detect_link_mii }, - { "SIOCDEVPRIVATE" , &detect_link_priv }, - { "wireless extension", &detect_link_wlan }, - { "IFF_RUNNING" , &detect_link_iff }, - }; - int i; - smallint iface_status; - smallint sv_logmode; + if (status == IFSTATUS_ERR) + return "error"; + return "down\0up" + (status * 5); +} + +static int run_script(const char *action) +{ + char *env_PREVIOUS, *env_CURRENT; + char *argv[5]; + int r; + + bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action); + + argv[0] = (char*) G.script_name; + argv[1] = (char*) G.iface; + argv[2] = (char*) action; + argv[3] = (char*) G.extra_arg; + argv[4] = NULL; + + env_PREVIOUS = xasprintf("%s=%s", IFPLUGD_ENV_PREVIOUS, strstatus(G.iface_prev_status)); + putenv(env_PREVIOUS); + env_CURRENT = xasprintf("%s=%s", IFPLUGD_ENV_CURRENT, strstatus(G.iface_last_status)); + putenv(env_CURRENT); + + /* r < 0 - can't exec, 0 <= r < 0x180 - exited, >=0x180 - killed by sig (r-0x180) */ + r = spawn_and_wait(argv); + + unsetenv(IFPLUGD_ENV_PREVIOUS); + unsetenv(IFPLUGD_ENV_CURRENT); + free(env_PREVIOUS); + free(env_CURRENT); + + bb_error_msg("exit code: %d", r & 0xff); + return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r; +} + +static void up_iface(void) +{ + struct ifreq ifrequest; - if (G.cached_detect_link_func) { - iface_status = G.cached_detect_link_func(); - if (iface_status != IFSTATUS_ERR) - return iface_status; + if (!G.iface_exists) + return; + + set_ifreq_to_ifname(&ifrequest); + if (network_ioctl(SIOCGIFFLAGS, &ifrequest, "getting interface flags") < 0) { + G.iface_exists = 0; + return; } - sv_logmode = logmode; - for (i = 0; i < ARRAY_SIZE(method); i++) { - logmode = LOGMODE_NONE; - iface_status = method[i].func(); - logmode = sv_logmode; - if (iface_status != IFSTATUS_ERR) { - G.cached_detect_link_func = method[i].func; - bb_error_msg("using %s detection mode", method[i].name); - break; + if (!(ifrequest.ifr_flags & IFF_UP)) { + ifrequest.ifr_flags |= IFF_UP; + /* Let user know we mess up with interface */ + bb_error_msg("upping interface"); + if (network_ioctl(SIOCSIFFLAGS, &ifrequest, "setting interface flags") < 0) + xfunc_die(); + } + +#if 0 /* why do we mess with IP addr? It's not our business */ + if (network_ioctl(SIOCGIFADDR, &ifrequest, "can't get interface address") < 0) { + } else if (ifrequest.ifr_addr.sa_family != AF_INET) { + bb_perror_msg("the interface is not IP-based"); + } else { + ((struct sockaddr_in*)(&ifrequest.ifr_addr))->sin_addr.s_addr = INADDR_ANY; + network_ioctl(SIOCSIFADDR, &ifrequest, "can't set interface address"); + } + network_ioctl(SIOCGIFFLAGS, &ifrequest, "can't get interface flags"); +#endif +} + +static void maybe_up_new_iface(void) +{ + if (!(option_mask32 & FLAG_NO_AUTO)) + up_iface(); + +#if 0 /* bloat */ + struct ifreq ifrequest; + struct ethtool_drvinfo driver_info; + + set_ifreq_to_ifname(&ifrequest); + driver_info.cmd = ETHTOOL_GDRVINFO; + ifrequest.ifr_data = &driver_info; + if (network_ioctl(SIOCETHTOOL, &ifrequest, NULL) == 0) { + char buf[sizeof("/xx:xx:xx:xx:xx:xx")]; + + /* Get MAC */ + buf[0] = '\0'; + set_ifreq_to_ifname(&ifrequest); + if (network_ioctl(SIOCGIFHWADDR, &ifrequest, NULL) == 0) { + sprintf(buf, "/%02X:%02X:%02X:%02X:%02X:%02X", + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[0]), + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[1]), + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[2]), + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[3]), + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[4]), + (uint8_t)(ifrequest.ifr_hwaddr.sa_data[5])); } + + bb_error_msg("using interface %s%s with driver<%s> (version: %s)", + G.iface, buf, driver_info.driver, driver_info.version); } - return iface_status; +#endif + if (G.api_mode[0] == 'a') + G.api_method_num = API_AUTO; } static smallint detect_link(void) @@ -398,18 +412,32 @@ static smallint detect_link(void) if (!(option_mask32 & FLAG_NO_AUTO)) up_iface(); - status = G.detect_link_func(); + if (G.api_method_num == API_AUTO) { + int i; + smallint sv_logmode; + + sv_logmode = logmode; + for (i = 0; i < ARRAY_SIZE(method_table); i++) { + logmode = LOGMODE_NONE; + status = method_table[i].func(); + logmode = sv_logmode; + if (status != IFSTATUS_ERR) { + G.api_method_num = i; + bb_error_msg("using %s detection mode", method_table[i].name); + break; + } + } + } else { + status = method_table[G.api_method_num].func(); + } + if (status == IFSTATUS_ERR) { if (option_mask32 & FLAG_IGNORE_FAIL) status = IFSTATUS_DOWN; - if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) + else if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE) status = IFSTATUS_UP; - } - - if (status == IFSTATUS_ERR - && G.detect_link_func == detect_link_auto - ) { - bb_error_msg("can't detect link status"); + else if (G.api_mode[0] == 'a') + bb_error_msg("can't detect link status"); } if (status != G.iface_last_status) { @@ -423,20 +451,24 @@ static smallint detect_link(void) static NOINLINE int check_existence_through_netlink(void) { int iface_len; - char replybuf[1024]; + /* Buffer was 1K, but on linux-3.9.9 it was reported to be too small. + * netlink.h: "limit to 8K to avoid MSG_TRUNC when PAGE_SIZE is very large". + * Note: on error returns (-1) we exit, no need to free replybuf. + */ + enum { BUF_SIZE = 8 * 1024 }; + char *replybuf = xmalloc(BUF_SIZE); iface_len = strlen(G.iface); while (1) { struct nlmsghdr *mhdr; ssize_t bytes; - bytes = recv(netlink_fd, &replybuf, sizeof(replybuf), MSG_DONTWAIT); + bytes = recv(netlink_fd, replybuf, BUF_SIZE, MSG_DONTWAIT); if (bytes < 0) { if (errno == EAGAIN) - return G.iface_exists; + goto ret; if (errno == EINTR) continue; - bb_perror_msg("netlink: recv"); return -1; } @@ -479,26 +511,11 @@ static NOINLINE int check_existence_through_netlink(void) } } + ret: + free(replybuf); return G.iface_exists; } -static NOINLINE int netlink_open(void) -{ - int fd; - struct sockaddr_nl addr; - - fd = xsocket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); - - memset(&addr, 0, sizeof(addr)); - addr.nl_family = AF_NETLINK; - addr.nl_groups = RTMGRP_LINK; - addr.nl_pid = getpid(); - - xbind(fd, (struct sockaddr*)&addr, sizeof(addr)); - - return fd; -} - #if ENABLE_FEATURE_PIDFILE static NOINLINE pid_t read_pid(const char *filename) { @@ -523,6 +540,7 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) const char *iface_status_str; struct pollfd netlink_pollfd[1]; unsigned opts; + const char *api_mode_found; #if ENABLE_FEATURE_PIDFILE char *pidfile_name; pid_t pid_from_pidfile; @@ -539,12 +557,13 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) applet_name = xasprintf("ifplugd(%s)", G.iface); #if ENABLE_FEATURE_PIDFILE - pidfile_name = xasprintf(_PATH_VARRUN"ifplugd.%s.pid", G.iface); + pidfile_name = xasprintf(CONFIG_PID_FILE_PATH "/ifplugd.%s.pid", G.iface); pid_from_pidfile = read_pid(pidfile_name); if (opts & FLAG_KILL) { if (pid_from_pidfile > 0) - kill(pid_from_pidfile, SIGQUIT); + /* Upstream tool use SIGINT for -k */ + kill(pid_from_pidfile, SIGINT); return EXIT_SUCCESS; } @@ -552,35 +571,26 @@ int ifplugd_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("daemon already running"); #endif - switch (G.api_mode[0]) { - case API_AUTO: - G.detect_link_func = detect_link_auto; - break; - case API_ETHTOOL: - G.detect_link_func = detect_link_ethtool; - break; - case API_MII: - G.detect_link_func = detect_link_mii; - break; - case API_PRIVATE: - G.detect_link_func = detect_link_priv; - break; - case API_WLAN: - G.detect_link_func = detect_link_wlan; - break; - case API_IFF: - G.detect_link_func = detect_link_iff; - break; - default: + api_mode_found = strchr(api_modes, G.api_mode[0]); + if (!api_mode_found) bb_error_msg_and_die("unknown API mode '%s'", G.api_mode); - } + G.api_method_num = api_mode_found - api_modes; if (!(opts & FLAG_NO_DAEMON)) bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); xmove_fd(xsocket(AF_INET, SOCK_DGRAM, 0), ioctl_fd); if (opts & FLAG_MONITOR) { - xmove_fd(netlink_open(), netlink_fd); + struct sockaddr_nl addr; + int fd = xsocket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE); + + memset(&addr, 0, sizeof(addr)); + addr.nl_family = AF_NETLINK; + addr.nl_groups = RTMGRP_LINK; + addr.nl_pid = getpid(); + + xbind(fd, (struct sockaddr*)&addr, sizeof(addr)); + xmove_fd(fd, netlink_fd); } write_pidfile(pidfile_name); diff --git a/networking/ifupdown.c b/networking/ifupdown.c index 69c56e8..0f0857c 100644 --- a/networking/ifupdown.c +++ b/networking/ifupdown.c @@ -14,18 +14,41 @@ * (defined via CONFIG_IFUPDOWN_IFSTATE_PATH) and can be overridden by build * configuration. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define ifup_trivial_usage +//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." +//usage:#define ifup_full_usage "\n\n" +//usage: " -a De/configure all interfaces automatically" +//usage: "\n -i FILE Use FILE for interface definitions" +//usage: "\n -n Print out what would happen, but don't do it" +//usage: IF_FEATURE_IFUPDOWN_MAPPING( +//usage: "\n (note: doesn't disable mappings)" +//usage: "\n -m Don't run any mappings" +//usage: ) +//usage: "\n -v Print out what would happen before doing it" +//usage: "\n -f Force de/configuration" +//usage: +//usage:#define ifdown_trivial_usage +//usage: "[-an"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] [-i FILE] IFACE..." +//usage:#define ifdown_full_usage "\n\n" +//usage: " -a De/configure all interfaces automatically" +//usage: "\n -i FILE Use FILE for interface definitions" +//usage: "\n -n Print out what would happen, but don't do it" +//usage: IF_FEATURE_IFUPDOWN_MAPPING( +//usage: "\n (note: doesn't disable mappings)" +//usage: "\n -m Don't run any mappings" +//usage: ) +//usage: "\n -v Print out what would happen before doing it" +//usage: "\n -f Force de/configuration" + #include "libbb.h" /* After libbb.h, since it needs sys/types.h on some systems */ #include #include #define MAX_OPT_DEPTH 10 -#define EUNBALBRACK 10001 -#define EUNDEFVAR 10002 -#define EUNBALPER 10000 #if ENABLE_FEATURE_IFUPDOWN_MAPPING #define MAX_INTERFACE_LENGTH 10 @@ -61,7 +84,6 @@ struct mapping_defn_t { char *script; - int max_mappings; int n_mappings; char **mapping; }; @@ -76,7 +98,6 @@ struct interface_defn_t { const struct method_t *method; char *iface; - int max_options; int n_options; struct variable_t *option; }; @@ -106,11 +127,20 @@ enum { struct globals { char **my_environ; const char *startup_PATH; + char *shell; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define INIT_G() do { } while (0) +static const char keywords_up_down[] ALIGN1 = + "up\0" + "down\0" + "pre-up\0" + "post-down\0" +; + + #if ENABLE_FEATURE_IFUPDOWN_IPV4 || ENABLE_FEATURE_IFUPDOWN_IPV6 static void addstr(char **bufp, const char *str, size_t str_length) @@ -164,7 +194,7 @@ static char *get_var(const char *id, size_t idlen, struct interface_defn_t *ifd) return NULL; } -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP static int count_netmask_bits(const char *dotted_quad) { // int result; @@ -195,12 +225,12 @@ static int count_netmask_bits(const char *dotted_quad) } return result; } -#endif +# endif static char *parse(const char *command, struct interface_defn_t *ifd) { size_t old_pos[MAX_OPT_DEPTH] = { 0 }; - int okay[MAX_OPT_DEPTH] = { 1 }; + smallint okay[MAX_OPT_DEPTH] = { 1 }; int opt_depth = 1; char *result = NULL; @@ -211,13 +241,10 @@ static char *parse(const char *command, struct interface_defn_t *ifd) command++; break; case '\\': - if (command[1]) { - addstr(&result, command + 1, 1); - command += 2; - } else { - addstr(&result, command, 1); + if (command[1]) command++; - } + addstr(&result, command, 1); + command++; break; case '[': if (command[1] == '[' && opt_depth < MAX_OPT_DEPTH) { @@ -226,7 +253,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd) opt_depth++; command += 2; } else { - addstr(&result, "[", 1); + addstr(&result, command, 1); command++; } break; @@ -238,7 +265,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd) } command += 2; } else { - addstr(&result, "]", 1); + addstr(&result, command, 1); command++; } break; @@ -250,7 +277,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd) command++; nextpercent = strchr(command, '%'); if (!nextpercent) { - errno = EUNBALPER; + /* Unterminated %var% */ free(result); return NULL; } @@ -258,17 +285,17 @@ static char *parse(const char *command, struct interface_defn_t *ifd) varvalue = get_var(command, nextpercent - command, ifd); if (varvalue) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* "hwaddress
": * unlike ifconfig, ip doesnt want * (usually "ether" keyword). Skip it. */ if (strncmp(command, "hwaddress", 9) == 0) { varvalue = skip_whitespace(skip_non_whitespace(varvalue)); } -#endif +# endif addstr(&result, varvalue, strlen(varvalue)); } else { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* Sigh... Add a special case for 'ip' to convert from * dotted quad to bit count style netmasks. */ if (strncmp(command, "bnmask", 6) == 0) { @@ -284,7 +311,7 @@ static char *parse(const char *command, struct interface_defn_t *ifd) } } } -#endif +# endif okay[opt_depth - 1] = 0; } @@ -295,13 +322,13 @@ static char *parse(const char *command, struct interface_defn_t *ifd) } if (opt_depth > 1) { - errno = EUNBALBRACK; + /* Unbalanced bracket */ free(result); return NULL; } if (!okay[0]) { - errno = EUNDEFVAR; + /* Undefined variable and we aren't in a bracket */ free(result); return NULL; } @@ -329,56 +356,64 @@ static int execute(const char *command, struct interface_defn_t *ifd, execfn *ex } return 1; } -#endif + +#endif /* FEATURE_IFUPDOWN_IPV4 || FEATURE_IFUPDOWN_IPV6 */ + #if ENABLE_FEATURE_IFUPDOWN_IPV6 + static int FAST_FUNC loopback_up6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr add ::1 dev %iface%", ifd, exec); result += execute("ip link set %iface% up", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% add ::1", ifd, exec); -#endif +# endif } static int FAST_FUNC loopback_down6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP return execute("ip link set %iface% down", ifd, exec); -#else +# else return execute("ifconfig %iface% del ::1", ifd, exec); -#endif +# endif +} + +static int FAST_FUNC manual_up_down6(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) +{ + return 1; } static int FAST_FUNC static_up6(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%netmask% dev %iface%[[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); /* Was: "[[ ip ....%gateway% ]]". Removed extra spaces w/o checking */ - result += execute("[[ip route add ::/0 via %gateway%]]", ifd, exec); -#else + result += execute("[[ip route add ::/0 via %gateway%]][[ prio %metric%]]", ifd, exec); +# else result = execute("ifconfig %iface%[[ media %media%]][[ hw %hwaddress%]][[ mtu %mtu%]] up", ifd, exec); result += execute("ifconfig %iface% add %address%/%netmask%", ifd, exec); - result += execute("[[route -A inet6 add ::/0 gw %gateway%]]", ifd, exec); -#endif + result += execute("[[route -A inet6 add ::/0 gw %gateway%[[ metric %metric%]]]]", ifd, exec); +# endif return ((result == 3) ? 3 : 0); } static int FAST_FUNC static_down6(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP return execute("ip link set %iface% down", ifd, exec); -#else +# else return execute("ifconfig %iface% down", ifd, exec); -#endif +# endif } -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP static int FAST_FUNC v4tunnel_up(struct interface_defn_t *ifd, execfn *exec) { int result; @@ -394,14 +429,15 @@ static int FAST_FUNC v4tunnel_down(struct interface_defn_t * ifd, execfn * exec) { return execute("ip tunnel del %iface%", ifd, exec); } -#endif +# endif static const struct method_t methods6[] = { -#if ENABLE_FEATURE_IFUPDOWN_IP - { "v4tunnel", v4tunnel_up, v4tunnel_down, }, -#endif - { "static", static_up6, static_down6, }, - { "loopback", loopback_up6, loopback_down6, }, +# if ENABLE_FEATURE_IFUPDOWN_IP + { "v4tunnel" , v4tunnel_up , v4tunnel_down , }, +# endif + { "static" , static_up6 , static_down6 , }, + { "manual" , manual_up_down6 , manual_up_down6 , }, + { "loopback" , loopback_up6 , loopback_down6 , }, }; static const struct address_family_t addr_inet6 = { @@ -409,43 +445,46 @@ static const struct address_family_t addr_inet6 = { ARRAY_SIZE(methods6), methods6 }; + #endif /* FEATURE_IFUPDOWN_IPV6 */ + #if ENABLE_FEATURE_IFUPDOWN_IPV4 + static int FAST_FUNC loopback_up(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr add 127.0.0.1/8 dev %iface%", ifd, exec); result += execute("ip link set %iface% up", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% 127.0.0.1 up", ifd, exec); -#endif +# endif } static int FAST_FUNC loopback_down(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP int result; result = execute("ip addr flush dev %iface%", ifd, exec); result += execute("ip link set %iface% down", ifd, exec); return ((result == 2) ? 2 : 0); -#else +# else return execute("ifconfig %iface% 127.0.0.1 down", ifd, exec); -#endif +# endif } static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr add %address%/%bnmask%[[ broadcast %broadcast%]] " "dev %iface%[[ peer %pointopoint%]][[ label %label%]]", ifd, exec); result += execute("ip link set[[ mtu %mtu%]][[ addr %hwaddress%]] %iface% up", ifd, exec); - result += execute("[[ip route add default via %gateway% dev %iface%]]", ifd, exec); + result += execute("[[ip route add default via %gateway% dev %iface%[[ prio %metric%]]]]", ifd, exec); return ((result == 3) ? 3 : 0); -#else +# else /* ifconfig said to set iface up before it processes hw %hwaddress%, * which then of course fails. Thus we run two separate ifconfig */ result = execute("ifconfig %iface%[[ hw %hwaddress%]][[ media %media%]][[ mtu %mtu%]] up", @@ -453,28 +492,28 @@ static int FAST_FUNC static_up(struct interface_defn_t *ifd, execfn *exec) result += execute("ifconfig %iface% %address% netmask %netmask%" "[[ broadcast %broadcast%]][[ pointopoint %pointopoint%]] ", ifd, exec); - result += execute("[[route add default gw %gateway% %iface%]]", ifd, exec); + result += execute("[[route add default gw %gateway%[[ metric %metric%]] %iface%]]", ifd, exec); return ((result == 3) ? 3 : 0); -#endif +# endif } static int FAST_FUNC static_down(struct interface_defn_t *ifd, execfn *exec) { int result; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP result = execute("ip addr flush dev %iface%", ifd, exec); result += execute("ip link set %iface% down", ifd, exec); -#else +# else /* result = execute("[[route del default gw %gateway% %iface%]]", ifd, exec); */ /* Bringing the interface down deletes the routes in itself. Otherwise this fails if we reference 'gateway' when using this from dhcp_down */ result = 1; result += execute("ifconfig %iface% down", ifd, exec); -#endif +# endif return ((result == 2) ? 2 : 0); } -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP struct dhcp_client_t { const char *name; const char *startcmd; @@ -483,7 +522,7 @@ struct dhcp_client_t { static const struct dhcp_client_t ext_dhcp_clients[] = { { "dhcpcd", - "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %clientid%]][[ -l %leasetime%]] %iface%", + "dhcpcd[[ -h %hostname%]][[ -i %vendor%]][[ -I %client%]][[ -l %leasetime%]] %iface%", "dhcpcd -k %iface%", }, { "dhclient", @@ -495,26 +534,26 @@ static const struct dhcp_client_t ext_dhcp_clients[] = { "pump -i %iface% -k", }, { "udhcpc", - "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %clientid%]]" + "udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid -i %iface%[[ -H %hostname%]][[ -c %client%]]" "[[ -s %script%]][[ %udhcpc_opts%]]", "kill `cat /var/run/udhcpc.%iface%.pid` 2>/dev/null", }, }; -#endif /* ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ +# endif /* FEATURE_IFUPDOWN_EXTERNAL_DHCPC */ -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) { unsigned i; -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; -#else +# else /* needed if we have hwaddress on dhcp iface */ if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) return 0; -#endif +# endif for (i = 0; i < ARRAY_SIZE(ext_dhcp_clients); i++) { if (exists_execable(ext_dhcp_clients[i].name)) return execute(ext_dhcp_clients[i].startcmd, ifd, exec); @@ -522,31 +561,31 @@ static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) bb_error_msg("no dhcp clients found"); return 0; } -#elif ENABLE_UDHCPC +# elif ENABLE_UDHCPC static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd, execfn *exec) { -#if ENABLE_FEATURE_IFUPDOWN_IP +# if ENABLE_FEATURE_IFUPDOWN_IP /* ip doesn't up iface when it configures it (unlike ifconfig) */ if (!execute("ip link set[[ addr %hwaddress%]] %iface% up", ifd, exec)) return 0; -#else +# else /* needed if we have hwaddress on dhcp iface */ if (!execute("ifconfig %iface%[[ hw %hwaddress%]] up", ifd, exec)) return 0; -#endif +# endif return execute("udhcpc " UDHCPC_CMD_OPTIONS " -p /var/run/udhcpc.%iface%.pid " - "-i %iface%[[ -H %hostname%]][[ -c %clientid%]][[ -s %script%]][[ %udhcpc_opts%]]", + "-i %iface%[[ -H %hostname%]][[ -c %client%]][[ -s %script%]][[ %udhcpc_opts%]]", ifd, exec); } -#else +# else static int FAST_FUNC dhcp_up(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { return 0; /* no dhcp support */ } -#endif +# endif -#if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP +# if ENABLE_FEATURE_IFUPDOWN_EXTERNAL_DHCP static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) { int result = 0; @@ -569,7 +608,7 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) result += static_down(ifd, exec); return ((result == 3) ? 3 : 0); } -#elif ENABLE_UDHCPC +# elif ENABLE_UDHCPC static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) { int result; @@ -586,13 +625,13 @@ static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd, execfn *exec) result += static_down(ifd, exec); return ((result == 3) ? 3 : 0); } -#else +# else static int FAST_FUNC dhcp_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { return 0; /* no dhcp support */ } -#endif +# endif static int FAST_FUNC manual_up_down(struct interface_defn_t *ifd UNUSED_PARAM, execfn *exec UNUSED_PARAM) { @@ -644,7 +683,8 @@ static const struct address_family_t addr_inet = { methods }; -#endif /* if ENABLE_FEATURE_IFUPDOWN_IPV4 */ +#endif /* FEATURE_IFUPDOWN_IPV4 */ + /* Returns pointer to the next word, or NULL. * In 1st case, advances *buf to the word after this one. @@ -703,7 +743,7 @@ static const struct method_t *get_method(const struct address_family_t *af, char return NULL; } -static struct interfaces_file_t *read_interfaces(const char *filename) +static struct interfaces_file_t *read_interfaces(const char *filename, struct interfaces_file_t *defn) { /* Let's try to be compatible. * @@ -718,19 +758,25 @@ static struct interfaces_file_t *read_interfaces(const char *filename) * be ignored. Blank lines are ignored. Lines may be indented freely. * A "\" character at the very end of the line indicates the next line * should be treated as a continuation of the current one. + * + * Lines beginning with "source" are used to include stanzas from + * other files, so configuration can be split into many files. + * The word "source" is followed by the path of file to be sourced. */ #if ENABLE_FEATURE_IFUPDOWN_MAPPING struct mapping_defn_t *currmap = NULL; #endif struct interface_defn_t *currif = NULL; - struct interfaces_file_t *defn; FILE *f; char *buf; char *first_word; char *rest_of_line; enum { NONE, IFACE, MAPPING } currently_processing = NONE; - defn = xzalloc(sizeof(*defn)); + if (!defn) + defn = xzalloc(sizeof(*defn)); + + debug_noise("reading %s file:\n", filename); f = xfopen_for_read(filename); while ((buf = xmalloc_fgetline(f)) != NULL) { @@ -763,7 +809,6 @@ static struct interfaces_file_t *read_interfaces(const char *filename) currmap->match = xrealloc_vector(currmap->match, 4, currmap->n_matches); currmap->match[currmap->n_matches++] = xstrdup(first_word); } - /*currmap->max_mappings = 0; - done by xzalloc */ /*currmap->n_mappings = 0;*/ /*currmap->mapping = NULL;*/ /*currmap->script = NULL;*/ @@ -842,29 +887,29 @@ static struct interfaces_file_t *read_interfaces(const char *filename) debug_noise("\nauto %s\n", first_word); } currently_processing = NONE; + } else if (strcmp(first_word, "source") == 0) { + read_interfaces(next_word(&rest_of_line), defn); } else { switch (currently_processing) { case IFACE: if (rest_of_line[0] == '\0') bb_error_msg_and_die("option with empty value \"%s\"", buf); - if (strcmp(first_word, "up") != 0 - && strcmp(first_word, "down") != 0 - && strcmp(first_word, "pre-up") != 0 - && strcmp(first_word, "post-down") != 0 - ) { + if (strcmp(first_word, "post-up") == 0) + first_word += 5; /* "up" */ + else if (strcmp(first_word, "pre-down") == 0) + first_word += 4; /* "down" */ + + /* If not one of "up", "down",... words... */ + if (index_in_strings(keywords_up_down, first_word) < 0) { int i; for (i = 0; i < currif->n_options; i++) { if (strcmp(currif->option[i].name, first_word) == 0) bb_error_msg_and_die("duplicate option \"%s\"", buf); } } - if (currif->n_options >= currif->max_options) { - currif->max_options += 10; - currif->option = xrealloc(currif->option, - sizeof(*currif->option) * currif->max_options); - } debug_noise("\t%s=%s\n", first_word, rest_of_line); + currif->option = xrealloc_vector(currif->option, 4, currif->n_options); currif->option[currif->n_options].name = xstrdup(first_word); currif->option[currif->n_options].value = xstrdup(rest_of_line); currif->n_options++; @@ -876,11 +921,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) bb_error_msg_and_die("duplicate script in mapping \"%s\"", buf); currmap->script = xstrdup(next_word(&rest_of_line)); } else if (strcmp(first_word, "map") == 0) { - if (currmap->n_mappings >= currmap->max_mappings) { - currmap->max_mappings = currmap->max_mappings * 2 + 1; - currmap->mapping = xrealloc(currmap->mapping, - sizeof(char *) * currmap->max_mappings); - } + currmap->mapping = xrealloc_vector(currmap->mapping, 2, currmap->n_mappings); currmap->mapping[currmap->n_mappings] = xstrdup(next_word(&rest_of_line)); currmap->n_mappings++; } else { @@ -901,6 +942,7 @@ static struct interfaces_file_t *read_interfaces(const char *filename) bb_error_msg_and_die("%s: I/O error", filename); } fclose(f); + debug_noise("\ndone reading %s\n\n", filename); return defn; } @@ -927,7 +969,7 @@ static char *setlocalenv(const char *format, const char *name, const char *value return result; } -static void set_environ(struct interface_defn_t *iface, const char *mode) +static void set_environ(struct interface_defn_t *iface, const char *mode, const char *opt) { int i; char **pp; @@ -940,15 +982,11 @@ static void set_environ(struct interface_defn_t *iface, const char *mode) } /* note: last element will stay NULL: */ - G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 6)); + G.my_environ = xzalloc(sizeof(char *) * (iface->n_options + 7)); pp = G.my_environ; for (i = 0; i < iface->n_options; i++) { - if (strcmp(iface->option[i].name, "up") == 0 - || strcmp(iface->option[i].name, "down") == 0 - || strcmp(iface->option[i].name, "pre-up") == 0 - || strcmp(iface->option[i].name, "post-down") == 0 - ) { + if (index_in_strings(keywords_up_down, iface->option[i].name) >= 0) { continue; } *pp++ = setlocalenv("IF_%s=%s", iface->option[i].name, iface->option[i].value); @@ -958,6 +996,7 @@ static void set_environ(struct interface_defn_t *iface, const char *mode) *pp++ = setlocalenv("%s=%s", "ADDRFAM", iface->address_family->name); *pp++ = setlocalenv("%s=%s", "METHOD", iface->method->name); *pp++ = setlocalenv("%s=%s", "MODE", mode); + *pp++ = setlocalenv("%s=%s", "PHASE", opt); if (G.startup_PATH) *pp++ = setlocalenv("%s=%s", "PATH", G.startup_PATH); } @@ -973,11 +1012,10 @@ static int doit(char *str) fflush_all(); child = vfork(); - switch (child) { - case -1: /* failure */ + if (child < 0) /* failure */ return 0; - case 0: /* child */ - execle(DEFAULT_SHELL, DEFAULT_SHELL, "-c", str, (char *) NULL, G.my_environ); + if (child == 0) { /* child */ + execle(G.shell, G.shell, "-c", str, (char *) NULL, G.my_environ); _exit(127); } safe_waitpid(child, &status, 0); @@ -1013,19 +1051,21 @@ static int check(char *str) static int iface_up(struct interface_defn_t *iface) { if (!iface->method->up(iface, check)) return -1; - set_environ(iface, "start"); + set_environ(iface, "start", "pre-up"); if (!execute_all(iface, "pre-up")) return 0; if (!iface->method->up(iface, doit)) return 0; + set_environ(iface, "start", "post-up"); if (!execute_all(iface, "up")) return 0; return 1; } static int iface_down(struct interface_defn_t *iface) { - if (!iface->method->down(iface,check)) return -1; - set_environ(iface, "stop"); + if (!iface->method->down(iface, check)) return -1; + set_environ(iface, "stop", "pre-down"); if (!execute_all(iface, "down")) return 0; if (!iface->method->down(iface, doit)) return 0; + set_environ(iface, "stop", "post-down"); if (!execute_all(iface, "post-down")) return 0; return 1; } @@ -1152,6 +1192,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) INIT_G(); G.startup_PATH = getenv("PATH"); + G.shell = xstrdup(get_shell_name()); cmds = iface_down; if (applet_name[2] == 'u') { @@ -1167,9 +1208,7 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) if (!DO_ALL) bb_show_usage(); } - debug_noise("reading %s file:\n", interfaces); - defn = read_interfaces(interfaces); - debug_noise("\ndone reading %s\n\n", interfaces); + defn = read_interfaces(interfaces, NULL); /* Create a list of interfaces to work on */ if (DO_ALL) { @@ -1207,13 +1246,13 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) /* ifup */ if (iface_state) { bb_error_msg("interface %s already configured", iface); - continue; + goto next; } } else { /* ifdown */ if (!iface_state) { bb_error_msg("interface %s not configured", iface); - continue; + goto next; } } llist_free(state_list, free); @@ -1277,9 +1316,9 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) llist_t *state_list = read_iface_state(); llist_t *iface_state = find_iface_state(state_list, iface); - if (cmds == iface_up) { - char * const newiface = xasprintf("%s=%s", iface, liface); - if (iface_state == NULL) { + if (cmds == iface_up && !any_failures) { + char *newiface = xasprintf("%s=%s", iface, liface); + if (!iface_state) { llist_add_to_end(&state_list, newiface); } else { free(iface_state->data); @@ -1303,6 +1342,9 @@ int ifupdown_main(int argc UNUSED_PARAM, char **argv) fclose(state_fp); llist_free(state_list, free); } + next: + free(iface); + free(liface); } return any_failures; diff --git a/networking/inetd.c b/networking/inetd.c index 7030062..584c5e5 100644 --- a/networking/inetd.c +++ b/networking/inetd.c @@ -154,14 +154,29 @@ * setuid() */ +//usage:#define inetd_trivial_usage +//usage: "[-fe] [-q N] [-R N] [CONFFILE]" +//usage:#define inetd_full_usage "\n\n" +//usage: "Listen for network connections and launch programs\n" +//usage: "\n -f Run in foreground" +//usage: "\n -e Log to stderr" +//usage: "\n -q N Socket listen queue (default: 128)" +//usage: "\n -R N Pause services after N connects/min" +//usage: "\n (default: 0 - disabled)" + #include +#include /* setrlimit */ +#include /* un.h may need this */ #include #include "libbb.h" #if ENABLE_FEATURE_INETD_RPC -#include -#include +# if defined(__UCLIBC__) && ! defined(__UCLIBC_HAS_RPC__) +# error "You need to build uClibc with UCLIBC_HAS_RPC for NFS support" +# endif +# include +# include #endif #if !BB_MMU @@ -171,8 +186,6 @@ #define ENABLE_FEATURE_INETD_SUPPORT_BUILTIN_CHARGEN 0 #endif -#define _PATH_INETDPID "/var/run/inetd.pid" - #define CNT_INTERVAL 60 /* servers in CNT_INTERVAL sec. */ #define RETRYTIME 60 /* retry after bind or server fail */ @@ -295,7 +308,7 @@ struct globals { struct rlimit rlim_ofile; servtab_t *serv_list; int global_queuelen; - int maxsock; /* max fd# in allsock, -1: unknown */ + int maxsock; /* max fd# in allsock, -1: unknown */ /* whenever maxsock grows, prev_maxsock is set to new maxsock, * but if maxsock is set to -1, prev_maxsock is not changed */ int prev_maxsock; @@ -344,10 +357,26 @@ struct BUG_G_too_big { config_filename = "/etc/inetd.conf"; \ } while (0) +#if 1 +# define dbg(...) ((void)0) +#else +# define dbg(...) \ +do { \ + int dbg_fd = open("inetd_debug.log", O_WRONLY | O_CREAT | O_APPEND, 0666); \ + if (dbg_fd >= 0) { \ + fdprintf(dbg_fd, "%d: ", getpid()); \ + fdprintf(dbg_fd, __VA_ARGS__); \ + close(dbg_fd); \ + } \ +} while (0) +#endif + static void maybe_close(int fd) { - if (fd >= 0) + if (fd >= 0) { close(fd); + dbg("closed fd:%d\n", fd); + } } // TODO: move to libbb? @@ -451,7 +480,9 @@ static void remove_fd_from_set(int fd) { if (fd >= 0) { FD_CLR(fd, &allsock); + dbg("stopped listening on fd:%d\n", fd); maxsock = -1; + dbg("maxsock:%d\n", maxsock); } } @@ -459,8 +490,10 @@ static void add_fd_to_set(int fd) { if (fd >= 0) { FD_SET(fd, &allsock); + dbg("started listening on fd:%d\n", fd); if (maxsock >= 0 && fd > maxsock) { prev_maxsock = maxsock = fd; + dbg("maxsock:%d\n", maxsock); if ((rlim_t)fd > rlim_ofile_cur - FD_MARGIN) bump_nofile(); } @@ -479,6 +512,7 @@ static void recalculate_maxsock(void) maxsock = fd; fd++; } + dbg("recalculated maxsock:%d\n", maxsock); prev_maxsock = maxsock; if ((rlim_t)maxsock > rlim_ofile_cur - FD_MARGIN) bump_nofile(); @@ -501,7 +535,7 @@ static void prepare_socket_fd(servtab_t *sep) /* zero out the port for all RPC services; let bind() * find one. */ - set_nport(sep->se_lsa, 0); + set_nport(&sep->se_lsa->u.sa, 0); /* for RPC services, attempt to use a reserved port * if they are going to be running as root. */ @@ -536,8 +570,13 @@ static void prepare_socket_fd(servtab_t *sep) rearm_alarm(); return; } - if (sep->se_socktype == SOCK_STREAM) + + if (sep->se_socktype == SOCK_STREAM) { listen(fd, global_queuelen); + dbg("new sep->se_fd:%d (stream)\n", fd); + } else { + dbg("new sep->se_fd:%d (!stream)\n", fd); + } add_fd_to_set(fd); sep->se_fd = fd; @@ -778,6 +817,12 @@ static servtab_t *parse_one_line(void) argc = 0; while ((arg = token[6+argc]) != NULL && argc < MAXARGV) sep->se_argv[argc++] = xstrdup(arg); + /* Some inetd.conf files have no argv's, not even argv[0]. + * Fix them up. + * (Technically, programs can be execed with argv[0] = NULL, + * but many programs do not like that at all) */ + if (argc == 0) + sep->se_argv[0] = xstrdup(sep->se_program); /* catch mixups. " stream udp ..." == wtf */ if (sep->se_socktype == SOCK_STREAM) { @@ -953,7 +998,7 @@ static void reread_config_file(int sig UNUSED_PARAM) } if (LONE_CHAR(sep->se_local_hostname, '*')) { lsa = xzalloc_lsa(sep->se_family); - set_nport(lsa, port); + set_nport(&lsa->u.sa, port); } else { lsa = host_and_af2sockaddr(sep->se_local_hostname, ntohs(port), sep->se_family); @@ -993,7 +1038,7 @@ static void reread_config_file(int sig UNUSED_PARAM) * new config file doesnt have them. */ block_CHLD_HUP_ALRM(&omask); sepp = &serv_list; - while ((sep = *sepp)) { + while ((sep = *sepp) != NULL) { if (sep->se_checked) { sepp = &sep->se_next; continue; @@ -1085,7 +1130,7 @@ static void clean_up_and_exit(int sig UNUSED_PARAM) if (ENABLE_FEATURE_CLEAN_UP) close(sep->se_fd); } - remove_pidfile(_PATH_INETDPID); + remove_pidfile(CONFIG_PID_FILE_PATH "/inetd.pid"); exit(EXIT_SUCCESS); } @@ -1134,7 +1179,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) setgroups(1, &gid); } - write_pidfile(_PATH_INETDPID); + write_pidfile(CONFIG_PID_FILE_PATH "/inetd.pid"); /* never fails under Linux (except if you pass it bad arguments) */ getrlimit(RLIMIT_NOFILE, &rlim_ofile); @@ -1147,12 +1192,17 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sigaddset(&sa.sa_mask, SIGALRM); sigaddset(&sa.sa_mask, SIGCHLD); sigaddset(&sa.sa_mask, SIGHUP); +//FIXME: explain why no SA_RESTART +//FIXME: retry_network_setup is unsafe to run in signal handler (many reasons)! sa.sa_handler = retry_network_setup; sigaction_set(SIGALRM, &sa); +//FIXME: reread_config_file is unsafe to run in signal handler(many reasons)! sa.sa_handler = reread_config_file; sigaction_set(SIGHUP, &sa); +//FIXME: reap_child is unsafe to run in signal handler (uses stdio)! sa.sa_handler = reap_child; sigaction_set(SIGCHLD, &sa); +//FIXME: clean_up_and_exit is unsafe to run in signal handler (uses stdio)! sa.sa_handler = clean_up_and_exit; sigaction_set(SIGTERM, &sa); sa.sa_handler = clean_up_and_exit; @@ -1182,11 +1232,13 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) } continue; } + dbg("ready_fd_cnt:%d\n", ready_fd_cnt); for (sep = serv_list; ready_fd_cnt && sep; sep = sep->se_next) { if (sep->se_fd == -1 || !FD_ISSET(sep->se_fd, &readable)) continue; + dbg("ready fd:%d\n", sep->se_fd); ready_fd_cnt--; ctrl = sep->se_fd; accepted_fd = -1; @@ -1194,6 +1246,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) if (!sep->se_wait) { if (sep->se_socktype == SOCK_STREAM) { ctrl = accepted_fd = accept(sep->se_fd, NULL, NULL); + dbg("accepted_fd:%d\n", accepted_fd); if (ctrl < 0) { if (errno != EINTR) bb_perror_msg("accept (for %s)", sep->se_service); @@ -1214,19 +1267,22 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * (can create many copies of same child, etc). * Parent must create and use new socket instead. */ new_udp_fd = socket(sep->se_family, SOCK_DGRAM, 0); + dbg("new_udp_fd:%d\n", new_udp_fd); if (new_udp_fd < 0) { /* error: eat packet, forget about it */ udp_err: recv(sep->se_fd, line, LINE_SIZE, MSG_DONTWAIT); continue; } setsockopt_reuseaddr(new_udp_fd); - /* TODO: better do bind after vfork in parent, + /* TODO: better do bind after fork in parent, * so that we don't have two wildcard bound sockets * even for a brief moment? */ if (bind(new_udp_fd, &sep->se_lsa->u.sa, sep->se_lsa->len) < 0) { + dbg("bind(new_udp_fd) failed\n"); close(new_udp_fd); goto udp_err; } + dbg("bind(new_udp_fd) succeeded\n"); } } @@ -1254,6 +1310,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_count = 0; rearm_alarm(); /* will revive it in RETRYTIME sec */ restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } @@ -1274,17 +1331,18 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_perror_msg("vfork"+1); sleep(1); restore_sigmask(&omask); + maybe_close(new_udp_fd); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } if (pid == 0) pid--; /* -1: "we did fork and we are child" */ } - /* if pid == 0 here, we never forked */ + /* if pid == 0 here, we didn't fork */ if (pid > 0) { /* parent */ if (sep->se_wait) { - /* tcp wait: we passed listening socket to child, + /* wait: we passed socket to child, * will wait for child to terminate */ sep->se_wait = pid; remove_fd_from_set(sep->se_fd); @@ -1293,17 +1351,19 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) /* udp nowait: child connected the socket, * we created and will use new, unconnected one */ xmove_fd(new_udp_fd, sep->se_fd); + dbg("moved new_udp_fd:%d to sep->se_fd:%d\n", new_udp_fd, sep->se_fd); } restore_sigmask(&omask); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ } - /* we are either child or didn't vfork at all */ + /* we are either child or didn't fork at all */ #ifdef INETD_BUILTINS_ENABLED if (sep->se_builtin) { - if (pid) { /* "pid" is -1: we did vfork */ + if (pid) { /* "pid" is -1: we did fork */ close(sep->se_fd); /* listening socket */ + dbg("closed sep->se_fd:%d\n", sep->se_fd); logmode = LOGMODE_NONE; /* make xwrite etc silent */ } restore_sigmask(&omask); @@ -1311,7 +1371,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) sep->se_builtin->bi_stream_fn(ctrl, sep); else sep->se_builtin->bi_dgram_fn(ctrl, sep); - if (pid) /* we did vfork */ + if (pid) /* we did fork */ _exit(EXIT_FAILURE); maybe_close(accepted_fd); continue; /* -> check next fd in fd set */ @@ -1321,9 +1381,14 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) setsid(); /* "nowait" udp */ if (new_udp_fd >= 0) { - len_and_sockaddr *lsa = xzalloc_lsa(sep->se_family); + len_and_sockaddr *lsa; + int r; + + close(new_udp_fd); + dbg("closed new_udp_fd:%d\n", new_udp_fd); + lsa = xzalloc_lsa(sep->se_family); /* peek at the packet and remember peer addr */ - int r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, + r = recvfrom(ctrl, NULL, 0, MSG_PEEK|MSG_DONTWAIT, &lsa->u.sa, &lsa->len); if (r < 0) goto do_exit1; @@ -1331,6 +1396,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) * only packets from this peer will be recv'ed, * and bare write()/send() will work on it */ connect(ctrl, &lsa->u.sa, lsa->len); + dbg("connected ctrl:%d to remote peer\n", ctrl); free(lsa); } /* prepare env and exec program */ @@ -1348,7 +1414,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) bb_error_msg("non-root must run services as himself"); goto do_exit1; } - if (pwd->pw_uid) { + if (pwd->pw_uid != 0) { if (sep->se_group) pwd->pw_gid = grp->gr_gid; /* initgroups, setgid, setuid: */ @@ -1367,6 +1433,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) */ xmove_fd(ctrl, STDIN_FILENO); xdup2(STDIN_FILENO, STDOUT_FILENO); + dbg("moved ctrl:%d to fd 0,1[,2]\n", ctrl); /* manpages of inetd I managed to find either say * that stderr is also redirected to the network, * or do not talk about redirection at all (!) */ @@ -1379,6 +1446,7 @@ int inetd_main(int argc UNUSED_PARAM, char **argv) maybe_close(sep2->se_fd); sigaction_set(SIGPIPE, &saved_pipe_handler); restore_sigmask(&omask); + dbg("execing:'%s'\n", sep->se_program); BB_EXECVP(sep->se_program, sep->se_argv); bb_perror_msg("can't execute '%s'", sep->se_program); do_exit1: diff --git a/networking/interface.c b/networking/interface.c index 659ac36..bf7d2b1 100644 --- a/networking/interface.c +++ b/networking/interface.c @@ -19,7 +19,7 @@ * Author: Fred N. van Kempen, * and others. Copyright 1993 MicroWalt Corporation * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Patched to support 'add' and 'del' keywords for INET(4) addresses * by Mrs. Brisby @@ -27,18 +27,17 @@ * {1.34} - 19980630 - Arnaldo Carvalho de Melo * - gettext instead of catgets for i18n * 10/1998 - Andi Kleen. Use interface list primitives. - * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu + * 20001008 - Bernd Eckenfels, Patch from RH for setting mtu * (default AF was wrong) */ + +#include "libbb.h" +#include "inet_common.h" #include #include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) +#ifdef HAVE_NET_ETHERNET_H # include -#else -# include #endif -#include "libbb.h" -#include "inet_common.h" #if ENABLE_FEATURE_HWIB /* #include */ @@ -723,68 +722,15 @@ static char* FAST_FUNC ether_print(unsigned char *ptr) return buff; } -static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap); - static const struct hwtype ether_hwtype = { .name = "ether", .title = "Ethernet", .type = ARPHRD_ETHER, .alen = ETH_ALEN, .print = ether_print, - .input = ether_input + .input = in_ether }; -static unsigned hexchar2int(char c) -{ - if (isdigit(c)) - return c - '0'; - c &= ~0x20; /* a -> A */ - if ((unsigned)(c - 'A') <= 5) - return c - ('A' - 10); - return ~0U; -} - -/* Input an Ethernet address and convert to binary. */ -static int FAST_FUNC ether_input(const char *bufp, struct sockaddr *sap) -{ - unsigned char *ptr; - char c; - int i; - unsigned val; - - sap->sa_family = ether_hwtype.type; - ptr = (unsigned char*) sap->sa_data; - - i = 0; - while ((*bufp != '\0') && (i < ETH_ALEN)) { - val = hexchar2int(*bufp++) * 0x10; - if (val > 0xff) { - errno = EINVAL; - return -1; - } - c = *bufp; - if (c == ':' || c == 0) - val >>= 4; - else { - val |= hexchar2int(c); - if (val > 0xff) { - errno = EINVAL; - return -1; - } - } - if (c != 0) - bufp++; - *ptr++ = (unsigned char) val; - i++; - - /* We might get a semicolon here - not required. */ - if (*bufp == ':') { - bufp++; - } - } - return 0; -} - static const struct hwtype ppp_hwtype = { .name = "ppp", .title = "Point-to-Point Protocol", @@ -927,9 +873,8 @@ static void print_bytes_scaled(unsigned long long ull, const char *end) static void ife_print6(struct interface *ptr) { - FILE *f; - char addr6[40], devname[20]; + char addr6[40], devname[21]; struct sockaddr_in6 sap; int plen, scope, dad_status, if_idx; char addr6p[8][5]; @@ -952,8 +897,8 @@ static void ife_print6(struct interface *ptr) (struct sockaddr *) &sap.sin6_addr); sap.sin6_family = AF_INET6; printf(" inet6 addr: %s/%d", - INET6_sprint((struct sockaddr *) &sap, 1), - plen); + INET6_sprint((struct sockaddr *) &sap, 1), + plen); printf(" Scope:"); switch (scope & IPV6_ADDR_SCOPE_MASK) { case 0: @@ -1021,7 +966,7 @@ static void ife_print(struct interface *ptr) if (ptr->has_ip) { printf(" %s addr:%s ", ap->name, - ap->sprint(&ptr->addr, 1)); + ap->sprint(&ptr->addr, 1)); if (ptr->flags & IFF_POINTOPOINT) { printf(" P-t-P:%s ", ap->sprint(&ptr->dstaddr, 1)); } @@ -1104,17 +1049,17 @@ static void ife_print(struct interface *ptr) printf(" "); printf("RX packets:%llu errors:%lu dropped:%lu overruns:%lu frame:%lu\n", - ptr->stats.rx_packets, ptr->stats.rx_errors, - ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors, - ptr->stats.rx_frame_errors); + ptr->stats.rx_packets, ptr->stats.rx_errors, + ptr->stats.rx_dropped, ptr->stats.rx_fifo_errors, + ptr->stats.rx_frame_errors); if (can_compress) printf(" compressed:%lu\n", - ptr->stats.rx_compressed); + ptr->stats.rx_compressed); printf(" "); printf("TX packets:%llu errors:%lu dropped:%lu overruns:%lu carrier:%lu\n", - ptr->stats.tx_packets, ptr->stats.tx_errors, - ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors, - ptr->stats.tx_carrier_errors); + ptr->stats.tx_packets, ptr->stats.tx_errors, + ptr->stats.tx_dropped, ptr->stats.tx_fifo_errors, + ptr->stats.tx_carrier_errors); printf(" collisions:%lu ", ptr->stats.collisions); if (can_compress) printf("compressed:%lu ", ptr->stats.tx_compressed); @@ -1131,13 +1076,12 @@ static void ife_print(struct interface *ptr) printf(" "); if (ptr->map.irq) printf("Interrupt:%d ", ptr->map.irq); - if (ptr->map.base_addr >= 0x100) /* Only print devices using it for - I/O maps */ + if (ptr->map.base_addr >= 0x100) /* Only print devices using it for I/O maps */ printf("Base address:0x%lx ", - (unsigned long) ptr->map.base_addr); + (unsigned long) ptr->map.base_addr); if (ptr->map.mem_start) { printf("Memory:%lx-%lx ", ptr->map.mem_start, - ptr->map.mem_end); + ptr->map.mem_end); } if (ptr->map.dma) printf("DMA chan:%x ", ptr->map.dma); @@ -1170,7 +1114,7 @@ static struct interface *lookup_interface(char *name) #ifdef UNUSED static int for_all_interfaces(int (*doit) (struct interface *, void *), - void *cookie) + void *cookie) { struct interface *ife; diff --git a/networking/ip.c b/networking/ip.c index 3a99fa3..98fe621 100644 --- a/networking/ip.c +++ b/networking/ip.c @@ -1,16 +1,86 @@ /* vi: set sw=4 ts=4: */ /* - * "ip" utility frontend. - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Authors: Alexey Kuznetsov, * * Changes: - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * Bernhard Reutner-Fischer rewrote to use index_in_substr_array */ +/* would need to make the " | " optional depending on more than one selected: */ +//usage:#define ip_trivial_usage +//usage: "[OPTIONS] {" +//usage: IF_FEATURE_IP_ADDRESS("address | ") +//usage: IF_FEATURE_IP_ROUTE("route | ") +//usage: IF_FEATURE_IP_LINK("link | ") +//usage: IF_FEATURE_IP_TUNNEL("tunnel | ") +//usage: IF_FEATURE_IP_RULE("rule") +//usage: "} {COMMAND}" +//usage:#define ip_full_usage "\n\n" +//usage: "ip [OPTIONS] OBJECT {COMMAND}\n" +//usage: "where OBJECT := {" +//usage: IF_FEATURE_IP_ADDRESS("address | ") +//usage: IF_FEATURE_IP_ROUTE("route | ") +//usage: IF_FEATURE_IP_LINK("link | ") +//usage: IF_FEATURE_IP_TUNNEL("tunnel | ") +//usage: IF_FEATURE_IP_RULE("rule") +//usage: "}\n" +//usage: "OPTIONS := { -f[amily] { inet | inet6 | link } | -o[neline] }" +//usage: +//usage:#define ipaddr_trivial_usage +//usage: "{ {add|del} IFADDR dev STRING | {show|flush}\n" +//usage: " [dev STRING] [to PREFIX] }" +//usage:#define ipaddr_full_usage "\n\n" +//usage: "ipaddr {add|delete} IFADDR dev STRING\n" +//usage: "ipaddr {show|flush} [dev STRING] [scope SCOPE-ID]\n" +//usage: " [to PREFIX] [label PATTERN]\n" +//usage: " IFADDR := PREFIX | ADDR peer PREFIX\n" +//usage: " [broadcast ADDR] [anycast ADDR]\n" +//usage: " [label STRING] [scope SCOPE-ID]\n" +//usage: " SCOPE-ID := [host | link | global | NUMBER]" +//usage: +//usage:#define iplink_trivial_usage +//usage: "{ set DEVICE { up | down | arp { on | off } | show [DEVICE] }" +//usage:#define iplink_full_usage "\n\n" +//usage: "iplink set DEVICE { up | down | arp | multicast { on | off } |\n" +//usage: " dynamic { on | off } |\n" +//usage: " mtu MTU }\n" +//usage: "iplink show [DEVICE]" +//usage: +//usage:#define iproute_trivial_usage +//usage: "{ list | flush | add | del | change | append |\n" +//usage: " replace | test } ROUTE" +//usage:#define iproute_full_usage "\n\n" +//usage: "iproute { list | flush } SELECTOR\n" +//usage: "iproute get ADDRESS [from ADDRESS iif STRING]\n" +//usage: " [oif STRING] [tos TOS]\n" +//usage: "iproute { add | del | change | append | replace | test } ROUTE\n" +//usage: " SELECTOR := [root PREFIX] [match PREFIX] [proto RTPROTO]\n" +//usage: " ROUTE := [TYPE] PREFIX [tos TOS] [proto RTPROTO] [metric METRIC]" +//usage: +//usage:#define iprule_trivial_usage +//usage: "{[list | add | del] RULE}" +//usage:#define iprule_full_usage "\n\n" +//usage: "iprule [list | add | del] SELECTOR ACTION\n" +//usage: " SELECTOR := [from PREFIX] [to PREFIX] [tos TOS] [fwmark FWMARK]\n" +//usage: " [dev STRING] [pref NUMBER]\n" +//usage: " ACTION := [table TABLE_ID] [nat ADDRESS]\n" +//usage: " [prohibit | reject | unreachable]\n" +//usage: " [realms [SRCREALM/]DSTREALM]\n" +//usage: " TABLE_ID := [local | main | default | NUMBER]" +//usage: +//usage:#define iptunnel_trivial_usage +//usage: "{ add | change | del | show } [NAME]\n" +//usage: " [mode { ipip | gre | sit }]\n" +//usage: " [remote ADDR] [local ADDR] [ttl TTL]" +//usage:#define iptunnel_full_usage "\n\n" +//usage: "iptunnel { add | change | del | show } [NAME]\n" +//usage: " [mode { ipip | gre | sit }] [remote ADDR] [local ADDR]\n" +//usage: " [[i|o]seq] [[i|o]key KEY] [[i|o]csum]\n" +//usage: " [ttl TTL] [tos TOS] [[no]pmtudisc] [dev PHYS_DEV]" + #include "libbb.h" #include "libiproute/utils.h" @@ -22,12 +92,12 @@ || ENABLE_FEATURE_IP_TUNNEL \ || ENABLE_FEATURE_IP_RULE -static int ip_print_help(char **argv UNUSED_PARAM) +static int FAST_FUNC ip_print_help(char **argv UNUSED_PARAM) { bb_show_usage(); } -typedef int (*ip_func_ptr_t)(char**); +typedef int FAST_FUNC (*ip_func_ptr_t)(char**); static int ip_do(ip_func_ptr_t ip_func, char **argv) { diff --git a/networking/ipcalc.c b/networking/ipcalc.c index 265009a..3c8b8bf 100644 --- a/networking/ipcalc.c +++ b/networking/ipcalc.c @@ -9,15 +9,41 @@ * from Red Hat. I didn't look at their source code, but there * is no denying that this is a loving reimplementation * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define ipcalc_trivial_usage +//usage: "[OPTIONS] ADDRESS[[/]NETMASK] [NETMASK]" +//usage:#define ipcalc_full_usage "\n\n" +//usage: "Calculate IP network settings from a IP address\n" +//usage: IF_FEATURE_IPCALC_LONG_OPTIONS( +//usage: "\n -b,--broadcast Display calculated broadcast address" +//usage: "\n -n,--network Display calculated network address" +//usage: "\n -m,--netmask Display default netmask for IP" +//usage: IF_FEATURE_IPCALC_FANCY( +//usage: "\n -p,--prefix Display the prefix for IP/NETMASK" +//usage: "\n -h,--hostname Display first resolved host name" +//usage: "\n -s,--silent Don't ever display error messages" +//usage: ) +//usage: ) +//usage: IF_NOT_FEATURE_IPCALC_LONG_OPTIONS( +//usage: "\n -b Display calculated broadcast address" +//usage: "\n -n Display calculated network address" +//usage: "\n -m Display default netmask for IP" +//usage: IF_FEATURE_IPCALC_FANCY( +//usage: "\n -p Display the prefix for IP/NETMASK" +//usage: "\n -h Display first resolved host name" +//usage: "\n -s Don't ever display error messages" +//usage: ) +//usage: ) + #include "libbb.h" /* After libbb.h, because on some systems it needs other includes */ #include -#define CLASS_A_NETMASK ntohl(0xFF000000) -#define CLASS_B_NETMASK ntohl(0xFFFF0000) -#define CLASS_C_NETMASK ntohl(0xFFFFFF00) +#define CLASS_A_NETMASK ntohl(0xFF000000) +#define CLASS_B_NETMASK ntohl(0xFFFF0000) +#define CLASS_C_NETMASK ntohl(0xFFFFFF00) static unsigned long get_netmask(unsigned long ipaddr) { diff --git a/networking/isrv.c b/networking/isrv.c index 66bb371..1c6491e 100644 --- a/networking/isrv.c +++ b/networking/isrv.c @@ -5,7 +5,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/networking/isrv.h b/networking/isrv.h index f20714d..4c7e01d 100644 --- a/networking/isrv.h +++ b/networking/isrv.h @@ -5,7 +5,7 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN diff --git a/networking/isrv_identd.c b/networking/isrv_identd.c index e8ba007..a41405c 100644 --- a/networking/isrv_identd.c +++ b/networking/isrv_identd.c @@ -4,9 +4,19 @@ * * Copyright (C) 2007 Denys Vlasenko * - * Licensed under GPL version 2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define fakeidentd_trivial_usage +//usage: "[-fiw] [-b ADDR] [STRING]" +//usage:#define fakeidentd_full_usage "\n\n" +//usage: "Provide fake ident (auth) service\n" +//usage: "\n -f Run in foreground" +//usage: "\n -i Inetd mode" +//usage: "\n -w Inetd 'wait' mode" +//usage: "\n -b ADDR Bind to specified address" +//usage: "\n STRING Ident answer string (default: nobody)" + #include "libbb.h" #include #include "isrv.h" diff --git a/networking/libiproute/Kbuild.src b/networking/libiproute/Kbuild.src index b0aa50a..7c78f3c 100644 --- a/networking/libiproute/Kbuild.src +++ b/networking/libiproute/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2004 by Erik Andersen # -# Licensed under the GPL v2 or later, see the file LICENSE in this tarball. +# Licensed under GPLv2 or later, see file LICENSE in this source tree. # lib-y:= diff --git a/networking/libiproute/ip_common.h b/networking/libiproute/ip_common.h index aef3252..30c7e59 100644 --- a/networking/libiproute/ip_common.h +++ b/networking/libiproute/ip_common.h @@ -15,22 +15,21 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -extern char **ip_parse_common_args(char **argv); -extern int print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); -extern int ipaddr_list_or_flush(char **argv, int flush); -extern int iproute_monitor(char **argv); -extern void iplink_usage(void) NORETURN; -extern void ipneigh_reset_filter(void); +char FAST_FUNC **ip_parse_common_args(char **argv); +//int FAST_FUNC print_neigh(struct sockaddr_nl *who, struct nlmsghdr *n, void *arg); +int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush); +//int FAST_FUNC iproute_monitor(char **argv); +//void FAST_FUNC ipneigh_reset_filter(void); -extern int do_ipaddr(char **argv); -extern int do_iproute(char **argv); -extern int do_iprule(char **argv); -extern int do_ipneigh(char **argv); -extern int do_iptunnel(char **argv); -extern int do_iplink(char **argv); -extern int do_ipmonitor(char **argv); -extern int do_multiaddr(char **argv); -extern int do_multiroute(char **argv); +int FAST_FUNC do_ipaddr(char **argv); +int FAST_FUNC do_iproute(char **argv); +int FAST_FUNC do_iprule(char **argv); +//int FAST_FUNC do_ipneigh(char **argv); +int FAST_FUNC do_iptunnel(char **argv); +int FAST_FUNC do_iplink(char **argv); +//int FAST_FUNC do_ipmonitor(char **argv); +//int FAST_FUNC do_multiaddr(char **argv); +//int FAST_FUNC do_multiroute(char **argv); POP_SAVED_FUNCTION_VISIBILITY diff --git a/networking/libiproute/ip_parse_common_args.c b/networking/libiproute/ip_parse_common_args.c index 5e4012b..59c759b 100644 --- a/networking/libiproute/ip_parse_common_args.c +++ b/networking/libiproute/ip_parse_common_args.c @@ -1,18 +1,15 @@ /* vi: set sw=4 ts=4: */ /* - * ip.c "ip" utility frontend. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses */ #include "ip_common.h" /* #include "libbb.h" is inside */ @@ -22,7 +19,7 @@ family_t preferred_family = AF_UNSPEC; smallint oneline; char _SL_; -char **ip_parse_common_args(char **argv) +char** FAST_FUNC ip_parse_common_args(char **argv) { static const char ip_common_commands[] ALIGN1 = "oneline" "\0" diff --git a/networking/libiproute/ipaddress.c b/networking/libiproute/ipaddress.c index 3812934..aa4779a 100644 --- a/networking/libiproute/ipaddress.c +++ b/networking/libiproute/ipaddress.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ipaddress.c "ip address". + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: - * Laszlo Valko 990223: address label must be zero terminated + * Laszlo Valko 990223: address label must be zero terminated */ #include @@ -20,7 +18,7 @@ #ifndef IFF_LOWER_UP /* from linux/if.h */ -#define IFF_LOWER_UP 0x10000 /* driver signals L1 up*/ +#define IFF_LOWER_UP 0x10000 /* driver signals L1 up */ #endif struct filter_t { @@ -164,6 +162,8 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("master %s ", ll_idx_n2a(*(int*)RTA_DATA(tb[IFLA_MASTER]), b1)); } #endif +/* IFLA_OPERSTATE was added to kernel with the same commit as IFF_DORMANT */ +#ifdef IFF_DORMANT if (tb[IFLA_OPERSTATE]) { static const char operstate_labels[] ALIGN1 = "UNKNOWN\0""NOTPRESENT\0""DOWN\0""LOWERLAYERDOWN\0" @@ -171,6 +171,7 @@ static NOINLINE int print_linkinfo(const struct nlmsghdr *n) printf("state %s ", nth_string(operstate_labels, *(uint8_t *)RTA_DATA(tb[IFLA_OPERSTATE]))); } +#endif if (G_filter.showqueue) print_queuelen((char*)RTA_DATA(tb[IFLA_IFNAME])); @@ -313,14 +314,16 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, if (rta_tb[IFA_BROADCAST]) { printf("brd %s ", rt_addr_n2a(ifa->ifa_family, - RTA_DATA(rta_tb[IFA_BROADCAST]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_BROADCAST]), + abuf, sizeof(abuf)) + ); } if (rta_tb[IFA_ANYCAST]) { printf("any %s ", rt_addr_n2a(ifa->ifa_family, - RTA_DATA(rta_tb[IFA_ANYCAST]), - abuf, sizeof(abuf))); + RTA_DATA(rta_tb[IFA_ANYCAST]), + abuf, sizeof(abuf)) + ); } printf("scope %s ", rtnl_rtscope_n2a(ifa->ifa_scope, b1)); if (ifa->ifa_flags & IFA_F_SECONDARY) { @@ -365,7 +368,7 @@ static int FAST_FUNC print_addrinfo(const struct sockaddr_nl *who UNUSED_PARAM, struct nlmsg_list { struct nlmsg_list *next; - struct nlmsghdr h; + struct nlmsghdr h; }; static int print_selected_addrinfo(int ifindex, struct nlmsg_list *ainfo) @@ -415,7 +418,7 @@ static void ipaddr_reset_filter(int _oneline) } /* Return value becomes exitcode. It's okay to not return at all */ -int ipaddr_list_or_flush(char **argv, int flush) +int FAST_FUNC ipaddr_list_or_flush(char **argv, int flush) { static const char option[] ALIGN1 = "to\0""scope\0""up\0""label\0""dev\0"; @@ -624,10 +627,12 @@ static int ipaddr_modify(int cmd, char **argv) req.ifa.ifa_family = preferred_family; while (*argv) { - const smalluint arg = index_in_strings(option, *argv); - if (arg <= 1) { /* peer, remote */ + unsigned arg = index_in_strings(option, *argv); + /* if search fails, "local" is assumed */ + if ((int)arg >= 0) NEXT_ARG(); + if (arg <= 1) { /* peer, remote */ if (peer_len) { duparg("peer", *argv); } @@ -640,7 +645,6 @@ static int ipaddr_modify(int cmd, char **argv) req.ifa.ifa_prefixlen = peer.bitlen; } else if (arg <= 3) { /* broadcast, brd */ inet_prefix addr; - NEXT_ARG(); if (brd_len) { duparg("broadcast", *argv); } @@ -657,7 +661,6 @@ static int ipaddr_modify(int cmd, char **argv) } } else if (arg == 4) { /* anycast */ inet_prefix addr; - NEXT_ARG(); if (any_len) { duparg("anycast", *argv); } @@ -669,22 +672,18 @@ static int ipaddr_modify(int cmd, char **argv) any_len = addr.bytelen; } else if (arg == 5) { /* scope */ uint32_t scope = 0; - NEXT_ARG(); if (rtnl_rtscope_a2n(&scope, *argv)) { invarg(*argv, "scope"); } req.ifa.ifa_scope = scope; scoped = 1; } else if (arg == 6) { /* dev */ - NEXT_ARG(); d = *argv; } else if (arg == 7) { /* label */ - NEXT_ARG(); l = *argv; addattr_l(&req.n, sizeof(req), IFA_LABEL, l, strlen(l) + 1); } else { - if (arg == 8) /* local */ - NEXT_ARG(); + /* local (specified or assumed) */ if (local_len) { duparg2("local", *argv); } @@ -721,7 +720,7 @@ static int ipaddr_modify(int cmd, char **argv) } brd = peer; if (brd.bitlen <= 30) { - for (i=31; i>=brd.bitlen; i--) { + for (i = 31; i >= brd.bitlen; i--) { if (brd_len == -1) brd.data[0] |= htonl(1<<(31-i)); else @@ -747,15 +746,15 @@ static int ipaddr_modify(int cmd, char **argv) } /* Return value becomes exitcode. It's okay to not return at all */ -int do_ipaddr(char **argv) +int FAST_FUNC do_ipaddr(char **argv) { static const char commands[] ALIGN1 = "add\0""delete\0""list\0""show\0""lst\0""flush\0"; - smalluint cmd = 2; + int cmd = 2; if (*argv) { cmd = index_in_substrings(commands, *argv); - if (cmd > 5) - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + if (cmd < 0) + invarg(*argv, applet_name); argv++; if (cmd <= 1) return ipaddr_modify((cmd == 0) ? RTM_NEWADDR : RTM_DELADDR, argv); diff --git a/networking/libiproute/iplink.c b/networking/libiproute/iplink.c index 8bf8927..286e59e 100644 --- a/networking/libiproute/iplink.c +++ b/networking/libiproute/iplink.c @@ -1,22 +1,40 @@ /* vi: set sw=4 ts=4: */ /* - * iplink.c "ip link". - * * Authors: Alexey Kuznetsov, + * Patrick McHardy * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include -#include +/*#include - not needed? */ #include -#include +#include +#include #include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" #include "utils.h" +#undef ETH_P_8021AD +#define ETH_P_8021AD 0x88A8 +#undef VLAN_FLAG_REORDER_HDR +#define VLAN_FLAG_REORDER_HDR 0x1 +#undef VLAN_FLAG_GVRP +#define VLAN_FLAG_GVRP 0x2 +#undef VLAN_FLAG_LOOSE_BINDING +#define VLAN_FLAG_LOOSE_BINDING 0x4 +#undef VLAN_FLAG_MVRP +#define VLAN_FLAG_MVRP 0x8 +#undef IFLA_VLAN_PROTOCOL +#define IFLA_VLAN_PROTOCOL 5 + +#ifndef IFLA_LINKINFO +# define IFLA_LINKINFO 18 +# define IFLA_INFO_KIND 1 +#endif + /* taken from linux/sockios.h */ -#define SIOCSIFNAME 0x8923 /* set interface name */ +#define SIOCSIFNAME 0x8923 /* set interface name */ /* Exits on error */ static int get_ctl_fd(void) @@ -274,12 +292,103 @@ static int ipaddr_list_link(char **argv) return ipaddr_list_or_flush(argv, 0); } +static void vlan_parse_opt(char **argv, struct nlmsghdr *n, unsigned int size) +{ + static const char keywords[] ALIGN1 = + "id\0" + "protocol\0" + "reorder_hdr\0" + "gvrp\0" + "mvrp\0" + "loose_binding\0" + ; + static const char protocols[] ALIGN1 = + "802.1q\0" + "802.1ad\0" + ; + static const char str_on_off[] ALIGN1 = + "on\0" + "off\0" + ; + enum { + ARG_id = 0, + ARG_reorder_hdr, + ARG_gvrp, + ARG_mvrp, + ARG_loose_binding, + ARG_protocol, + }; + enum { + PROTO_8021Q = 0, + PROTO_8021AD, + }; + enum { + PARM_on = 0, + PARM_off + }; + int arg; + uint16_t id, proto; + struct ifla_vlan_flags flags = {}; + + while (*argv) { + arg = index_in_substrings(keywords, *argv); + if (arg < 0) + invarg(*argv, "type vlan"); + + NEXT_ARG(); + if (arg == ARG_id) { + id = get_u16(*argv, "id"); + addattr_l(n, size, IFLA_VLAN_ID, &id, sizeof(id)); + } else if (arg == ARG_protocol) { + arg = index_in_substrings(protocols, *argv); + if (arg == PROTO_8021Q) + proto = ETH_P_8021Q; + else if (arg == PROTO_8021AD) + proto = ETH_P_8021AD; + else + bb_error_msg_and_die("unknown VLAN encapsulation protocol '%s'", + *argv); + addattr_l(n, size, IFLA_VLAN_PROTOCOL, &proto, sizeof(proto)); + } else { + int param = index_in_strings(str_on_off, *argv); + if (param < 0) + die_must_be_on_off(nth_string(keywords, arg)); + + if (arg == ARG_reorder_hdr) { + flags.mask |= VLAN_FLAG_REORDER_HDR; + flags.flags &= ~VLAN_FLAG_REORDER_HDR; + if (param == PARM_on) + flags.flags |= VLAN_FLAG_REORDER_HDR; + } else if (arg == ARG_gvrp) { + flags.mask |= VLAN_FLAG_GVRP; + flags.flags &= ~VLAN_FLAG_GVRP; + if (param == PARM_on) + flags.flags |= VLAN_FLAG_GVRP; + } else if (arg == ARG_mvrp) { + flags.mask |= VLAN_FLAG_MVRP; + flags.flags &= ~VLAN_FLAG_MVRP; + if (param == PARM_on) + flags.flags |= VLAN_FLAG_MVRP; + } else { /*if (arg == ARG_loose_binding) */ + flags.mask |= VLAN_FLAG_LOOSE_BINDING; + flags.flags &= ~VLAN_FLAG_LOOSE_BINDING; + if (param == PARM_on) + flags.flags |= VLAN_FLAG_LOOSE_BINDING; + } + } + argv++; + } + + if (flags.mask) + addattr_l(n, size, IFLA_VLAN_FLAGS, &flags, sizeof(flags)); +} + #ifndef NLMSG_TAIL #define NLMSG_TAIL(nmsg) \ ((struct rtattr *) (((void *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len))) #endif /* Return value becomes exitcode. It's okay to not return at all */ -static int do_change(char **argv, const unsigned rtm) +static int do_add_or_delete(char **argv, const unsigned rtm) { static const char keywords[] ALIGN1 = "link\0""name\0""type\0""dev\0"; @@ -291,9 +400,9 @@ static int do_change(char **argv, const unsigned rtm) }; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct ifinfomsg i; - char buf[1024]; + struct nlmsghdr n; + struct ifinfomsg i; + char buf[1024]; } req; smalluint arg; char *name_str = NULL, *link_str = NULL, *type_str = NULL, *dev_str = NULL; @@ -309,15 +418,17 @@ static int do_change(char **argv, const unsigned rtm) while (*argv) { arg = index_in_substrings(keywords, *argv); + if (arg == ARG_type) { + NEXT_ARG(); + type_str = *argv++; + break; + } if (arg == ARG_link) { NEXT_ARG(); link_str = *argv; } else if (arg == ARG_name) { NEXT_ARG(); name_str = *argv; - } else if (arg == ARG_type) { - NEXT_ARG(); - type_str = *argv; } else { if (arg == ARG_dev) { if (dev_str) @@ -336,6 +447,17 @@ static int do_change(char **argv, const unsigned rtm) addattr_l(&req.n, sizeof(req), IFLA_LINKINFO, NULL, 0); addattr_l(&req.n, sizeof(req), IFLA_INFO_KIND, type_str, strlen(type_str)); + + if (*argv) { + struct rtattr *data = NLMSG_TAIL(&req.n); + addattr_l(&req.n, sizeof(req), IFLA_INFO_DATA, NULL, 0); + + if (strcmp(type_str, "vlan") == 0) + vlan_parse_opt(argv, &req.n, sizeof(req)); + + data->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)data; + } + linkinfo->rta_len = (void *)NLMSG_TAIL(&req.n) - (void *)linkinfo; } if (rtm != RTM_NEWLINK) { @@ -362,18 +484,18 @@ static int do_change(char **argv, const unsigned rtm) } /* Return value becomes exitcode. It's okay to not return at all */ -int do_iplink(char **argv) +int FAST_FUNC do_iplink(char **argv) { static const char keywords[] ALIGN1 = "add\0""delete\0""set\0""show\0""lst\0""list\0"; if (*argv) { - smalluint key = index_in_substrings(keywords, *argv); - if (key > 5) /* invalid argument */ - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + int key = index_in_substrings(keywords, *argv); + if (key < 0) /* invalid argument */ + invarg(*argv, applet_name); argv++; if (key <= 1) /* add/delete */ - return do_change(argv, key ? RTM_DELLINK : RTM_NEWLINK); - else if (key == 2) /* set */ + return do_add_or_delete(argv, key ? RTM_DELLINK : RTM_NEWLINK); + if (key == 2) /* set */ return do_set(argv); } /* show, lst, list */ diff --git a/networking/libiproute/iproute.c b/networking/libiproute/iproute.c index d771a60..f8a67d9 100644 --- a/networking/libiproute/iproute.c +++ b/networking/libiproute/iproute.c @@ -1,19 +1,16 @@ /* vi: set sw=4 ts=4: */ /* - * iproute.c "ip route". - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - * - * Authors: Alexey Kuznetsov, + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * Kunihiro Ishiguro 001102: rtnh_ifindex was not initialized */ -#include "ip_common.h" /* #include "libbb.h" is inside */ +#include "ip_common.h" /* #include "libbb.h" is inside */ #include "rt_names.h" #include "utils.h" @@ -34,8 +31,8 @@ struct filter_t { //int type; - read-only //int typemask; - unused //int tos, tosmask; - unused - int iif, iifmask; - int oif, oifmask; + int iif; + int oif; //int realm, realmmask; - unused //inet_prefix rprefsrc; - read-only inet_prefix rvia; @@ -85,7 +82,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, { struct rtmsg *r = NLMSG_DATA(n); int len = n->nlmsg_len; - struct rtattr * tb[RTA_MAX+1]; + struct rtattr *tb[RTA_MAX+1]; char abuf[256]; inet_prefix dst; inet_prefix src; @@ -162,8 +159,21 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, } memset(tb, 0, sizeof(tb)); + memset(&src, 0, sizeof(src)); + memset(&dst, 0, sizeof(dst)); parse_rtattr(tb, RTA_MAX, RTM_RTA(r), len); + if (tb[RTA_SRC]) { + src.bitlen = r->rtm_src_len; + src.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(src.data, RTA_DATA(tb[RTA_SRC]), src.bytelen); + } + if (tb[RTA_DST]) { + dst.bitlen = r->rtm_dst_len; + dst.bytelen = (r->rtm_family == AF_INET6 ? 16 : 4); + memcpy(dst.data, RTA_DATA(tb[RTA_DST]), dst.bytelen); + } + if (G_filter.rdst.family && inet_addr_match(&dst, &G_filter.rdst, G_filter.rdst.bitlen) ) { @@ -185,23 +195,32 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, ) { return 0; } - if (G_filter.flushb - && r->rtm_family == AF_INET6 - && r->rtm_dst_len == 0 - && r->rtm_type == RTN_UNREACHABLE - && tb[RTA_PRIORITY] - && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 - ) { - return 0; + if (G_filter.oif != 0) { + if (!tb[RTA_OIF]) + return 0; + if (G_filter.oif != *(int*)RTA_DATA(tb[RTA_OIF])) + return 0; } if (G_filter.flushb) { struct nlmsghdr *fn; + + /* We are creating route flush commands */ + + if (r->rtm_family == AF_INET6 + && r->rtm_dst_len == 0 + && r->rtm_type == RTN_UNREACHABLE + && tb[RTA_PRIORITY] + && *(int*)RTA_DATA(tb[RTA_PRIORITY]) == -1 + ) { + return 0; + } + if (NLMSG_ALIGN(G_filter.flushp) + n->nlmsg_len > G_filter.flushe) { if (flush_update()) bb_error_msg_and_die("flush"); } - fn = (struct nlmsghdr*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); + fn = (void*)(G_filter.flushb + NLMSG_ALIGN(G_filter.flushp)); memcpy(fn, n, n->nlmsg_len); fn->nlmsg_type = RTM_DELROUTE; fn->nlmsg_flags = NLM_F_REQUEST; @@ -211,6 +230,8 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, return 0; } + /* We are printing routes */ + if (n->nlmsg_type == RTM_DELROUTE) { printf("Deleted "); } @@ -260,10 +281,12 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, RTA_DATA(tb[RTA_GATEWAY]), abuf, sizeof(abuf))); } - if (tb[RTA_OIF] && G_filter.oifmask != -1) { + if (tb[RTA_OIF]) { printf("dev %s ", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_OIF]))); } + /* Todo: parse & show "proto kernel", "scope link" here */ + if (tb[RTA_PREFSRC] && /*G_filter.rprefsrc.bitlen - always 0*/ 0 != host_len) { /* Do not use format_host(). It is our local addr and symbolic name will not be useful. @@ -295,7 +318,7 @@ static int FAST_FUNC print_route(const struct sockaddr_nl *who UNUSED_PARAM, printf(" error %d", ci->rta_error); } } - if (tb[RTA_IIF] && G_filter.iifmask != -1) { + if (tb[RTA_IIF] && G_filter.iif == 0) { printf(" iif %s", ll_index_to_name(*(int*)RTA_DATA(tb[RTA_IIF]))); } bb_putchar('\n'); @@ -327,9 +350,9 @@ IF_FEATURE_IP_RULE(ARG_table,) }; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[1024]; + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; } req; char mxbuf[256]; struct rtattr * mxrta = (void*)mxbuf; @@ -416,7 +439,8 @@ IF_FEATURE_IP_RULE(ARG_table,) NEXT_ARG(); } if ((**argv < '0' || **argv > '9') - && rtnl_rtntype_a2n(&type, *argv) == 0) { + && rtnl_rtntype_a2n(&type, *argv) == 0 + ) { NEXT_ARG(); req.r.rtm_type = type; ok |= type_ok; @@ -665,12 +689,10 @@ static int iproute_list_or_flush(char **argv, int flush) if (id) { idx = xll_name_to_index(id); G_filter.iif = idx; - G_filter.iifmask = -1; } if (od) { idx = xll_name_to_index(od); G_filter.oif = idx; - G_filter.oifmask = -1; } } @@ -791,8 +813,8 @@ static int iproute_get(char **argv) } req.r.rtm_dst_len = addr.bitlen; } - argv++; } + argv++; } if (req.r.rtm_dst_len == 0) { @@ -869,7 +891,7 @@ static int iproute_get(char **argv) } /* Return value becomes exitcode. It's okay to not return at all */ -int do_iproute(char **argv) +int FAST_FUNC do_iproute(char **argv) { static const char ip_route_commands[] ALIGN1 = /*0-3*/ "add\0""append\0""change\0""chg\0" diff --git a/networking/libiproute/iprule.c b/networking/libiproute/iprule.c index 835529e..8dbe6bd 100644 --- a/networking/libiproute/iprule.c +++ b/networking/libiproute/iprule.c @@ -1,18 +1,15 @@ /* vi: set sw=4 ts=4: */ /* - * iprule.c "ip rule". - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses * initially integrated into busybox by Bernhard Reutner-Fischer */ @@ -76,15 +73,17 @@ static int FAST_FUNC print_rule(const struct sockaddr_nl *who UNUSED_PARAM, if (tb[RTA_SRC]) { if (r->rtm_src_len != host_len) { printf("%s/%u", rt_addr_n2a(r->rtm_family, - RTA_DATA(tb[RTA_SRC]), - abuf, sizeof(abuf)), + RTA_DATA(tb[RTA_SRC]), + abuf, sizeof(abuf)), r->rtm_src_len - ); + ); } else { fputs(format_host(r->rtm_family, - RTA_PAYLOAD(tb[RTA_SRC]), - RTA_DATA(tb[RTA_SRC]), - abuf, sizeof(abuf)), stdout); + RTA_PAYLOAD(tb[RTA_SRC]), + RTA_DATA(tb[RTA_SRC]), + abuf, sizeof(abuf)), + stdout + ); } } else if (r->rtm_src_len) { printf("0/%d", r->rtm_src_len); @@ -191,9 +190,9 @@ static int iprule_modify(int cmd, char **argv) bool table_ok = 0; struct rtnl_handle rth; struct { - struct nlmsghdr n; - struct rtmsg r; - char buf[1024]; + struct nlmsghdr n; + struct rtmsg r; + char buf[1024]; } req; smalluint key; @@ -216,7 +215,7 @@ static int iprule_modify(int cmd, char **argv) while (*argv) { key = index_in_substrings(keywords, *argv) + 1; if (key == 0) /* no match found in keywords array, bail out. */ - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + invarg(*argv, applet_name); if (key == ARG_from) { inet_prefix dst; NEXT_ARG(); @@ -304,14 +303,14 @@ static int iprule_modify(int cmd, char **argv) } /* Return value becomes exitcode. It's okay to not return at all */ -int do_iprule(char **argv) +int FAST_FUNC do_iprule(char **argv) { static const char ip_rule_commands[] ALIGN1 = "add\0""delete\0""list\0""show\0"; if (*argv) { - smalluint cmd = index_in_substrings(ip_rule_commands, *argv); - if (cmd > 3) - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + int cmd = index_in_substrings(ip_rule_commands, *argv); + if (cmd < 0) + invarg(*argv, applet_name); argv++; if (cmd < 2) return iprule_modify((cmd == 0) ? RTM_NEWRULE : RTM_DELRULE, argv); diff --git a/networking/libiproute/iptunnel.c b/networking/libiproute/iptunnel.c index 2573438..b54c3c5 100644 --- a/networking/libiproute/iptunnel.c +++ b/networking/libiproute/iptunnel.c @@ -1,16 +1,14 @@ /* vi: set sw=4 ts=4: */ /* - * iptunnel.c "ip tunnel" + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses - * Rani Assaf 980930: do not allow key for ipip/sit - * Phil Karn 990408: "pmtudisc" flag + * Rani Assaf 980929: resolve addresses + * Rani Assaf 980930: do not allow key for ipip/sit + * Phil Karn 990408: "pmtudisc" flag */ #include @@ -440,7 +438,7 @@ static void print_tunnel(struct ip_tunnel_parm *p) printf(" inherit"); if (p->iph.tos & ~1) printf("%c%s ", p->iph.tos & 1 ? '/' : ' ', - rtnl_dsfield_n2a(p->iph.tos & ~1, b1)); + rtnl_dsfield_n2a(p->iph.tos & ~1, b1)); } if (!(p->iph.frag_off & htons(IP_DF))) printf(" nopmtudisc"); @@ -556,16 +554,16 @@ static int do_show(char **argv) } /* Return value becomes exitcode. It's okay to not return at all */ -int do_iptunnel(char **argv) +int FAST_FUNC do_iptunnel(char **argv) { static const char keywords[] ALIGN1 = "add\0""change\0""delete\0""show\0""list\0""lst\0"; enum { ARG_add = 0, ARG_change, ARG_del, ARG_show, ARG_list, ARG_lst }; if (*argv) { - smalluint key = index_in_substrings(keywords, *argv); - if (key > 5) - bb_error_msg_and_die(bb_msg_invalid_arg, *argv, applet_name); + int key = index_in_substrings(keywords, *argv); + if (key < 0) + invarg(*argv, applet_name); argv++; if (key == ARG_add) return do_add(SIOCADDTUNNEL, argv); diff --git a/networking/libiproute/libnetlink.c b/networking/libiproute/libnetlink.c index ba24832..c7533a4 100644 --- a/networking/libiproute/libnetlink.c +++ b/networking/libiproute/libnetlink.c @@ -1,14 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * libnetlink.c RTnetlink service routines. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, */ #include @@ -17,12 +14,7 @@ #include "libbb.h" #include "libnetlink.h" -void FAST_FUNC rtnl_close(struct rtnl_handle *rth) -{ - close(rth->fd); -} - -int FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) +void FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) { socklen_t addr_len; @@ -44,7 +36,6 @@ int FAST_FUNC xrtnl_open(struct rtnl_handle *rth/*, unsigned subscriptions*/) bb_error_msg_and_die("wrong address family %d", rth->local.nl_family); */ rth->seq = time(NULL); - return 0; } int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int type) @@ -53,10 +44,6 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty struct nlmsghdr nlh; struct rtgenmsg g; } req; - struct sockaddr_nl nladdr; - - memset(&nladdr, 0, sizeof(nladdr)); - nladdr.nl_family = AF_NETLINK; req.nlh.nlmsg_len = sizeof(req); req.nlh.nlmsg_type = type; @@ -65,10 +52,10 @@ int FAST_FUNC xrtnl_wilddump_request(struct rtnl_handle *rth, int family, int ty req.nlh.nlmsg_seq = rth->dump = ++rth->seq; req.g.rtgen_family = family; - return xsendto(rth->fd, (void*)&req, sizeof(req), - (struct sockaddr*)&nladdr, sizeof(nladdr)); + return rtnl_send(rth, (void*)&req, sizeof(req)); } +//TODO: pass rth->fd instead of full rth? int FAST_FUNC rtnl_send(struct rtnl_handle *rth, char *buf, int len) { struct sockaddr_nl nladdr; @@ -86,8 +73,8 @@ int FAST_FUNC rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, in struct iovec iov[2] = { { &nlh, sizeof(nlh) }, { req, len } }; struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - iov, 2, - NULL, 0, + iov, 2, + NULL, 0, 0 }; @@ -120,8 +107,8 @@ static int rtnl_dump_filter(struct rtnl_handle *rth, struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - &iov, 1, - NULL, 0, + &iov, 1, + NULL, 0, 0 }; @@ -226,8 +213,8 @@ int FAST_FUNC rtnl_talk(struct rtnl_handle *rtnl, struct nlmsghdr *n, char *buf = xmalloc(8*1024); /* avoid big stack buffer */ struct msghdr msg = { (void*)&nladdr, sizeof(nladdr), - &iov, 1, - NULL, 0, + &iov, 1, + NULL, 0, 0 }; @@ -339,8 +326,10 @@ int FAST_FUNC addattr32(struct nlmsghdr *n, int maxlen, int type, uint32_t data) { int len = RTA_LENGTH(4); struct rtattr *rta; - if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) + + if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) { return -1; + } rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; @@ -354,8 +343,9 @@ int FAST_FUNC addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, in int len = RTA_LENGTH(alen); struct rtattr *rta; - if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) + if ((int)(NLMSG_ALIGN(n->nlmsg_len) + len) > maxlen) { return -1; + } rta = (struct rtattr*)(((char*)n) + NLMSG_ALIGN(n->nlmsg_len)); rta->rta_type = type; rta->rta_len = len; @@ -397,16 +387,15 @@ int FAST_FUNC rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data } -int FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) +void FAST_FUNC parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) { while (RTA_OK(rta, len)) { if (rta->rta_type <= max) { tb[rta->rta_type] = rta; } - rta = RTA_NEXT(rta,len); + rta = RTA_NEXT(rta, len); } if (len) { bb_error_msg("deficit %d, rta_len=%d!", len, rta->rta_len); } - return 0; } diff --git a/networking/libiproute/libnetlink.h b/networking/libiproute/libnetlink.h index 41ecfa6..51bee2d 100644 --- a/networking/libiproute/libnetlink.h +++ b/networking/libiproute/libnetlink.h @@ -11,15 +11,15 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct rtnl_handle { - int fd; - struct sockaddr_nl local; - struct sockaddr_nl peer; - uint32_t seq; - uint32_t dump; + int fd; + struct sockaddr_nl local; + struct sockaddr_nl peer; + uint32_t seq; + uint32_t dump; }; -extern int xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; -extern void rtnl_close(struct rtnl_handle *rth) FAST_FUNC; +extern void xrtnl_open(struct rtnl_handle *rth) FAST_FUNC; +#define rtnl_close(rth) (close((rth)->fd)) extern int xrtnl_wilddump_request(struct rtnl_handle *rth, int fam, int type) FAST_FUNC; extern int rtnl_dump_request(struct rtnl_handle *rth, int type, void *req, int len) FAST_FUNC; extern int xrtnl_dump_filter(struct rtnl_handle *rth, @@ -42,7 +42,7 @@ extern int addattr_l(struct nlmsghdr *n, int maxlen, int type, void *data, int a extern int rta_addattr32(struct rtattr *rta, int maxlen, int type, uint32_t data) FAST_FUNC; extern int rta_addattr_l(struct rtattr *rta, int maxlen, int type, void *data, int alen) FAST_FUNC; -extern int parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC; +extern void parse_rtattr(struct rtattr *tb[], int max, struct rtattr *rta, int len) FAST_FUNC; POP_SAVED_FUNCTION_VISIBILITY diff --git a/networking/libiproute/ll_addr.c b/networking/libiproute/ll_addr.c index c2c0130..33a54ea 100644 --- a/networking/libiproute/ll_addr.c +++ b/networking/libiproute/ll_addr.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * ll_addr.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 free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include diff --git a/networking/libiproute/ll_map.c b/networking/libiproute/ll_map.c index 246b9e3..27cd90f 100644 --- a/networking/libiproute/ll_map.c +++ b/networking/libiproute/ll_map.c @@ -1,17 +1,14 @@ /* vi: set sw=4 ts=4: */ /* - * ll_map.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. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, */ -#include /* struct ifreq and co. */ +#include /* struct ifreq and co. */ #include "libbb.h" #include "libnetlink.h" diff --git a/networking/libiproute/ll_proto.c b/networking/libiproute/ll_proto.c index 145902b..da2b53c 100644 --- a/networking/libiproute/ll_proto.c +++ b/networking/libiproute/ll_proto.c @@ -1,38 +1,91 @@ /* vi: set sw=4 ts=4: */ /* - * ll_proto.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 free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include "libbb.h" #include "rt_names.h" #include "utils.h" -#if defined(__GLIBC__) && __GLIBC__ >=2 && __GLIBC_MINOR__ >= 1 -#include -#else -#include +#include + +/* Please conditionalize exotic protocols on CONFIG_something */ + +static const uint16_t llproto_ids[] = { +#define __PF(f,n) ETH_P_##f, +__PF(LOOP,loop) +__PF(PUP,pup) +#ifdef ETH_P_PUPAT +__PF(PUPAT,pupat) +#endif +__PF(IP,ip) +__PF(X25,x25) +__PF(ARP,arp) +__PF(BPQ,bpq) +#ifdef ETH_P_IEEEPUP +__PF(IEEEPUP,ieeepup) +#endif +#ifdef ETH_P_IEEEPUPAT +__PF(IEEEPUPAT,ieeepupat) +#endif +__PF(DEC,dec) +__PF(DNA_DL,dna_dl) +__PF(DNA_RC,dna_rc) +__PF(DNA_RT,dna_rt) +__PF(LAT,lat) +__PF(DIAG,diag) +__PF(CUST,cust) +__PF(SCA,sca) +__PF(RARP,rarp) +__PF(ATALK,atalk) +__PF(AARP,aarp) +__PF(IPX,ipx) +__PF(IPV6,ipv6) +#ifdef ETH_P_PPP_DISC +__PF(PPP_DISC,ppp_disc) +#endif +#ifdef ETH_P_PPP_SES +__PF(PPP_SES,ppp_ses) +#endif +#ifdef ETH_P_ATMMPOA +__PF(ATMMPOA,atmmpoa) +#endif +#ifdef ETH_P_ATMFATE +__PF(ATMFATE,atmfate) #endif -#if !ENABLE_WERROR -#warning de-bloat +__PF(802_3,802_3) +__PF(AX25,ax25) +__PF(ALL,all) +__PF(802_2,802_2) +__PF(SNAP,snap) +__PF(DDCMP,ddcmp) +__PF(WAN_PPP,wan_ppp) +__PF(PPP_MP,ppp_mp) +__PF(LOCALTALK,localtalk) +__PF(PPPTALK,ppptalk) +__PF(TR_802_2,tr_802_2) +__PF(MOBITEX,mobitex) +__PF(CONTROL,control) +__PF(IRDA,irda) +#ifdef ETH_P_ECONET +__PF(ECONET,econet) #endif -/* Before re-enabling this, please (1) conditionalize exotic protocols - * on CONFIG_something, and (2) decouple strings and numbers - * (use llproto_ids[] = n,n,n..; and llproto_names[] = "loop\0" "pup\0" ...;) - */ -#define __PF(f,n) { ETH_P_##f, #n }, -static struct { - int id; - const char *name; -} llproto_names[] = { +0x8100, +ETH_P_IP +}; +#undef __PF + +/* Keep declarations above and below in sync! */ + +static const char llproto_names[] = +#define __PF(f,n) #n "\0" __PF(LOOP,loop) __PF(PUP,pup) #ifdef ETH_P_PUPAT @@ -92,9 +145,9 @@ __PF(IRDA,irda) __PF(ECONET,econet) #endif -{ 0x8100, "802.1Q" }, -{ ETH_P_IP, "ipv4" }, -}; +"802.1Q" "\0" +"ipv4" "\0" +; #undef __PF @@ -102,23 +155,26 @@ const char* FAST_FUNC ll_proto_n2a(unsigned short id, char *buf, int len) { unsigned i; id = ntohs(id); - for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { - if (llproto_names[i].id == id) - return llproto_names[i].name; + for (i = 0; i < ARRAY_SIZE(llproto_ids); i++) { + if (llproto_ids[i] == id) + return nth_string(llproto_names, i); } - snprintf(buf, len, "[%d]", id); + snprintf(buf, len, "[%u]", id); return buf; } int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf) { unsigned i; - for (i = 0; i < ARRAY_SIZE(llproto_names); i++) { - if (strcasecmp(llproto_names[i].name, buf) == 0) { - i = llproto_names[i].id; - goto good; - } + const char *name = llproto_names; + for (i = 0; i < ARRAY_SIZE(llproto_ids); i++) { + if (strcasecmp(name, buf) == 0) { + i = llproto_ids[i]; + goto good; + } + name += strlen(name) + 1; } + errno = 0; i = bb_strtou(buf, NULL, 0); if (errno || i > 0xffff) return -1; @@ -126,4 +182,3 @@ int FAST_FUNC ll_proto_a2n(unsigned short *id, char *buf) *id = htons(i); return 0; } - diff --git a/networking/libiproute/ll_types.c b/networking/libiproute/ll_types.c index 3861c28..bb42e26 100644 --- a/networking/libiproute/ll_types.c +++ b/networking/libiproute/ll_types.c @@ -1,14 +1,13 @@ /* vi: set sw=4 ts=4: */ /* - * ll_types.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 free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ +#include /* linux/if_arp.h needs it on some systems */ #include #include diff --git a/networking/libiproute/rt_names.c b/networking/libiproute/rt_names.c index 8dd16e3..c474ab9 100644 --- a/networking/libiproute/rt_names.c +++ b/networking/libiproute/rt_names.c @@ -1,13 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * rt_names.c rtnetlink names DB. + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version - * 2 of the License, or (at your option) any later version. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, */ #include "libbb.h" #include "rt_names.h" diff --git a/networking/libiproute/rtm_map.c b/networking/libiproute/rtm_map.c index 5e358e1..3bab53b 100644 --- a/networking/libiproute/rtm_map.c +++ b/networking/libiproute/rtm_map.c @@ -1,14 +1,11 @@ /* vi: set sw=4 ts=4: */ /* - * rtm_map.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. - * - * Authors: Alexey Kuznetsov, + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. * + * Authors: Alexey Kuznetsov, */ #include "libbb.h" diff --git a/networking/libiproute/utils.c b/networking/libiproute/utils.c index 85034c0..d0fe306 100644 --- a/networking/libiproute/utils.c +++ b/networking/libiproute/utils.c @@ -1,14 +1,12 @@ /* vi: set sw=4 ts=4: */ /* - * utils.c + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Changes: * - * Rani Assaf 980929: resolve addresses + * Rani Assaf 980929: resolve addresses */ #include "libbb.h" @@ -64,7 +62,7 @@ int get_addr_1(inet_prefix *addr, char *name, int family) { memset(addr, 0, sizeof(*addr)); - if (strcmp(name, bb_str_default) == 0 + if (strcmp(name, "default") == 0 || strcmp(name, "all") == 0 || strcmp(name, "any") == 0 ) { @@ -85,73 +83,98 @@ int get_addr_1(inet_prefix *addr, char *name, int family) return 0; } - addr->family = AF_INET; if (family != AF_UNSPEC && family != AF_INET) return -1; + + /* Try to parse it as IPv4 */ + addr->family = AF_INET; +#if 0 /* Doesn't handle e.g. "10.10", for example, "ip r l root 10.10/16" */ if (inet_pton(AF_INET, name, addr->data) <= 0) return -1; +#else + { + unsigned i = 0; + unsigned n = 0; + const char *cp = name - 1; + while (*++cp) { + if ((unsigned char)(*cp - '0') <= 9) { + n = 10 * n + (unsigned char)(*cp - '0'); + if (n >= 256) + return -1; + ((uint8_t*)addr->data)[i] = n; + continue; + } + if (*cp == '.' && ++i <= 3) { + n = 0; + continue; + } + return -1; + } + } +#endif addr->bytelen = 4; addr->bitlen = -1; + return 0; } -static int get_prefix_1(inet_prefix *dst, char *arg, int family) +static void get_prefix_1(inet_prefix *dst, char *arg, int family) { - int err; - unsigned plen; char *slash; memset(dst, 0, sizeof(*dst)); - if (strcmp(arg, bb_str_default) == 0 + if (strcmp(arg, "default") == 0 || strcmp(arg, "all") == 0 || strcmp(arg, "any") == 0 ) { dst->family = family; /*dst->bytelen = 0; - done by memset */ /*dst->bitlen = 0;*/ - return 0; + return; } slash = strchr(arg, '/'); if (slash) *slash = '\0'; - err = get_addr_1(dst, arg, family); - if (err == 0) { + + if (get_addr_1(dst, arg, family) == 0) { dst->bitlen = (dst->family == AF_INET6) ? 128 : 32; if (slash) { + unsigned plen; inet_prefix netmask_pfx; netmask_pfx.family = AF_UNSPEC; plen = bb_strtou(slash + 1, NULL, 0); if ((errno || plen > dst->bitlen) - && (get_addr_1(&netmask_pfx, slash + 1, family))) - err = -1; - else if (netmask_pfx.family == AF_INET) { + && get_addr_1(&netmask_pfx, slash + 1, family) != 0 + ) { + goto bad; + } + if (netmask_pfx.family == AF_INET) { /* fill in prefix length of dotted quad */ uint32_t mask = ntohl(netmask_pfx.data[0]); uint32_t host = ~mask; /* a valid netmask must be 2^n - 1 */ - if (!(host & (host + 1))) { - for (plen = 0; mask; mask <<= 1) - ++plen; - if (plen <= dst->bitlen) { - dst->bitlen = plen; - /* dst->flags |= PREFIXLEN_SPECIFIED; */ - } else - err = -1; - } else - err = -1; - } else { - /* plain prefix */ - dst->bitlen = plen; + if (host & (host + 1)) + goto bad; + + for (plen = 0; mask; mask <<= 1) + ++plen; + if (plen > dst->bitlen) + goto bad; + /* dst->flags |= PREFIXLEN_SPECIFIED; */ } + dst->bitlen = plen; } } + if (slash) *slash = '/'; - return err; + return; + bad: + bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); } int get_addr(inet_prefix *dst, char *arg, int family) @@ -165,15 +188,12 @@ int get_addr(inet_prefix *dst, char *arg, int family) return 0; } -int get_prefix(inet_prefix *dst, char *arg, int family) +void get_prefix(inet_prefix *dst, char *arg, int family) { if (family == AF_PACKET) { bb_error_msg_and_die("\"%s\" may be inet %s, but it is not allowed in this context", arg, "prefix"); } - if (get_prefix_1(dst, arg, family)) { - bb_error_msg_and_die("an %s %s is expected rather than \"%s\"", "inet", "prefix", arg); - } - return 0; + get_prefix_1(dst, arg, family); } uint32_t get_addr32(char *name) @@ -206,10 +226,10 @@ void duparg2(const char *key, const char *arg) bb_error_msg_and_die("either \"%s\" is duplicate, or \"%s\" is garbage", key, arg); } -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits) { - uint32_t *a1 = a->data; - uint32_t *a2 = b->data; + const uint32_t *a1 = a->data; + const uint32_t *a2 = b->data; int words = bits >> 5; bits &= 0x1f; diff --git a/networking/libiproute/utils.h b/networking/libiproute/utils.h index ed03e78..5fb4a86 100644 --- a/networking/libiproute/utils.h +++ b/networking/libiproute/utils.h @@ -17,14 +17,14 @@ extern smallint oneline; extern char _SL_; #ifndef IPPROTO_ESP -#define IPPROTO_ESP 50 +#define IPPROTO_ESP 50 #endif #ifndef IPPROTO_AH -#define IPPROTO_AH 51 +#define IPPROTO_AH 51 #endif #define SPRINT_BSIZE 64 -#define SPRINT_BUF(x) char x[SPRINT_BSIZE] +#define SPRINT_BUF(x) char x[SPRINT_BSIZE] extern void incomplete_command(void) NORETURN; @@ -58,9 +58,9 @@ struct ipx_addr { extern uint32_t get_addr32(char *name); extern int get_addr_1(inet_prefix *dst, char *arg, int family); -/*extern int get_prefix_1(inet_prefix *dst, char *arg, int family);*/ +/*extern void get_prefix_1(inet_prefix *dst, char *arg, int family);*/ extern int get_addr(inet_prefix *dst, char *arg, int family); -extern int get_prefix(inet_prefix *dst, char *arg, int family); +extern void get_prefix(inet_prefix *dst, char *arg, int family); extern unsigned get_unsigned(char *arg, const char *errmsg); extern uint32_t get_u32(char *arg, const char *errmsg); @@ -77,7 +77,7 @@ extern const char *format_host(int af, int len, void *addr, char *buf, int bufle void invarg(const char *, const char *) NORETURN; void duparg(const char *, const char *) NORETURN; void duparg2(const char *, const char *) NORETURN; -int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits); +int inet_addr_match(const inet_prefix *a, const inet_prefix *b, int bits); const char *dnet_ntop(int af, const void *addr, char *str, size_t len); int dnet_pton(int af, const char *src, void *addr); diff --git a/networking/nameif.c b/networking/nameif.c index 046e308..9a8846d 100644 --- a/networking/nameif.c +++ b/networking/nameif.c @@ -7,9 +7,68 @@ * Glenn McGrath * Extended matching support 2008 by Nico Erfurth * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//config:config NAMEIF +//config: bool "nameif" +//config: default y +//config: select PLATFORM_LINUX +//config: select FEATURE_SYSLOG +//config: help +//config: nameif is used to rename network interface by its MAC address. +//config: Renamed interfaces MUST be in the down state. +//config: It is possible to use a file (default: /etc/mactab) +//config: with list of new interface names and MACs. +//config: Maximum interface name length: IFNAMSIZ = 16 +//config: File fields are separated by space or tab. +//config: File format: +//config: # Comment +//config: new_interface_name XX:XX:XX:XX:XX:XX +//config: +//config:config FEATURE_NAMEIF_EXTENDED +//config: bool "Extended nameif" +//config: default y +//config: depends on NAMEIF +//config: help +//config: This extends the nameif syntax to support the bus_info, driver, +//config: phyaddr selectors. The syntax is compatible to the normal nameif. +//config: File format: +//config: new_interface_name driver=asix bus=usb-0000:00:08.2-3 +//config: new_interface_name bus=usb-0000:00:08.2-3 00:80:C8:38:91:B5 +//config: new_interface_name phy_address=2 00:80:C8:38:91:B5 +//config: new_interface_name mac=00:80:C8:38:91:B5 +//config: new_interface_name 00:80:C8:38:91:B5 + +//usage:#define nameif_trivial_usage +//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( +//usage: "[-s] [-c FILE] [IFNAME HWADDR]..." +//usage: ) +//usage: IF_FEATURE_NAMEIF_EXTENDED( +//usage: "[-s] [-c FILE] [IFNAME SELECTOR]..." +//usage: ) +//usage:#define nameif_full_usage "\n\n" +//usage: "Rename network interface while it in the down state." +//usage: IF_NOT_FEATURE_NAMEIF_EXTENDED( +//usage: "\nThe device with address HWADDR is renamed to IFACE." +//usage: ) +//usage: IF_FEATURE_NAMEIF_EXTENDED( +//usage: "\nThe device matched by SELECTOR is renamed to IFACE." +//usage: "\nSELECTOR can be a combination of:" +//usage: "\n driver=STRING" +//usage: "\n bus=STRING" +//usage: "\n phy_address=NUM" +//usage: "\n [mac=]XX:XX:XX:XX:XX:XX" +//usage: ) +//usage: "\n" +//usage: "\n -c FILE Configuration file (default: /etc/mactab)" +//usage: "\n -s Log to syslog" +//usage: +//usage:#define nameif_example_usage +//usage: "$ nameif -s dmz0 00:A0:C9:8C:F6:3F\n" +//usage: " or\n" +//usage: "$ nameif -c /etc/my_mactab_file\n" + #include "libbb.h" #include #include @@ -21,10 +80,10 @@ #endif /* Taken from linux/sockios.h */ -#define SIOCSIFNAME 0x8923 /* set interface name */ +#define SIOCSIFNAME 0x8923 /* set interface name */ /* Octets in one Ethernet addr, from */ -#define ETH_ALEN 6 +#define ETH_ALEN 6 #ifndef ifr_newname #define ifr_newname ifr_ifru.ifru_slave @@ -38,6 +97,7 @@ typedef struct ethtable_s { #if ENABLE_FEATURE_NAMEIF_EXTENDED char *bus_info; char *driver; + int32_t phy_address; #endif } ethtable_t; @@ -59,6 +119,25 @@ struct ethtool_drvinfo { uint32_t eedump_len; /* Size of data from ETHTOOL_GEEPROM (bytes) */ uint32_t regdump_len; /* Size of data from ETHTOOL_GREGS (bytes) */ }; + +struct ethtool_cmd { + uint32_t cmd; + uint32_t supported; /* Features this interface supports */ + uint32_t advertising; /* Features this interface advertises */ + uint16_t speed; /* The forced speed, 10Mb, 100Mb, gigabit */ + uint8_t duplex; /* Duplex, half or full */ + uint8_t port; /* Which connector port */ + uint8_t phy_address; + uint8_t transceiver; /* Which transceiver to use */ + uint8_t autoneg; /* Enable or disable autonegotiation */ + uint32_t maxtxpkt; /* Tx pkts before generating tx int */ + uint32_t maxrxpkt; /* Rx pkts before generating rx int */ + uint16_t speed_hi; + uint16_t reserved2; + uint32_t reserved[3]; +}; + +#define ETHTOOL_GSET 0x00000001 /* Get settings. */ #define ETHTOOL_GDRVINFO 0x00000003 /* Get driver info. */ #endif @@ -74,6 +153,7 @@ static void nameif_parse_selector(ethtable_t *ch, char *selector) #endif selector = skip_whitespace(selector); #if ENABLE_FEATURE_NAMEIF_EXTENDED + ch->phy_address = -1; if (*selector == '\0') break; /* Search for the end .... */ @@ -87,6 +167,9 @@ static void nameif_parse_selector(ethtable_t *ch, char *selector) } else if (strncmp(selector, "driver=", 7) == 0) { ch->driver = xstrdup(selector + 7); found_selector++; + } else if (strncmp(selector, "phyaddr=", 8) == 0) { + ch->phy_address = xatoi_positive(selector + 8); + found_selector++; } else { #endif lmac = xmalloc(ETH_ALEN); @@ -133,7 +216,7 @@ void delete_eth_table(ethtable_t *ch); #endif int nameif_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int nameif_main(int argc, char **argv) +int nameif_main(int argc UNUSED_PARAM, char **argv) { ethtable_t *clist = NULL; const char *fname = "/etc/mactab"; @@ -148,17 +231,15 @@ int nameif_main(int argc, char **argv) * can't hurt. 2>/dev/null if you don't like it: */ logmode |= LOGMODE_SYSLOG; } - argc -= optind; argv += optind; - if (argc & 1) - bb_show_usage(); - - if (argc) { - while (*argv) { - char *ifname = xstrdup(*argv++); - prepend_new_eth_table(&clist, ifname, *argv++); - } + if (argv[0]) { + do { + if (!argv[1]) + bb_show_usage(); + prepend_new_eth_table(&clist, argv[0], argv[1]); + argv += 2; + } while (*argv); } else { parser = config_open(fname); while (config_read(parser, token, 2, 2, "# \t", PARSE_NORMAL)) @@ -173,8 +254,9 @@ int nameif_main(int argc, char **argv) struct ifreq ifr; #if ENABLE_FEATURE_NAMEIF_EXTENDED struct ethtool_drvinfo drvinfo; + struct ethtool_cmd eth_settings; #endif - if (parser->lineno < 2) + if (parser->lineno <= 2) continue; /* Skip the first two lines */ /* Find the current interface name and copy it to ifr.ifr_name */ @@ -182,8 +264,14 @@ int nameif_main(int argc, char **argv) strncpy_IFNAMSIZ(ifr.ifr_name, token[0]); #if ENABLE_FEATURE_NAMEIF_EXTENDED + /* Check for phy address */ + memset(ð_settings, 0, sizeof(eth_settings)); + eth_settings.cmd = ETHTOOL_GSET; + ifr.ifr_data = (caddr_t) ð_settings; + ioctl(ctl_sk, SIOCETHTOOL, &ifr); + /* Check for driver etc. */ - memset(&drvinfo, 0, sizeof(struct ethtool_drvinfo)); + memset(&drvinfo, 0, sizeof(drvinfo)); drvinfo.cmd = ETHTOOL_GDRVINFO; ifr.ifr_data = (caddr_t) &drvinfo; /* Get driver and businfo first, so we have it in drvinfo */ @@ -198,16 +286,17 @@ int nameif_main(int argc, char **argv) continue; if (ch->driver && strcmp(ch->driver, drvinfo.driver) != 0) continue; + if (ch->phy_address != -1 && ch->phy_address != eth_settings.phy_address) + continue; #endif if (ch->mac && memcmp(ch->mac, ifr.ifr_hwaddr.sa_data, ETH_ALEN) != 0) continue; /* if we came here, all selectors have matched */ - break; + goto found; } /* Nothing found for current interface */ - if (!ch) - continue; - + continue; + found: if (strcmp(ifr.ifr_name, ch->ifname) != 0) { strcpy(ifr.ifr_newname, ch->ifname); ioctl_or_perror_and_die(ctl_sk, SIOCSIFNAME, &ifr, @@ -223,10 +312,14 @@ int nameif_main(int argc, char **argv) ch->next->prev = ch->prev; if (ENABLE_FEATURE_CLEAN_UP) delete_eth_table(ch); - } + } /* while */ + if (ENABLE_FEATURE_CLEAN_UP) { - for (ch = clist; ch; ch = ch->next) + ethtable_t *next; + for (ch = clist; ch; ch = next) { + next = ch->next; delete_eth_table(ch); + } config_close(parser); }; diff --git a/networking/nbd-client.c b/networking/nbd-client.c new file mode 100644 index 0000000..cadda52 --- /dev/null +++ b/networking/nbd-client.c @@ -0,0 +1,155 @@ +/* + * Copyright 2010 Rob Landley + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "libbb.h" +#include +#include + +//applet:IF_NBDCLIENT(APPLET_ODDNAME(nbd-client, nbdclient, BB_DIR_USR_SBIN, BB_SUID_DROP, nbdclient)) + +//kbuild:lib-$(CONFIG_NBDCLIENT) += nbd-client.o + +//config:config NBDCLIENT +//config: bool "nbd-client" +//config: default y +//config: help +//config: Network block device client + +#define NBD_SET_SOCK _IO(0xab, 0) +#define NBD_SET_BLKSIZE _IO(0xab, 1) +#define NBD_SET_SIZE _IO(0xab, 2) +#define NBD_DO_IT _IO(0xab, 3) +#define NBD_CLEAR_SOCK _IO(0xab, 4) +#define NBD_CLEAR_QUEUE _IO(0xab, 5) +#define NBD_PRINT_DEBUG _IO(0xab, 6) +#define NBD_SET_SIZE_BLOCKS _IO(0xab, 7) +#define NBD_DISCONNECT _IO(0xab, 8) +#define NBD_SET_TIMEOUT _IO(0xab, 9) + +//usage:#define nbdclient_trivial_usage +//usage: "HOST PORT BLOCKDEV" +//usage:#define nbdclient_full_usage "\n\n" +//usage: "Connect to HOST and provide a network block device on BLOCKDEV" + +//TODO: more compat with nbd-client version 2.9.13 - +//Usage: nbd-client [bs=blocksize] [timeout=sec] host port nbd_device [-swap] [-persist] [-nofork] +//Or : nbd-client -d nbd_device +//Or : nbd-client -c nbd_device +//Default value for blocksize is 1024 (recommended for ethernet) +//Allowed values for blocksize are 512,1024,2048,4096 +//Note, that kernel 2.4.2 and older ones do not work correctly with +//blocksizes other than 1024 without patches + +int nbdclient_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int nbdclient_main(int argc, char **argv) +{ + unsigned long timeout = 0; +#if BB_MMU + int nofork = 0; +#endif + char *host, *port, *device; + struct nbd_header_t { + uint64_t magic1; // "NBDMAGIC" + uint64_t magic2; // 0x420281861253 big endian + uint64_t devsize; + uint32_t flags; + char data[124]; + } nbd_header; + struct bug_check { + char c[offsetof(struct nbd_header_t, data) == 8+8+8+4 ? 1 : -1]; + }; + + // Parse command line stuff (just a stub now) + if (argc != 4) + bb_show_usage(); + +#if !BB_MMU + bb_daemonize_or_rexec(DAEMON_CLOSE_EXTRA_FDS, argv); +#endif + + host = argv[1]; + port = argv[2]; + device = argv[3]; + + // Repeat until spanked (-persist behavior) + for (;;) { + int sock, nbd; + int ro; + + // Make sure the /dev/nbd exists + nbd = xopen(device, O_RDWR); + + // Find and connect to server + sock = create_and_connect_stream_or_die(host, xatou16(port)); + setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, &const_int_1, sizeof(const_int_1)); + + // Log on to the server + xread(sock, &nbd_header, 8+8+8+4 + 124); + if (memcmp(&nbd_header.magic1, "NBDMAGIC""\x00\x00\x42\x02\x81\x86\x12\x53", 16) != 0) + bb_error_msg_and_die("login failed"); + + // Set 4k block size. Everything uses that these days + ioctl(nbd, NBD_SET_BLKSIZE, 4096); + ioctl(nbd, NBD_SET_SIZE_BLOCKS, SWAP_BE64(nbd_header.devsize) / 4096); + ioctl(nbd, NBD_CLEAR_SOCK); + + // If the sucker was exported read only, respect that locally + ro = (nbd_header.flags & SWAP_BE32(2)) / SWAP_BE32(2); + if (ioctl(nbd, BLKROSET, &ro) < 0) + bb_perror_msg_and_die("BLKROSET"); + + if (timeout) + if (ioctl(nbd, NBD_SET_TIMEOUT, timeout)) + bb_perror_msg_and_die("NBD_SET_TIMEOUT"); + if (ioctl(nbd, NBD_SET_SOCK, sock)) + bb_perror_msg_and_die("NBD_SET_SOCK"); + + // if (swap) mlockall(MCL_CURRENT|MCL_FUTURE); + +#if BB_MMU + // Open the device to force reread of the partition table. + // Need to do it in a separate process, since open(device) + // needs some other process to sit in ioctl(nbd, NBD_DO_IT). + if (fork() == 0) { + char *s = strrchr(device, '/'); + sprintf(nbd_header.data, "/sys/block/%.32s/pid", s ? s + 1 : device); + // Is it up yet? + for (;;) { + int fd = open(nbd_header.data, O_RDONLY); + if (fd >= 0) { + //close(fd); + break; + } + sleep(1); + } + open(device, O_RDONLY); + return 0; + } + + // Daemonize here + if (!nofork) { + daemon(0, 0); + nofork = 1; + } +#endif + + // This turns us (the process that calls this ioctl) + // into a dedicated NBD request handler. + // We block here for a long time. + // When exactly ioctl returns? On a signal, + // or if someone does ioctl(NBD_DISCONNECT) [nbd-client -d]. + if (ioctl(nbd, NBD_DO_IT) >= 0 || errno == EBADR) { + // Flush queue and exit + ioctl(nbd, NBD_CLEAR_QUEUE); + ioctl(nbd, NBD_CLEAR_SOCK); + break; + } + + close(sock); + close(nbd); + } + + return 0; +} diff --git a/networking/nc.c b/networking/nc.c index c771374..2f9e174 100644 --- a/networking/nc.c +++ b/networking/nc.c @@ -1,10 +1,10 @@ /* vi: set sw=4 ts=4: */ -/* nc: mini-netcat - built from the ground up for LRP +/* nc: mini-netcat - built from the ground up for LRP * - * Copyright (C) 1998, 1999 Charles P. Wright - * Copyright (C) 1998 Dave Cinege + * Copyright (C) 1998, 1999 Charles P. Wright + * Copyright (C) 1998 Dave Cinege * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" @@ -24,7 +24,7 @@ //config: Allow netcat to act as a server. //config: //config:config NC_EXTRA -//config: bool "Netcat extensions (-eiw and filename)" +//config: bool "Netcat extensions (-eiw and -f FILE)" //config: default y //config: depends on NC //config: help @@ -40,7 +40,7 @@ //config: This option makes nc closely follow original nc-1.10. //config: The code is about 2.5k bigger. It enables //config: -s ADDR, -n, -u, -v, -o FILE, -z options, but loses -//config: busybox-specific extensions: -f FILE and -ll. +//config: busybox-specific extensions: -f FILE. #if ENABLE_NC_110_COMPAT # include "nc_bloaty.c" @@ -49,7 +49,7 @@ //usage:#if !ENABLE_NC_110_COMPAT //usage: //usage:#if ENABLE_NC_SERVER || ENABLE_NC_EXTRA -//usage:#define NC_OPTIONS_STR "\n\nOptions:" +//usage:#define NC_OPTIONS_STR "\n" //usage:#else //usage:#define NC_OPTIONS_STR //usage:#endif @@ -60,17 +60,18 @@ //usage:#define nc_full_usage "\n\n" //usage: "Open a pipe to IP:PORT" IF_NC_EXTRA(" or FILE") //usage: NC_OPTIONS_STR -//usage: IF_NC_EXTRA( -//usage: "\n -e PROG Run PROG after connect" //usage: IF_NC_SERVER( //usage: "\n -l Listen mode, for inbound connects" //usage: IF_NC_EXTRA( -//usage: "\n (use -l twice with -e for persistent server)") +//usage: "\n (use -ll with -e for persistent server)" +//usage: ) //usage: "\n -p PORT Local port" //usage: ) -//usage: "\n -w SEC Timeout for connect" +//usage: IF_NC_EXTRA( +//usage: "\n -w SEC Connect timeout" //usage: "\n -i SEC Delay interval for lines sent" //usage: "\n -f FILE Use file (ala /dev/ttyS0) instead of network" +//usage: "\n -e PROG Run PROG after connect" //usage: ) //usage: //usage:#define nc_notes_usage "" @@ -120,7 +121,7 @@ int nc_main(int argc, char **argv) /* getopt32 is _almost_ usable: ** it cannot handle "... -e PROG -prog-opt" */ while ((opt = getopt(argc, argv, - "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 + "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0 ) { if (ENABLE_NC_SERVER && opt == 'l') IF_NC_SERVER(do_listen++); @@ -147,7 +148,7 @@ int nc_main(int argc, char **argv) *p++ = argv[optind++]; } ) - /* optind points to argv[arvc] (NULL) now. + /* optind points to argv[argc] (NULL) now. ** FIXME: we assume that getopt will not count options ** possibly present on "-e PROG ARGS" and will not ** include them into final value of optind @@ -226,10 +227,9 @@ int nc_main(int argc, char **argv) /* child, or main thread if only one -l */ xmove_fd(cfd, 0); xdup2(0, 1); - xdup2(0, 2); + /*xdup2(0, 2); - original nc 1.10 does this, we don't */ IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);) - /* Don't print stuff or it will go over the wire... */ - _exit(127); + IF_NC_EXTRA(bb_perror_msg_and_die("can't execute '%s'", execparam[0]);) } /* Select loop copying stdin to cfd, and cfd to stdout */ @@ -261,7 +261,7 @@ int nc_main(int argc, char **argv) if (nread < 1) { /* Close outgoing half-connection so they get EOF, * but leave incoming alone so we can see response */ - shutdown(cfd, 1); + shutdown(cfd, SHUT_WR); FD_CLR(STDIN_FILENO, &readfds); } ofd = cfd; diff --git a/networking/nc_bloaty.c b/networking/nc_bloaty.c index aebb9cb..b9eff3d 100644 --- a/networking/nc_bloaty.c +++ b/networking/nc_bloaty.c @@ -3,7 +3,7 @@ * * Copyright (C) 2007 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* Author's comments from nc 1.10: @@ -48,6 +48,12 @@ * - TCP connects from wrong ip/ports (if peer ip:port is specified * on the command line, but accept() says that it came from different addr) * are closed, but we don't exit - we continue to listen/accept. + * Since bbox 1.22: + * - nc exits when _both_ stdin and network are closed. + * This makes these two commands: + * echo "Yes" | nc 127.0.0.1 1234 + * echo "no" | nc -lp 1234 + * exchange their data _and exit_ instead of being stuck. */ /* done in nc.c: #include "libbb.h" */ @@ -57,12 +63,18 @@ //usage:#define nc_trivial_usage //usage: "[OPTIONS] HOST PORT - connect" //usage: IF_NC_SERVER("\n" -//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen") +//usage: "nc [OPTIONS] -l -p PORT [HOST] [PORT] - listen" +//usage: ) //usage:#define nc_full_usage "\n\n" -//usage: "Options:" -//usage: "\n -e PROG Run PROG after connect (must be last)" +//usage: " -e PROG Run PROG after connect (must be last)" //usage: IF_NC_SERVER( //usage: "\n -l Listen mode, for inbound connects" +//usage: "\n -lk With -e, provides persistent server" +/* -ll does the same as -lk, but its our extension, while -k is BSD'd, + * presumably more widely known. Therefore we advertise it, not -ll. + * I would like to drop -ll support, but our "small" nc supports it, + * and Rob uses it. + */ //usage: ) //usage: "\n -p PORT Local port" //usage: "\n -s ADDR Local address" @@ -115,6 +127,7 @@ struct globals { unsigned wrote_out; /* total stdout bytes */ unsigned wrote_net; /* total net bytes */ #endif + char *proggie0saved; /* ouraddr is never NULL and goes through three states as we progress: 1 - local address before bind (IP/port possibly zero) 2 - local address after bind (port is nonzero) @@ -127,9 +140,6 @@ struct globals { jmp_buf jbuf; /* timer crud */ - /* will malloc up the following globals: */ - fd_set ding1; /* for select loop */ - fd_set ding2; char bigbuf_in[BIGSIZ]; /* data buffers */ char bigbuf_net[BIGSIZ]; }; @@ -141,8 +151,6 @@ struct globals { #define themaddr (G.themaddr ) #define remend (G.remend ) #define jbuf (G.jbuf ) -#define ding1 (G.ding1 ) -#define ding2 (G.ding2 ) #define bigbuf_in (G.bigbuf_in ) #define bigbuf_net (G.bigbuf_net) #define o_verbose (G.o_verbose ) @@ -159,26 +167,21 @@ struct globals { /* Must match getopt32 call! */ enum { - OPT_h = (1 << 0), - OPT_n = (1 << 1), - OPT_p = (1 << 2), - OPT_s = (1 << 3), - OPT_u = (1 << 4), - OPT_v = (1 << 5), - OPT_w = (1 << 6), - OPT_l = (1 << 7) * ENABLE_NC_SERVER, - OPT_i = (1 << (7+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_o = (1 << (8+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, - OPT_z = (1 << (9+ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_n = (1 << 0), + OPT_p = (1 << 1), + OPT_s = (1 << 2), + OPT_u = (1 << 3), + OPT_v = (1 << 4), + OPT_w = (1 << 5), + OPT_l = (1 << 6) * ENABLE_NC_SERVER, + OPT_k = (1 << 7) * ENABLE_NC_SERVER, + OPT_i = (1 << (7+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_o = (1 << (8+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, + OPT_z = (1 << (9+2*ENABLE_NC_SERVER)) * ENABLE_NC_EXTRA, }; #define o_nflag (option_mask32 & OPT_n) #define o_udpmode (option_mask32 & OPT_u) -#if ENABLE_NC_SERVER -#define o_listen (option_mask32 & OPT_l) -#else -#define o_listen 0 -#endif #if ENABLE_NC_EXTRA #define o_ofile (option_mask32 & OPT_o) #define o_zero (option_mask32 & OPT_z) @@ -263,12 +266,13 @@ Debug("findline returning whole thing: %d", siz); static int doexec(char **proggie) NORETURN; static int doexec(char **proggie) { + if (G.proggie0saved) + proggie[0] = G.proggie0saved; xmove_fd(netfd, 0); dup2(0, 1); /* dup2(0, 2); - do we *really* want this? NO! * exec'ed prog can do it yourself, if needed */ - execvp(proggie[0], proggie); - bb_perror_msg_and_die("can't execute '%s'", proggie[0]); + BB_EXECVP_or_die(proggie); } /* connect_w_timeout: @@ -298,7 +302,7 @@ static int connect_w_timeout(int fd) incoming and returns an open connection *from* someplace. If we were given host/port args, any connections from elsewhere are rejected. This in conjunction with local-address binding should limit things nicely... */ -static void dolisten(void) +static void dolisten(int is_persistent, char **proggie) { int rr; @@ -371,6 +375,7 @@ create new one, and bind() it. TODO */ xconnect(netfd, &remend.u.sa, ouraddr->len); } else { /* TCP */ + another: arm(o_wait); /* wrap this in a timer, too; 0 = forever */ if (setjmp(jbuf) == 0) { again: @@ -386,10 +391,10 @@ create new one, and bind() it. TODO */ if (port == 0) { /* "nc -nl -p LPORT RHOST" (w/o RPORT!): * we should accept any remote port */ - set_nport(&remend, 0); /* blot out remote port# */ + set_nport(&remend.u.sa, 0); /* blot out remote port# */ } r = memcmp(&remend.u.sa, &themaddr->u.sa, remend.len); - set_nport(&remend, sv_port); /* restore */ + set_nport(&remend.u.sa, sv_port); /* restore */ if (r != 0) { /* nc 1.10 bails out instead, and its error message * is not suppressed by o_verbose */ @@ -405,6 +410,19 @@ create new one, and bind() it. TODO */ unarm(); } else bb_error_msg_and_die("timeout"); + + if (is_persistent && proggie) { + /* -l -k -e PROG */ + signal(SIGCHLD, SIG_IGN); /* no zombies please */ + if (xvfork() != 0) { + /* parent: go back and accept more connections */ + close(rr); + goto another; + } + /* child */ + signal(SIGCHLD, SIG_DFL); + } + xmove_fd(rr, netfd); /* dump the old socket, here's our new one */ /* find out what address the connection was *to* on our end, in case we're doing a listen-on-any on a multihomed machine. This allows one to @@ -429,8 +447,7 @@ create new one, and bind() it. TODO */ rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x); if (rr >= 0 && x) { /* we've got options, lessee em... */ - bin2hex(bigbuf_net, optbuf, x); - bigbuf_net[2*x] = '\0'; + *bin2hex(bigbuf_net, optbuf, x) = '\0'; fprintf(stderr, "IP options: %s\n", bigbuf_net); } #endif @@ -455,6 +472,9 @@ create new one, and bind() it. TODO */ if (!o_nflag) free(remhostname); } + + if (proggie) + doexec(proggie); } /* udptest: @@ -486,7 +506,7 @@ static int udptest(void) us to hang forever, and hit it */ o_wait = 5; /* enough that we'll notice?? */ rr = xsocket(ouraddr->u.sa.sa_family, SOCK_STREAM, 0); - set_nport(themaddr, htons(SLEAZE_PORT)); + set_nport(&themaddr->u.sa, htons(SLEAZE_PORT)); connect_w_timeout(rr); /* don't need to restore themaddr's port, it's not used anymore */ close(rr); @@ -572,26 +592,27 @@ static int readwrite(void) unsigned rzleft; unsigned rnleft; unsigned netretry; /* net-read retry counter */ - unsigned wretry; /* net-write sanity counter */ - unsigned wfirst; /* one-shot flag to skip first net read */ + unsigned fds_open; /* if you don't have all this FD_* macro hair in sys/types.h, you'll have to either find it or do your own bit-bashing: *ding1 |= (1 << fd), etc... */ - FD_SET(netfd, &ding1); /* global: the net is open */ + fd_set ding1; /* for select loop */ + fd_set ding2; + FD_ZERO(&ding1); + FD_SET(netfd, &ding1); + FD_SET(STDIN_FILENO, &ding1); + fds_open = 2; + netretry = 2; - wfirst = 0; rzleft = rnleft = 0; if (o_interval) sleep(o_interval); /* pause *before* sending stuff, too */ - errno = 0; /* clear from sleep, close, whatever */ /* and now the big ol' select shoveling loop ... */ - while (FD_ISSET(netfd, &ding1)) { /* i.e. till the *net* closes! */ - wretry = 8200; /* more than we'll ever hafta write */ - if (wfirst) { /* any saved stdin buffer? */ - wfirst = 0; /* clear flag for the duration */ - goto shovel; /* and go handle it first */ - } + /* nc 1.10 has "while (FD_ISSET(netfd)" here */ + while (fds_open) { + unsigned wretry = 8200; /* net-write sanity counter */ + ding2 = ding1; /* FD_COPY ain't portable... */ /* some systems, notably linux, crap into their select timers on return, so we create a expendable copy and give *that* to select. */ @@ -611,13 +632,14 @@ static int readwrite(void) /* if we have a timeout AND stdin is closed AND we haven't heard anything from the net during that time, assume it's dead and close it too. */ if (rr == 0) { - if (!FD_ISSET(STDIN_FILENO, &ding1)) + if (!FD_ISSET(STDIN_FILENO, &ding1)) { netretry--; /* we actually try a coupla times. */ - if (!netretry) { - if (o_verbose > 1) /* normally we don't care */ - fprintf(stderr, "net timeout\n"); - close(netfd); - return 0; /* not an error! */ + if (!netretry) { + if (o_verbose > 1) /* normally we don't care */ + fprintf(stderr, "net timeout\n"); + /*close(netfd); - redundant, exit will do it */ + return 0; /* not an error! */ + } } } /* select timeout */ /* xxx: should we check the exception fds too? The read fds seem to give @@ -631,7 +653,8 @@ static int readwrite(void) /* nc 1.10 doesn't do this */ bb_perror_msg("net read"); } - FD_CLR(netfd, &ding1); /* net closed, we'll finish up... */ + FD_CLR(netfd, &ding1); /* net closed */ + fds_open--; rzleft = 0; /* can't write anymore: broken pipe */ } else { rnleft = rr; @@ -651,11 +674,12 @@ Debug("got %d from the net, errno %d", rr, errno); /* Considered making reads here smaller for UDP mode, but 8192-byte mobygrams are kinda fun and exercise the reassembler. */ if (rr <= 0) { /* at end, or fukt, or ... */ - FD_CLR(STDIN_FILENO, &ding1); /* disable and close stdin */ - close(STDIN_FILENO); -// Does it make sense to shutdown(net_fd, SHUT_WR) -// to let other side know that we won't write anything anymore? -// (and what about keeping compat if we do that?) + FD_CLR(STDIN_FILENO, &ding1); /* disable stdin */ + /*close(STDIN_FILENO); - not really necessary */ + /* Let peer know we have no more data */ + /* nc 1.10 doesn't do this: */ + shutdown(netfd, SHUT_WR); + fds_open--; } else { rzleft = rr; zp = bigbuf_in; @@ -666,24 +690,14 @@ Debug("got %d from the net, errno %d", rr, errno); Geez, why does this look an awful lot like the big loop in "rsh"? ... not sure if the order of this matters, but write net -> stdout first. */ - /* sanity check. Works because they're both unsigned... */ - if ((rzleft > 8200) || (rnleft > 8200)) { - holler_error("bogus buffers: %u, %u", rzleft, rnleft); - rzleft = rnleft = 0; - } - /* net write retries sometimes happen on UDP connections */ - if (!wretry) { /* is something hung? */ - holler_error("too many output retries"); - return 1; - } if (rnleft) { rr = write(STDOUT_FILENO, np, rnleft); if (rr > 0) { if (o_ofile) /* log the stdout */ oprint('<', (unsigned char *)np, rr); - np += rr; /* fix up ptrs and whatnot */ - rnleft -= rr; /* will get sanity-checked above */ - wrote_out += rr; /* global count */ + np += rr; + rnleft -= rr; + wrote_out += rr; /* global count */ } Debug("wrote %d to stdout, errno %d", rr, errno); } /* rnleft */ @@ -698,20 +712,24 @@ Debug("wrote %d to stdout, errno %d", rr, errno); oprint('>', (unsigned char *)zp, rr); zp += rr; rzleft -= rr; - wrote_net += rr; /* global count */ + wrote_net += rr; /* global count */ } Debug("wrote %d to net, errno %d", rr, errno); } /* rzleft */ if (o_interval) { /* cycle between slow lines, or ... */ sleep(o_interval); - errno = 0; /* clear from sleep */ continue; /* ...with hairy select loop... */ } - if ((rzleft) || (rnleft)) { /* shovel that shit till they ain't */ + if (rzleft || rnleft) { /* shovel that shit till they ain't */ wretry--; /* none left, and get another load */ + /* net write retries sometimes happen on UDP connections */ + if (!wretry) { /* is something hung? */ + holler_error("too many output retries"); + return 1; + } goto shovel; } - } /* while ding1:netfd is open */ + } /* while (fds_open) */ /* XXX: maybe want a more graceful shutdown() here, or screw around with linger times?? I suspect that I don't need to since I'm always doing @@ -728,9 +746,10 @@ int nc_main(int argc UNUSED_PARAM, char **argv) { char *str_p, *str_s; IF_NC_EXTRA(char *str_i, *str_o;) - char *themdotted = themdotted; /* gcc */ + char *themdotted = themdotted; /* for compiler */ char **proggie; int x; + unsigned cnt_l = 0; unsigned o_lport = 0; INIT_G(); @@ -756,22 +775,40 @@ int nc_main(int argc UNUSED_PARAM, char **argv) proggie++; goto e_found; } + /* -e PROG [ARGS] ? */ + /* (aboriginal linux uses this form) */ + if (proggie[0][0] == '-') { + char *optpos = *proggie + 1; + /* Skip all valid opts w/o params */ + optpos = optpos + strspn(optpos, "nuv"IF_NC_SERVER("lk")IF_NC_EXTRA("z")); + if (*optpos == 'e' && !optpos[1]) { + *optpos = '\0'; + proggie++; + G.proggie0saved = *proggie; + *proggie = NULL; /* terminate argv for getopt32 */ + goto e_found; + } + } } proggie = NULL; e_found: // -g -G -t -r deleted, unimplemented -a deleted too - opt_complementary = "?2:vv:w+"; /* max 2 params; -v is a counter; -w N */ - getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l") + opt_complementary = "?2:vv:ll:w+"; /* max 2 params; -v and -l are counters; -w N */ + getopt32(argv, "np:s:uvw:" IF_NC_SERVER("lk") IF_NC_EXTRA("i:o:z"), &str_p, &str_s, &o_wait - IF_NC_EXTRA(, &str_i, &str_o, &o_verbose)); + IF_NC_EXTRA(, &str_i, &str_o), &o_verbose IF_NC_SERVER(, &cnt_l)); argv += optind; #if ENABLE_NC_EXTRA if (option_mask32 & OPT_i) /* line-interval time */ o_interval = xatou_range(str_i, 1, 0xffff); #endif +#if ENABLE_NC_SERVER //if (option_mask32 & OPT_l) /* listen mode */ + if (option_mask32 & OPT_k) /* persistent server mode */ + cnt_l = 2; +#endif //if (option_mask32 & OPT_n) /* numeric-only, no DNS lookups */ //if (option_mask32 & OPT_o) /* hexdump log */ if (option_mask32 & OPT_p) { /* local source port */ @@ -813,14 +850,14 @@ int nc_main(int argc UNUSED_PARAM, char **argv) (themaddr ? themaddr->u.sa.sa_family : AF_UNSPEC), x); if (o_lport) - set_nport(ouraddr, htons(o_lport)); + set_nport(&ouraddr->u.sa, htons(o_lport)); } xmove_fd(x, netfd); setsockopt_reuseaddr(netfd); if (o_udpmode) socket_want_pktinfo(netfd); if (!ENABLE_FEATURE_UNIX_LOCAL - || o_listen + || cnt_l != 0 /* listen */ || ouraddr->u.sa.sa_family != AF_UNIX ) { xbind(netfd, &ouraddr->u.sa, ouraddr->len); @@ -839,9 +876,8 @@ int nc_main(int argc UNUSED_PARAM, char **argv) } #endif - FD_SET(STDIN_FILENO, &ding1); /* stdin *is* initially open */ if (proggie) { - close(0); /* won't need stdin */ + close(STDIN_FILENO); /* won't need stdin */ option_mask32 &= ~OPT_o; /* -o with -e is meaningless! */ } #if ENABLE_NC_EXTRA @@ -849,16 +885,14 @@ int nc_main(int argc UNUSED_PARAM, char **argv) xmove_fd(xopen(str_o, O_WRONLY|O_CREAT|O_TRUNC), ofd); #endif - if (o_listen) { - dolisten(); + if (cnt_l != 0) { + dolisten((cnt_l - 1), proggie); /* dolisten does its own connect reporting */ - if (proggie) /* -e given? */ - doexec(proggie); x = readwrite(); /* it even works with UDP! */ } else { /* Outbound connects. Now we're more picky about args... */ if (!themaddr) - bb_error_msg_and_die("no destination"); + bb_show_usage(); remend = *themaddr; if (o_verbose) diff --git a/networking/netstat.c b/networking/netstat.c index 8b7a574..f80b845 100644 --- a/networking/netstat.c +++ b/networking/netstat.c @@ -11,22 +11,42 @@ * 2008-07-10 * optional '-p' flag support ported from net-tools by G. Somlo * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #include "libbb.h" #include "inet_common.h" +//usage:#define netstat_trivial_usage +//usage: "[-"IF_ROUTE("r")"al] [-tuwx] [-en"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]" +//usage:#define netstat_full_usage "\n\n" +//usage: "Display networking information\n" +//usage: IF_ROUTE( +//usage: "\n -r Routing table" +//usage: ) +//usage: "\n -a All sockets" +//usage: "\n -l Listening sockets" +//usage: "\n Else: connected sockets" +//usage: "\n -t TCP sockets" +//usage: "\n -u UDP sockets" +//usage: "\n -w Raw sockets" +//usage: "\n -x Unix sockets" +//usage: "\n Else: all socket types" +//usage: "\n -e Other/more information" +//usage: "\n -n Don't resolve names" +//usage: IF_FEATURE_NETSTAT_WIDE( +//usage: "\n -W Wide display" +//usage: ) +//usage: IF_FEATURE_NETSTAT_PRG( +//usage: "\n -p Show PID/program name for sockets" +//usage: ) + #define NETSTAT_OPTS "laentuwx" \ IF_ROUTE( "r") \ IF_FEATURE_NETSTAT_WIDE("W") \ IF_FEATURE_NETSTAT_PRG( "p") enum { - OPTBIT_KEEP_OLD = 7, - IF_ROUTE( OPTBIT_ROUTE,) - IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) - IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) OPT_sock_listen = 1 << 0, // l OPT_sock_all = 1 << 1, // a OPT_extended = 1 << 2, // e @@ -35,6 +55,10 @@ enum { OPT_sock_udp = 1 << 5, // u OPT_sock_raw = 1 << 6, // w OPT_sock_unix = 1 << 7, // x + OPTBIT_x = 7, + IF_ROUTE( OPTBIT_ROUTE,) + IF_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,) + IF_FEATURE_NETSTAT_PRG( OPTBIT_PRG ,) OPT_route = IF_ROUTE( (1 << OPTBIT_ROUTE)) + 0, // r OPT_wide = IF_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W OPT_prg = IF_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG )) + 0, // p @@ -88,24 +112,25 @@ typedef enum { SS_DISCONNECTING /* in process of disconnecting */ } socket_state; -#define SO_ACCEPTCON (1<<16) /* performed a listen */ -#define SO_WAITDATA (1<<17) /* wait data to read */ -#define SO_NOSPACE (1<<18) /* no space to write */ - -/* Standard printout size */ -#define PRINT_IP_MAX_SIZE 23 -#define PRINT_NET_CONN "%s %6ld %6ld %-23s %-23s %-12s" -#define PRINT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State " +#define SO_ACCEPTCON (1<<16) /* performed a listen */ +#define SO_WAITDATA (1<<17) /* wait data to read */ +#define SO_NOSPACE (1<<18) /* no space to write */ +#define ADDR_NORMAL_WIDTH 23 /* When there are IPv6 connections the IPv6 addresses will be * truncated to none-recognition. The '-W' option makes the * address columns wide enough to accomodate for longest possible * IPv6 addresses, i.e. addresses of the form * xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:ddd.ddd.ddd.ddd */ -#define PRINT_IP_MAX_SIZE_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ -#define PRINT_NET_CONN_WIDE "%s %6ld %6ld %-51s %-51s %-12s" -#define PRINT_NET_CONN_HEADER_WIDE "\nProto Recv-Q Send-Q %-51s %-51s State " +#define ADDR_WIDE 51 /* INET6_ADDRSTRLEN + 5 for the port number */ +#if ENABLE_FEATURE_NETSTAT_WIDE +# define FMT_NET_CONN_DATA "%s %6lu %6lu %-*s %-*s %-12s" +# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-*s %-*s State %s\n" +#else +# define FMT_NET_CONN_DATA "%s %6lu %6lu %-23s %-23s %-12s" +# define FMT_NET_CONN_HEADER "\nProto Recv-Q Send-Q %-23s %-23s State %s\n" +#endif #define PROGNAME_WIDTH 20 #define PROGNAME_WIDTH_STR "20" @@ -121,22 +146,30 @@ struct prg_node { #define PRG_HASH_SIZE 211 struct globals { - const char *net_conn_line; smallint flags; #if ENABLE_FEATURE_NETSTAT_PRG smallint prg_cache_loaded; struct prg_node *prg_hash[PRG_HASH_SIZE]; #endif +#if ENABLE_FEATURE_NETSTAT_PRG + const char *progname_banner; +#endif +#if ENABLE_FEATURE_NETSTAT_WIDE + unsigned addr_width; +#endif }; #define G (*ptr_to_globals) #define flags (G.flags ) -#define net_conn_line (G.net_conn_line ) -#define prg_hash (G.prg_hash ) #define prg_cache_loaded (G.prg_cache_loaded) +#define prg_hash (G.prg_hash ) +#if ENABLE_FEATURE_NETSTAT_PRG +# define progname_banner (G.progname_banner ) +#else +# define progname_banner "" +#endif #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ flags = NETSTAT_CONNECTED | NETSTAT_ALLPROTO; \ - net_conn_line = PRINT_NET_CONN; \ } while (0) @@ -145,10 +178,6 @@ struct globals { /* Deliberately truncating long to unsigned *int* */ #define PRG_HASHIT(x) ((unsigned)(x) % PRG_HASH_SIZE) -#define print_progname_banner() do { \ - if (option_mask32 & OPT_prg) printf(PROGNAME_BANNER); \ -} while (0) - static void prg_cache_add(long inode, char *name) { unsigned hi = PRG_HASHIT(inode); @@ -158,7 +187,7 @@ static void prg_cache_add(long inode, char *name) for (pnp = prg_hash + hi; (pn = *pnp) != NULL; pnp = &pn->next) { if (pn->inode == inode) { /* Some warning should be appropriate here - as we got multiple processes for one i-node */ + * as we got multiple processes for one i-node */ return; } } @@ -201,12 +230,12 @@ static long extract_socket_inode(const char *lname) if (strncmp(lname, "socket:[", sizeof("socket:[")-1) == 0) { /* "socket:[12345]", extract the "12345" as inode */ - inode = bb_strtol(lname + sizeof("socket:[")-1, (char**)&lname, 0); + inode = bb_strtoul(lname + sizeof("socket:[")-1, (char**)&lname, 0); if (*lname != ']') inode = -1; } else if (strncmp(lname, "[0000]:", sizeof("[0000]:")-1) == 0) { /* "[0000]:12345", extract the "12345" as inode */ - inode = bb_strtol(lname + sizeof("[0000]:")-1, NULL, 0); + inode = bb_strtoul(lname + sizeof("[0000]:")-1, NULL, 0); if (errno) /* not NUL terminated? */ inode = -1; } @@ -218,9 +247,9 @@ static long extract_socket_inode(const char *lname) return inode; } -static int FAST_FUNC file_act(const char *fileName, +static int FAST_FUNC add_to_prg_cache_if_socket(const char *fileName, struct stat *statbuf UNUSED_PARAM, - void *userData, + void *pid_slash_progname, int depth UNUSED_PARAM) { char *linkname; @@ -231,7 +260,7 @@ static int FAST_FUNC file_act(const char *fileName, inode = extract_socket_inode(linkname); free(linkname); if (inode >= 0) - prg_cache_add(inode, (char *)userData); + prg_cache_add(inode, (char *)pid_slash_progname); } return TRUE; } @@ -241,38 +270,40 @@ static int FAST_FUNC dir_act(const char *fileName, void *userData UNUSED_PARAM, int depth) { - const char *shortName; - char *p, *q; + const char *pid; + char *pid_slash_progname; + char proc_pid_fname[sizeof("/proc/%u/cmdline") + sizeof(long)*3]; char cmdline_buf[512]; - int i; + int n, len; if (depth == 0) /* "/proc" itself */ return TRUE; /* continue looking one level below /proc */ - shortName = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ - if (!isdigit(shortName[0])) /* skip /proc entries whic aren't processes */ + pid = fileName + sizeof("/proc/")-1; /* point after "/proc/" */ + if (!isdigit(pid[0])) /* skip /proc entries which aren't processes */ return SKIP; - p = concat_path_file(fileName, "cmdline"); /* "/proc/PID/cmdline" */ - i = open_read_close(p, cmdline_buf, sizeof(cmdline_buf) - 1); - free(p); - if (i < 0) + len = snprintf(proc_pid_fname, sizeof(proc_pid_fname), "%s/cmdline", fileName); + n = open_read_close(proc_pid_fname, cmdline_buf, sizeof(cmdline_buf) - 1); + if (n < 0) return FALSE; - cmdline_buf[i] = '\0'; - q = concat_path_file(shortName, bb_basename(cmdline_buf)); /* "PID/argv0" */ - - /* go through all files in /proc/PID/fd */ - p = concat_path_file(fileName, "fd"); - i = recursive_action(p, ACTION_RECURSE | ACTION_QUIET, - file_act, NULL, (void *)q, 0); - - free(p); - free(q); - - if (!i) - return FALSE; /* signal permissions error to caller */ - - return SKIP; /* caller should not recurse further into this dir. */ + cmdline_buf[n] = '\0'; + + /* go through all files in /proc/PID/fd and check whether they are sockets */ + strcpy(proc_pid_fname + len - (sizeof("cmdline")-1), "fd"); + pid_slash_progname = concat_path_file(pid, bb_basename(cmdline_buf)); /* "PID/argv0" */ + n = recursive_action(proc_pid_fname, + ACTION_RECURSE | ACTION_QUIET, + add_to_prg_cache_if_socket, + NULL, + (void *)pid_slash_progname, + 0); + free(pid_slash_progname); + + if (!n) + return FALSE; /* signal permissions error to caller */ + + return SKIP; /* caller should not recurse further into this dir */ } static void prg_cache_load(void) @@ -294,7 +325,6 @@ static void prg_cache_load(void) #else #define prg_cache_clear() ((void)0) -#define print_progname_banner() ((void)0) #endif //ENABLE_FEATURE_NETSTAT_PRG @@ -364,13 +394,16 @@ struct inet_params { static int scan_inet_proc_line(struct inet_params *param, char *line) { int num; - char local_addr[64], rem_addr[64]; + /* IPv6 /proc files use 32-char hex representation + * of IPv6 address, followed by :PORT_IN_HEX + */ + char local_addr[33], rem_addr[33]; /* 32 + 1 for NUL */ num = sscanf(line, - "%*d: %64[0-9A-Fa-f]:%X " - "%64[0-9A-Fa-f]:%X %X " + "%*d: %32[0-9A-Fa-f]:%X " + "%32[0-9A-Fa-f]:%X %X " "%lX:%lX %*X:%*X " - "%*X %d %*d %ld ", + "%*X %d %*d %lu ", local_addr, ¶m->local_port, rem_addr, ¶m->rem_port, ¶m->state, ¶m->txq, ¶m->rxq, @@ -403,8 +436,11 @@ static void print_inet_line(struct inet_params *param, char *r = ip_port_str( ¶m->remaddr.sa, param->rem_port, proto, flags & NETSTAT_NUMERIC); - printf(net_conn_line, - proto, param->rxq, param->txq, l, r, state_str); + printf(FMT_NET_CONN_DATA, + proto, param->rxq, param->txq, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) l, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) r, + state_str); #if ENABLE_FEATURE_NETSTAT_PRG if (option_mask32 & OPT_prg) printf("%."PROGNAME_WIDTH_STR"s", prg_cache_get(param->inode)); @@ -419,6 +455,7 @@ static int FAST_FUNC tcp_do_one(char *line) { struct inet_params param; + memset(¶m, 0, sizeof(param)); if (scan_inet_proc_line(¶m, line)) return 1; @@ -446,6 +483,7 @@ static int FAST_FUNC udp_do_one(char *line) const char *state_str; struct inet_params param; + memset(¶m, 0, sizeof(param)); /* otherwise we display garbage IPv6 scope_ids */ if (scan_inet_proc_line(¶m, line)) return 1; @@ -573,7 +611,7 @@ static int FAST_FUNC unix_do_one(char *line) strcat(ss_flags, "N "); strcat(ss_flags, "]"); - printf("%-5s %-6ld %-11s %-10s %-13s %6lu ", + printf("%-5s %-6lu %-11s %-10s %-13s %6lu ", ss_proto, refcnt, ss_flags, ss_type, ss_state, inode ); @@ -617,38 +655,39 @@ static void do_info(const char *file, int FAST_FUNC (*proc)(char *)) int netstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int netstat_main(int argc UNUSED_PARAM, char **argv) { - const char *net_conn_line_header = PRINT_NET_CONN_HEADER; unsigned opt; INIT_G(); /* Option string must match NETSTAT_xxx constants */ opt = getopt32(argv, NETSTAT_OPTS); - if (opt & 0x1) { // -l + if (opt & OPT_sock_listen) { // -l flags &= ~NETSTAT_CONNECTED; flags |= NETSTAT_LISTENING; } - if (opt & 0x2) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a - //if (opt & 0x4) // -e - if (opt & 0x8) flags |= NETSTAT_NUMERIC; // -n - //if (opt & 0x10) // -t: NETSTAT_TCP - //if (opt & 0x20) // -u: NETSTAT_UDP - //if (opt & 0x40) // -w: NETSTAT_RAW - //if (opt & 0x80) // -x: NETSTAT_UNIX - if (opt & OPT_route) { // -r + if (opt & OPT_sock_all) flags |= NETSTAT_LISTENING | NETSTAT_CONNECTED; // -a + //if (opt & OPT_extended) // -e + if (opt & OPT_noresolve) flags |= NETSTAT_NUMERIC; // -n + //if (opt & OPT_sock_tcp) // -t: NETSTAT_TCP + //if (opt & OPT_sock_udp) // -u: NETSTAT_UDP + //if (opt & OPT_sock_raw) // -w: NETSTAT_RAW + //if (opt & OPT_sock_unix) // -x: NETSTAT_UNIX #if ENABLE_ROUTE + if (opt & OPT_route) { // -r bb_displayroutes(flags & NETSTAT_NUMERIC, !(opt & OPT_extended)); return 0; -#else - bb_show_usage(); -#endif } +#endif +#if ENABLE_FEATURE_NETSTAT_WIDE + G.addr_width = ADDR_NORMAL_WIDTH; if (opt & OPT_wide) { // -W - net_conn_line = PRINT_NET_CONN_WIDE; - net_conn_line_header = PRINT_NET_CONN_HEADER_WIDE; + G.addr_width = ADDR_WIDE; } +#endif #if ENABLE_FEATURE_NETSTAT_PRG + progname_banner = ""; if (opt & OPT_prg) { // -p + progname_banner = PROGNAME_BANNER; prg_cache_load(); } #endif @@ -659,7 +698,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) flags |= opt; } if (flags & (NETSTAT_TCP|NETSTAT_UDP|NETSTAT_RAW)) { - printf("Active Internet connections "); /* xxx */ + printf("Active Internet connections "); /* xxx */ if ((flags & (NETSTAT_LISTENING|NETSTAT_CONNECTED)) == (NETSTAT_LISTENING|NETSTAT_CONNECTED)) printf("(servers and established)"); @@ -667,9 +706,11 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) printf("(only servers)"); else printf("(w/o servers)"); - printf(net_conn_line_header, "Local Address", "Foreign Address"); - print_progname_banner(); - bb_putchar('\n'); + printf(FMT_NET_CONN_HEADER, + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Local Address", + IF_FEATURE_NETSTAT_WIDE(G.addr_width,) "Foreign Address", + progname_banner + ); } if (flags & NETSTAT_TCP) { do_info("/proc/net/tcp", tcp_do_one); @@ -697,9 +738,7 @@ int netstat_main(int argc UNUSED_PARAM, char **argv) printf("(only servers)"); else printf("(w/o servers)"); - printf("\nProto RefCnt Flags Type State I-Node "); - print_progname_banner(); - printf("Path\n"); + printf("\nProto RefCnt Flags Type State I-Node %sPath\n", progname_banner); do_info("/proc/net/unix", unix_do_one); } prg_cache_clear(); diff --git a/networking/nslookup.c b/networking/nslookup.c index 2628711..dd4b1ff 100644 --- a/networking/nslookup.c +++ b/networking/nslookup.c @@ -8,9 +8,23 @@ * Correct default name server display and explicit name server option * added by Ben Zeckel June 2001 * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define nslookup_trivial_usage +//usage: "[HOST] [SERVER]" +//usage:#define nslookup_full_usage "\n\n" +//usage: "Query the nameserver for the IP address of the given HOST\n" +//usage: "optionally using a specified DNS server" +//usage: +//usage:#define nslookup_example_usage +//usage: "$ nslookup localhost\n" +//usage: "Server: default\n" +//usage: "Address: default\n" +//usage: "\n" +//usage: "Name: debian\n" +//usage: "Address: 127.0.0.1\n" + #include #include "libbb.h" @@ -66,7 +80,7 @@ static int print_host(const char *hostname, const char *header) // hint.ai_flags = AI_CANONNAME; rc = getaddrinfo(hostname, NULL /*service*/, &hint, &result); - if (!rc) { + if (rc == 0) { struct addrinfo *cur = result; unsigned cnt = 0; @@ -94,7 +108,7 @@ static int print_host(const char *hostname, const char *header) bb_error_msg("can't resolve '%s'", hostname); #endif } - if (ENABLE_FEATURE_CLEAN_UP) + if (ENABLE_FEATURE_CLEAN_UP && result) freeaddrinfo(result); return (rc != 0); } @@ -124,6 +138,9 @@ static void set_default_dns(const char *server) { len_and_sockaddr *lsa; + if (!server) + return; + /* NB: this works even with, say, "[::1]:5353"! :) */ lsa = xhost2sockaddr(server, 53); @@ -167,9 +184,17 @@ int nslookup_main(int argc, char **argv) /* (but it also says "may be enabled in /etc/resolv.conf") */ /*_res.options |= RES_USE_INET6;*/ - if (argv[2]) - set_default_dns(argv[2]); + set_default_dns(argv[2]); server_print(); + + /* getaddrinfo and friends are free to request a resolver + * reinitialization. Just in case, set_default_dns() again + * after getaddrinfo (in server_print). This reportedly helps + * with bug 675 "nslookup does not properly use second argument" + * at least on Debian Wheezy and Openwrt AA (eglibc based). + */ + set_default_dns(argv[2]); + return print_host(argv[1], "Name:"); } diff --git a/networking/ntpd.c b/networking/ntpd.c index 14c3a5f..c4b0187 100644 --- a/networking/ntpd.c +++ b/networking/ntpd.c @@ -3,7 +3,7 @@ * * Author: Adam Tkac * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * * Parts of OpenNTPD clock syncronization code is replaced by * code which is based on ntp-4.2.6, whuch carries the following @@ -27,9 +27,26 @@ * * *********************************************************************** */ + +//usage:#define ntpd_trivial_usage +//usage: "[-dnqNw"IF_FEATURE_NTPD_SERVER("l")"] [-S PROG] [-p PEER]..." +//usage:#define ntpd_full_usage "\n\n" +//usage: "NTP client/server\n" +//usage: "\n -d Verbose" +//usage: "\n -n Do not daemonize" +//usage: "\n -q Quit after clock is set" +//usage: "\n -N Run at high priority" +//usage: "\n -w Do not set time (only query peers), implies -n" +//usage: IF_FEATURE_NTPD_SERVER( +//usage: "\n -l Run as server on port 123" +//usage: ) +//usage: "\n -S PROG Run PROG after stepping time, stratum change, and every 11 mins" +//usage: "\n -p PEER Obtain time from PEER (may be repeated)" + #include "libbb.h" #include #include /* For IPTOS_LOWDELAY definition */ +#include /* setpriority */ #include #ifndef IPTOS_LOWDELAY # define IPTOS_LOWDELAY 0x10 @@ -40,16 +57,16 @@ /* Verbosity control (max level of -dddd options accepted). - * max 5 is very talkative (and bloated). 2 is non-bloated, + * max 6 is very talkative (and bloated). 3 is non-bloated, * production level setting. */ -#define MAX_VERBOSE 2 +#define MAX_VERBOSE 3 /* High-level description of the algorithm: * * We start running with very small poll_exp, BURSTPOLL, - * in order to quickly accumulate INITIAL_SAMLPES datapoints + * in order to quickly accumulate INITIAL_SAMPLES datapoints * for each peer. Then, time is stepped if the offset is larger * than STEP_THRESHOLD, otherwise it isn't; anyway, we enlarge * poll_exp to MINPOLL and enter frequency measurement step: @@ -73,11 +90,24 @@ * was hibernated, someone set totally wrong date, etc), * then the time is stepped, all datapoints are discarded, * and we go back to steady state. + * + * Made some changes to speed up re-syncing after our clock goes bad + * (tested with suspending my laptop): + * - if largish offset (>= STEP_THRESHOLD * 8 == 1 sec) is seen + * from a peer, schedule next query for this peer soon + * without drastically lowering poll interval for everybody. + * This makes us collect enough data for step much faster: + * e.g. at poll = 10 (1024 secs), step was done within 5 minutes + * after first reply which indicated that our clock is 14 seconds off. + * - on step, do not discard d_dispersion data of the existing datapoints, + * do not clear reachable_bits. This prevents discarding first ~8 + * datapoints after the step. */ -#define RETRY_INTERVAL 5 /* on error, retry in N secs */ +#define RETRY_INTERVAL 5 /* on error, retry in N secs */ #define RESPONSE_INTERVAL 15 /* wait for reply up to N secs */ -#define INITIAL_SAMLPES 4 /* how many samples do we want for init */ +#define INITIAL_SAMPLES 4 /* how many samples do we want for init */ +#define BAD_DELAY_GROWTH 4 /* drop packet if its delay grew by more than this */ /* Clock discipline parameters and constants */ @@ -89,14 +119,21 @@ //UNUSED: #define PANIC_THRESHOLD 1000 /* panic threshold (sec) */ #define FREQ_TOLERANCE 0.000015 /* frequency tolerance (15 PPM) */ -#define BURSTPOLL 0 /* initial poll */ +#define BURSTPOLL 0 /* initial poll */ #define MINPOLL 5 /* minimum poll interval. std ntpd uses 6 (6: 64 sec) */ -#define BIGPOLL 10 /* drop to lower poll at any trouble (10: 17 min) */ +/* If we got largish offset from a peer, cap next query interval + * for this peer by this many seconds: + */ +#define BIGOFF_INTERVAL (1 << 6) +/* If offset > discipline_jitter * POLLADJ_GATE, and poll interval is >= 2^BIGPOLL, + * then it is decreased _at once_. (If < 2^BIGPOLL, it will be decreased _eventually_). + */ +#define BIGPOLL 10 /* 2^10 sec ~= 17 min */ #define MAXPOLL 12 /* maximum poll interval (12: 1.1h, 17: 36.4h). std ntpd uses 17 */ /* Actively lower poll when we see such big offsets. * With STEP_THRESHOLD = 0.125, it means we try to sync more aggressively - * if offset increases over 0.03 sec */ -#define POLLDOWN_OFFSET (STEP_THRESHOLD / 4) + * if offset increases over ~0.04 sec */ +#define POLLDOWN_OFFSET (STEP_THRESHOLD / 3) #define MINDISP 0.01 /* minimum dispersion (sec) */ #define MAXDISP 16 /* maximum dispersion (sec) */ #define MAXSTRAT 16 /* maximum stratum (infinity metric) */ @@ -108,17 +145,18 @@ /* Poll-adjust threshold. * When we see that offset is small enough compared to discipline jitter, - * we grow a counter: += MINPOLL. When it goes over POLLADJ_LIMIT, + * we grow a counter: += MINPOLL. When counter goes over POLLADJ_LIMIT, * we poll_exp++. If offset isn't small, counter -= poll_exp*2, - * and when it goes below -POLLADJ_LIMIT, we poll_exp-- - * (bumped from 30 to 36 since otherwise I often see poll_exp going *2* steps down) + * and when it goes below -POLLADJ_LIMIT, we poll_exp--. + * (Bumped from 30 to 40 since otherwise I often see poll_exp going *2* steps down) */ -#define POLLADJ_LIMIT 36 -/* If offset < POLLADJ_GATE * discipline_jitter, then we can increase +#define POLLADJ_LIMIT 40 +/* If offset < discipline_jitter * POLLADJ_GATE, then we decide to increase * poll interval (we think we can't improve timekeeping * by staying at smaller poll). */ #define POLLADJ_GATE 4 +#define TIMECONST_HACK_GATE 2 /* Compromise Allan intercept (sec). doc uses 1500, std ntpd uses 512 */ #define ALLAN 512 /* PLL loop gain */ @@ -192,22 +230,22 @@ typedef struct { } msg_t; typedef struct { - double d_recv_time; double d_offset; + double d_recv_time; double d_dispersion; } datapoint_t; typedef struct { len_and_sockaddr *p_lsa; char *p_dotted; - /* when to send new query (if p_fd == -1) - * or when receive times out (if p_fd >= 0): */ int p_fd; int datapoint_idx; uint32_t lastpkt_refid; uint8_t lastpkt_status; uint8_t lastpkt_stratum; uint8_t reachable_bits; + /* when to send new query (if p_fd == -1) + * or when receive times out (if p_fd >= 0): */ double next_action_time; double p_xmttime; double lastpkt_recv_time; @@ -238,6 +276,8 @@ enum { OPT_p = (1 << 5), OPT_S = (1 << 6), OPT_l = (1 << 7) * ENABLE_FEATURE_NTPD_SERVER, + /* We hijack some bits for other purposes */ + OPT_qq = (1 << 31), }; struct globals { @@ -254,15 +294,19 @@ struct globals { llist_t *ntp_peers; #if ENABLE_FEATURE_NTPD_SERVER int listen_fd; +# define G_listen_fd (G.listen_fd) +#else +# define G_listen_fd (-1) #endif unsigned verbose; unsigned peer_cnt; /* refid: 32-bit code identifying the particular server or reference clock - * in stratum 0 packets this is a four-character ASCII string, - * called the kiss code, used for debugging and monitoring - * in stratum 1 packets this is a four-character ASCII string - * assigned to the reference clock by IANA. Example: "GPS " - * in stratum 2+ packets, it's IPv4 address or 4 first bytes of MD5 hash of IPv6 + * in stratum 0 packets this is a four-character ASCII string, + * called the kiss code, used for debugging and monitoring + * in stratum 1 packets this is a four-character ASCII string + * assigned to the reference clock by IANA. Example: "GPS " + * in stratum 2+ packets, it's IPv4 address or 4 first bytes + * of MD5 hash of IPv6 */ uint32_t refid; uint8_t ntp_status; @@ -271,34 +315,42 @@ struct globals { * mains-frequency clock incrementing at 60 Hz is 16 ms, even when the * system clock hardware representation is to the nanosecond. * - * Delays, jitters of various kinds are clamper down to precision. + * Delays, jitters of various kinds are clamped down to precision. * * If precision_sec is too large, discipline_jitter gets clamped to it - * and if offset is much smaller than discipline_jitter, poll interval - * grows even though we really can benefit from staying at smaller one, - * collecting non-lagged datapoits and correcting the offset. + * and if offset is smaller than discipline_jitter * POLLADJ_GATE, poll + * interval grows even though we really can benefit from staying at + * smaller one, collecting non-lagged datapoits and correcting offset. * (Lagged datapoits exist when poll_exp is large but we still have * systematic offset error - the time distance between datapoints - * is significat and older datapoints have smaller offsets. + * is significant and older datapoints have smaller offsets. * This makes our offset estimation a bit smaller than reality) * Due to this effect, setting G_precision_sec close to * STEP_THRESHOLD isn't such a good idea - offsets may grow * too big and we will step. I observed it with -6. * - * OTOH, setting precision too small would result in futile attempts - * to syncronize to the unachievable precision. + * OTOH, setting precision_sec far too small would result in futile + * attempts to syncronize to an unachievable precision. * * -6 is 1/64 sec, -7 is 1/128 sec and so on. + * -8 is 1/256 ~= 0.003906 (worked well for me --vda) + * -9 is 1/512 ~= 0.001953 (let's try this for some time) + */ +#define G_precision_exp -9 + /* + * G_precision_exp is used only for construction outgoing packets. + * It's ok to set G_precision_sec to a slightly different value + * (One which is "nicer looking" in logs). + * Exact value would be (1.0 / (1 << (- G_precision_exp))): */ -#define G_precision_exp -8 -#define G_precision_sec (1.0 / (1 << (- G_precision_exp))) +#define G_precision_sec 0.002 uint8_t stratum; /* Bool. After set to 1, never goes back to 0: */ smallint initial_poll_complete; #define STATE_NSET 0 /* initial state, "nothing is set" */ //#define STATE_FSET 1 /* frequency set from file */ -#define STATE_SPIK 2 /* spike detected */ +//#define STATE_SPIK 2 /* spike detected */ //#define STATE_FREQ 3 /* initial frequency */ #define STATE_SYNC 4 /* clock synchronized (normal operation) */ uint8_t discipline_state; // doc calls it c.state @@ -309,6 +361,10 @@ struct globals { double last_update_offset; // c.last double last_update_recv_time; // s.t double discipline_jitter; // c.jitter + /* Since we only compare it with ints, can simplify code + * by not making this variable floating point: + */ + unsigned offset_to_jitter_ratio; //double cluster_offset; // s.offset //double cluster_jitter; // s.jitter #if !USING_KERNEL_PLL_LOOP @@ -327,6 +383,7 @@ static const int const_IPTOS_LOWDELAY = IPTOS_LOWDELAY; #define VERB3 if (MAX_VERBOSE >= 3 && G.verbose >= 3) #define VERB4 if (MAX_VERBOSE >= 4 && G.verbose >= 4) #define VERB5 if (MAX_VERBOSE >= 5 && G.verbose >= 5) +#define VERB6 if (MAX_VERBOSE >= 6 && G.verbose >= 6) static double LOG2D(int a) @@ -482,23 +539,34 @@ static void filter_datapoints(peer_t *p) { int i, idx; + double sum, wavg; + datapoint_t *fdp; + +#if 0 +/* Simulations have shown that use of *averaged* offset for p->filter_offset + * is in fact worse than simply using last received one: with large poll intervals + * (>= 2048) averaging code uses offset values which are outdated by hours, + * and time/frequency correction goes totally wrong when fed essentially bogus offsets. + */ int got_newest; - double minoff, maxoff, wavg, sum, w; + double minoff, maxoff, w; double x = x; /* for compiler */ double oldest_off = oldest_off; double oldest_age = oldest_age; double newest_off = newest_off; double newest_age = newest_age; - minoff = maxoff = p->filter_datapoint[0].d_offset; + fdp = p->filter_datapoint; + + minoff = maxoff = fdp[0].d_offset; for (i = 1; i < NUM_DATAPOINTS; i++) { - if (minoff > p->filter_datapoint[i].d_offset) - minoff = p->filter_datapoint[i].d_offset; - if (maxoff < p->filter_datapoint[i].d_offset) - maxoff = p->filter_datapoint[i].d_offset; + if (minoff > fdp[i].d_offset) + minoff = fdp[i].d_offset; + if (maxoff < fdp[i].d_offset) + maxoff = fdp[i].d_offset; } - idx = p->datapoint_idx; /* most recent datapoint */ + idx = p->datapoint_idx; /* most recent datapoint's index */ /* Average offset: * Drop two outliers and take weighted average of the rest: * most_recent/2 + older1/4 + older2/8 ... + older5/32 + older6/32 @@ -517,27 +585,27 @@ filter_datapoints(peer_t *p) got_newest = 0; sum = 0; for (i = 0; i < NUM_DATAPOINTS; i++) { - VERB4 { + VERB5 { bb_error_msg("datapoint[%d]: off:%f disp:%f(%f) age:%f%s", i, - p->filter_datapoint[idx].d_offset, - p->filter_datapoint[idx].d_dispersion, dispersion(&p->filter_datapoint[idx]), - G.cur_time - p->filter_datapoint[idx].d_recv_time, - (minoff == p->filter_datapoint[idx].d_offset || maxoff == p->filter_datapoint[idx].d_offset) + fdp[idx].d_offset, + fdp[idx].d_dispersion, dispersion(&fdp[idx]), + G.cur_time - fdp[idx].d_recv_time, + (minoff == fdp[idx].d_offset || maxoff == fdp[idx].d_offset) ? " (outlier by offset)" : "" ); } - sum += dispersion(&p->filter_datapoint[idx]) / (2 << i); + sum += dispersion(&fdp[idx]) / (2 << i); - if (minoff == p->filter_datapoint[idx].d_offset) { + if (minoff == fdp[idx].d_offset) { minoff -= 1; /* so that we don't match it ever again */ } else - if (maxoff == p->filter_datapoint[idx].d_offset) { + if (maxoff == fdp[idx].d_offset) { maxoff += 1; } else { - oldest_off = p->filter_datapoint[idx].d_offset; - oldest_age = G.cur_time - p->filter_datapoint[idx].d_recv_time; + oldest_off = fdp[idx].d_offset; + oldest_age = G.cur_time - fdp[idx].d_recv_time; if (!got_newest) { got_newest = 1; newest_off = oldest_off; @@ -570,6 +638,32 @@ filter_datapoints(peer_t *p) } p->filter_offset = wavg; +#else + + fdp = p->filter_datapoint; + idx = p->datapoint_idx; /* most recent datapoint's index */ + + /* filter_offset: simply use the most recent value */ + p->filter_offset = fdp[idx].d_offset; + + /* n-1 + * --- dispersion(i) + * filter_dispersion = \ ------------- + * / (i+1) + * --- 2 + * i=0 + */ + wavg = 0; + sum = 0; + for (i = 0; i < NUM_DATAPOINTS; i++) { + sum += dispersion(&fdp[idx]) / (2 << i); + wavg += fdp[idx].d_offset; + idx = (idx - 1) & (NUM_DATAPOINTS - 1); + } + wavg /= NUM_DATAPOINTS; + p->filter_dispersion = sum; +#endif + /* +----- -----+ ^ 1/2 * | n-1 | * | --- | @@ -583,16 +677,15 @@ filter_datapoints(peer_t *p) */ sum = 0; for (i = 0; i < NUM_DATAPOINTS; i++) { - sum += SQUARE(wavg - p->filter_datapoint[i].d_offset); + sum += SQUARE(wavg - fdp[i].d_offset); } sum = SQRT(sum / NUM_DATAPOINTS); p->filter_jitter = sum > G_precision_sec ? sum : G_precision_sec; - VERB3 bb_error_msg("filter offset:%f(corr:%e) disp:%f jitter:%f", - p->filter_offset, x, + VERB4 bb_error_msg("filter offset:%+f disp:%f jitter:%f", + p->filter_offset, p->filter_dispersion, p->filter_jitter); - } static void @@ -601,26 +694,42 @@ reset_peer_stats(peer_t *p, double offset) int i; bool small_ofs = fabs(offset) < 16 * STEP_THRESHOLD; + /* Used to set p->filter_datapoint[i].d_dispersion = MAXDISP + * and clear reachable bits, but this proved to be too agressive: + * after step (tested with suspinding laptop for ~30 secs), + * this caused all previous data to be considered invalid, + * making us needing to collect full ~8 datapoins per peer + * after step in order to start trusting them. + * In turn, this was making poll interval decrease even after + * step was done. (Poll interval decreases already before step + * in this scenario, because we see large offsets and end up with + * no good peer to select). + */ + for (i = 0; i < NUM_DATAPOINTS; i++) { if (small_ofs) { p->filter_datapoint[i].d_recv_time += offset; if (p->filter_datapoint[i].d_offset != 0) { - p->filter_datapoint[i].d_offset += offset; + p->filter_datapoint[i].d_offset -= offset; + //bb_error_msg("p->filter_datapoint[%d].d_offset %f -> %f", + // i, + // p->filter_datapoint[i].d_offset + offset, + // p->filter_datapoint[i].d_offset); } } else { p->filter_datapoint[i].d_recv_time = G.cur_time; p->filter_datapoint[i].d_offset = 0; - p->filter_datapoint[i].d_dispersion = MAXDISP; + /*p->filter_datapoint[i].d_dispersion = MAXDISP;*/ } } if (small_ofs) { p->lastpkt_recv_time += offset; } else { - p->reachable_bits = 0; + /*p->reachable_bits = 0;*/ p->lastpkt_recv_time = G.cur_time; } filter_datapoints(p); /* recalc p->filter_xxx */ - VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); + VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); } static void @@ -702,6 +811,12 @@ send_query_to_peer(peer_t *p) free(local_lsa); } + /* Emit message _before_ attempted send. Think of a very short + * roundtrip networks: we need to go back to recv loop ASAP, + * to reduce delay. Printing messages after send works against that. + */ + VERB1 bb_error_msg("sending query to %s", p->p_dotted); + /* * Send out a random 64-bit number as our transmit time. The NTP * server will copy said number into the originate field on the @@ -719,23 +834,34 @@ send_query_to_peer(peer_t *p) p->p_xmt_msg.m_xmttime.fractionl = random(); p->p_xmttime = gettime1900d(); + /* Were doing it only if sendto worked, but + * loss of sync detection needs reachable_bits updated + * even if sending fails *locally*: + * "network is unreachable" because cable was pulled? + * We still need to declare "unsync" if this condition persists. + */ + p->reachable_bits <<= 1; + if (do_sendto(p->p_fd, /*from:*/ NULL, /*to:*/ &p->p_lsa->u.sa, /*addrlen:*/ p->p_lsa->len, &p->p_xmt_msg, NTP_MSGSIZE_NOAUTH) == -1 ) { close(p->p_fd); p->p_fd = -1; + /* + * We know that we sent nothing. + * We can retry *soon* without fearing + * that we are flooding the peer. + */ set_next(p, RETRY_INTERVAL); return; } - p->reachable_bits <<= 1; - VERB1 bb_error_msg("sent query to %s", p->p_dotted); set_next(p, RESPONSE_INTERVAL); } /* Note that there is no provision to prevent several run_scripts - * to be done in quick succession. In fact, it happens rather often + * to be started in quick succession. In fact, it happens rather often * if initial syncronization results in a step. * You will see "step" and then "stratum" script runs, sometimes * as close as only 0.002 seconds apart. @@ -746,6 +872,8 @@ static void run_script(const char *action, double offset) char *argv[3]; char *env1, *env2, *env3, *env4; + G.last_script_run = G.cur_time; + if (!G.script_name) return; @@ -782,8 +910,6 @@ static void run_script(const char *action, double offset) free(env2); free(env3); free(env4); - - G.last_script_run = G.cur_time; } static NOINLINE void @@ -791,37 +917,49 @@ step_time(double offset) { llist_t *item; double dtime; - struct timeval tv; - char buf[80]; + struct timeval tvc, tvn; + char buf[sizeof("yyyy-mm-dd hh:mm:ss") + /*paranoia:*/ 4]; time_t tval; - gettimeofday(&tv, NULL); /* never fails */ - dtime = offset + tv.tv_sec; - dtime += 1.0e-6 * tv.tv_usec; - d_to_tv(dtime, &tv); - - if (settimeofday(&tv, NULL) == -1) + gettimeofday(&tvc, NULL); /* never fails */ + dtime = tvc.tv_sec + (1.0e-6 * tvc.tv_usec) + offset; + d_to_tv(dtime, &tvn); + if (settimeofday(&tvn, NULL) == -1) bb_perror_msg_and_die("settimeofday"); - tval = tv.tv_sec; - strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); - - bb_error_msg("setting clock to %s (offset %fs)", buf, offset); + VERB2 { + tval = tvc.tv_sec; + strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); + bb_error_msg("current time is %s.%06u", buf, (unsigned)tvc.tv_usec); + } + tval = tvn.tv_sec; + strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); + bb_error_msg("setting time to %s.%06u (offset %+fs)", buf, (unsigned)tvn.tv_usec, offset); /* Correct various fields which contain time-relative values: */ + /* Globals: */ + G.cur_time += offset; + G.last_update_recv_time += offset; + G.last_script_run += offset; + /* p->lastpkt_recv_time, p->next_action_time and such: */ for (item = G.ntp_peers; item != NULL; item = item->link) { peer_t *pp = (peer_t *) item->data; reset_peer_stats(pp, offset); - //bb_error_msg("offset:%f pp->next_action_time:%f -> %f", + //bb_error_msg("offset:%+f pp->next_action_time:%f -> %f", // offset, pp->next_action_time, pp->next_action_time + offset); pp->next_action_time += offset; + if (pp->p_fd >= 0) { + /* We wait for reply from this peer too. + * But due to step we are doing, reply's data is no longer + * useful (in fact, it'll be bogus). Stop waiting for it. + */ + close(pp->p_fd); + pp->p_fd = -1; + set_next(pp, RETRY_INTERVAL); + } } - /* Globals: */ - G.cur_time += offset; - G.last_update_recv_time += offset; - G.last_script_run += offset; } @@ -863,27 +1001,27 @@ fit(peer_t *p, double rd) { if ((p->reachable_bits & (p->reachable_bits-1)) == 0) { /* One or zero bits in reachable_bits */ - VERB3 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); + VERB4 bb_error_msg("peer %s unfit for selection: unreachable", p->p_dotted); return 0; } -#if 0 /* we filter out such packets earlier */ +#if 0 /* we filter out such packets earlier */ if ((p->lastpkt_status & LI_ALARM) == LI_ALARM || p->lastpkt_stratum >= MAXSTRAT ) { - VERB3 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted); + VERB4 bb_error_msg("peer %s unfit for selection: bad status/stratum", p->p_dotted); return 0; } #endif /* rd is root_distance(p) */ if (rd > MAXDIST + FREQ_TOLERANCE * (1 << G.poll_exp)) { - VERB3 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted); + VERB4 bb_error_msg("peer %s unfit for selection: root distance too high", p->p_dotted); return 0; } //TODO // /* Do we have a loop? */ // if (p->refid == p->dstaddr || p->refid == s.refid) // return 0; - return 1; + return 1; } static peer_t* select_and_cluster(void) @@ -916,7 +1054,7 @@ select_and_cluster(void) continue; } - VERB4 bb_error_msg("interval: [%f %f %f] %s", + VERB5 bb_error_msg("interval: [%f %f %f] %s", offset - rd, offset, offset + rd, @@ -941,7 +1079,7 @@ select_and_cluster(void) } num_candidates = num_points / 3; if (num_candidates == 0) { - VERB3 bb_error_msg("no valid datapoints, no peer selected"); + VERB3 bb_error_msg("no valid datapoints%s", ", no peer selected"); return NULL; } //TODO: sorting does not seem to be done in reference code @@ -999,12 +1137,13 @@ select_and_cluster(void) break; num_falsetickers++; if (num_falsetickers * 2 >= num_candidates) { - VERB3 bb_error_msg("too many falsetickers:%d (candidates:%d), no peer selected", - num_falsetickers, num_candidates); + VERB3 bb_error_msg("falsetickers:%d, candidates:%d%s", + num_falsetickers, num_candidates, + ", no peer selected"); return NULL; } } - VERB3 bb_error_msg("selected interval: [%f, %f]; candidates:%d falsetickers:%d", + VERB4 bb_error_msg("selected interval: [%f, %f]; candidates:%d falsetickers:%d", low, high, num_candidates, num_falsetickers); /* Clustering */ @@ -1022,7 +1161,7 @@ select_and_cluster(void) survivor[num_survivors].p = p; /* x.opt_rd == root_distance(p); */ survivor[num_survivors].metric = MAXDIST * p->lastpkt_stratum + point[i].opt_rd; - VERB4 bb_error_msg("survivor[%d] metric:%f peer:%s", + VERB5 bb_error_msg("survivor[%d] metric:%f peer:%s", num_survivors, survivor[num_survivors].metric, p->p_dotted); num_survivors++; } @@ -1032,8 +1171,9 @@ select_and_cluster(void) * is acceptable. */ if (num_survivors < MIN_SELECTED) { - VERB3 bb_error_msg("num_survivors %d < %d, no peer selected", - num_survivors, MIN_SELECTED); + VERB3 bb_error_msg("survivors:%d%s", + num_survivors, + ", no peer selected"); return NULL; } @@ -1053,7 +1193,7 @@ select_and_cluster(void) double min_jitter = min_jitter; if (num_survivors <= MIN_CLUSTERED) { - VERB3 bb_error_msg("num_survivors %d <= %d, not discarding more", + VERB4 bb_error_msg("num_survivors %d <= %d, not discarding more", num_survivors, MIN_CLUSTERED); break; } @@ -1079,11 +1219,11 @@ select_and_cluster(void) max_selection_jitter = selection_jitter_sq; max_idx = i; } - VERB5 bb_error_msg("survivor %d selection_jitter^2:%f", + VERB6 bb_error_msg("survivor %d selection_jitter^2:%f", i, selection_jitter_sq); } max_selection_jitter = SQRT(max_selection_jitter / num_survivors); - VERB4 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f", + VERB5 bb_error_msg("max_selection_jitter (at %d):%f min_jitter:%f", max_idx, max_selection_jitter, min_jitter); /* If the maximum selection jitter is less than the @@ -1092,7 +1232,7 @@ select_and_cluster(void) * as well stop. */ if (max_selection_jitter < min_jitter) { - VERB3 bb_error_msg("max_selection_jitter:%f < min_jitter:%f, num_survivors:%d, not discarding more", + VERB4 bb_error_msg("max_selection_jitter:%f < min_jitter:%f, num_survivors:%d, not discarding more", max_selection_jitter, min_jitter, num_survivors); break; } @@ -1100,7 +1240,7 @@ select_and_cluster(void) /* Delete survivor[max_idx] from the list * and go around again. */ - VERB5 bb_error_msg("dropping survivor %d", max_idx); + VERB6 bb_error_msg("dropping survivor %d", max_idx); num_survivors--; while (max_idx < num_survivors) { survivor[max_idx] = survivor[max_idx + 1]; @@ -1142,7 +1282,7 @@ select_and_cluster(void) /* Starting from 1 is ok here */ for (i = 1; i < num_survivors; i++) { if (G.last_update_peer == survivor[i].p) { - VERB4 bb_error_msg("keeping old synced peer"); + VERB5 bb_error_msg("keeping old synced peer"); p = G.last_update_peer; goto keep_old; } @@ -1150,7 +1290,7 @@ select_and_cluster(void) } G.last_update_peer = p; keep_old: - VERB3 bb_error_msg("selected peer %s filter_offset:%f age:%f", + VERB4 bb_error_msg("selected peer %s filter_offset:%+f age:%f", p->p_dotted, p->filter_offset, G.cur_time - p->lastpkt_recv_time @@ -1169,7 +1309,7 @@ set_new_values(int disc_state, double offset, double recv_time) * of the last clock filter sample, which must be earlier than * the current time. */ - VERB3 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f", + VERB4 bb_error_msg("disc_state=%d last update offset=%f recv_time=%f", disc_state, offset, recv_time); G.discipline_state = disc_state; G.last_update_offset = offset; @@ -1207,8 +1347,8 @@ update_local_clock(peer_t *p) * an old sample or the same sample twice. */ if (recv_time <= G.last_update_recv_time) { - VERB3 bb_error_msg("same or older datapoint: %f >= %f, not using it", - G.last_update_recv_time, recv_time); + VERB3 bb_error_msg("update from %s: same or older datapoint, not using it", + p->p_dotted); return 0; /* "leave poll interval as is" */ } @@ -1224,7 +1364,7 @@ update_local_clock(peer_t *p) if (G.discipline_state == STATE_FREQ) { /* Ignore updates until the stepout threshold */ if (since_last_update < WATCH_THRESHOLD) { - VERB3 bb_error_msg("measuring drift, datapoint ignored, %f sec remains", + VERB4 bb_error_msg("measuring drift, datapoint ignored, %f sec remains", WATCH_THRESHOLD - since_last_update); return 0; /* "leave poll interval as is" */ } @@ -1238,10 +1378,21 @@ update_local_clock(peer_t *p) * offset exceeds the step threshold and when it does not. */ if (abs_offset > STEP_THRESHOLD) { +#if 0 + double remains; + +// This "spike state" seems to be useless, peer selection already drops +// occassional "bad" datapoints. If we are here, there were _many_ +// large offsets. When a few first large offsets are seen, +// we end up in "no valid datapoints, no peer selected" state. +// Only when enough of them are seen (which means it's not a fluke), +// we end up here. Looks like _our_ clock is off. switch (G.discipline_state) { case STATE_SYNC: /* The first outlyer: ignore it, switch to SPIK state */ - VERB3 bb_error_msg("offset:%f - spike detected", offset); + VERB3 bb_error_msg("update from %s: offset:%+f, spike%s", + p->p_dotted, offset, + ""); G.discipline_state = STATE_SPIK; return -1; /* "decrease poll interval" */ @@ -1249,13 +1400,16 @@ update_local_clock(peer_t *p) /* Ignore succeeding outlyers until either an inlyer * is found or the stepout threshold is exceeded. */ - if (since_last_update < WATCH_THRESHOLD) { - VERB3 bb_error_msg("spike detected, datapoint ignored, %f sec remains", - WATCH_THRESHOLD - since_last_update); + remains = WATCH_THRESHOLD - since_last_update; + if (remains > 0) { + VERB3 bb_error_msg("update from %s: offset:%+f, spike%s", + p->p_dotted, offset, + ", datapoint ignored"); return -1; /* "decrease poll interval" */ } /* fall through: we need to step */ } /* switch */ +#endif /* Step the time and clamp down the poll interval. * @@ -1278,7 +1432,7 @@ update_local_clock(peer_t *p) * is always suppressed, even at the longer poll * intervals. */ - VERB3 bb_error_msg("stepping time by %f; poll_exp=MINPOLL", offset); + VERB4 bb_error_msg("stepping time by %+f; poll_exp=MINPOLL", offset); step_time(offset); if (option_mask32 & OPT_q) { /* We were only asked to set time once. Done. */ @@ -1291,18 +1445,21 @@ update_local_clock(peer_t *p) run_script("step", offset); + recv_time += offset; + #if USING_INITIAL_FREQ_ESTIMATION if (G.discipline_state == STATE_NSET) { set_new_values(STATE_FREQ, /*offset:*/ 0, recv_time); return 1; /* "ok to increase poll interval" */ } #endif - set_new_values(STATE_SYNC, /*offset:*/ 0, recv_time); + abs_offset = offset = 0; + set_new_values(STATE_SYNC, offset, recv_time); } else { /* abs_offset <= STEP_THRESHOLD */ if (G.poll_exp < MINPOLL && G.initial_poll_complete) { - VERB3 bb_error_msg("small offset:%f, disabling burst mode", offset); + VERB4 bb_error_msg("small offset:%+f, disabling burst mode", offset); G.polladj_count = 0; G.poll_exp = MINPOLL; } @@ -1311,9 +1468,8 @@ update_local_clock(peer_t *p) * weighted offset differences. Used by the poll adjust code. */ etemp = SQUARE(G.discipline_jitter); - dtemp = SQUARE(MAXD(fabs(offset - G.last_update_offset), G_precision_sec)); + dtemp = SQUARE(offset - G.last_update_offset); G.discipline_jitter = SQRT(etemp + (dtemp - etemp) / AVG); - VERB3 bb_error_msg("discipline jitter=%f", G.discipline_jitter); switch (G.discipline_state) { case STATE_NSET: @@ -1332,7 +1488,7 @@ update_local_clock(peer_t *p) #else set_new_values(STATE_SYNC, offset, recv_time); #endif - VERB3 bb_error_msg("transitioning to FREQ, datapoint ignored"); + VERB4 bb_error_msg("transitioning to FREQ, datapoint ignored"); return 0; /* "leave poll interval as is" */ #if 0 /* this is dead code for now */ @@ -1390,6 +1546,10 @@ update_local_clock(peer_t *p) } } + if (G.discipline_jitter < G_precision_sec) + G.discipline_jitter = G_precision_sec; + G.offset_to_jitter_ratio = abs_offset / G.discipline_jitter; + G.reftime = G.cur_time; G.ntp_status = p->lastpkt_status; G.refid = p->lastpkt_refid; @@ -1397,11 +1557,11 @@ update_local_clock(peer_t *p) dtemp = p->filter_jitter; // SQRT(SQUARE(p->filter_jitter) + SQUARE(G.cluster_jitter)); dtemp += MAXD(p->filter_dispersion + FREQ_TOLERANCE * (G.cur_time - p->lastpkt_recv_time) + abs_offset, MINDISP); G.rootdisp = p->lastpkt_rootdisp + dtemp; - VERB3 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); + VERB4 bb_error_msg("updating leap/refid/reftime/rootdisp from peer %s", p->p_dotted); /* We are in STATE_SYNC now, but did not do adjtimex yet. * (Any other state does not reach this, they all return earlier) - * By this time, freq_drift and G.last_update_offset are set + * By this time, freq_drift and offset are set * to values suitable for adjtimex. */ #if !USING_KERNEL_PLL_LOOP @@ -1417,18 +1577,18 @@ update_local_clock(peer_t *p) dtemp = SQUARE(dtemp); G.discipline_wander = SQRT(etemp + (dtemp - etemp) / AVG); - VERB3 bb_error_msg("discipline freq_drift=%.9f(int:%ld corr:%e) wander=%f", + VERB4 bb_error_msg("discipline freq_drift=%.9f(int:%ld corr:%e) wander=%f", G.discipline_freq_drift, (long)(G.discipline_freq_drift * 65536e6), freq_drift, G.discipline_wander); #endif - VERB3 { + VERB4 { memset(&tmx, 0, sizeof(tmx)); if (adjtimex(&tmx) < 0) bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("p adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); + bb_error_msg("p adjtimex freq:%ld offset:%+ld status:0x%x tc:%ld", + tmx.freq, tmx.offset, tmx.status, tmx.constant); } memset(&tmx, 0, sizeof(tmx)); @@ -1440,40 +1600,42 @@ update_local_clock(peer_t *p) tmx.modes = ADJ_FREQUENCY | ADJ_OFFSET; /* 65536 is one ppm */ tmx.freq = G.discipline_freq_drift * 65536e6; - tmx.offset = G.last_update_offset * 1000000; /* usec */ #endif tmx.modes = ADJ_OFFSET | ADJ_STATUS | ADJ_TIMECONST;// | ADJ_MAXERROR | ADJ_ESTERROR; - tmx.offset = (G.last_update_offset * 1000000); /* usec */ - /* + (G.last_update_offset < 0 ? -0.5 : 0.5) - too small to bother */ + tmx.offset = (offset * 1000000); /* usec */ tmx.status = STA_PLL; if (G.ntp_status & LI_PLUSSEC) tmx.status |= STA_INS; if (G.ntp_status & LI_MINUSSEC) tmx.status |= STA_DEL; + tmx.constant = G.poll_exp - 4; - //tmx.esterror = (u_int32)(clock_jitter * 1e6); - //tmx.maxerror = (u_int32)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); + /* EXPERIMENTAL. + * The below if statement should be unnecessary, but... + * It looks like Linux kernel's PLL is far too gentle in changing + * tmx.freq in response to clock offset. Offset keeps growing + * and eventually we fall back to smaller poll intervals. + * We can make correction more agressive (about x2) by supplying + * PLL time constant which is one less than the real one. + * To be on a safe side, let's do it only if offset is significantly + * larger than jitter. + */ + if (tmx.constant > 0 && G.offset_to_jitter_ratio >= TIMECONST_HACK_GATE) + tmx.constant--; + + //tmx.esterror = (uint32_t)(clock_jitter * 1e6); + //tmx.maxerror = (uint32_t)((sys_rootdelay / 2 + sys_rootdisp) * 1e6); rc = adjtimex(&tmx); if (rc < 0) bb_perror_msg_and_die("adjtimex"); /* NB: here kernel returns constant == G.poll_exp, not == G.poll_exp - 4. * Not sure why. Perhaps it is normal. */ - VERB3 bb_error_msg("adjtimex:%d freq:%ld offset:%ld constant:%ld status:0x%x", - rc, tmx.freq, tmx.offset, tmx.constant, tmx.status); -#if 0 - VERB3 { - /* always gives the same output as above msg */ - memset(&tmx, 0, sizeof(tmx)); - if (adjtimex(&tmx) < 0) - bb_perror_msg_and_die("adjtimex"); - VERB3 bb_error_msg("c adjtimex freq:%ld offset:%ld constant:%ld status:0x%x", - tmx.freq, tmx.offset, tmx.constant, tmx.status); - } -#endif + VERB4 bb_error_msg("adjtimex:%d freq:%ld offset:%+ld status:0x%x", + rc, tmx.freq, tmx.offset, tmx.status); G.kernel_freq_drift = tmx.freq / 65536; - VERB2 bb_error_msg("update peer:%s, offset:%f, clock drift:%ld ppm", - p->p_dotted, G.last_update_offset, G.kernel_freq_drift); + VERB2 bb_error_msg("update from:%s offset:%+f jitter:%f clock drift:%+.3fppm tc:%d", + p->p_dotted, offset, G.discipline_jitter, (double)tmx.freq / 65536, (int)tmx.constant); return 1; /* "ok to increase poll interval" */ } @@ -1491,7 +1653,7 @@ retry_interval(void) interval = RETRY_INTERVAL; r = random(); interval += r % (unsigned)(RETRY_INTERVAL / 4); - VERB3 bb_error_msg("chose retry interval:%u", interval); + VERB4 bb_error_msg("chose retry interval:%u", interval); return interval; } static unsigned @@ -1504,7 +1666,7 @@ poll_interval(int exponent) interval = 1 << exponent; r = random(); interval += ((r & (interval-1)) >> 4) + ((r >> 8) & 1); /* + 1/16 of interval, max */ - VERB3 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); + VERB4 bb_error_msg("chose poll interval:%u (poll_exp:%d exp:%d)", interval, G.poll_exp, exponent); return interval; } static NOINLINE void @@ -1514,10 +1676,13 @@ recv_and_process_peer_pkt(peer_t *p) ssize_t size; msg_t msg; double T1, T2, T3, T4; + double dv, offset; unsigned interval; datapoint_t *datapoint; peer_t *q; + offset = 0; + /* We can recvfrom here and check from.IP, but some multihomed * ntp servers reply from their *other IP*. * TODO: maybe we should check at least what we can: from.port == 123? @@ -1532,22 +1697,30 @@ recv_and_process_peer_pkt(peer_t *p) ) { //TODO: always do this? interval = retry_interval(); - goto set_next_and_close_sock; + goto set_next_and_ret; } xfunc_die(); } if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { bb_error_msg("malformed packet received from %s", p->p_dotted); - goto bail; + return; } if (msg.m_orgtime.int_partl != p->p_xmt_msg.m_xmttime.int_partl || msg.m_orgtime.fractionl != p->p_xmt_msg.m_xmttime.fractionl ) { - goto bail; + /* Somebody else's packet */ + return; } + /* We do not expect any more packets from this peer for now. + * Closing the socket informs kernel about it. + * We open a new socket when we send a new query. + */ + close(p->p_fd); + p->p_fd = -1; + if ((msg.m_status & LI_ALARM) == LI_ALARM || msg.m_stratum == 0 || msg.m_stratum > NTP_MAXSTRATUM @@ -1555,9 +1728,8 @@ recv_and_process_peer_pkt(peer_t *p) // TODO: stratum 0 responses may have commands in 32-bit m_refid field: // "DENY", "RSTR" - peer does not like us at all // "RATE" - peer is overloaded, reduce polling freq - interval = poll_interval(0); - bb_error_msg("reply from %s: not synced, next query in %us", p->p_dotted, interval); - goto set_next_and_close_sock; + bb_error_msg("reply from %s: peer is unsynced", p->p_dotted); + goto pick_normal_interval; } // /* Verify valid root distance */ @@ -1590,41 +1762,51 @@ recv_and_process_peer_pkt(peer_t *p) T4 = G.cur_time; p->lastpkt_recv_time = T4; + VERB6 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); - VERB5 bb_error_msg("%s->lastpkt_recv_time=%f", p->p_dotted, p->lastpkt_recv_time); - p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; - datapoint = &p->filter_datapoint[p->datapoint_idx]; - datapoint->d_recv_time = T4; - datapoint->d_offset = ((T2 - T1) + (T3 - T4)) / 2; /* The delay calculation is a special case. In cases where the * server and client clocks are running at different rates and * with very fast networks, the delay can appear negative. In * order to avoid violating the Principle of Least Astonishment, * the delay is clamped not less than the system precision. */ + dv = p->lastpkt_delay; p->lastpkt_delay = (T4 - T1) - (T3 - T2); if (p->lastpkt_delay < G_precision_sec) p->lastpkt_delay = G_precision_sec; + /* + * If this packet's delay is much bigger than the last one, + * it's better to just ignore it than use its much less precise value. + */ + if (p->reachable_bits && p->lastpkt_delay > dv * BAD_DELAY_GROWTH) { + bb_error_msg("reply from %s: delay %f is too high, ignoring", p->p_dotted, p->lastpkt_delay); + goto pick_normal_interval; + } + + p->datapoint_idx = p->reachable_bits ? (p->datapoint_idx + 1) % NUM_DATAPOINTS : 0; + datapoint = &p->filter_datapoint[p->datapoint_idx]; + datapoint->d_recv_time = T4; + datapoint->d_offset = offset = ((T2 - T1) + (T3 - T4)) / 2; datapoint->d_dispersion = LOG2D(msg.m_precision_exp) + G_precision_sec; if (!p->reachable_bits) { /* 1st datapoint ever - replicate offset in every element */ int i; - for (i = 1; i < NUM_DATAPOINTS; i++) { - p->filter_datapoint[i].d_offset = datapoint->d_offset; + for (i = 0; i < NUM_DATAPOINTS; i++) { + p->filter_datapoint[i].d_offset = offset; } } p->reachable_bits |= 1; if ((MAX_VERBOSE && G.verbose) || (option_mask32 & OPT_w)) { - bb_error_msg("reply from %s: reach 0x%02x offset %f delay %f status 0x%02x strat %d refid 0x%08x rootdelay %f", + bb_error_msg("reply from %s: offset:%+f delay:%f status:0x%02x strat:%d refid:0x%08x rootdelay:%f reach:0x%02x", p->p_dotted, - p->reachable_bits, - datapoint->d_offset, + offset, p->lastpkt_delay, p->lastpkt_status, p->lastpkt_stratum, p->lastpkt_refid, - p->lastpkt_rootdelay + p->lastpkt_rootdelay, + p->reachable_bits /* not shown: m_ppoll, m_precision_exp, m_rootdisp, * m_reftime, m_orgtime, m_rectime, m_xmttime */ @@ -1643,7 +1825,7 @@ recv_and_process_peer_pkt(peer_t *p) * drop poll interval one step down. */ if (fabs(q->filter_offset) >= POLLDOWN_OFFSET) { - VERB3 bb_error_msg("offset:%f > POLLDOWN_OFFSET", q->filter_offset); + VERB4 bb_error_msg("offset:%+f > POLLDOWN_OFFSET", q->filter_offset); goto poll_down; } } @@ -1657,14 +1839,7 @@ recv_and_process_peer_pkt(peer_t *p) * is increased, otherwise it is decreased. A bit of hysteresis * helps calm the dance. Works best using burst mode. */ - VERB4 if (rc > 0) { - bb_error_msg("offset:%f POLLADJ_GATE*discipline_jitter:%f poll:%s", - q->filter_offset, POLLADJ_GATE * G.discipline_jitter, - fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter - ? "grows" : "falls" - ); - } - if (rc > 0 && fabs(q->filter_offset) < POLLADJ_GATE * G.discipline_jitter) { + if (rc > 0 && G.offset_to_jitter_ratio <= POLLADJ_GATE) { /* was += G.poll_exp but it is a bit * too optimistic for my taste at high poll_exp's */ G.polladj_count += MINPOLL; @@ -1672,11 +1847,11 @@ recv_and_process_peer_pkt(peer_t *p) G.polladj_count = 0; if (G.poll_exp < MAXPOLL) { G.poll_exp++; - VERB3 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", + VERB4 bb_error_msg("polladj: discipline_jitter:%f ++poll_exp=%d", G.discipline_jitter, G.poll_exp); } } else { - VERB3 bb_error_msg("polladj: incr:%d", G.polladj_count); + VERB4 bb_error_msg("polladj: incr:%d", G.polladj_count); } } else { G.polladj_count -= G.poll_exp * 2; @@ -1698,28 +1873,35 @@ recv_and_process_peer_pkt(peer_t *p) if (pp->p_fd < 0) pp->next_action_time -= (1 << G.poll_exp); } - VERB3 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d", + VERB4 bb_error_msg("polladj: discipline_jitter:%f --poll_exp=%d", G.discipline_jitter, G.poll_exp); } } else { - VERB3 bb_error_msg("polladj: decr:%d", G.polladj_count); + VERB4 bb_error_msg("polladj: decr:%d", G.polladj_count); } } } /* Decide when to send new query for this peer */ + pick_normal_interval: interval = poll_interval(0); + if (fabs(offset) >= STEP_THRESHOLD * 8 && interval > BIGOFF_INTERVAL) { + /* If we are synced, offsets are less than STEP_THRESHOLD, + * or at the very least not much larger than it. + * Now we see a largish one. + * Either this peer is feeling bad, or packet got corrupted, + * or _our_ clock is wrong now and _all_ peers will show similar + * largish offsets too. + * I observed this with laptop suspend stopping clock. + * In any case, it makes sense to make next request soonish: + * cases 1 and 2: get a better datapoint, + * case 3: allows to resync faster. + */ + interval = BIGOFF_INTERVAL; + } - set_next_and_close_sock: + set_next_and_ret: set_next(p, interval); - /* We do not expect any more packets from this peer for now. - * Closing the socket informs kernel about it. - * We open a new socket when we send a new query. - */ - close(p->p_fd); - p->p_fd = -1; - bail: - return; } #if ENABLE_FEATURE_NTPD_SERVER @@ -1727,17 +1909,17 @@ static NOINLINE void recv_and_process_client_pkt(void /*int fd*/) { ssize_t size; - uint8_t version; + //uint8_t version; len_and_sockaddr *to; struct sockaddr *from; msg_t msg; uint8_t query_status; l_fixedpt_t query_xmttime; - to = get_sock_lsa(G.listen_fd); + to = get_sock_lsa(G_listen_fd); from = xzalloc(to->len); - size = recv_from_to(G.listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); + size = recv_from_to(G_listen_fd, &msg, sizeof(msg), MSG_DONTWAIT, from, &to->u.sa, to->len); if (size != NTP_MSGSIZE_NOAUTH && size != NTP_MSGSIZE) { char *addr; if (size < 0) { @@ -1756,27 +1938,31 @@ recv_and_process_client_pkt(void /*int fd*/) /* Build a reply packet */ memset(&msg, 0, sizeof(msg)); - msg.m_status = G.stratum < MAXSTRAT ? G.ntp_status : LI_ALARM; + msg.m_status = G.stratum < MAXSTRAT ? (G.ntp_status & LI_MASK) : LI_ALARM; msg.m_status |= (query_status & VERSION_MASK); msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ? - MODE_SERVER : MODE_SYM_PAS; + MODE_SERVER : MODE_SYM_PAS; msg.m_stratum = G.stratum; msg.m_ppoll = G.poll_exp; msg.m_precision_exp = G_precision_exp; /* this time was obtained between poll() and recv() */ msg.m_rectime = d_to_lfp(G.cur_time); msg.m_xmttime = d_to_lfp(gettime1900d()); /* this instant */ + if (G.peer_cnt == 0) { + /* we have no peers: "stratum 1 server" mode. reftime = our own time */ + G.reftime = G.cur_time; + } msg.m_reftime = d_to_lfp(G.reftime); msg.m_orgtime = query_xmttime; msg.m_rootdelay = d_to_sfp(G.rootdelay); //simple code does not do this, fix simple code! msg.m_rootdisp = d_to_sfp(G.rootdisp); - version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ + //version = (query_status & VERSION_MASK); /* ... >> VERSION_SHIFT - done below instead */ msg.m_refid = G.refid; // (version > (3 << VERSION_SHIFT)) ? G.refid : G.refid3; /* We reply from the local address packet was sent to, * this makes to/from look swapped here: */ - do_sendto(G.listen_fd, + do_sendto(G_listen_fd, /*from:*/ &to->u.sa, /*to:*/ from, /*addrlen:*/ to->len, &msg, size); @@ -1903,27 +2089,54 @@ static NOINLINE void ntp_init(char **argv) bb_show_usage(); // if (opts & OPT_x) /* disable stepping, only slew is allowed */ // G.time_was_stepped = 1; - while (peers) - add_peers(llist_pop(&peers)); + if (peers) { + while (peers) + add_peers(llist_pop(&peers)); + } else { + /* -l but no peers: "stratum 1 server" mode */ + G.stratum = 1; + } if (!(opts & OPT_n)) { bb_daemonize_or_rexec(DAEMON_DEVNULL_STDIO, argv); logmode = LOGMODE_NONE; } #if ENABLE_FEATURE_NTPD_SERVER - G.listen_fd = -1; + G_listen_fd = -1; if (opts & OPT_l) { - G.listen_fd = create_and_bind_dgram_or_die(NULL, 123); - socket_want_pktinfo(G.listen_fd); - setsockopt(G.listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); + G_listen_fd = create_and_bind_dgram_or_die(NULL, 123); + socket_want_pktinfo(G_listen_fd); + setsockopt(G_listen_fd, IPPROTO_IP, IP_TOS, &const_IPTOS_LOWDELAY, sizeof(const_IPTOS_LOWDELAY)); } #endif /* I hesitate to set -20 prio. -15 should be high enough for timekeeping */ if (opts & OPT_N) setpriority(PRIO_PROCESS, 0, -15); - bb_signals((1 << SIGTERM) | (1 << SIGINT), record_signo); - /* Removed SIGHUP here: */ - bb_signals((1 << SIGPIPE) | (1 << SIGCHLD), SIG_IGN); + /* If network is up, syncronization occurs in ~10 seconds. + * We give "ntpd -q" 10 seconds to get first reply, + * then another 50 seconds to finish syncing. + * + * I tested ntpd 4.2.6p1 and apparently it never exits + * (will try forever), but it does not feel right. + * The goal of -q is to act like ntpdate: set time + * after a reasonably small period of polling, or fail. + */ + if (opts & OPT_q) { + option_mask32 |= OPT_qq; + alarm(10); + } + + bb_signals(0 + | (1 << SIGTERM) + | (1 << SIGINT) + | (1 << SIGALRM) + , record_signo + ); + bb_signals(0 + | (1 << SIGPIPE) + | (1 << SIGCHLD) + , SIG_IGN + ); } int ntpd_main(int argc UNUSED_PARAM, char **argv) MAIN_EXTERNALLY_VISIBLE; @@ -1945,14 +2158,16 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) idx2peer = xzalloc(sizeof(idx2peer[0]) * cnt); pfd = xzalloc(sizeof(pfd[0]) * cnt); - /* Countdown: we never sync before we sent INITIAL_SAMLPES+1 + /* Countdown: we never sync before we sent INITIAL_SAMPLES+1 * packets to each peer. * NB: if some peer is not responding, we may end up sending * fewer packets to it and more to other peers. - * NB2: sync usually happens using INITIAL_SAMLPES packets, + * NB2: sync usually happens using INITIAL_SAMPLES packets, * since last reply does not come back instantaneously. */ - cnt = G.peer_cnt * (INITIAL_SAMLPES + 1); + cnt = G.peer_cnt * (INITIAL_SAMPLES + 1); + + write_pidfile(CONFIG_PID_FILE_PATH "/ntpd.pid"); while (!bb_got_signal) { llist_t *item; @@ -1966,8 +2181,8 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) i = 0; #if ENABLE_FEATURE_NTPD_SERVER - if (G.listen_fd != -1) { - pfd[0].fd = G.listen_fd; + if (G_listen_fd != -1) { + pfd[0].fd = G_listen_fd; pfd[0].events = POLLIN; i++; } @@ -2012,16 +2227,33 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) timeout++; /* (nextaction - G.cur_time) rounds down, compensating */ /* Here we may block */ - VERB2 bb_error_msg("poll %us, sockets:%u, poll interval:%us", timeout, i, 1 << G.poll_exp); + VERB2 { + if (i > (ENABLE_FEATURE_NTPD_SERVER && G_listen_fd != -1)) { + /* We wait for at least one reply. + * Poll for it, without wasting time for message. + * Since replies often come under 1 second, this also + * reduces clutter in logs. + */ + nfds = poll(pfd, i, 1000); + if (nfds != 0) + goto did_poll; + if (--timeout <= 0) + goto did_poll; + } + bb_error_msg("poll:%us sockets:%u interval:%us", timeout, i, 1 << G.poll_exp); + } nfds = poll(pfd, i, timeout * 1000); + did_poll: gettime1900d(); /* sets G.cur_time */ if (nfds <= 0) { - if (G.script_name && G.cur_time - G.last_script_run > 11*60) { + if (!bb_got_signal /* poll wasn't interrupted by a signal */ + && G.cur_time - G.last_script_run > 11*60 + ) { /* Useful for updating battery-backed RTC and such */ run_script("periodic", G.last_update_offset); gettime1900d(); /* sets G.cur_time */ } - continue; + goto check_unsync; } /* Process any received packets */ @@ -2038,13 +2270,38 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) #endif for (; nfds != 0 && j < i; j++) { if (pfd[j].revents /* & (POLLIN|POLLERR)*/) { + /* + * At init, alarm was set to 10 sec. + * Now we did get a reply. + * Increase timeout to 50 seconds to finish syncing. + */ + if (option_mask32 & OPT_qq) { + option_mask32 &= ~OPT_qq; + alarm(50); + } nfds--; recv_and_process_peer_pkt(idx2peer[j]); gettime1900d(); /* sets G.cur_time */ } } + + check_unsync: + if (G.ntp_peers && G.stratum != MAXSTRAT) { + for (item = G.ntp_peers; item != NULL; item = item->link) { + peer_t *p = (peer_t *) item->data; + if (p->reachable_bits) + goto have_reachable_peer; + } + /* No peer responded for last 8 packets, panic */ + G.polladj_count = 0; + G.poll_exp = MINPOLL; + G.stratum = MAXSTRAT; + run_script("unsync", 0.0); + have_reachable_peer: ; + } } /* while (!bb_got_signal) */ + remove_pidfile(CONFIG_PID_FILE_PATH "/ntpd.pid"); kill_myself_with_sig(bb_got_signal); } @@ -2061,7 +2318,6 @@ int ntpd_main(int argc UNUSED_PARAM, char **argv) static double direct_freq(double fp_offset) { - #ifdef KERNEL_PLL /* * If the kernel is enabled, we need the residual offset to @@ -2084,7 +2340,7 @@ direct_freq(double fp_offset) } static void -set_freq(double freq) /* frequency update */ +set_freq(double freq) /* frequency update */ { char tbuf[80]; @@ -2176,14 +2432,13 @@ set_freq(double freq) /* frequency update */ if (pps_enable) { if (!(pll_status & STA_PPSTIME)) report_event(EVNT_KERN, - NULL, "PPS enabled"); + NULL, "PPS enabled"); ntv.status |= STA_PPSTIME | STA_PPSFREQ; } else { if (pll_status & STA_PPSTIME) report_event(EVNT_KERN, - NULL, "PPS disabled"); - ntv.status &= ~(STA_PPSTIME | - STA_PPSFREQ); + NULL, "PPS disabled"); + ntv.status &= ~(STA_PPSTIME | STA_PPSFREQ); } if (sys_leap == LEAP_ADDSECOND) ntv.status |= STA_INS; @@ -2199,7 +2454,7 @@ set_freq(double freq) /* frequency update */ if (ntp_adjtime(&ntv) == TIME_ERROR) { if (!(ntv.status & STA_PPSSIGNAL)) report_event(EVNT_KERN, NULL, - "PPS no signal"); + "PPS no signal"); } pll_status = ntv.status; #ifdef STA_NANO diff --git a/networking/ntpd_simple.c b/networking/ntpd_simple.c index 5e48306..3e7fc47 100644 --- a/networking/ntpd_simple.c +++ b/networking/ntpd_simple.c @@ -3,10 +3,11 @@ * * Author: Adam Tkac * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" #include /* For IPTOS_LOWDELAY definition */ +#include /* setpriority */ #ifndef IPTOS_LOWDELAY # define IPTOS_LOWDELAY 0x10 #endif @@ -377,7 +378,7 @@ step_time_once(double offset) bb_perror_msg_and_die("settimeofday"); tval = tv.tv_sec; - strftime(buf, sizeof(buf), "%a %b %e %H:%M:%S %Z %Y", localtime(&tval)); + strftime_YYYYMMDDHHMMSS(buf, sizeof(buf), &tval); bb_error_msg("setting clock to %s (offset %fs)", buf, offset); @@ -709,7 +710,7 @@ recv_and_process_client_pkt(void /*int fd*/) msg.m_status = G.synced ? G.leap : LI_ALARM; msg.m_status |= (query_status & VERSION_MASK); msg.m_status |= ((query_status & MODE_MASK) == MODE_CLIENT) ? - MODE_SERVER : MODE_SYM_PAS; + MODE_SERVER : MODE_SYM_PAS; msg.m_stratum = G.stratum; msg.m_ppoll = query_ppoll; msg.m_precision_exp = G_precision_exp; @@ -870,7 +871,7 @@ static NOINLINE void ntp_init(char **argv) int prec = 0; int b; # if 0 - struct timespec tp; + struct timespec tp; /* We can use sys_clock_getres but assuming 10ms tick should be fine */ clock_getres(CLOCK_REALTIME, &tp); tp.tv_sec = 0; diff --git a/networking/ping.c b/networking/ping.c index 6a766a4..5d71fe8 100644 --- a/networking/ping.c +++ b/networking/ping.c @@ -11,7 +11,7 @@ * This code is derived from software contributed to Berkeley by * Mike Muuss. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* from ping6.c: * Copyright (C) 1999 by Randolph Chung @@ -29,6 +29,109 @@ #include #include "libbb.h" +#ifdef __BIONIC__ +/* should be in netinet/ip_icmp.h */ +# define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +# define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +# define ICMP_REDIRECT 5 /* Redirect (change route) */ +# define ICMP_ECHO 8 /* Echo Request */ +# define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +# define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +# define ICMP_TIMESTAMP 13 /* Timestamp Request */ +# define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +# define ICMP_INFO_REQUEST 15 /* Information Request */ +# define ICMP_INFO_REPLY 16 /* Information Reply */ +# define ICMP_ADDRESS 17 /* Address Mask Request */ +# define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ +#endif + +//config:config PING +//config: bool "ping" +//config: default y +//config: select PLATFORM_LINUX +//config: help +//config: ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to +//config: elicit an ICMP ECHO_RESPONSE from a host or gateway. +//config: +//config:config PING6 +//config: bool "ping6" +//config: default y +//config: depends on FEATURE_IPV6 && PING +//config: help +//config: This will give you a ping that can talk IPv6. +//config: +//config:config FEATURE_FANCY_PING +//config: bool "Enable fancy ping output" +//config: default y +//config: depends on PING +//config: help +//config: Make the output from the ping applet include statistics, and at the +//config: same time provide full support for ICMP packets. + +/* Needs socket(AF_INET, SOCK_RAW, IPPROTO_ICMP), therefore BB_SUID_MAYBE: */ +//applet:IF_PING(APPLET(ping, BB_DIR_BIN, BB_SUID_MAYBE)) +//applet:IF_PING6(APPLET(ping6, BB_DIR_BIN, BB_SUID_MAYBE)) + +//kbuild:lib-$(CONFIG_PING) += ping.o +//kbuild:lib-$(CONFIG_PING6) += ping.o + +//usage:#if !ENABLE_FEATURE_FANCY_PING +//usage:# define ping_trivial_usage +//usage: "HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:# define ping6_trivial_usage +//usage: "HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts" +//usage:#else +//usage:# define ping_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: IF_PING6( +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: ) +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -t TTL Set TTL" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -W SEC Seconds to wait for the first response (default:10)" +//usage: "\n (after all -c CNT packets are sent)" +//usage: "\n -w SEC Seconds until ping exits (default:infinite)" +//usage: "\n (can exit earlier with -c CNT)" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:# define ping6_trivial_usage +//usage: "[OPTIONS] HOST" +//usage:# define ping6_full_usage "\n\n" +//usage: "Send ICMP ECHO_REQUEST packets to network hosts\n" +//usage: "\n -c CNT Send only CNT pings" +//usage: "\n -s SIZE Send SIZE data bytes in packets (default:56)" +//usage: "\n -I IFACE/IP Use interface or IP address as source" +//usage: "\n -q Quiet, only displays output at start" +//usage: "\n and when finished" +//usage: +//usage:#endif +//usage: +//usage:#define ping_example_usage +//usage: "$ ping localhost\n" +//usage: "PING slag (127.0.0.1): 56 data bytes\n" +//usage: "64 bytes from 127.0.0.1: icmp_seq=0 ttl=255 time=20.1 ms\n" +//usage: "\n" +//usage: "--- debian ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" +//usage:#define ping6_example_usage +//usage: "$ ping6 ip6-localhost\n" +//usage: "PING ip6-localhost (::1): 56 data bytes\n" +//usage: "64 bytes from ::1: icmp6_seq=0 ttl=64 time=20.1 ms\n" +//usage: "\n" +//usage: "--- ip6-localhost ping statistics ---\n" +//usage: "1 packets transmitted, 1 packets received, 0% packet loss\n" +//usage: "round-trip min/avg/max = 20.1/20.1/20.1 ms\n" + #if ENABLE_PING6 # include /* I see RENUMBERED constants in bits/in.h - !!? @@ -46,31 +149,44 @@ enum { MAX_DUP_CHK = (8 * 128), MAXWAIT = 10, PINGINTERVAL = 1, /* 1 second */ + pingsock = 0, }; -/* Common routines */ - -static int in_cksum(unsigned short *buf, int sz) +static void +#if ENABLE_PING6 +create_icmp_socket(len_and_sockaddr *lsa) +#else +create_icmp_socket(void) +#define create_icmp_socket(lsa) create_icmp_socket() +#endif { - int nleft = sz; - int sum = 0; - unsigned short *w = buf; - unsigned short ans = 0; - - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - if (nleft == 1) { - *(unsigned char *) (&ans) = *(unsigned char *) w; - sum += ans; + int sock; +#if ENABLE_PING6 + if (lsa->u.sa.sa_family == AF_INET6) + sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + else +#endif + sock = socket(AF_INET, SOCK_RAW, 1); /* 1 == ICMP */ + if (sock < 0) { + if (errno != EPERM) + bb_perror_msg_and_die(bb_msg_can_not_create_raw_socket); +#if defined(__linux__) || defined(__APPLE__) + /* We don't have root privileges. Try SOCK_DGRAM instead. + * Linux needs net.ipv4.ping_group_range for this to work. + * MacOSX allows ICMP_ECHO, ICMP_TSTAMP or ICMP_MASKREQ + */ +#if ENABLE_PING6 + if (lsa->u.sa.sa_family == AF_INET6) + sock = socket(AF_INET6, SOCK_DGRAM, IPPROTO_ICMPV6); + else +#endif + sock = socket(AF_INET, SOCK_DGRAM, 1); /* 1 == ICMP */ + if (sock < 0) +#endif + bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); } - sum = (sum >> 16) + (sum & 0xFFFF); - sum += (sum >> 16); - ans = ~sum; - return ans; + xmove_fd(sock, pingsock); } #if !ENABLE_FEATURE_FANCY_PING @@ -93,24 +209,26 @@ static void noresp(int ign UNUSED_PARAM) static void ping4(len_and_sockaddr *lsa) { struct icmp *pkt; - int pingsock, c; - - pingsock = create_icmp_socket(); + int c; pkt = (struct icmp *) G.packet; - memset(pkt, 0, sizeof(G.packet)); + /*memset(pkt, 0, sizeof(G.packet)); already is */ pkt->icmp_type = ICMP_ECHO; - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, sizeof(G.packet)); + pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, sizeof(G.packet)); xsendto(pingsock, G.packet, DEFDATALEN + ICMP_MINLEN, &lsa->u.sa, lsa->len); /* listen for replies */ while (1) { +#if 0 struct sockaddr_in from; socklen_t fromlen = sizeof(from); c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &fromlen); +#else + c = recv(pingsock, G.packet, sizeof(G.packet), 0); +#endif if (c < 0) { if (errno != EINTR) bb_perror_msg("recvfrom"); @@ -132,13 +250,11 @@ static void ping4(len_and_sockaddr *lsa) static void ping6(len_and_sockaddr *lsa) { struct icmp6_hdr *pkt; - int pingsock, c; + int c; int sockopt; - pingsock = create_icmp6_socket(); - pkt = (struct icmp6_hdr *) G.packet; - memset(pkt, 0, sizeof(G.packet)); + /*memset(pkt, 0, sizeof(G.packet)); already is */ pkt->icmp6_type = ICMP6_ECHO_REQUEST; sockopt = offsetof(struct icmp6_hdr, icmp6_cksum); @@ -148,18 +264,21 @@ static void ping6(len_and_sockaddr *lsa) /* listen for replies */ while (1) { +#if 0 struct sockaddr_in6 from; socklen_t fromlen = sizeof(from); c = recvfrom(pingsock, G.packet, sizeof(G.packet), 0, (struct sockaddr *) &from, &fromlen); +#else + c = recv(pingsock, G.packet, sizeof(G.packet), 0); +#endif if (c < 0) { if (errno != EINTR) bb_perror_msg("recvfrom"); continue; } - if (c >= ICMP_MINLEN) { /* icmp6_hdr */ - pkt = (struct icmp6_hdr *) G.packet; + if (c >= ICMP_MINLEN) { /* icmp6_hdr */ if (pkt->icmp6_type == ICMP6_ECHO_REPLY) break; } @@ -207,6 +326,7 @@ static int common_ping_main(sa_family_t af, char **argv) signal(SIGALRM, noresp); alarm(5); /* give the host 5000ms to respond */ + create_icmp_socket(lsa); #if ENABLE_PING6 if (lsa->u.sa.sa_family == AF_INET6) ping6(lsa); @@ -223,27 +343,29 @@ static int common_ping_main(sa_family_t af, char **argv) /* Full(er) version */ -#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6")) +#define OPT_STRING ("qvc:s:t:w:W:I:n4" IF_PING6("6")) enum { OPT_QUIET = 1 << 0, OPT_VERBOSE = 1 << 1, OPT_c = 1 << 2, OPT_s = 1 << 3, - OPT_w = 1 << 4, - OPT_W = 1 << 5, - OPT_I = 1 << 6, - OPT_IPV4 = 1 << 7, - OPT_IPV6 = (1 << 8) * ENABLE_PING6, + OPT_t = 1 << 4, + OPT_w = 1 << 5, + OPT_W = 1 << 6, + OPT_I = 1 << 7, + /*OPT_n = 1 << 8, - ignored */ + OPT_IPV4 = 1 << 9, + OPT_IPV6 = (1 << 10) * ENABLE_PING6, }; struct globals { - int pingsock; int if_index; char *str_I; len_and_sockaddr *source_lsa; unsigned datalen; unsigned pingcount; /* must be int-sized */ + unsigned opt_ttl; unsigned long ntransmitted, nreceived, nrepeats; uint16_t myid; unsigned tmin, tmax; /* in us */ @@ -263,18 +385,15 @@ struct globals { struct sockaddr_in6 sin6; #endif } pingaddr; - char rcvd_tbl[MAX_DUP_CHK / 8]; + unsigned char rcvd_tbl[MAX_DUP_CHK / 8]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define pingsock (G.pingsock ) #define if_index (G.if_index ) #define source_lsa (G.source_lsa ) #define str_I (G.str_I ) #define datalen (G.datalen ) -#define ntransmitted (G.ntransmitted) -#define nreceived (G.nreceived ) -#define nrepeats (G.nrepeats ) #define pingcount (G.pingcount ) +#define opt_ttl (G.opt_ttl ) #define myid (G.myid ) #define tmin (G.tmin ) #define tmax (G.tmax ) @@ -290,59 +409,65 @@ void BUG_ping_globals_too_big(void); #define INIT_G() do { \ if (sizeof(G) > COMMON_BUFSIZE) \ BUG_ping_globals_too_big(); \ - pingsock = -1; \ datalen = DEFDATALEN; \ timeout = MAXWAIT; \ tmin = UINT_MAX; \ } while (0) -#define A(bit) rcvd_tbl[(bit)>>3] /* identify byte in array */ -#define B(bit) (1 << ((bit) & 0x07)) /* identify bit in byte */ -#define SET(bit) (A(bit) |= B(bit)) -#define CLR(bit) (A(bit) &= (~B(bit))) -#define TST(bit) (A(bit) & B(bit)) - -/**************************************************************************/ +#define BYTE(bit) rcvd_tbl[(bit)>>3] +#define MASK(bit) (1 << ((bit) & 7)) +#define SET(bit) (BYTE(bit) |= MASK(bit)) +#define CLR(bit) (BYTE(bit) &= (~MASK(bit))) +#define TST(bit) (BYTE(bit) & MASK(bit)) static void print_stats_and_exit(int junk) NORETURN; static void print_stats_and_exit(int junk UNUSED_PARAM) { + unsigned long ul; + unsigned long nrecv; + signal(SIGINT, SIG_IGN); - printf("\n--- %s ping statistics ---\n", hostname); - printf("%lu packets transmitted, ", ntransmitted); - printf("%lu packets received, ", nreceived); - if (nrepeats) - printf("%lu duplicates, ", nrepeats); - if (ntransmitted) - ntransmitted = (ntransmitted - nreceived) * 100 / ntransmitted; - printf("%lu%% packet loss\n", ntransmitted); + nrecv = G.nreceived; + printf("\n--- %s ping statistics ---\n" + "%lu packets transmitted, " + "%lu packets received, ", + hostname, G.ntransmitted, nrecv + ); + if (G.nrepeats) + printf("%lu duplicates, ", G.nrepeats); + ul = G.ntransmitted; + if (ul != 0) + ul = (ul - nrecv) * 100 / ul; + printf("%lu%% packet loss\n", ul); if (tmin != UINT_MAX) { - unsigned tavg = tsum / (nreceived + nrepeats); + unsigned tavg = tsum / (nrecv + G.nrepeats); printf("round-trip min/avg/max = %u.%03u/%u.%03u/%u.%03u ms\n", tmin / 1000, tmin % 1000, tavg / 1000, tavg % 1000, tmax / 1000, tmax % 1000); } /* if condition is true, exit with 1 -- 'failure' */ - exit(nreceived == 0 || (deadline && nreceived < pingcount)); + exit(nrecv == 0 || (deadline && nrecv < pingcount)); } -static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) +static void sendping_tail(void (*sp)(int), int size_pkt) { int sz; - CLR((uint16_t)ntransmitted % MAX_DUP_CHK); - ntransmitted++; + CLR((uint16_t)G.ntransmitted % MAX_DUP_CHK); + G.ntransmitted++; + + size_pkt += datalen; /* sizeof(pingaddr) can be larger than real sa size, but I think * it doesn't matter */ - sz = xsendto(pingsock, pkt, size_pkt, &pingaddr.sa, sizeof(pingaddr)); + sz = xsendto(pingsock, G.snd_packet, size_pkt, &pingaddr.sa, sizeof(pingaddr)); if (sz != size_pkt) bb_error_msg_and_die(bb_msg_write_error); - if (pingcount == 0 || deadline || ntransmitted < pingcount) { + if (pingcount == 0 || deadline || G.ntransmitted < pingcount) { /* Didn't send all pings yet - schedule next in 1s */ signal(SIGALRM, sp); if (deadline) { @@ -358,7 +483,7 @@ static void sendping_tail(void (*sp)(int), const void *pkt, int size_pkt) * otherwise ping waits for two RTTs. */ unsigned expire = timeout; - if (nreceived) { + if (G.nreceived) { /* approx. 2*tmax, in seconds (2 RTT) */ expire = tmax / (512*1024); if (expire == 0) @@ -377,7 +502,7 @@ static void sendping4(int junk UNUSED_PARAM) pkt->icmp_type = ICMP_ECHO; /*pkt->icmp_code = 0;*/ pkt->icmp_cksum = 0; /* cksum is calculated with this field set to 0 */ - pkt->icmp_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ + pkt->icmp_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp_id = myid; /* If datalen < 4, we store timestamp _past_ the packet, @@ -387,28 +512,28 @@ static void sendping4(int junk UNUSED_PARAM) /* No hton: we'll read it back on the same machine */ *(uint32_t*)&pkt->icmp_dun = monotonic_us(); - pkt->icmp_cksum = in_cksum((unsigned short *) pkt, datalen + ICMP_MINLEN); + pkt->icmp_cksum = inet_cksum((uint16_t *) pkt, datalen + ICMP_MINLEN); - sendping_tail(sendping4, pkt, datalen + ICMP_MINLEN); + sendping_tail(sendping4, ICMP_MINLEN); } #if ENABLE_PING6 static void sendping6(int junk UNUSED_PARAM) { - struct icmp6_hdr *pkt = alloca(datalen + sizeof(struct icmp6_hdr) + 4); + struct icmp6_hdr *pkt = G.snd_packet; //memset(pkt, 0, datalen + sizeof(struct icmp6_hdr) + 4); pkt->icmp6_type = ICMP6_ECHO_REQUEST; /*pkt->icmp6_code = 0;*/ /*pkt->icmp6_cksum = 0;*/ - pkt->icmp6_seq = htons(ntransmitted); /* don't ++ here, it can be a macro */ + pkt->icmp6_seq = htons(G.ntransmitted); /* don't ++ here, it can be a macro */ pkt->icmp6_id = myid; /*if (datalen >= 4)*/ - *(uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); + *(bb__aliased_uint32_t*)(&pkt->icmp6_data8[4]) = monotonic_us(); - //TODO? pkt->icmp_cksum = in_cksum(...); + //TODO? pkt->icmp_cksum = inet_cksum(...); - sendping_tail(sendping6, pkt, datalen + sizeof(struct icmp6_hdr)); + sendping_tail(sendping6, sizeof(struct icmp6_hdr)); } #endif @@ -464,11 +589,10 @@ static void unpack_tail(int sz, uint32_t *tp, const char *from_str, uint16_t recv_seq, int ttl) { + unsigned char *b, m; const char *dupmsg = " (DUP!)"; unsigned triptime = triptime; /* for gcc */ - ++nreceived; - if (tp) { /* (int32_t) cast is for hypothetical 64-bit unsigned */ /* (doesn't hurt 32-bit real-world anyway) */ @@ -480,11 +604,15 @@ static void unpack_tail(int sz, uint32_t *tp, tmax = triptime; } - if (TST(recv_seq % MAX_DUP_CHK)) { - ++nrepeats; - --nreceived; + b = &BYTE(recv_seq % MAX_DUP_CHK); + m = MASK(recv_seq % MAX_DUP_CHK); + /*if TST(recv_seq % MAX_DUP_CHK):*/ + if (*b & m) { + ++G.nrepeats; } else { - SET(recv_seq % MAX_DUP_CHK); + /*SET(recv_seq % MAX_DUP_CHK):*/ + *b |= m; + ++G.nreceived; dupmsg += 7; } @@ -532,7 +660,7 @@ static void unpack4(char *buf, int sz, struct sockaddr_in *from) } } #if ENABLE_PING6 -static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hoplimit) +static void unpack6(char *packet, int sz, struct sockaddr_in6 *from, int hoplimit) { struct icmp6_hdr *icmppkt; char buf[INET6_ADDRSTRLEN]; @@ -552,7 +680,7 @@ static void unpack6(char *packet, int sz, /*struct sockaddr_in6 *from,*/ int hop if (sz >= sizeof(struct icmp6_hdr) + sizeof(uint32_t)) tp = (uint32_t *) &icmppkt->icmp6_data8[4]; unpack_tail(sz, tp, - inet_ntop(AF_INET6, &pingaddr.sin6.sin6_addr, + inet_ntop(AF_INET6, &from->sin6_addr, buf, sizeof(buf)), recv_seq, hoplimit); } else if (icmppkt->icmp6_type != ICMP6_ECHO_REQUEST) { @@ -567,7 +695,6 @@ static void ping4(len_and_sockaddr *lsa) { int sockopt; - pingsock = create_icmp_socket(); pingaddr.sin = lsa->u.sin; if (source_lsa) { if (setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_IF, @@ -575,8 +702,6 @@ static void ping4(len_and_sockaddr *lsa) bb_error_msg_and_die("can't set multicast source interface"); xbind(pingsock, &source_lsa->u.sa, source_lsa->len); } - if (str_I) - setsockopt_bindtodevice(pingsock, str_I); /* enable broadcast pings */ setsockopt_broadcast(pingsock); @@ -586,6 +711,12 @@ static void ping4(len_and_sockaddr *lsa) sockopt = (datalen * 2) + 7 * 1024; /* giving it a bit of extra room */ setsockopt(pingsock, SOL_SOCKET, SO_RCVBUF, &sockopt, sizeof(sockopt)); + if (opt_ttl != 0) { + setsockopt(pingsock, IPPROTO_IP, IP_TTL, &opt_ttl, sizeof(opt_ttl)); + /* above doesnt affect packets sent to bcast IP, so... */ + setsockopt(pingsock, IPPROTO_IP, IP_MULTICAST_TTL, &opt_ttl, sizeof(opt_ttl)); + } + signal(SIGINT, print_stats_and_exit); /* start the ping's going ... */ @@ -605,7 +736,7 @@ static void ping4(len_and_sockaddr *lsa) continue; } unpack4(G.rcv_packet, c, &from); - if (pingcount && nreceived >= pingcount) + if (pingcount && G.nreceived >= pingcount) break; } } @@ -619,13 +750,9 @@ static void ping6(len_and_sockaddr *lsa) struct iovec iov; char control_buf[CMSG_SPACE(36)]; - pingsock = create_icmp6_socket(); pingaddr.sin6 = lsa->u.sin6; - /* untested whether "-I addr" really works for IPv6: */ if (source_lsa) xbind(pingsock, &source_lsa->u.sa, source_lsa->len); - if (str_I) - setsockopt_bindtodevice(pingsock, str_I); #ifdef ICMP6_FILTER { @@ -637,7 +764,7 @@ static void ping6(len_and_sockaddr *lsa) ICMP6_FILTER_SETPASSALL(&filt); } if (setsockopt(pingsock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, - sizeof(filt)) < 0) + sizeof(filt)) < 0) bb_error_msg_and_die("setsockopt(ICMP6_FILTER)"); } #endif /*ICMP6_FILTER*/ @@ -696,8 +823,8 @@ static void ping6(len_and_sockaddr *lsa) move_from_unaligned_int(hoplimit, CMSG_DATA(mp)); } } - unpack6(G.rcv_packet, c, /*&from,*/ hoplimit); - if (pingcount && nreceived >= pingcount) + unpack6(G.rcv_packet, c, &from, hoplimit); + if (pingcount && G.nreceived >= pingcount) break; } } @@ -712,6 +839,11 @@ static void ping(len_and_sockaddr *lsa) } printf(": %d data bytes\n", datalen); + create_icmp_socket(lsa); + /* untested whether "-I addr" really works for IPv6: */ + if (str_I) + setsockopt_bindtodevice(pingsock, str_I); + G.sizeof_rcv_packet = datalen + MAXIPLEN + MAXICMPLEN; G.rcv_packet = xzalloc(G.sizeof_rcv_packet); #if ENABLE_PING6 @@ -735,9 +867,9 @@ static int common_ping_main(int opt, char **argv) INIT_G(); - /* exactly one argument needed; -v and -q don't mix; -c NUM, -w NUM, -W NUM */ - opt_complementary = "=1:q--v:v--q:c+:w+:W+"; - opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &deadline, &timeout, &str_I); + /* exactly one argument needed; -v and -q don't mix; -c NUM, -t NUM, -w NUM, -W NUM */ + opt_complementary = "=1:q--v:v--q:c+:t+:w+:W+"; + opt |= getopt32(argv, OPT_STRING, &pingcount, &str_s, &opt_ttl, &deadline, &timeout, &str_I); if (opt & OPT_s) datalen = xatou16(str_s); // -s if (opt & OPT_I) { // -I diff --git a/networking/pscan.c b/networking/pscan.c index 5fb6af0..72ed8cd 100644 --- a/networking/pscan.c +++ b/networking/pscan.c @@ -3,9 +3,20 @@ * * Copyright 2007 Tito Ragusa * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define pscan_trivial_usage +//usage: "[-cb] [-p MIN_PORT] [-P MAX_PORT] [-t TIMEOUT] [-T MIN_RTT] HOST" +//usage:#define pscan_full_usage "\n\n" +//usage: "Scan a host, print all open ports\n" +//usage: "\n -c Show closed ports too" +//usage: "\n -b Show blocked ports too" +//usage: "\n -p Scan from this port (default 1)" +//usage: "\n -P Scan up to this port (default 1024)" +//usage: "\n -t Timeout (default 5000 ms)" +//usage: "\n -T Minimum rtt (default 5 ms, increase for congested hosts)" + #include "libbb.h" /* debugging */ @@ -76,7 +87,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv) DMSG("rtt %u", rtt_4); /* The SOCK_STREAM socket type is implemented on the TCP/IP protocol. */ - set_nport(lsap, htons(port)); + set_nport(&lsap->u.sa, htons(port)); s = xsocket(lsap->u.sa.sa_family, SOCK_STREAM, 0); /* We need unblocking socket so we don't need to wait for ETIMEOUT. */ /* Nonblocking connect typically "fails" with errno == EINPROGRESS */ @@ -146,7 +157,7 @@ int pscan_main(int argc UNUSED_PARAM, char **argv) } if (ENABLE_FEATURE_CLEAN_UP) free(lsap); - printf("%d closed, %d open, %d timed out (or blocked) ports\n", + printf("%u closed, %u open, %u timed out (or blocked) ports\n", closed_ports, open_ports, nports - (closed_ports + open_ports)); diff --git a/networking/route.c b/networking/route.c index a319962..4235ea7 100644 --- a/networking/route.c +++ b/networking/route.c @@ -10,7 +10,7 @@ * Fred N. van Kempen, * (derived from FvK's 'route.c 1.70 01/04/94') * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * * displayroute() code added by Vladimir N. Oleynik @@ -25,6 +25,14 @@ * remove ridiculous amounts of bloat. */ +//usage:#define route_trivial_usage +//usage: "[{add|del|delete}]" +//usage:#define route_full_usage "\n\n" +//usage: "Edit kernel routing tables\n" +//usage: "\n -n Don't resolve names" +//usage: "\n -e Display other/more information" +//usage: "\n -A inet" IF_FEATURE_IPV6("{6}") " Select address family" + #include #include @@ -153,7 +161,10 @@ static int kw_lookup(const char *kwtbl, char ***pargs) static NOINLINE void INET_setroute(int action, char **args) { - struct rtentry rt; + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char rt_buf[sizeof(struct rtentry)]; + struct rtentry *const rt = (void *)rt_buf; + const char *netmask = NULL; int skfd, isnet, xflag; @@ -166,7 +177,7 @@ static NOINLINE void INET_setroute(int action, char **args) } /* Clean out the RTREQ structure. */ - memset(&rt, 0, sizeof(rt)); + memset(rt, 0, sizeof(*rt)); { const char *target = *args++; @@ -178,17 +189,17 @@ static NOINLINE void INET_setroute(int action, char **args) int prefix_len; prefix_len = xatoul_range(prefix+1, 0, 32); - mask_in_addr(rt) = htonl( ~(0xffffffffUL >> prefix_len)); + mask_in_addr(*rt) = htonl( ~(0xffffffffUL >> prefix_len)); *prefix = '\0'; #if HAVE_NEW_ADDRT - rt.rt_genmask.sa_family = AF_INET; + rt->rt_genmask.sa_family = AF_INET; #endif } else { /* Default netmask. */ - netmask = bb_str_default; + netmask = "default"; } /* Prefer hostname lookup is -host flag (xflag==1) was given. */ - isnet = INET_resolve(target, (struct sockaddr_in *) &rt.rt_dst, + isnet = INET_resolve(target, (struct sockaddr_in *) &rt->rt_dst, (xflag & HOST_FLAG)); if (isnet < 0) { bb_error_msg_and_die("resolving %s", target); @@ -204,20 +215,20 @@ static NOINLINE void INET_setroute(int action, char **args) } /* Fill in the other fields. */ - rt.rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST)); + rt->rt_flags = ((isnet) ? RTF_UP : (RTF_UP | RTF_HOST)); while (*args) { int k = kw_lookup(tbl_ipvx, &args); const char *args_m1 = args[-1]; if (k & KW_IPVx_FLAG_ONLY) { - rt.rt_flags |= flags_ipvx[k & 3]; + rt->rt_flags |= flags_ipvx[k & 3]; continue; } #if HAVE_NEW_ADDRT if (k == KW_IPVx_METRIC) { - rt.rt_metric = xatoul(args_m1) + 1; + rt->rt_metric = xatoul(args_m1) + 1; continue; } #endif @@ -225,7 +236,7 @@ static NOINLINE void INET_setroute(int action, char **args) if (k == KW_IPVx_NETMASK) { struct sockaddr mask; - if (mask_in_addr(rt)) { + if (mask_in_addr(*rt)) { bb_show_usage(); } @@ -234,18 +245,18 @@ static NOINLINE void INET_setroute(int action, char **args) if (isnet < 0) { bb_error_msg_and_die("resolving %s", netmask); } - rt.rt_genmask = full_mask(mask); + rt->rt_genmask = full_mask(mask); continue; } if (k == KW_IPVx_GATEWAY) { - if (rt.rt_flags & RTF_GATEWAY) { + if (rt->rt_flags & RTF_GATEWAY) { bb_show_usage(); } isnet = INET_resolve(args_m1, - (struct sockaddr_in *) &rt.rt_gateway, 1); - rt.rt_flags |= RTF_GATEWAY; + (struct sockaddr_in *) &rt->rt_gateway, 1); + rt->rt_flags |= RTF_GATEWAY; if (isnet) { if (isnet < 0) { @@ -257,24 +268,24 @@ static NOINLINE void INET_setroute(int action, char **args) } if (k == KW_IPVx_MSS) { /* Check valid MSS bounds. */ - rt.rt_flags |= RTF_MSS; - rt.rt_mss = xatoul_range(args_m1, 64, 32768); + rt->rt_flags |= RTF_MSS; + rt->rt_mss = xatoul_range(args_m1, 64, 32768); continue; } if (k == KW_IPVx_WINDOW) { /* Check valid window bounds. */ - rt.rt_flags |= RTF_WINDOW; - rt.rt_window = xatoul_range(args_m1, 128, INT_MAX); + rt->rt_flags |= RTF_WINDOW; + rt->rt_window = xatoul_range(args_m1, 128, INT_MAX); continue; } #ifdef RTF_IRTT if (k == KW_IPVx_IRTT) { - rt.rt_flags |= RTF_IRTT; - rt.rt_irtt = xatoul(args_m1); - rt.rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ + rt->rt_flags |= RTF_IRTT; + rt->rt_irtt = xatoul(args_m1); + rt->rt_irtt *= (sysconf(_SC_CLK_TCK) / 100); /* FIXME */ #if 0 /* FIXME: do we need to check anything of this? */ - if (rt.rt_irtt < 1 || rt.rt_irtt > (120 * HZ)) { + if (rt->rt_irtt < 1 || rt->rt_irtt > (120 * HZ)) { bb_error_msg_and_die("bad irtt"); } #endif @@ -284,9 +295,9 @@ static NOINLINE void INET_setroute(int action, char **args) /* Device is special in that it can be the last arg specified * and doesn't requre the dev/device keyword in that case. */ - if (!rt.rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { + if (!rt->rt_dev && ((k == KW_IPVx_DEVICE) || (!k && !*++args))) { /* Don't use args_m1 here since args may have changed! */ - rt.rt_dev = args[-1]; + rt->rt_dev = args[-1]; continue; } @@ -295,41 +306,41 @@ static NOINLINE void INET_setroute(int action, char **args) } #ifdef RTF_REJECT - if ((rt.rt_flags & RTF_REJECT) && !rt.rt_dev) { - rt.rt_dev = (char*)"lo"; + if ((rt->rt_flags & RTF_REJECT) && !rt->rt_dev) { + rt->rt_dev = (char*)"lo"; } #endif /* sanity checks.. */ - if (mask_in_addr(rt)) { - uint32_t mask = mask_in_addr(rt); + if (mask_in_addr(*rt)) { + uint32_t mask = mask_in_addr(*rt); mask = ~ntohl(mask); - if ((rt.rt_flags & RTF_HOST) && mask != 0xffffffff) { + if ((rt->rt_flags & RTF_HOST) && mask != 0xffffffff) { bb_error_msg_and_die("netmask %.8x and host route conflict", (unsigned int) mask); } if (mask & (mask + 1)) { bb_error_msg_and_die("bogus netmask %s", netmask); } - mask = ((struct sockaddr_in *) &rt.rt_dst)->sin_addr.s_addr; - if (mask & ~(uint32_t)mask_in_addr(rt)) { + mask = ((struct sockaddr_in *) &rt->rt_dst)->sin_addr.s_addr; + if (mask & ~(uint32_t)mask_in_addr(*rt)) { bb_error_msg_and_die("netmask and route address conflict"); } } /* Fill out netmask if still unset */ - if ((action == RTACTION_ADD) && (rt.rt_flags & RTF_HOST)) { - mask_in_addr(rt) = 0xffffffff; + if ((action == RTACTION_ADD) && (rt->rt_flags & RTF_HOST)) { + mask_in_addr(*rt) = 0xffffffff; } /* Create a socket to the INET kernel. */ skfd = xsocket(AF_INET, SOCK_DGRAM, 0); if (action == RTACTION_ADD) - xioctl(skfd, SIOCADDRT, &rt); + xioctl(skfd, SIOCADDRT, rt); else - xioctl(skfd, SIOCDELRT, &rt); + xioctl(skfd, SIOCDELRT, rt); if (ENABLE_FEATURE_CLEAN_UP) close(skfd); } @@ -346,7 +357,7 @@ static NOINLINE void INET6_setroute(int action, char **args) /* We know args isn't NULL from the check in route_main. */ const char *target = *args++; - if (strcmp(target, bb_str_default) == 0) { + if (strcmp(target, "default") == 0) { prefix_len = 0; memset(&sa6, 0, sizeof(sa6)); } else { @@ -398,7 +409,7 @@ static NOINLINE void INET6_setroute(int action, char **args) bb_error_msg_and_die("resolving %s", args_m1); } memcpy(&rt.rtmsg_gateway, sa6.sin6_addr.s6_addr, - sizeof(struct in6_addr)); + sizeof(struct in6_addr)); rt.rtmsg_flags |= RTF_GATEWAY; continue; } @@ -424,7 +435,7 @@ static NOINLINE void INET6_setroute(int action, char **args) struct ifreq ifr; memset(&ifr, 0, sizeof(ifr)); strncpy_IFNAMSIZ(ifr.ifr_name, devname); - xioctl(skfd, SIOGIFINDEX, &ifr); + xioctl(skfd, SIOCGIFINDEX, &ifr); rt.rtmsg_ifindex = ifr.ifr_ifindex; } @@ -487,17 +498,17 @@ void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt) FILE *fp = xfopen_for_read("/proc/net/route"); printf("Kernel IP routing table\n" - "Destination Gateway Genmask Flags %s Iface\n", + "Destination Gateway Genmask Flags %s Iface\n", netstatfmt ? " MSS Window irtt" : "Metric Ref Use"); if (fscanf(fp, "%*[^\n]\n") < 0) { /* Skip the first line. */ - goto ERROR; /* Empty or missing line, or read error. */ + goto ERROR; /* Empty or missing line, or read error. */ } while (1) { int r; r = fscanf(fp, "%63s%lx%lx%X%d%d%d%lx%d%d%d\n", - devname, &d, &g, &flgs, &ref, &use, &metric, &m, - &mtu, &win, &ir); + devname, &d, &g, &flgs, &ref, &use, &metric, &m, + &mtu, &win, &ir); if (r != 11) { if ((r < 0) && feof(fp)) { /* EOF with no (nonspace) chars read. */ break; @@ -534,6 +545,7 @@ void FAST_FUNC bb_displayroutes(int noresolve, int netstatfmt) printf("%-6d %-2d %7d %s\n", metric, ref, use, devname); } } + fclose(fp); } #if ENABLE_FEATURE_IPV6 @@ -555,8 +567,8 @@ static void INET6_displayroutes(void) FILE *fp = xfopen_for_read("/proc/net/ipv6_route"); printf("Kernel IPv6 routing table\n%-44s%-40s" - "Flags Metric Ref Use Iface\n", - "Destination", "Next Hop"); + "Flags Metric Ref Use Iface\n", + "Destination", "Next Hop"); while (1) { int r; @@ -601,13 +613,13 @@ static void INET6_displayroutes(void) set_flags(flags, (iflags & IPV6_MASK)); r = 0; - do { + while (1) { inet_pton(AF_INET6, addr6x + r, (struct sockaddr *) &snaddr6.sin6_addr); snaddr6.sin6_family = AF_INET6; naddr6 = INET6_rresolve((struct sockaddr_in6 *) &snaddr6, - 0x0fff /* Apparently, upstream never resolves. */ - ); + 0x0fff /* Apparently, upstream never resolves. */ + ); if (!r) { /* 1st pass */ snprintf(addr6, sizeof(addr6), "%s/%d", naddr6, prefix_len); @@ -620,8 +632,9 @@ static void INET6_displayroutes(void) free(naddr6); break; } - } while (1); + } } + fclose(fp); } #endif diff --git a/networking/slattach.c b/networking/slattach.c index 12a3067..a500da6 100644 --- a/networking/slattach.c +++ b/networking/slattach.c @@ -4,7 +4,7 @@ * * Author: Ignacio Garcia Perez (iggarpe at gmail dot com) * - * License: GPLv2 or later, see LICENSE file in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * There are some differences from the standard net-tools slattach: * @@ -13,6 +13,19 @@ * - The -F options allows disabling of RTS/CTS flow control. */ +//usage:#define slattach_trivial_usage +//usage: "[-cehmLF] [-s SPEED] [-p PROTOCOL] DEVICE" +//usage:#define slattach_full_usage "\n\n" +//usage: "Attach network interface(s) to serial line(s)\n" +//usage: "\n -p PROT Set protocol (slip, cslip, slip6, clisp6 or adaptive)" +//usage: "\n -s SPD Set line speed" +//usage: "\n -e Exit after initializing device" +//usage: "\n -h Exit when the carrier is lost" +//usage: "\n -c PROG Run PROG when the line is hung up" +//usage: "\n -m Do NOT initialize the line in raw 8 bits mode" +//usage: "\n -L Enable 3-wire operation" +//usage: "\n -F Disable RTS/CTS flow control" + #include "libbb.h" #include "libiproute/utils.h" /* invarg() */ @@ -134,9 +147,9 @@ int slattach_main(int argc UNUSED_PARAM, char **argv) int i, encap, opt; struct termios state; const char *proto = "cslip"; - const char *extcmd; /* Command to execute after hangup */ + const char *extcmd; /* Command to execute after hangup */ const char *baud_str; - int baud_code = -1; /* Line baud rate (system code) */ + int baud_code = -1; /* Line baud rate (system code) */ enum { OPT_p_proto = 1 << 0, diff --git a/networking/tc.c b/networking/tc.c index 6a5a850..533f7c0 100644 --- a/networking/tc.c +++ b/networking/tc.c @@ -1,14 +1,33 @@ /* vi: set sw=4 ts=4: */ /* - * tc.c "tc" utility frontend. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. - * - * Authors: Alexey Kuznetsov, + * Authors: Alexey Kuznetsov, * * Bernhard Reutner-Fischer adjusted for busybox */ +//usage:#define tc_trivial_usage +/* //usage: "[OPTIONS] OBJECT CMD [dev STRING]" */ +//usage: "OBJECT CMD [dev STRING]" +//usage:#define tc_full_usage "\n\n" +//usage: "OBJECT: {qdisc|class|filter}\n" +//usage: "CMD: {add|del|change|replace|show}\n" +//usage: "\n" +//usage: "qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" +/* //usage: "[ estimator INTERVAL TIME_CONSTANT ]\n" */ +//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" +//usage: " QDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" +//usage: "qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n" +//usage: "class [ classid CLASSID ] [ root | parent CLASSID ]\n" +//usage: " [ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" +//usage: "class show [ dev STRING ] [ root | parent CLASSID ]\n" +//usage: "filter [ pref PRIO ] [ protocol PROTO ]\n" +/* //usage: "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ +//usage: " [ root | classid CLASSID ] [ handle FILTERID ]\n" +//usage: " [ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" +//usage: "filter show [ dev STRING ] [ root | parent CLASSID ]" + #include "libbb.h" #include "libiproute/utils.h" @@ -39,23 +58,21 @@ struct globals { int filter_ifindex; - __u32 filter_qdisc; - __u32 filter_parent; - __u32 filter_prio; - __u32 filter_proto; + uint32_t filter_qdisc; + uint32_t filter_parent; + uint32_t filter_prio; + uint32_t filter_proto; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) +struct BUG_G_too_big { + char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; +}; #define filter_ifindex (G.filter_ifindex) #define filter_qdisc (G.filter_qdisc) #define filter_parent (G.filter_parent) #define filter_prio (G.filter_prio) #define filter_proto (G.filter_proto) - -void BUG_tc_globals_too_big(void); -#define INIT_G() do { \ - if (sizeof(G) > COMMON_BUFSIZE) \ - BUG_tc_globals_too_big(); \ -} while (0) +#define INIT_G() do { } while (0) /* Allocates a buffer containing the name of a class id. * The caller must free the returned memory. */ @@ -77,8 +94,8 @@ static char* print_tc_classid(uint32_t cid) } /* Get a qdisc handle. Return 0 on success, !0 otherwise. */ -static int get_qdisc_handle(__u32 *h, const char *str) { - __u32 maj; +static int get_qdisc_handle(uint32_t *h, const char *str) { + uint32_t maj; char *p; maj = TC_H_UNSPEC; @@ -96,8 +113,8 @@ static int get_qdisc_handle(__u32 *h, const char *str) { } /* Get class ID. Return 0 on success, !0 otherwise. */ -static int get_tc_classid(__u32 *h, const char *str) { - __u32 maj, min; +static int get_tc_classid(uint32_t *h, const char *str) { + uint32_t maj, min; char *p; maj = TC_H_ROOT; @@ -374,7 +391,7 @@ static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, printf("root "); else if (msg->tcm_parent) { classid = print_tc_classid(filter_qdisc ? - TC_H_MIN(msg->tcm_parent) : msg->tcm_parent); + TC_H_MIN(msg->tcm_parent) : msg->tcm_parent); printf("parent %s ", classid); if (ENABLE_FEATURE_CLEAN_UP) free(classid); @@ -401,9 +418,6 @@ static int print_class(const struct sockaddr_nl *who UNUSED_PARAM, static int print_filter(const struct sockaddr_nl *who UNUSED_PARAM, struct nlmsghdr *hdr, void *arg UNUSED_PARAM) { - struct tcmsg *msg = NLMSG_DATA(hdr); - int len = hdr->nlmsg_len; - struct rtattr * tb[TCA_MAX+1]; return 0; } @@ -496,7 +510,7 @@ int tc_main(int argc UNUSED_PARAM, char **argv) if (obj == OBJ_filter) filter_parent = TC_H_ROOT; } else if (arg == ARG_parent) { - __u32 handle; + uint32_t handle; if (msg.tcm_parent) duparg(*argv, "parent"); if (get_tc_classid(&handle, *argv)) @@ -509,11 +523,12 @@ int tc_main(int argc UNUSED_PARAM, char **argv) duparg(*argv, "handle"); /* reject LONG_MIN || LONG_MAX */ /* TODO: for fw - if ((slash = strchr(handle, '/')) != NULL) + slash = strchr(handle, '/'); + if (slash != NULL) *slash = '\0'; */ msg.tcm_handle = get_u32(*argv, "handle"); - /* if (slash) {if (get_u32(__u32 &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ + /* if (slash) {if (get_u32(uint32_t &mask, slash+1, NULL)) inv mask; addattr32(n, MAX_MSG, TCA_FW_MASK, mask); */ } else if (arg == ARG_classid && obj == OBJ_class && cmd == CMD_change){ } else if (arg == ARG_pref || arg == ARG_prio) { /* filter::list */ if (filter_prio) diff --git a/networking/tcpudp.c b/networking/tcpudp.c index 53e622b..3df6a98 100644 --- a/networking/tcpudp.c +++ b/networking/tcpudp.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* Based on ipsvd-0.12.1. This tcpsvd accepts all options @@ -29,10 +29,50 @@ * - don't know how to retrieve ORIGDST for udp. */ +//usage:#define tcpsvd_trivial_usage +//usage: "[-hEv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] IP PORT PROG" +/* with not-implemented options: */ +/* //usage: "[-hpEvv] [-c N] [-C N[:MSG]] [-b N] [-u USER] [-l NAME] [-i DIR|-x CDB] [-t SEC] IP PORT PROG" */ +//usage:#define tcpsvd_full_usage "\n\n" +//usage: "Create TCP socket, bind to IP:PORT and listen\n" +//usage: "for incoming connection. Run PROG for each connection.\n" +//usage: "\n IP IP to listen on, 0 = all" +//usage: "\n PORT Port to listen on" +//usage: "\n PROG ARGS Program to run" +//usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" +//usage: "\n -u USER[:GRP] Change to user/group after bind" +//usage: "\n -c N Handle up to N connections simultaneously" +//usage: "\n -b N Allow a backlog of approximately N TCP SYNs" +//usage: "\n -C N[:MSG] Allow only up to N connections from the same IP" +//usage: "\n New connections from this IP address are closed" +//usage: "\n immediately. MSG is written to the peer before close" +//usage: "\n -h Look up peer's hostname" +//usage: "\n -E Don't set up environment variables" +//usage: "\n -v Verbose" +//usage: +//usage:#define udpsvd_trivial_usage +//usage: "[-hEv] [-c N] [-u USER] [-l NAME] IP PORT PROG" +//usage:#define udpsvd_full_usage "\n\n" +//usage: "Create UDP socket, bind to IP:PORT and wait\n" +//usage: "for incoming packets. Run PROG for each packet,\n" +//usage: "redirecting all further packets with same peer ip:port to it.\n" +//usage: "\n IP IP to listen on, 0 = all" +//usage: "\n PORT Port to listen on" +//usage: "\n PROG ARGS Program to run" +//usage: "\n -l NAME Local hostname (else looks up local hostname in DNS)" +//usage: "\n -u USER[:GRP] Change to user/group after bind" +//usage: "\n -c N Handle up to N connections simultaneously" +//usage: "\n -h Look up peer's hostname" +//usage: "\n -E Don't set up environment variables" +//usage: "\n -v Verbose" + #include "libbb.h" + /* Wants etc, thus included after libbb.h: */ +#ifdef __linux__ #include /* for __be32 etc */ #include +#endif // TODO: move into this file: #include "tcpudp_perhost.h" @@ -384,7 +424,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) * already bound in parent! This seems to work in Linux. * (otherwise we can move socket to fd #0 only if bind succeeds) */ close(0); - set_nport(localp, htons(local_port)); + set_nport(&localp->u.sa, htons(local_port)); xmove_fd(xsocket(localp->u.sa.sa_family, SOCK_DGRAM, 0), 0); setsockopt_reuseaddr(0); /* crucial */ xbind(0, &localp->u.sa, localp->len); @@ -464,6 +504,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) /* setup ucspi env */ const char *proto = tcp ? "TCP" : "UDP"; +#ifdef SO_ORIGINAL_DST /* Extract "original" destination addr:port * from Linux firewall. Useful when you redirect * an outbond connection to local handler, and it needs @@ -473,6 +514,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) xsetenv_plain("TCPORIGDSTADDR", addr); free(addr); } +#endif xsetenv_plain("PROTO", proto); xsetenv_proto(proto, "LOCALADDR", local_addr); xsetenv_proto(proto, "REMOTEADDR", remote_addr); diff --git a/networking/tcpudp_perhost.c b/networking/tcpudp_perhost.c index 3005f12..1054108 100644 --- a/networking/tcpudp_perhost.c +++ b/networking/tcpudp_perhost.c @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" diff --git a/networking/tcpudp_perhost.h b/networking/tcpudp_perhost.h index d370036..3e57576 100644 --- a/networking/tcpudp_perhost.h +++ b/networking/tcpudp_perhost.h @@ -4,7 +4,7 @@ * * Copyright (C) 2007 Denys Vlasenko. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN diff --git a/networking/telnet.c b/networking/telnet.c index 57997f6..a255797 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -8,7 +8,7 @@ * Created: Thu Apr 7 13:29:41 1994 too * Last modified: Fri Jun 9 14:34:24 2000 too * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * HISTORY * Revision 3.1 1994/04/17 11:31:54 too @@ -21,14 +21,44 @@ * */ +//usage:#if ENABLE_FEATURE_TELNET_AUTOLOGIN +//usage:#define telnet_trivial_usage +//usage: "[-a] [-l USER] HOST [PORT]" +//usage:#define telnet_full_usage "\n\n" +//usage: "Connect to telnet server\n" +//usage: "\n -a Automatic login with $USER variable" +//usage: "\n -l USER Automatic login as USER" +//usage: +//usage:#else +//usage:#define telnet_trivial_usage +//usage: "HOST [PORT]" +//usage:#define telnet_full_usage "\n\n" +//usage: "Connect to telnet server" +//usage:#endif + #include #include #include "libbb.h" +#ifdef __BIONIC__ +/* should be in arpa/telnet.h */ +# define IAC 255 /* interpret as command: */ +# define DONT 254 /* you are not to use option */ +# define DO 253 /* please, you use option */ +# define WONT 252 /* I won't use option */ +# define WILL 251 /* I will use option */ +# define SB 250 /* interpret as subnegotiation */ +# define SE 240 /* end sub negotiation */ +# define TELOPT_ECHO 1 /* echo */ +# define TELOPT_SGA 3 /* suppress go ahead */ +# define TELOPT_TTYPE 24 /* terminal type */ +# define TELOPT_NAWS 31 /* window size */ +#endif + #ifdef DOTRACE -#define TRACE(x, y) do { if (x) printf y; } while (0) +# define TRACE(x, y) do { if (x) printf y; } while (0) #else -#define TRACE(x, y) +# define TRACE(x, y) #endif enum { @@ -42,11 +72,13 @@ enum { UF_ECHO = 0x01, UF_SGA = 0x02, - TS_0 = 1, + TS_NORMAL = 0, + TS_COPY = 1, TS_IAC = 2, TS_OPT = 3, TS_SUB1 = 4, TS_SUB2 = 5, + TS_CR = 6, }; typedef unsigned char byte; @@ -83,22 +115,20 @@ struct globals { }; \ } while (0) -/* Function prototypes */ + static void rawmode(void); static void cookmode(void); static void do_linemode(void); static void will_charmode(void); static void telopt(byte c); -static int subneg(byte c); +static void subneg(byte c); static void iac_flush(void) { - write(netfd, G.iacbuf, G.iaclen); + full_write(netfd, G.iacbuf, G.iaclen); G.iaclen = 0; } -#define write_str(fd, str) write(fd, str, sizeof(str) - 1) - static void doexit(int ev) NORETURN; static void doexit(int ev) { @@ -113,7 +143,7 @@ static void con_escape(void) if (bb_got_signal) /* came from line mode... go raw */ rawmode(); - write_str(1, "\r\nConsole escape. Commands are:\r\n\n" + full_write1_str("\r\nConsole escape. Commands are:\r\n\n" " l go to line mode\r\n" " c go to character mode\r\n" " z suspend telnet\r\n" @@ -144,51 +174,45 @@ static void con_escape(void) doexit(EXIT_SUCCESS); } - write_str(1, "continuing...\r\n"); + full_write1_str("continuing...\r\n"); if (bb_got_signal) cookmode(); ret: bb_got_signal = 0; - } static void handle_net_output(int len) { - /* here we could do smart tricks how to handle 0xFF:s in output - * stream like writing twice every sequence of FF:s (thus doing - * many write()s. But I think interactive telnet application does - * not need to be 100% 8-bit clean, so changing every 0xff:s to - * 0x7f:s - * - * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com) - * I don't agree. - * first - I cannot use programs like sz/rz - * second - the 0x0D is sent as one character and if the next - * char is 0x0A then it's eaten by a server side. - * third - why do you have to make 'many write()s'? - * I don't understand. - * So I implemented it. It's really useful for me. I hope that - * other people will find it interesting too. - */ - - int i, j; - byte *p = (byte*)G.buf; - byte outbuf[4*DATABUFSIZE]; - - for (i = len, j = 0; i > 0; i--, p++) { - if (*p == 0x1d) { + byte outbuf[2 * DATABUFSIZE]; + byte *dst = outbuf; + byte *src = (byte*)G.buf; + byte *end = src + len; + + while (src < end) { + byte c = *src++; + if (c == 0x1d) { con_escape(); return; } - outbuf[j++] = *p; - if (*p == 0xff) - outbuf[j++] = 0xff; - else if (*p == 0x0d) - outbuf[j++] = 0x00; + *dst = c; + if (c == IAC) + *++dst = c; /* IAC -> IAC IAC */ + else + if (c == '\r' || c == '\n') { + /* Enter key sends '\r' in raw mode and '\n' in cooked one. + * + * See RFC 1123 3.3.1 Telnet End-of-Line Convention. + * Using CR LF instead of other allowed possibilities + * like CR NUL - easier to talk to HTTP/SMTP servers. + */ + *dst = '\r'; /* Enter -> CR LF */ + *++dst = '\n'; + } + dst++; } - if (j > 0) - write(netfd, outbuf, j); + if (dst - outbuf != 0) + full_write(netfd, outbuf, dst - outbuf); } static void handle_net_input(int len) @@ -199,25 +223,44 @@ static void handle_net_input(int len) for (i = 0; i < len; i++) { byte c = G.buf[i]; - if (G.telstate == 0) { /* most of the time state == 0 */ + if (G.telstate == TS_NORMAL) { /* most typical state */ if (c == IAC) { cstart = i; G.telstate = TS_IAC; } + else if (c == '\r') { + cstart = i + 1; + G.telstate = TS_CR; + } + /* No IACs were seen so far, no need to copy + * bytes within G.buf: */ continue; } + switch (G.telstate) { - case TS_0: + case TS_CR: + /* Prev char was CR. If cur one is NUL, ignore it. + * See RFC 1123 section 3.3.1 for discussion of telnet EOL handling. + */ + G.telstate = TS_COPY; + if (c == '\0') + break; + /* else: fall through - need to handle CR IAC ... properly */ + + case TS_COPY: /* Prev char was ordinary */ + /* Similar to NORMAL, but in TS_COPY we need to copy bytes */ if (c == IAC) G.telstate = TS_IAC; else G.buf[cstart++] = c; + if (c == '\r') + G.telstate = TS_CR; break; - case TS_IAC: - if (c == IAC) { /* IAC IAC -> 0xFF */ + case TS_IAC: /* Prev char was IAC */ + if (c == IAC) { /* IAC IAC -> one IAC */ G.buf[cstart++] = c; - G.telstate = TS_0; + G.telstate = TS_COPY; break; } /* else */ @@ -229,34 +272,38 @@ static void handle_net_input(int len) case DONT: case WILL: case WONT: - G.telwish = c; + G.telwish = c; G.telstate = TS_OPT; break; + /* DATA MARK must be added later */ default: - G.telstate = TS_0; /* DATA MARK must be added later */ + G.telstate = TS_COPY; } break; - case TS_OPT: /* WILL, WONT, DO, DONT */ + + case TS_OPT: /* Prev chars were IAC WILL/WONT/DO/DONT */ telopt(c); - G.telstate = TS_0; + G.telstate = TS_COPY; break; + case TS_SUB1: /* Subnegotiation */ case TS_SUB2: /* Subnegotiation */ - if (subneg(c)) - G.telstate = TS_0; + subneg(c); /* can change G.telstate */ break; } } - if (G.telstate) { + + if (G.telstate != TS_NORMAL) { + /* We had some IACs, or CR */ if (G.iaclen) iac_flush(); - if (G.telstate == TS_0) - G.telstate = 0; + if (G.telstate == TS_COPY) /* we aren't in the middle of IAC */ + G.telstate = TS_NORMAL; len = cstart; } if (len) - write(STDOUT_FILENO, G.buf, len); + full_write(STDOUT_FILENO, G.buf, len); } static void put_iac(int c) @@ -334,30 +381,31 @@ static void put_iac_naws(byte c, int x, int y) put_iac(SB); put_iac(c); - put_iac((x >> 8) & 0xff); - put_iac(x & 0xff); - put_iac((y >> 8) & 0xff); - put_iac(y & 0xff); + /* "... & 0xff" implicitly done below */ + put_iac(x >> 8); + put_iac(x); + put_iac(y >> 8); + put_iac(y); put_iac(IAC); put_iac(SE); } #endif -static char const escapecharis[] ALIGN1 = "\r\nEscape character is "; - static void setConMode(void) { if (G.telflags & UF_ECHO) { if (G.charmode == CHM_TRY) { G.charmode = CHM_ON; - printf("\r\nEntering character mode%s'^]'.\r\n", escapecharis); + printf("\r\nEntering %s mode" + "\r\nEscape character is '^%c'.\r\n", "character", ']'); rawmode(); } } else { if (G.charmode != CHM_OFF) { G.charmode = CHM_OFF; - printf("\r\nEntering line mode%s'^C'.\r\n", escapecharis); + printf("\r\nEntering %s mode" + "\r\nEscape character is '^%c'.\r\n", "line", 'C'); cookmode(); } } @@ -496,7 +544,7 @@ static void telopt(byte c) } /* subnegotiation -- ignore all (except TTYPE,NAWS) */ -static int subneg(byte c) +static void subneg(byte c) { switch (G.telstate) { case TS_SUB1: @@ -514,12 +562,13 @@ static int subneg(byte c) #endif break; case TS_SUB2: - if (c == SE) - return TRUE; + if (c == SE) { + G.telstate = TS_COPY; + return; + } G.telstate = TS_SUB1; - /* break; */ + break; } - return FALSE; } static void rawmode(void) @@ -534,21 +583,13 @@ static void cookmode(void) tcsetattr(0, TCSADRAIN, &G.termios_def); } -/* poll gives smaller (-70 bytes) code */ -#define USE_POLL 1 - int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int telnet_main(int argc UNUSED_PARAM, char **argv) { char *host; int port; int len; -#ifdef USE_POLL struct pollfd ufds[2]; -#else - fd_set readfds; - int maxfd; -#endif INIT_G(); @@ -586,63 +627,39 @@ int telnet_main(int argc UNUSED_PARAM, char **argv) signal(SIGINT, record_signo); -#ifdef USE_POLL - ufds[0].fd = 0; ufds[1].fd = netfd; - ufds[0].events = ufds[1].events = POLLIN; -#else - FD_ZERO(&readfds); - FD_SET(STDIN_FILENO, &readfds); - FD_SET(netfd, &readfds); - maxfd = netfd + 1; -#endif + ufds[0].fd = STDIN_FILENO; + ufds[0].events = POLLIN; + ufds[1].fd = netfd; + ufds[1].events = POLLIN; while (1) { -#ifndef USE_POLL - fd_set rfds = readfds; - - switch (select(maxfd, &rfds, NULL, NULL, NULL)) -#else - switch (poll(ufds, 2, -1)) -#endif - { - case 0: - /* timeout */ - case -1: + if (poll(ufds, 2, -1) < 0) { /* error, ignore and/or log something, bay go to loop */ if (bb_got_signal) con_escape(); else sleep(1); - break; - default: + continue; + } -#ifdef USE_POLL - if (ufds[0].revents) -#else - if (FD_ISSET(STDIN_FILENO, &rfds)) -#endif - { - len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); - if (len <= 0) - doexit(EXIT_SUCCESS); - TRACE(0, ("Read con: %d\n", len)); - handle_net_output(len); - } +// FIXME: reads can block. Need full bidirectional buffering. -#ifdef USE_POLL - if (ufds[1].revents) -#else - if (FD_ISSET(netfd, &rfds)) -#endif - { - len = safe_read(netfd, G.buf, DATABUFSIZE); - if (len <= 0) { - full_write1_str("Connection closed by foreign host\r\n"); - doexit(EXIT_FAILURE); - } - TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); - handle_net_input(len); + if (ufds[0].revents) { + len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); + if (len <= 0) + doexit(EXIT_SUCCESS); + TRACE(0, ("Read con: %d\n", len)); + handle_net_output(len); + } + + if (ufds[1].revents) { + len = safe_read(netfd, G.buf, DATABUFSIZE); + if (len <= 0) { + full_write1_str("Connection closed by foreign host\r\n"); + doexit(EXIT_FAILURE); } + TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); + handle_net_input(len); } } /* while (1) */ } diff --git a/networking/telnetd.c b/networking/telnetd.c index ea66a25..9e7a84c 100644 --- a/networking/telnetd.c +++ b/networking/telnetd.c @@ -3,7 +3,7 @@ * Simple telnet server * Bjorn Wesen, Axis Communications AB (bjornw@axis.com) * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * --------------------------------------------------------------------------- * (C) Copyright 2000, Axis Communications AB, LUND, SWEDEN @@ -20,6 +20,27 @@ * Vladimir Oleynik 2001 * Set process group corrections, initial busybox port */ + +//usage:#define telnetd_trivial_usage +//usage: "[OPTIONS]" +//usage:#define telnetd_full_usage "\n\n" +//usage: "Handle incoming telnet connections" +//usage: IF_NOT_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" +//usage: "\n -l LOGIN Exec LOGIN on connect" +//usage: "\n -f ISSUE_FILE Display ISSUE_FILE instead of /etc/issue" +//usage: "\n -K Close connection as soon as login exits" +//usage: "\n (normally wait until all programs close slave pty)" +//usage: IF_FEATURE_TELNETD_STANDALONE( +//usage: "\n -p PORT Port to listen on" +//usage: "\n -b ADDR[:PORT] Address to bind to" +//usage: "\n -F Run in foreground" +//usage: "\n -i Inetd mode" +//usage: IF_FEATURE_TELNETD_INETD_WAIT( +//usage: "\n -w SEC Inetd 'wait' mode, linger time SEC" +//usage: "\n -S Log to syslog (implied by -i or without -F and -w)" +//usage: ) +//usage: ) + #define DEBUG 0 #include "libbb.h" @@ -31,10 +52,6 @@ #endif #include -#if ENABLE_FEATURE_UTMP -# include /* LOGIN_PROCESS */ -#endif - struct tsession { struct tsession *next; @@ -108,6 +125,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) /* We map \r\n ==> \r for pragmatic reasons. * Many client implementations send \r\n when * the user hits the CarriageReturn key. + * See RFC 1123 3.3.1 Telnet End-of-Line Convention. */ if (c == '\r' && ptr < end && (*ptr == '\n' || *ptr == '\0')) ptr++; @@ -141,7 +159,7 @@ remove_iacs(struct tsession *ts, int *pnum_totty) if (ptr[1] == SB && ptr[2] == TELOPT_NAWS) { struct winsize ws; if ((ptr+8) >= end) - break; /* incomplete, can't process */ + break; /* incomplete, can't process */ ws.ws_col = (ptr[3] << 8) | ptr[4]; ws.ws_row = (ptr[5] << 8) | ptr[6]; ioctl(ts->ptyfd, TIOCSWINSZ, (char *)&ws); @@ -273,8 +291,8 @@ make_new_session( static const char iacs_to_send[] ALIGN1 = { IAC, DO, TELOPT_ECHO, IAC, DO, TELOPT_NAWS, - /* This requires telnetd.ctrlSQ.patch (incomplete) */ - /* IAC, DO, TELOPT_LFLOW, */ + /* This requires telnetd.ctrlSQ.patch (incomplete) */ + /*IAC, DO, TELOPT_LFLOW,*/ IAC, WILL, TELOPT_ECHO, IAC, WILL, TELOPT_SGA }; @@ -314,6 +332,8 @@ make_new_session( /* Restore default signal handling ASAP */ bb_signals((1 << SIGCHLD) + (1 << SIGPIPE), SIG_DFL); + pid = getpid(); + if (ENABLE_FEATURE_UTMP) { len_and_sockaddr *lsa = get_peer_lsa(sock); char *hostname = NULL; @@ -335,7 +355,6 @@ make_new_session( xopen(tty_name, O_RDWR); /* becomes our ctty */ xdup2(0, 1); xdup2(0, 2); - pid = getpid(); tcsetpgrp(0, pid); /* switch this tty's process group to us */ /* The pseudo-terminal allocated to the client is configured to operate diff --git a/networking/tftp.c b/networking/tftp.c index 43ae136..630fdaf 100644 --- a/networking/tftp.c +++ b/networking/tftp.c @@ -16,9 +16,42 @@ * * tftpd added by Denys Vlasenko & Vladimir Dronnikov * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define tftp_trivial_usage +//usage: "[OPTIONS] HOST [PORT]" +//usage:#define tftp_full_usage "\n\n" +//usage: "Transfer a file from/to tftp server\n" +//usage: "\n -l FILE Local FILE" +//usage: "\n -r FILE Remote FILE" +//usage: IF_FEATURE_TFTP_GET( +//usage: "\n -g Get file" +//usage: ) +//usage: IF_FEATURE_TFTP_PUT( +//usage: "\n -p Put file" +//usage: ) +//usage: IF_FEATURE_TFTP_BLOCKSIZE( +//usage: "\n -b SIZE Transfer blocks of SIZE octets" +//usage: ) +//usage: +//usage:#define tftpd_trivial_usage +//usage: "[-cr] [-u USER] [DIR]" +//usage:#define tftpd_full_usage "\n\n" +//usage: "Transfer a file on tftp client's request\n" +//usage: "\n" +//usage: "tftpd should be used as an inetd service.\n" +//usage: "tftpd's line for inetd.conf:\n" +//usage: " 69 dgram udp nowait root tftpd tftpd -l /files/to/serve\n" +//usage: "It also can be ran from udpsvd:\n" +//usage: " udpsvd -vE 0.0.0.0 69 tftpd /files/to/serve\n" +//usage: "\n -r Prohibit upload" +//usage: "\n -c Allow file creation via upload" +//usage: "\n -u Access files as USER" +//usage: "\n -l Log to syslog (inetd mode requires this)" + #include "libbb.h" +#include #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT @@ -59,6 +92,7 @@ enum { TFTPD_OPT_r = (1 << 8) * ENABLE_TFTPD, TFTPD_OPT_c = (1 << 9) * ENABLE_TFTPD, TFTPD_OPT_u = (1 << 10) * ENABLE_TFTPD, + TFTPD_OPT_l = (1 << 11) * ENABLE_TFTPD, }; #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT @@ -82,7 +116,7 @@ enum { struct globals { /* u16 TFTP_ERROR; u16 reason; both network-endian, then error text: */ uint8_t error_pkt[4 + 32]; - char *user_opt; + struct passwd *pw; /* used in tftpd_main(), a bit big for stack: */ char block_buf[TFTP_BLKSIZE_DEFAULT]; #if ENABLE_FEATURE_TFTP_PROGRESS_BAR @@ -96,48 +130,28 @@ struct globals { struct BUG_G_too_big { char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; }; -#define block_buf (G.block_buf ) -#define user_opt (G.user_opt ) -#define error_pkt (G.error_pkt ) #define INIT_G() do { } while (0) -#define error_pkt_reason (error_pkt[3]) -#define error_pkt_str (error_pkt + 4) +#define G_error_pkt_reason (G.error_pkt[3]) +#define G_error_pkt_str ((char*)(G.error_pkt + 4)) #if ENABLE_FEATURE_TFTP_PROGRESS_BAR -/* SIGALRM logic nicked from the wget applet */ -static void progress_meter(int flag) +static void tftp_progress_update(void) { - /* We can be called from signal handler */ - int save_errno = errno; - - if (flag == -1) { /* first call to progress_meter */ - bb_progress_init(&G.pmt); - } - - bb_progress_update(&G.pmt, G.file, 0, G.pos, G.size); - - if (flag == 0) { - /* last call to progress_meter */ - alarm(0); - bb_putchar_stderr('\n'); - } else { - if (flag == -1) { /* first call to progress_meter */ - signal_SA_RESTART_empty_mask(SIGALRM, progress_meter); - } - alarm(1); - } - - errno = save_errno; + bb_progress_update(&G.pmt, 0, G.pos, G.size); } static void tftp_progress_init(void) { - progress_meter(-1); + bb_progress_init(&G.pmt, G.file); + tftp_progress_update(); } static void tftp_progress_done(void) { - if (G.pmt.inited) - progress_meter(0); + if (is_bb_progress_inited(&G.pmt)) { + tftp_progress_update(); + bb_putchar_stderr('\n'); + bb_progress_free(&G.pmt); + } } #else # define tftp_progress_init() ((void)0) @@ -255,12 +269,11 @@ static int tftp_protocol( xconnect(socket_fd, &peer_lsa->u.sa, peer_lsa->len); /* Is there an error already? Send pkt and bail out */ - if (error_pkt_reason || error_pkt_str[0]) + if (G_error_pkt_reason || G_error_pkt_str[0]) goto send_err_pkt; - if (user_opt) { - struct passwd *pw = xgetpwnam(user_opt); - change_identity(pw); /* initgroups, setgid, setuid */ + if (G.pw) { + change_identity(G.pw); /* initgroups, setgid, setuid */ } } @@ -312,8 +325,8 @@ static int tftp_protocol( /* Open file (must be after changing user) */ local_fd = open(local_file, open_mode, 0666); if (local_fd < 0) { - error_pkt_reason = ERR_NOFILE; - strcpy((char*)error_pkt_str, "can't open file"); + G_error_pkt_reason = ERR_NOFILE; + strcpy(G_error_pkt_str, "can't open file"); goto send_err_pkt; } /* gcc 4.3.1 would NOT optimize it out as it should! */ @@ -439,6 +452,7 @@ static int tftp_protocol( finished = 1; } cp += len; + IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += len;) } send_pkt: /* Send packet */ @@ -447,7 +461,7 @@ static int tftp_protocol( /* NB: send_len value is preserved in code below * for potential resend */ - retries = TFTP_NUM_RETRIES; /* re-initialize */ + retries = TFTP_NUM_RETRIES; /* re-initialize */ waittime_ms = TFTP_TIMEOUT_MS; send_again: @@ -460,9 +474,8 @@ static int tftp_protocol( xsendto(socket_fd, xbuf, send_len, &peer_lsa->u.sa, peer_lsa->len); #if ENABLE_FEATURE_TFTP_PROGRESS_BAR - if (ENABLE_TFTP && remote_file) { /* tftp */ - G.pos = (block_nr - 1) * (uoff_t)blksize; - } + if (is_bb_progress_inited(&G.pmt)) + tftp_progress_update(); #endif /* Was it final ACK? then exit */ if (finished && (opcode == TFTP_ACK)) @@ -479,6 +492,7 @@ static int tftp_protocol( case 0: retries--; if (retries == 0) { + tftp_progress_done(); bb_error_msg("timeout"); goto ret; /* no err packet sent */ } @@ -557,7 +571,7 @@ static int tftp_protocol( if (res) { blksize = tftp_blksize_check(res, blksize); if (blksize < 0) { - error_pkt_reason = ERR_BAD_OPT; + G_error_pkt_reason = ERR_BAD_OPT; goto send_err_pkt; } io_bufsize = blksize + 4; @@ -596,13 +610,14 @@ static int tftp_protocol( if (recv_blk == block_nr) { int sz = full_write(local_fd, &rbuf[4], len - 4); if (sz != len - 4) { - strcpy((char*)error_pkt_str, bb_msg_write_error); - error_pkt_reason = ERR_WRITE; + strcpy(G_error_pkt_str, bb_msg_write_error); + G_error_pkt_reason = ERR_WRITE; goto send_err_pkt; } if (sz != blksize) { finished = 1; } + IF_FEATURE_TFTP_PROGRESS_BAR(G.pos += sz;) continue; /* send ACK */ } /* Disabled to cope with servers with Sorcerer's Apprentice Syndrome */ @@ -645,12 +660,12 @@ static int tftp_protocol( return finished == 0; /* returns 1 on failure */ send_read_err_pkt: - strcpy((char*)error_pkt_str, bb_msg_read_error); + strcpy(G_error_pkt_str, bb_msg_read_error); send_err_pkt: - if (error_pkt_str[0]) - bb_error_msg("%s", (char*)error_pkt_str); - error_pkt[1] = TFTP_ERROR; - xsendto(socket_fd, error_pkt, 4 + 1 + strlen((char*)error_pkt_str), + if (G_error_pkt_str[0]) + bb_error_msg("%s", G_error_pkt_str); + G.error_pkt[1] = TFTP_ERROR; + xsendto(socket_fd, G.error_pkt, 4 + 1 + strlen(G_error_pkt_str), &peer_lsa->u.sa, peer_lsa->len); return EXIT_FAILURE; #undef remote_file @@ -742,7 +757,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) { len_and_sockaddr *our_lsa; len_and_sockaddr *peer_lsa; - char *local_file, *mode; + char *local_file, *mode, *user_opt; const char *error_msg; int opt, result, opcode; IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;) @@ -764,19 +779,28 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) peer_lsa->len = our_lsa->len; /* Shifting to not collide with TFTP_OPTs */ - opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:", &user_opt) << 8); + opt = option_mask32 = TFTPD_OPT | (getopt32(argv, "rcu:l", &user_opt) << 8); argv += optind; - if (argv[0]) - xchdir(argv[0]); + if (opt & TFTPD_OPT_l) { + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode = LOGMODE_SYSLOG; + } + if (opt & TFTPD_OPT_u) { + /* Must be before xchroot */ + G.pw = xgetpwnam(user_opt); + } + if (argv[0]) { + xchroot(argv[0]); + } - result = recv_from_to(STDIN_FILENO, block_buf, sizeof(block_buf), + result = recv_from_to(STDIN_FILENO, G.block_buf, sizeof(G.block_buf), 0 /* flags */, &peer_lsa->u.sa, &our_lsa->u.sa, our_lsa->len); error_msg = "malformed packet"; - opcode = ntohs(*(uint16_t*)block_buf); - if (result < 4 || result >= sizeof(block_buf) - || block_buf[result-1] != '\0' + opcode = ntohs(*(uint16_t*)G.block_buf); + if (result < 4 || result >= sizeof(G.block_buf) + || G.block_buf[result-1] != '\0' || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */ IF_GETPUT(&&) IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */ @@ -784,26 +808,27 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) ) { goto err; } - local_file = block_buf + 2; + local_file = G.block_buf + 2; if (local_file[0] == '.' || strstr(local_file, "/.")) { error_msg = "dot in file name"; goto err; } mode = local_file + strlen(local_file) + 1; - if (mode >= block_buf + result || strcmp(mode, "octet") != 0) { + /* RFC 1350 says mode string is case independent */ + if (mode >= G.block_buf + result || strcasecmp(mode, "octet") != 0) { goto err; } # if ENABLE_FEATURE_TFTP_BLOCKSIZE { char *res; char *opt_str = mode + sizeof("octet"); - int opt_len = block_buf + result - opt_str; + int opt_len = G.block_buf + result - opt_str; if (opt_len > 0) { res = tftp_get_option("blksize", opt_str, opt_len); if (res) { blksize = tftp_blksize_check(res, 65564); if (blksize < 0) { - error_pkt_reason = ERR_BAD_OPT; + G_error_pkt_reason = ERR_BAD_OPT; /* will just send error pkt */ goto do_proto; } @@ -821,7 +846,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) if (!ENABLE_FEATURE_TFTP_PUT || opcode == TFTP_WRQ) { if (opt & TFTPD_OPT_r) { /* This would mean "disk full" - not true */ - /*error_pkt_reason = ERR_WRITE;*/ + /*G_error_pkt_reason = ERR_WRITE;*/ error_msg = bb_msg_write_error; goto err; } @@ -830,7 +855,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */ } - /* NB: if error_pkt_str or error_pkt_reason is set up, + /* NB: if G_error_pkt_str or G_error_pkt_reason is set up, * tftp_protocol() just sends one error pkt and returns */ do_proto: @@ -845,7 +870,7 @@ int tftpd_main(int argc UNUSED_PARAM, char **argv) return result; err: - strcpy((char*)error_pkt_str, error_msg); + strcpy(G_error_pkt_str, error_msg); goto do_proto; } diff --git a/networking/traceroute.c b/networking/traceroute.c index 2d3e770..97a7a19 100644 --- a/networking/traceroute.c +++ b/networking/traceroute.c @@ -210,6 +210,49 @@ * Tue Dec 20 03:50:13 PST 1988 */ +//usage:#define traceroute_trivial_usage +//usage: "[-"IF_TRACEROUTE6("46")"FIldnrv] [-f 1ST_TTL] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-g GATEWAY] [-i IFACE]\n" +//usage: " [-z PAUSE_MSEC] HOST [BYTES]" +//usage:#define traceroute_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: IF_TRACEROUTE6( +//usage: "\n -4,-6 Force IP or IPv6 name resolution" +//usage: ) +//usage: "\n -F Set the don't fragment bit" +//usage: "\n -I Use ICMP ECHO instead of UDP datagrams" +//usage: "\n -l Display the TTL value of the returned packet" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" +//usage: "\n -g Loose source route gateway (8 max)" +//usage: +//usage:#define traceroute6_trivial_usage +//usage: "[-dnrv] [-m MAXTTL] [-p PORT] [-q PROBES]\n" +//usage: " [-s SRC_IP] [-t TOS] [-w WAIT_SEC] [-i IFACE]\n" +//usage: " HOST [BYTES]" +//usage:#define traceroute6_full_usage "\n\n" +//usage: "Trace the route to HOST\n" +//usage: "\n -d Set SO_DEBUG options to socket" +//usage: "\n -n Print numeric addresses" +//usage: "\n -r Bypass routing tables, send directly to HOST" +//usage: "\n -v Verbose" +//usage: "\n -m Max time-to-live (max number of hops)" +//usage: "\n -p Base UDP port number used in probes" +//usage: "\n (default is 33434)" +//usage: "\n -q Number of probes per TTL (default 3)" +//usage: "\n -s IP address to use as the source address" +//usage: "\n -t Type-of-service in probe packets (default 0)" +//usage: "\n -w Time in seconds to wait for a response (default 3)" + #define TRACEROUTE_SO_DEBUG 0 /* TODO: undefs were uncommented - ??! we have config system for that! */ @@ -247,9 +290,10 @@ #endif -#define OPT_STRING "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ - IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ - "4" IF_TRACEROUTE6("6") +#define OPT_STRING \ + "FIlnrdvxt:i:m:p:q:s:w:z:f:" \ + IF_FEATURE_TRACEROUTE_SOURCE_ROUTE("g:") \ + "4" IF_TRACEROUTE6("6") enum { OPT_DONT_FRAGMNT = (1 << 0), /* F */ OPT_USE_ICMP = (1 << 1) * ENABLE_FEATURE_TRACEROUTE_USE_ICMP, /* I */ @@ -353,56 +397,28 @@ static len_and_sockaddr* dup_sockaddr(const len_and_sockaddr *lsa) static int -wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to) +wait_for_reply(len_and_sockaddr *from_lsa, struct sockaddr *to, unsigned *timestamp_us, int *left_ms) { struct pollfd pfd[1]; int read_len = 0; pfd[0].fd = rcvsock; pfd[0].events = POLLIN; - if (safe_poll(pfd, 1, waittime * 1000) > 0) { + if (*left_ms >= 0 && safe_poll(pfd, 1, *left_ms) > 0) { + unsigned t; + read_len = recv_from_to(rcvsock, recv_pkt, sizeof(recv_pkt), - /*flags:*/ 0, + /*flags:*/ MSG_DONTWAIT, &from_lsa->u.sa, to, from_lsa->len); + t = monotonic_us(); + *left_ms -= (t - *timestamp_us) / 1000; + *timestamp_us = t; } return read_len; } -/* - * Checksum routine for Internet Protocol family headers (C Version) - */ -static uint16_t -in_cksum(uint16_t *addr, int len) -{ - int nleft = len; - uint16_t *w = addr; - uint16_t answer; - int sum = 0; - - /* - * Our algorithm is simple, using a 32 bit accumulator (sum), - * we add sequential 16 bit words to it, and at the end, fold - * back all the carry bits from the top 16 bits into the lower - * 16 bits. - */ - while (nleft > 1) { - sum += *w++; - nleft -= 2; - } - - /* mop up an odd byte, if necessary */ - if (nleft == 1) - sum += *(unsigned char *)w; - - /* add back carry outs from top 16 bits to low 16 bits */ - sum = (sum >> 16) + (sum & 0xffff); /* add hi 16 to low 16 */ - sum += (sum >> 16); /* add carry */ - answer = ~sum; /* truncate to 16 bits */ - return answer; -} - static void send_probe(int seq, int ttl) { @@ -429,7 +445,7 @@ send_probe(int seq, int ttl) /* Always calculate checksum for icmp packets */ outicmp->icmp_cksum = 0; - outicmp->icmp_cksum = in_cksum((uint16_t *)outicmp, + outicmp->icmp_cksum = inet_cksum((uint16_t *)outicmp, packlen - (sizeof(*outip) + optlen)); if (outicmp->icmp_cksum == 0) outicmp->icmp_cksum = 0xffff; @@ -482,7 +498,7 @@ send_probe(int seq, int ttl) if (!(option_mask32 & OPT_USE_ICMP)) { out = outdata; len -= sizeof(*outudp); - set_nport(dest_lsa, htons(port + seq)); + set_nport(&dest_lsa->u.sa, htons(port + seq)); } } @@ -666,7 +682,6 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, return (type == ICMP6_TIME_EXCEEDED ? -1 : (code<<8)+1); } } - } # if ENABLE_FEATURE_TRACEROUTE_VERBOSE @@ -686,7 +701,7 @@ packet_ok(int read_len, len_and_sockaddr *from_lsa, type, pr_type(type), icp->icmp6_code); read_len -= sizeof(struct icmp6_hdr); - for (i = 0; i < read_len ; i++) { + for (i = 0; i < read_len; i++) { if (i % 16 == 0) printf("%04x:", i); if (i % 4 == 0) @@ -752,7 +767,8 @@ print(int read_len, const struct sockaddr *from, const struct sockaddr *to) } else #endif { - read_len -= ((struct ip*)recv_pkt)->ip_hl << 2; + struct ip *ip4packet = (struct ip*)recv_pkt; + read_len -= ip4packet->ip_hl << 2; } printf(" %d bytes to %s", read_len, ina); free(ina); @@ -774,9 +790,10 @@ print_delta_ms(unsigned t1p, unsigned t2p) static int common_traceroute_main(int op, char **argv) { - int i; int minpacket; +#ifdef IP_TOS int tos = 0; +#endif int max_ttl = 30; int nprobes = 3; int first_ttl = 1; @@ -790,6 +807,7 @@ common_traceroute_main(int op, char **argv) char *waittime_str; char *pausemsecs_str; char *first_ttl_str; + char *dest_str; #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE llist_t *source_route_list = NULL; int lsrr = 0; @@ -822,8 +840,10 @@ common_traceroute_main(int op, char **argv) if (op & OPT_IP_CHKSUM) bb_error_msg("warning: ip checksums disabled"); #endif +#ifdef IP_TOS if (op & OPT_TOS) tos = xatou_range(tos_str, 0, 255); +#endif if (op & OPT_MAX_TTL) max_ttl = xatou_range(max_ttl_str, 1, 255); if (op & OPT_PORT) @@ -928,6 +948,7 @@ common_traceroute_main(int op, char **argv) #if ENABLE_FEATURE_TRACEROUTE_SOURCE_ROUTE && defined IP_OPTIONS if (lsrr > 0) { unsigned char optlist[MAX_IPOPTLEN]; + unsigned size; /* final hop */ gwlist[lsrr] = dest_lsa->u.sin.sin_addr.s_addr; @@ -937,14 +958,14 @@ common_traceroute_main(int op, char **argv) optlist[0] = IPOPT_NOP; /* loose source route option */ optlist[1] = IPOPT_LSRR; - i = lsrr * sizeof(gwlist[0]); - optlist[2] = i + 3; + size = lsrr * sizeof(gwlist[0]); + optlist[2] = size + 3; /* pointer to LSRR addresses */ optlist[3] = IPOPT_MINOFF; - memcpy(optlist + 4, gwlist, i); + memcpy(optlist + 4, gwlist, size); if (setsockopt(sndsock, IPPROTO_IP, IP_OPTIONS, - (char *)optlist, i + sizeof(gwlist[0])) < 0) { + (char *)optlist, size + sizeof(gwlist[0])) < 0) { bb_perror_msg_and_die("IP_OPTIONS"); } } @@ -1018,10 +1039,10 @@ common_traceroute_main(int op, char **argv) int probe_fd = xsocket(af, SOCK_DGRAM, 0); if (op & OPT_DEVICE) setsockopt_bindtodevice(probe_fd, device); - set_nport(dest_lsa, htons(1025)); + set_nport(&dest_lsa->u.sa, htons(1025)); /* dummy connect. makes kernel pick source IP (and port) */ xconnect(probe_fd, &dest_lsa->u.sa, dest_lsa->len); - set_nport(dest_lsa, htons(port)); + set_nport(&dest_lsa->u.sa, htons(port)); /* read IP and port */ source_lsa = get_sock_lsa(probe_fd); @@ -1031,7 +1052,7 @@ common_traceroute_main(int op, char **argv) close(probe_fd); /* bind our sockets to this IP (but not port) */ - set_nport(source_lsa, 0); + set_nport(&source_lsa->u.sa, 0); xbind(sndsock, &source_lsa->u.sa, source_lsa->len); xbind(rcvsock, &source_lsa->u.sa, source_lsa->len); @@ -1043,8 +1064,12 @@ common_traceroute_main(int op, char **argv) xsetgid(getgid()); xsetuid(getuid()); - printf("traceroute to %s (%s)", argv[0], - xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa)); + dest_str = xmalloc_sockaddr2dotted_noport(&dest_lsa->u.sa); + printf("traceroute to %s (%s)", argv[0], dest_str); + if (ENABLE_FEATURE_CLEAN_UP) { + free(dest_str); + } + if (op & OPT_SOURCE) printf(" from %s", source); printf(", %d hops max, %d byte packets\n", max_ttl, packlen); @@ -1058,28 +1083,34 @@ common_traceroute_main(int op, char **argv) int unreachable = 0; /* counter */ int gotlastaddr = 0; /* flags */ int got_there = 0; - int first = 1; printf("%2d", ttl); for (probe = 0; probe < nprobes; ++probe) { int read_len; unsigned t1; unsigned t2; + int left_ms; struct ip *ip; - if (!first && pausemsecs > 0) - usleep(pausemsecs * 1000); fflush_all(); + if (probe != 0 && pausemsecs > 0) + usleep(pausemsecs * 1000); - t1 = monotonic_us(); send_probe(++seq, ttl); + t2 = t1 = monotonic_us(); + + left_ms = waittime * 1000; + while ((read_len = wait_for_reply(from_lsa, to, &t2, &left_ms)) != 0) { + int icmp_code; + + /* Recv'ed a packet, or read error */ + /* t2 = monotonic_us() - set by wait_for_reply */ - first = 0; - while ((read_len = wait_for_reply(from_lsa, to)) != 0) { - t2 = monotonic_us(); - i = packet_ok(read_len, from_lsa, to, seq); + if (read_len < 0) + continue; + icmp_code = packet_ok(read_len, from_lsa, to, seq); /* Skip short packet */ - if (i == 0) + if (icmp_code == 0) continue; if (!gotlastaddr @@ -1098,10 +1129,10 @@ common_traceroute_main(int op, char **argv) printf(" (%d)", ip->ip_ttl); /* time exceeded in transit */ - if (i == -1) + if (icmp_code == -1) break; - i--; - switch (i) { + icmp_code--; + switch (icmp_code) { #if ENABLE_TRACEROUTE6 case ICMP6_DST_UNREACH_NOPORT << 8: got_there = 1; @@ -1174,16 +1205,18 @@ common_traceroute_main(int op, char **argv) ++unreachable; break; default: - printf(" !<%d>", i); + printf(" !<%d>", icmp_code); ++unreachable; break; } break; - } + } /* while (wait and read a packet) */ + /* there was no packet at all? */ if (read_len == 0) printf(" *"); - } + } /* for (nprobes) */ + bb_putchar('\n'); if (got_there || (unreachable > 0 && unreachable >= nprobes - 1) @@ -1192,6 +1225,12 @@ common_traceroute_main(int op, char **argv) } } + if (ENABLE_FEATURE_CLEAN_UP) { + free(to); + free(lastaddr); + free(from_lsa); + } + return 0; } diff --git a/networking/tunctl.c b/networking/tunctl.c index 02ff71d..3a0870e 100644 --- a/networking/tunctl.c +++ b/networking/tunctl.c @@ -7,8 +7,26 @@ * Original code: * Jeff Dike * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define tunctl_trivial_usage +//usage: "[-f device] ([-t name] | -d name)" IF_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]") +//usage:#define tunctl_full_usage "\n\n" +//usage: "Create or delete tun interfaces\n" +//usage: "\n -f name tun device (/dev/net/tun)" +//usage: "\n -t name Create iface 'name'" +//usage: "\n -d name Delete iface 'name'" +//usage: IF_FEATURE_TUNCTL_UG( +//usage: "\n -u owner Set iface owner" +//usage: "\n -g group Set iface group" +//usage: "\n -b Brief output" +//usage: ) +//usage: +//usage:#define tunctl_example_usage +//usage: "# tunctl\n" +//usage: "# tunctl -d tun0\n" + #include #include #include diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src index aac8856..6bfa398 100644 --- a/networking/udhcp/Config.src +++ b/networking/udhcp/Config.src @@ -8,6 +8,7 @@ INSERT config UDHCPD bool "udhcp server (udhcpd)" default y + select PLATFORM_LINUX help udhcpd is a DHCP server geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. @@ -38,7 +39,21 @@ config FEATURE_UDHCPD_WRITE_LEASES_EARLY If selected, udhcpd will write a new file with leases every time a new lease has been accepted, thus eliminating the need to send SIGUSR1 for the initial writing or updating. Any timed - rewriting remains undisturbed + rewriting remains undisturbed. + +config FEATURE_UDHCPD_BASE_IP_ON_MAC + bool "Select IP address based on client MAC" + default n + depends on UDHCPD + help + If selected, udhcpd will base its selection of IP address to offer + on the client's hardware address. Otherwise udhcpd uses the next + consecutive free address. + + This reduces the frequency of IP address changes for clients + which let their lease expire, and makes consecutive DHCPOFFERS + for the same client to (almost always) contain the same + IP address. config DHCPD_LEASES_FILE string "Absolute path to lease file" @@ -51,6 +66,7 @@ config DHCPD_LEASES_FILE config UDHCPC bool "udhcp client (udhcpc)" default y + select PLATFORM_LINUX help udhcpc is a DHCP client geared primarily toward embedded systems, while striving to be fully functional and RFC compliant. @@ -70,7 +86,7 @@ config FEATURE_UDHCPC_ARPING config FEATURE_UDHCP_PORT bool "Enable '-P port' option for udhcpd and udhcpc" - default y + default n depends on UDHCPD || UDHCPC help At the cost of ~300 bytes, enables -P port option. @@ -83,7 +99,7 @@ config UDHCP_DEBUG depends on UDHCPD || UDHCPC || DHCPRELAY help Verbosity can be increased with multiple -v options. - This options controls how high it can be cranked up. + This option controls how high it can be cranked up. Bigger values result in bigger code. Levels above 1 are very verbose and useful for debugging only. @@ -97,6 +113,14 @@ config FEATURE_UDHCP_RFC3397 search lists via option 119, specified in RFC 3397, and SIP servers option 120, specified in RFC 3361. +config FEATURE_UDHCP_8021Q + bool "Support for 802.1Q VLAN parameters" + default y + depends on UDHCPD || UDHCPC + help + If selected, both client and server will support passing of VLAN + ID and priority via options 132 and 133 as per 802.1Q. + config UDHCPC_DEFAULT_SCRIPT string "Absolute path to config script" default "/usr/share/udhcpc/default.script" diff --git a/networking/udhcp/Kbuild.src b/networking/udhcp/Kbuild.src index f845bc1..b8767ba 100644 --- a/networking/udhcp/Kbuild.src +++ b/networking/udhcp/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2004 by Erik Andersen # -# Licensed under the GPL v2 or later, see the file LICENSE in this tarball. +# Licensed under GPLv2 or later, see file LICENSE in this source tree. # lib-y:= diff --git a/networking/udhcp/arpping.c b/networking/udhcp/arpping.c index 7c8c244..b43e52e 100644 --- a/networking/udhcp/arpping.c +++ b/networking/udhcp/arpping.c @@ -3,7 +3,7 @@ * Mostly stolen from: dhcpcd - DHCP client daemon * by Yoichi Hariguchi * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include #include @@ -118,8 +118,13 @@ int FAST_FUNC arpping(uint32_t test_nip, break; } } - timeout_ms -= (unsigned)monotonic_ms() - prevTime; - } while (timeout_ms > 0); + timeout_ms -= (unsigned)monotonic_ms() - prevTime + 1; + + /* We used to check "timeout_ms > 0", but + * this is more under/overflow-resistant + * (people did see overflows here when system time jumps): + */ + } while ((unsigned)timeout_ms <= 2000); ret: close(s); diff --git a/networking/udhcp/common.c b/networking/udhcp/common.c index 90a07ed..fe322db 100644 --- a/networking/udhcp/common.c +++ b/networking/udhcp/common.c @@ -2,7 +2,7 @@ /* * Rewrite by Russ Dill July 2001 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "common.h" @@ -29,15 +29,19 @@ const struct dhcp_optflag dhcp_optflags[] = { // { OPTION_IP | OPTION_LIST , 0x07 }, /* DHCP_LOG_SERVER */ // { OPTION_IP | OPTION_LIST , 0x08 }, /* DHCP_COOKIE_SERVER */ { OPTION_IP | OPTION_LIST , 0x09 }, /* DHCP_LPR_SERVER */ - { OPTION_STRING | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0c }, /* DHCP_HOST_NAME */ { OPTION_U16 , 0x0d }, /* DHCP_BOOT_SIZE */ - { OPTION_STRING | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ + { OPTION_STRING_HOST | OPTION_REQ, 0x0f }, /* DHCP_DOMAIN_NAME */ { OPTION_IP , 0x10 }, /* DHCP_SWAP_SERVER */ { OPTION_STRING , 0x11 }, /* DHCP_ROOT_PATH */ { OPTION_U8 , 0x17 }, /* DHCP_IP_TTL */ { OPTION_U16 , 0x1a }, /* DHCP_MTU */ +//TODO: why do we request DHCP_BROADCAST? Can't we assume that +//in the unlikely case it is different from typical N.N.255.255, +//server would let us know anyway? { OPTION_IP | OPTION_REQ, 0x1c }, /* DHCP_BROADCAST */ - { OPTION_STRING , 0x28 }, /* DHCP_NIS_DOMAIN */ + { OPTION_IP_PAIR | OPTION_LIST , 0x21 }, /* DHCP_ROUTES */ + { OPTION_STRING_HOST , 0x28 }, /* DHCP_NIS_DOMAIN */ { OPTION_IP | OPTION_LIST , 0x29 }, /* DHCP_NIS_SERVER */ { OPTION_IP | OPTION_LIST | OPTION_REQ, 0x2a }, /* DHCP_NTP_SERVER */ { OPTION_IP | OPTION_LIST , 0x2c }, /* DHCP_WINS_SERVER */ @@ -45,7 +49,7 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_IP , 0x36 }, /* DHCP_SERVER_ID */ { OPTION_STRING , 0x38 }, /* DHCP_ERR_MESSAGE */ //TODO: must be combined with 'sname' and 'file' handling: - { OPTION_STRING , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ + { OPTION_STRING_HOST , 0x42 }, /* DHCP_TFTP_SERVER_NAME */ { OPTION_STRING , 0x43 }, /* DHCP_BOOT_FILE */ //TODO: not a string, but a set of LASCII strings: // { OPTION_STRING , 0x4D }, /* DHCP_USER_CLASS */ @@ -53,7 +57,14 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_DNS_STRING | OPTION_LIST , 0x77 }, /* DHCP_DOMAIN_SEARCH */ { OPTION_SIP_SERVERS , 0x78 }, /* DHCP_SIP_SERVERS */ #endif - { OPTION_STATIC_ROUTES , 0x79 }, /* DHCP_STATIC_ROUTES */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0x79 }, /* DHCP_STATIC_ROUTES */ +#if ENABLE_FEATURE_UDHCP_8021Q + { OPTION_U16 , 0x84 }, /* DHCP_VLAN_ID */ + { OPTION_U8 , 0x85 }, /* DHCP_VLAN_PRIORITY */ +#endif + { OPTION_STRING , 0xd1 }, /* DHCP_PXE_CONF_FILE */ + { OPTION_6RD , 0xd4 }, /* DHCP_6RD */ + { OPTION_STATIC_ROUTES | OPTION_LIST , 0xf9 }, /* DHCP_MS_STATIC_ROUTES */ { OPTION_STRING , 0xfc }, /* DHCP_WPAD */ /* Options below have no match in dhcp_option_strings[], @@ -66,9 +77,10 @@ const struct dhcp_optflag dhcp_optflags[] = { { OPTION_IP , 0x32 }, /* DHCP_REQUESTED_IP */ { OPTION_U8 , 0x35 }, /* DHCP_MESSAGE_TYPE */ { OPTION_U16 , 0x39 }, /* DHCP_MAX_SIZE */ - { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ -//FIXME: handling of this option is not exactly correct: - { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ +//looks like these opts will work just fine even without these defs: +// { OPTION_STRING , 0x3c }, /* DHCP_VENDOR */ +// /* not really a string: */ +// { OPTION_STRING , 0x3d }, /* DHCP_CLIENT_ID */ { 0, 0 } /* zeroed terminating entry */ }; @@ -95,6 +107,7 @@ const char dhcp_option_strings[] ALIGN1 = "ipttl" "\0" /* DHCP_IP_TTL */ "mtu" "\0" /* DHCP_MTU */ "broadcast" "\0" /* DHCP_BROADCAST */ + "routes" "\0" /* DHCP_ROUTES */ "nisdomain" "\0" /* DHCP_NIS_DOMAIN */ "nissrv" "\0" /* DHCP_NIS_SERVER */ "ntpsrv" "\0" /* DHCP_NTP_SERVER */ @@ -111,9 +124,14 @@ const char dhcp_option_strings[] ALIGN1 = // is not handled yet by "string->option" conversion code: "sipsrv" "\0" /* DHCP_SIP_SERVERS */ #endif -// doesn't work in udhcpd.conf since OPTION_STATIC_ROUTES -// is not handled yet by "string->option" conversion code: "staticroutes" "\0"/* DHCP_STATIC_ROUTES */ +#if ENABLE_FEATURE_UDHCP_8021Q + "vlanid" "\0" /* DHCP_VLAN_ID */ + "vlanpriority" "\0"/* DHCP_VLAN_PRIORITY */ +#endif + "pxeconffile" "\0" /* DHCP_PXE_CONF_FILE */ + "ip6rd" "\0" /* DHCP_6RD */ + "msstaticroutes""\0"/* DHCP_MS_STATIC_ROUTES */ "wpad" "\0" /* DHCP_WPAD */ ; @@ -130,6 +148,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_IP_PAIR] = 8, // [OPTION_BOOLEAN] = 1, [OPTION_STRING] = 1, /* ignored by udhcp_str2optset */ + [OPTION_STRING_HOST] = 1, /* ignored by udhcp_str2optset */ #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING] = 1, /* ignored by both udhcp_str2optset and xmalloc_optname_optval */ [OPTION_SIP_SERVERS] = 1, @@ -141,6 +160,7 @@ const uint8_t dhcp_option_lengths[] ALIGN1 = { [OPTION_S32] = 4, /* Just like OPTION_STRING, we use minimum length here */ [OPTION_STATIC_ROUTES] = 5, + [OPTION_6RD] = 22, /* ignored by udhcp_str2optset */ }; @@ -318,7 +338,8 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg) lsa = host_and_af2sockaddr(str, 0, AF_INET); if (!lsa) return 0; - *(uint32_t*)arg = lsa->u.sin.sin_addr.s_addr; + /* arg maybe unaligned */ + move_to_unaligned32((uint32_t*)arg, lsa->u.sin.sin_addr.s_addr); free(lsa); return 1; } @@ -352,25 +373,28 @@ static NOINLINE void attach_option( char *buffer, int length) { - struct option_set *existing, *new, **curr; - char *allocated = NULL; + struct option_set *existing; + char *allocated; - existing = udhcp_find_option(*opt_list, optflag->code); - if (!existing) { - log2("Attaching option %02x to list", optflag->code); - allocated = allocate_tempopt_if_needed(optflag, buffer, &length); + allocated = allocate_tempopt_if_needed(optflag, buffer, &length); #if ENABLE_FEATURE_UDHCP_RFC3397 - if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { - /* reuse buffer and length for RFC1035-formatted string */ - allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); - } + if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { + /* reuse buffer and length for RFC1035-formatted string */ + allocated = buffer = (char *)dname_enc(NULL, 0, buffer, &length); + } #endif + + existing = udhcp_find_option(*opt_list, optflag->code); + if (!existing) { + struct option_set *new, **curr; + /* make a new option */ + log2("Attaching option %02x to list", optflag->code); new = xmalloc(sizeof(*new)); new->data = xmalloc(length + OPT_DATA); new->data[OPT_CODE] = optflag->code; new->data[OPT_LEN] = length; - memcpy(new->data + OPT_DATA, buffer, length); + memcpy(new->data + OPT_DATA, (allocated ? allocated : buffer), length); curr = opt_list; while (*curr && (*curr)->data[OPT_CODE] < optflag->code) @@ -386,24 +410,19 @@ static NOINLINE void attach_option( /* add it to an existing option */ log2("Attaching option %02x to existing member of list", optflag->code); - allocated = allocate_tempopt_if_needed(optflag, buffer, &length); old_len = existing->data[OPT_LEN]; -#if ENABLE_FEATURE_UDHCP_RFC3397 - if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_DNS_STRING) { - /* reuse buffer and length for RFC1035-formatted string */ - allocated = buffer = (char *)dname_enc(existing->data + OPT_DATA, old_len, buffer, &length); - } -#endif if (old_len + length < 255) { /* actually 255 is ok too, but adding a space can overlow it */ existing->data = xrealloc(existing->data, OPT_DATA + 1 + old_len + length); - if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING) { + if ((optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING + || (optflag->flags & OPTION_TYPE_MASK) == OPTION_STRING_HOST + ) { /* add space separator between STRING options in a list */ existing->data[OPT_DATA + old_len] = ' '; old_len++; } - memcpy(existing->data + OPT_DATA + old_len, buffer, length); + memcpy(existing->data + OPT_DATA + old_len, (allocated ? allocated : buffer), length); existing->data[OPT_LEN] = old_len + length; } /* else, ignore the data, we could put this in a second option in the future */ } /* else, ignore the new data */ @@ -415,13 +434,14 @@ static NOINLINE void attach_option( int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) { struct option_set **opt_list = arg; - char *opt, *val, *endptr; + char *opt, *val; char *str; const struct dhcp_optflag *optflag; struct dhcp_optflag bin_optflag; unsigned optcode; int retval, length; - char buffer[8] ALIGNED(4); + /* IP_PAIR needs 8 bytes, STATIC_ROUTES needs 9 max */ + char buffer[9] ALIGNED(4); uint16_t *result_u16 = (uint16_t *) buffer; uint32_t *result_u32 = (uint32_t *) buffer; @@ -462,6 +482,7 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) retval = udhcp_str2nip(val, buffer + 4); break; case OPTION_STRING: + case OPTION_STRING_HOST: #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: #endif @@ -478,34 +499,53 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) // break; // } case OPTION_U8: - buffer[0] = strtoul(val, &endptr, 0); - retval = (endptr[0] == '\0'); + buffer[0] = bb_strtou32(val, NULL, 0); + retval = (errno == 0); break; /* htonX are macros in older libc's, using temp var * in code below for safety */ /* TODO: use bb_strtoX? */ case OPTION_U16: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u16 = htons(tmp); - retval = (endptr[0] == '\0' /*&& tmp < 0x10000*/); + retval = (errno == 0 /*&& tmp < 0x10000*/); break; } // case OPTION_S16: { -// long tmp = strtol(val, &endptr, 0); +// long tmp = bb_strtoi32(val, NULL, 0); // *result_u16 = htons(tmp); -// retval = (endptr[0] == '\0'); +// retval = (errno == 0); // break; // } case OPTION_U32: { - unsigned long tmp = strtoul(val, &endptr, 0); + uint32_t tmp = bb_strtou32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); break; } case OPTION_S32: { - long tmp = strtol(val, &endptr, 0); + int32_t tmp = bb_strtoi32(val, NULL, 0); *result_u32 = htonl(tmp); - retval = (endptr[0] == '\0'); + retval = (errno == 0); + break; + } + case OPTION_STATIC_ROUTES: { + /* Input: "a.b.c.d/m" */ + /* Output: mask(1 byte),pfx(0-4 bytes),gw(4 bytes) */ + unsigned mask; + char *slash = strchr(val, '/'); + if (slash) { + *slash = '\0'; + retval = udhcp_str2nip(val, buffer + 1); + buffer[0] = mask = bb_strtou(slash + 1, NULL, 10); + val = strtok(NULL, ", \t/-"); + if (!val || mask > 32 || errno) + retval = 0; + if (retval) { + length = ((mask + 7) >> 3) + 5; + retval = udhcp_str2nip(val, buffer + (length - 4)); + } + } break; } case OPTION_BIN: /* handled in attach_option() */ @@ -516,7 +556,26 @@ int FAST_FUNC udhcp_str2optset(const char *const_str, void *arg) } if (retval) attach_option(opt_list, optflag, opt, length); - } while (retval && optflag->flags & OPTION_LIST); + } while (retval && (optflag->flags & OPTION_LIST)); return retval; } + +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int FAST_FUNC sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) +{ + char hexstrbuf[16 * 2]; + bin2hex(hexstrbuf, (void*)ip, 16); + return sprintf(dest, /* "%s" */ + "%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s:%.4s", + /* pre, */ + hexstrbuf + 0 * 4, + hexstrbuf + 1 * 4, + hexstrbuf + 2 * 4, + hexstrbuf + 3 * 4, + hexstrbuf + 4 * 4, + hexstrbuf + 5 * 4, + hexstrbuf + 6 * 4, + hexstrbuf + 7 * 4 + ); +} diff --git a/networking/udhcp/common.h b/networking/udhcp/common.h index ce81d18..5e70d60 100644 --- a/networking/udhcp/common.h +++ b/networking/udhcp/common.h @@ -3,7 +3,7 @@ * Russ Dill September 2001 * Rewritten by Vladimir Oleynik (C) 2003 * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifndef UDHCP_COMMON_H #define UDHCP_COMMON_H 1 @@ -14,7 +14,7 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -extern const uint8_t MAC_BCAST_ADDR[6]; /* six all-ones */ +extern const uint8_t MAC_BCAST_ADDR[6] ALIGN2; /* six all-ones */ /*** DHCP packet ***/ @@ -63,14 +63,14 @@ struct udp_dhcp_packet { } PACKED; enum { - IP_UPD_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, - UPD_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + IP_UDP_DHCP_SIZE = sizeof(struct ip_udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, + UDP_DHCP_SIZE = sizeof(struct udp_dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, DHCP_SIZE = sizeof(struct dhcp_packet) - CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS, }; /* Let's see whether compiler understood us right */ struct BUG_bad_sizeof_struct_ip_udp_dhcp_packet { - char c[IP_UPD_DHCP_SIZE == 576 ? 1 : -1]; + char c[IP_UDP_DHCP_SIZE == 576 ? 1 : -1]; }; @@ -80,6 +80,9 @@ enum { OPTION_IP = 1, OPTION_IP_PAIR, OPTION_STRING, + /* Opts of STRING_HOST type will be sanitized before they are passed + * to udhcpc script's environment: */ + OPTION_STRING_HOST, // OPTION_BOOLEAN, OPTION_U8, OPTION_U16, @@ -88,6 +91,7 @@ enum { OPTION_S32, OPTION_BIN, OPTION_STATIC_ROUTES, + OPTION_6RD, #if ENABLE_FEATURE_UDHCP_RFC3397 OPTION_DNS_STRING, /* RFC1035 compressed domain name list */ OPTION_SIP_SERVERS, @@ -103,7 +107,7 @@ enum { /* DHCP option codes (partial list). See RFC 2132 and * http://www.iana.org/assignments/bootp-dhcp-parameters/ * Commented out options are handled by common option machinery, - * uncommented ones have spacial cases (grep for them to see). + * uncommented ones have special cases (grep for them to see). */ #define DHCP_PADDING 0x00 #define DHCP_SUBNET 0x01 @@ -123,6 +127,7 @@ enum { //#define DHCP_IP_TTL 0x17 //#define DHCP_MTU 0x1a //#define DHCP_BROADCAST 0x1c +//#define DHCP_ROUTES 0x21 //#define DHCP_NIS_DOMAIN 0x28 //#define DHCP_NIS_SERVER 0x29 //#define DHCP_NTP_SERVER 0x2a @@ -144,6 +149,10 @@ enum { //#define DHCP_DOMAIN_SEARCH 0x77 /* RFC 3397. set of ASCIZ string, DNS-style compressed */ //#define DHCP_SIP_SERVERS 0x78 /* RFC 3361. flag byte, then: 0: domain names, 1: IP addrs */ //#define DHCP_STATIC_ROUTES 0x79 /* RFC 3442. (mask,ip,router) tuples */ +//#define DHCP_VLAN_ID 0x84 /* 802.1P VLAN ID */ +//#define DHCP_VLAN_PRIORITY 0x85 /* 802.1Q VLAN priority */ +//#define DHCP_PXE_CONF_FILE 0xd1 /* RFC 5071 Configuration File */ +//#define DHCP_MS_STATIC_ROUTES 0xf9 /* Microsoft's pre-RFC 3442 code for 0x79? */ //#define DHCP_WPAD 0xfc /* MSIE's Web Proxy Autodiscovery Protocol */ #define DHCP_END 0xff @@ -179,8 +188,8 @@ struct option_set { }; extern const struct dhcp_optflag dhcp_optflags[]; -extern const char dhcp_option_strings[]; -extern const uint8_t dhcp_option_lengths[]; +extern const char dhcp_option_strings[] ALIGN1; +extern const uint8_t dhcp_option_lengths[] ALIGN1; unsigned FAST_FUNC udhcp_option_idx(const char *name); @@ -244,6 +253,7 @@ struct option_set *udhcp_find_option(struct option_set *opt_list, uint8_t code) /*** Logging ***/ #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ extern unsigned dhcp_verbose; # define log1(...) do { if (dhcp_verbose >= 1) bb_info_msg(__VA_ARGS__); } while (0) # if CONFIG_UDHCP_DEBUG >= 2 @@ -259,6 +269,7 @@ void udhcp_dump_packet(struct dhcp_packet *packet) FAST_FUNC; # define log3(...) ((void)0) # endif #else +# define IF_UDHCP_VERBOSE(...) # define udhcp_dump_packet(...) ((void)0) # define log1(...) ((void)0) # define log2(...) ((void)0) @@ -273,8 +284,6 @@ int FAST_FUNC udhcp_str2nip(const char *str, void *arg); /* 2nd param is "struct option_set**" */ int FAST_FUNC udhcp_str2optset(const char *str, void *arg); -uint16_t udhcp_checksum(void *addr, int count) FAST_FUNC; - void udhcp_init_header(struct dhcp_packet *packet, char type) FAST_FUNC; int udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) FAST_FUNC; @@ -303,6 +312,9 @@ int arpping(uint32_t test_nip, uint8_t *from_mac, const char *interface) FAST_FUNC; +/* note: ip is a pointer to an IPv6 in network order, possibly misaliged */ +int sprint_nip6(char *dest, /*const char *pre,*/ const uint8_t *ip) FAST_FUNC; + POP_SAVED_FUNCTION_VISIBILITY #endif diff --git a/networking/udhcp/d6_common.h b/networking/udhcp/d6_common.h new file mode 100644 index 0000000..eb211ea --- /dev/null +++ b/networking/udhcp/d6_common.h @@ -0,0 +1,127 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#ifndef UDHCP_D6_COMMON_H +#define UDHCP_D6_COMMON_H 1 + +#include + +PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN + + +/*** DHCPv6 packet ***/ + +/* DHCPv6 protocol. See RFC 3315 */ +#define D6_MSG_SOLICIT 1 +#define D6_MSG_ADVERTISE 2 +#define D6_MSG_REQUEST 3 +#define D6_MSG_CONFIRM 4 +#define D6_MSG_RENEW 5 +#define D6_MSG_REBIND 6 +#define D6_MSG_REPLY 7 +#define D6_MSG_RELEASE 8 +#define D6_MSG_DECLINE 9 +#define D6_MSG_RECONFIGURE 10 +#define D6_MSG_INFORMATION_REQUEST 11 +#define D6_MSG_RELAY_FORW 12 +#define D6_MSG_RELAY_REPL 13 + +struct d6_packet { + union { + uint8_t d6_msg_type; + uint32_t d6_xid32; + } d6_u; + uint8_t d6_options[576 - sizeof(struct iphdr) - sizeof(struct udphdr) - 4 + + CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS]; +} PACKED; +#define d6_msg_type d6_u.d6_msg_type +#define d6_xid32 d6_u.d6_xid32 + +struct ip6_udp_d6_packet { + struct ip6_hdr ip6; + struct udphdr udp; + struct d6_packet data; +} PACKED; + +struct udp_d6_packet { + struct udphdr udp; + struct d6_packet data; +} PACKED; + +/*** Options ***/ + +struct d6_option { + uint8_t code_hi; + uint8_t code; + uint8_t len_hi; + uint8_t len; + uint8_t data[1]; +} PACKED; + +#define D6_OPT_CLIENTID 1 +#define D6_OPT_SERVERID 2 +#define D6_OPT_IA_NA 3 +#define D6_OPT_IA_TA 4 +#define D6_OPT_IAADDR 5 +#define D6_OPT_ORO 6 +#define D6_OPT_PREFERENCE 7 +#define D6_OPT_ELAPSED_TIME 8 +#define D6_OPT_RELAY_MSG 9 +#define D6_OPT_AUTH 11 +#define D6_OPT_UNICAST 12 +#define D6_OPT_STATUS_CODE 13 +#define D6_OPT_RAPID_COMMIT 14 +#define D6_OPT_USER_CLASS 15 +#define D6_OPT_VENDOR_CLASS 16 +#define D6_OPT_VENDOR_OPTS 17 +#define D6_OPT_INTERFACE_ID 18 +#define D6_OPT_RECONF_MSG 19 +#define D6_OPT_RECONF_ACCEPT 20 + +#define D6_OPT_IA_PD 25 +#define D6_OPT_IAPREFIX 26 + +/*** Other shared functions ***/ + +struct client6_data_t { + struct d6_option *server_id; + struct d6_option *ia_na; + char **env_ptr; + unsigned env_idx; +}; + +#define client6_data (*(struct client6_data_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE - sizeof(struct client6_data_t)])) + +int FAST_FUNC d6_listen_socket(int port, const char *inf); + +int FAST_FUNC d6_recv_kernel_packet( + struct in6_addr *peer_ipv6, + struct d6_packet *packet, int fd +); + +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex +); + +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port +); + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +void FAST_FUNC d6_dump_packet(struct d6_packet *packet); +#else +# define d6_dump_packet(packet) ((void)0) +#endif + + +POP_SAVED_FUNCTION_VISIBILITY + +#endif diff --git a/networking/udhcp/d6_dhcpc.c b/networking/udhcp/d6_dhcpc.c new file mode 100644 index 0000000..b0f0798 --- /dev/null +++ b/networking/udhcp/d6_dhcpc.c @@ -0,0 +1,1492 @@ +/* vi: set sw=4 ts=4: */ +/* + * DHCPv6 client. + * + * 2011-11. + * WARNING: THIS CODE IS INCOMPLETE. IT IS NOWHERE NEAR + * TO BE READY FOR PRODUCTION USE. + * + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config UDHCPC6 +//config: bool "udhcp client for DHCPv6 (udhcpc6)" +//config: default n # not yet ready +//config: depends on FEATURE_IPV6 +//config: help +//config: udhcpc6 is a DHCPv6 client + +//applet:IF_UDHCPC6(APPLET(udhcpc6, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_UDHCPC6) += d6_dhcpc.o d6_packet.o d6_socket.o common.o socket.o signalpipe.o + + +#include +/* Override ENABLE_FEATURE_PIDFILE - ifupdown needs our pidfile to always exist */ +#define WANT_PIDFILE 1 +#include "common.h" +#include "dhcpd.h" +#include "dhcpc.h" +#include "d6_common.h" + +#include +#include +#include + +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ + + +#if ENABLE_LONG_OPTS +static const char udhcpc6_longopts[] ALIGN1 = + "interface\0" Required_argument "i" + "now\0" No_argument "n" + "pidfile\0" Required_argument "p" + "quit\0" No_argument "q" + "release\0" No_argument "R" + "request\0" Required_argument "r" + "script\0" Required_argument "s" + "timeout\0" Required_argument "T" + "retries\0" Required_argument "t" + "tryagain\0" Required_argument "A" + "syslog\0" No_argument "S" + "request-option\0" Required_argument "O" + "no-default-options\0" No_argument "o" + "foreground\0" No_argument "f" + "background\0" No_argument "b" +/// IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") + IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") + ; +#endif +/* Must match getopt32 option string order */ +enum { + OPT_i = 1 << 0, + OPT_n = 1 << 1, + OPT_p = 1 << 2, + OPT_q = 1 << 3, + OPT_R = 1 << 4, + OPT_r = 1 << 5, + OPT_s = 1 << 6, + OPT_T = 1 << 7, + OPT_t = 1 << 8, + OPT_S = 1 << 9, + OPT_A = 1 << 10, + OPT_O = 1 << 11, + OPT_o = 1 << 12, + OPT_x = 1 << 13, + OPT_f = 1 << 14, +/* The rest has variable bit positions, need to be clever */ + OPTBIT_f = 14, + USE_FOR_MMU( OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPTBIT_P,) + USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) + ///IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) +}; + + +/*** Utility functions ***/ + +static void *d6_find_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + /* Next option's len is too big? */ + if (option[3] > len_m4) + return NULL; /* yes. bogus packet! */ + /* So far we treat any opts with code >255 + * or len >255 as bogus, and stop at once. + * This simplifies big-endian handling. + */ + if (option[0] != 0 || option[2] != 0) + return NULL; + /* Option seems to be valid */ + /* Does its code match? */ + if (option[1] == code) + return option; /* yes! */ + option += option[3] + 4; + len_m4 -= option[3] + 4; + } + return NULL; +} + +static void *d6_copy_option(uint8_t *option, uint8_t *option_end, unsigned code) +{ + uint8_t *opt = d6_find_option(option, option_end, code); + if (!opt) + return opt; + return memcpy(xmalloc(opt[3] + 4), opt, opt[3] + 4); +} + +static void *d6_store_blob(void *dst, const void *src, unsigned len) +{ + memcpy(dst, src, len); + return dst + len; +} + + +/*** Script execution code ***/ + +static char** new_env(void) +{ + client6_data.env_ptr = xrealloc_vector(client6_data.env_ptr, 3, client6_data.env_idx); + return &client6_data.env_ptr[client6_data.env_idx++]; +} + +/* put all the parameters into the environment */ +static void option_to_env(uint8_t *option, uint8_t *option_end) +{ + /* "length minus 4" */ + int len_m4 = option_end - option - 4; + while (len_m4 >= 0) { + uint32_t v32; + char ipv6str[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")]; + + if (option[0] != 0 || option[2] != 0) + break; + + switch (option[1]) { + //case D6_OPT_CLIENTID: + //case D6_OPT_SERVERID: + case D6_OPT_IA_NA: + case D6_OPT_IA_PD: + option_to_env(option + 16, option + 4 + option[3]); + break; + //case D6_OPT_IA_TA: + case D6_OPT_IAADDR: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + sprint_nip6(ipv6str, option + 4); + *new_env() = xasprintf("ipv6=%s", ipv6str); + + move_from_unaligned32(v32, option + 4 + 16 + 4); + *new_env() = xasprintf("lease=%u", (unsigned)v32); + break; + + //case D6_OPT_ORO: + //case D6_OPT_PREFERENCE: + //case D6_OPT_ELAPSED_TIME: + //case D6_OPT_RELAY_MSG: + //case D6_OPT_AUTH: + //case D6_OPT_UNICAST: + //case D6_OPT_STATUS_CODE: + //case D6_OPT_RAPID_COMMIT: + //case D6_OPT_USER_CLASS: + //case D6_OPT_VENDOR_CLASS: + //case D6_OPT_VENDOR_OPTS: + //case D6_OPT_INTERFACE_ID: + //case D6_OPT_RECONF_MSG: + //case D6_OPT_RECONF_ACCEPT: + + case D6_OPT_IAPREFIX: +/* 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAPREFIX | option-length | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | prefix-length | | + * +-+-+-+-+-+-+-+-+ IPv6 prefix | + * | (16 octets) | + * | | + * | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * +-+-+-+-+-+-+-+-+ + */ + //move_from_unaligned32(v32, option + 4 + 4); + //*new_env() = xasprintf("lease=%u", (unsigned)v32); + + sprint_nip6(ipv6str, option + 4 + 4 + 1); + *new_env() = xasprintf("ipv6prefix=%s/%u", ipv6str, (unsigned)(option[4 + 4])); + } + option += 4 + option[3]; + len_m4 -= 4 + option[3]; + } +} + +static char **fill_envp(struct d6_packet *packet) +{ + char **envp, **curr; + + client6_data.env_ptr = NULL; + client6_data.env_idx = 0; + + *new_env() = xasprintf("interface=%s", client_config.interface); + + if (packet) + option_to_env(packet->d6_options, packet->d6_options + sizeof(packet->d6_options)); + + envp = curr = client6_data.env_ptr; + while (*curr) + putenv(*curr++); + + return envp; +} + +/* Call a script with a par file and env vars */ +static void d6_run_script(struct d6_packet *packet, const char *name) +{ + char **envp, **curr; + char *argv[3]; + + envp = fill_envp(packet); + + /* call script */ + log1("Executing %s %s", client_config.script, name); + argv[0] = (char*) client_config.script; + argv[1] = (char*) name; + argv[2] = NULL; + spawn_and_wait(argv); + + for (curr = envp; *curr; curr++) { + log2(" %s", *curr); + bb_unsetenv_and_free(*curr); + } + free(envp); +} + + +/*** Sending/receiving packets ***/ + +static ALWAYS_INLINE uint32_t random_xid(void) +{ + uint32_t t = rand() & htonl(0x00ffffff); + return t; +} + +/* Initialize the packet with the proper defaults */ +static uint8_t *init_d6_packet(struct d6_packet *packet, char type, uint32_t xid) +{ + struct d6_option *clientid; + + memset(packet, 0, sizeof(*packet)); + + packet->d6_xid32 = xid; + packet->d6_msg_type = type; + + clientid = (void*)client_config.clientid; + return d6_store_blob(packet->d6_options, clientid, clientid->len + 2+2); +} + +static uint8_t *add_d6_client_options(uint8_t *ptr) +{ + return ptr; + //uint8_t c; + //int i, end, len; + + /* Add a "param req" option with the list of options we'd like to have + * from stubborn DHCP servers. Pull the data from the struct in common.c. + * No bounds checking because it goes towards the head of the packet. */ + //... + + /* Add -x options if any */ + //... +} + +static int d6_mcast_from_client_config_ifindex(struct d6_packet *packet, uint8_t *end) +{ + static const uint8_t FF02__1_2[16] = { + 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, + }; + + return d6_send_raw_packet( + packet, (end - (uint8_t*) packet), + /*src*/ NULL, CLIENT_PORT6, + /*dst*/ (struct in6_addr*)FF02__1_2, SERVER_PORT6, MAC_BCAST_ADDR, + client_config.ifindex + ); +} + +/* Milticast a DHCPv6 Solicit packet to the network, with an optionally requested IP. + * + * RFC 3315 17.1.1. Creation of Solicit Messages + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client includes IA options for any IAs to which + * it wants the server to assign addresses. The client MAY include + * addresses in the IAs as a hint to the server about addresses for + * which the client has a preference. ... + * + * The client uses IA_NA options to request the assignment of non- + * temporary addresses and uses IA_TA options to request the assignment + * of temporary addresses. Either IA_NA or IA_TA options, or a + * combination of both, can be included in DHCP messages. + * + * The client SHOULD include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY additionally include instances of those options that are + * identified in the Option Request option, with data values as hints to + * the server about parameter values the client would like to have + * returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * if the client is willing to accept Reconfigure messages from the + * server. + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_CLIENTID | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . DUID . + . (variable length) . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IA_NA | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | IAID (4 octets) | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T1 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | T2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + . IA_NA-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_IAADDR | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | | + | IPv6 address | + | | + | | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | preferred-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | valid-lifetime | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + . . + . IAaddr-options . + . . + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_ORO | option-len | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | requested-option-code-1 | requested-option-code-2 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | ... | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | OPTION_RECONF_ACCEPT | 0 | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_discover(uint32_t xid, struct in6_addr *requested_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + unsigned len; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_SOLICIT, xid); + + /* Create new IA_NA, optionally with included IAADDR with requested IP */ + free(client6_data.ia_na); + len = requested_ipv6 ? 2+2+4+4+4 + 2+2+16+4+4 : 2+2+4+4+4; + client6_data.ia_na = xzalloc(len); + client6_data.ia_na->code = D6_OPT_IA_NA; + client6_data.ia_na->len = len - 4; + *(uint32_t*)client6_data.ia_na->data = rand(); /* IAID */ + if (requested_ipv6) { + struct d6_option *iaaddr = (void*)(client6_data.ia_na->data + 4+4+4); + iaaddr->code = D6_OPT_IAADDR; + iaaddr->len = 16+4+4; + memcpy(iaaddr->data, requested_ipv6, 16); + } + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, len); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending discover..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Multicast a DHCPv6 request message + * + * RFC 3315 18.1.1. Creation and Transmission of Request Messages + * + * The client uses a Request message to populate IAs with addresses and + * obtain other configuration information. The client includes one or + * more IA options in the Request message. The server then returns + * addresses and other information about the IAs to the client in IA + * options in a Reply message. + * + * The client generates a transaction ID and inserts this value in the + * "transaction-id" field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any other appropriate options, + * including one or more IA options (if the client is requesting that + * the server assign it some network addresses). + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + * + * The client includes a Reconfigure Accept option (see section 22.20) + * indicating whether or not the client is willing to accept Reconfigure + * messages from the server. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_select(uint32_t xid) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_REQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending select..."); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast or broadcast a DHCP renew message + * + * RFC 3315 18.1.3. Creation and Transmission of Renew Messages + * + * To extend the valid and preferred lifetimes for the addresses + * associated with an IA, the client sends a Renew message to the server + * from which the client obtained the addresses in the IA containing an + * IA option for the IA. The client includes IA Address options in the + * IA option for the addresses associated with the IA. The server + * determines new lifetimes for the addresses in the IA according to the + * administrative configuration of the server. The server may also add + * new addresses to the IA. The server may remove addresses from the IA + * by setting the preferred and valid lifetimes of those addresses to + * zero. + * + * The server controls the time at which the client contacts the server + * to extend the lifetimes on assigned addresses through the T1 and T2 + * parameters assigned to an IA. + * + * At time T1 for an IA, the client initiates a Renew/Reply message + * exchange to extend the lifetimes on any addresses in the IA. The + * client includes an IA option with all addresses currently assigned to + * the IA in its Renew message. + * + * If T1 or T2 is set to 0 by the server (for an IA_NA) or there are no + * T1 or T2 times (for an IA_TA), the client may send a Renew or Rebind + * message, respectively, at the client's discretion. + * + * The client sets the "msg-type" field to RENEW. The client generates + * a transaction ID and inserts this value in the "transaction-id" + * field. + * + * The client places the identifier of the destination server in a + * Server Identifier option. + * + * The client MUST include a Client Identifier option to identify itself + * to the server. The client adds any appropriate options, including + * one or more IA options. The client MUST include the list of + * addresses the client currently has associated with the IAs in the + * Renew message. + * + * The client MUST include an Option Request option (see section 22.7) + * to indicate the options the client is interested in receiving. The + * client MAY include options with data values as hints to the server + * about parameter values the client would like to have returned. + */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_d6_renew(uint32_t xid, struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, DHCPREQUEST, xid); + + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains requested IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + /* Add options: + * "param req" option according to -O, options specified with -x + */ + opt_ptr = add_d6_client_options(opt_ptr); + + bb_info_msg("Sending renew..."); + if (server_ipv6) + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT6, + server_ipv6, SERVER_PORT6 + ); + return d6_mcast_from_client_config_ifindex(&packet, opt_ptr); +} + +/* Unicast a DHCP release message */ +static int send_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + struct d6_packet packet; + uint8_t *opt_ptr; + + /* Fill in: msg type, client id */ + opt_ptr = init_d6_packet(&packet, D6_MSG_RELEASE, random_xid()); + /* server id */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.server_id, client6_data.server_id->len + 2+2); + /* IA NA (contains our current IP) */ + opt_ptr = d6_store_blob(opt_ptr, client6_data.ia_na, client6_data.ia_na->len + 2+2); + + bb_info_msg("Sending release..."); + return d6_send_kernel_packet( + &packet, (opt_ptr - (uint8_t*) &packet), + our_cur_ipv6, CLIENT_PORT6, + server_ipv6, SERVER_PORT6 + ); +} + +/* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int d6_recv_raw_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *d6_pkt, int fd) +{ + int bytes; + struct ip6_udp_d6_packet packet; + + bytes = safe_read(fd, &packet, sizeof(packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + /* NB: possible down interface, etc. Caller should pause. */ + return bytes; /* returns -1 */ + } + + if (bytes < (int) (sizeof(packet.ip6) + sizeof(packet.udp))) { + log1("Packet is too short, ignoring"); + return -2; + } + + if (bytes < sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen)) { + /* packet is bigger than sizeof(packet), we did partial read */ + log1("Oversized packet, ignoring"); + return -2; + } + + /* ignore any extra garbage bytes */ + bytes = sizeof(packet.ip6) + ntohs(packet.ip6.ip6_plen); + + /* make sure its the right packet for us, and that it passes sanity checks */ + if (packet.ip6.ip6_nxt != IPPROTO_UDP + || (packet.ip6.ip6_vfc >> 4) != 6 + || packet.udp.dest != htons(CLIENT_PORT6) + /* || bytes > (int) sizeof(packet) - can't happen */ + || packet.udp.len != packet.ip6.ip6_plen + ) { + log1("Unrelated/bogus packet, ignoring"); + return -2; + } + +//How to do this for ipv6? +// /* verify UDP checksum. IP header has to be modified for this */ +// memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); +// /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ +// packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ +// check = packet.udp.check; +// packet.udp.check = 0; +// if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { +// log1("Packet with bad UDP checksum received, ignoring"); +// return -2; +// } + + log1("Received a packet"); + d6_dump_packet(&packet.data); + + bytes -= sizeof(packet.ip6) + sizeof(packet.udp); + memcpy(d6_pkt, &packet.data, bytes); + return bytes; +} + + +/*** Main ***/ + +static int sockfd = -1; + +#define LISTEN_NONE 0 +#define LISTEN_KERNEL 1 +#define LISTEN_RAW 2 +static smallint listen_mode; + +/* initial state: (re)start DHCP negotiation */ +#define INIT_SELECTING 0 +/* discover was sent, DHCPOFFER reply received */ +#define REQUESTING 1 +/* select/renew was sent, DHCPACK reply received */ +#define BOUND 2 +/* half of lease passed, want to renew it by sending unicast renew requests */ +#define RENEWING 3 +/* renew requests were not answered, lease is almost over, send broadcast renew */ +#define REBINDING 4 +/* manually requested renew (SIGUSR1) */ +#define RENEW_REQUESTED 5 +/* release, possibly manually requested (SIGUSR2) */ +#define RELEASED 6 +static smallint state; + +static int d6_raw_socket(int ifindex) +{ + int fd; + struct sockaddr_ll sock; + + /* + * Comment: + * + * I've selected not to see LL header, so BPF doesn't see it, too. + * The filter may also pass non-IP and non-ARP packets, but we do + * a more complete check when receiving the message in userspace. + * + * and filter shamelessly stolen from: + * + * http://www.flamewarmaster.de/software/dhcpclient/ + * + * There are a few other interesting ideas on that page (look under + * "Motivation"). Use of netlink events is most interesting. Think + * of various network servers listening for events and reconfiguring. + * That would obsolete sending HUP signals and/or make use of restarts. + * + * Copyright: 2006, 2007 Stefan Rompf . + * License: GPL v2. + * + * TODO: make conditional? + */ +#if 0 + static const struct sock_filter filter_instr[] = { + /* load 9th byte (protocol) */ + BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT6, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), + }; + static const struct sock_fprog filter_prog = { + .len = sizeof(filter_instr) / sizeof(filter_instr[0]), + /* casting const away: */ + .filter = (struct sock_filter *) filter_instr, + }; +#endif + + log1("Opening raw socket on ifindex %d", ifindex); //log2? + + fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + log1("Got raw socket fd %d", fd); //log2? + + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IPV6); + sock.sll_ifindex = ifindex; + xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); + +#if 0 + if (CLIENT_PORT6 == 546) { + /* Use only if standard port is in use */ + /* Ignoring error (kernel may lack support for this) */ + if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, + sizeof(filter_prog)) >= 0) + log1("Attached filter to raw socket fd %d", fd); // log? + } +#endif + + log1("Created raw socket"); + + return fd; +} + +static void change_listen_mode(int new_mode) +{ + log1("Entering listen mode: %s", + new_mode != LISTEN_NONE + ? (new_mode == LISTEN_KERNEL ? "kernel" : "raw") + : "none" + ); + + listen_mode = new_mode; + if (sockfd >= 0) { + close(sockfd); + sockfd = -1; + } + if (new_mode == LISTEN_KERNEL) + sockfd = udhcp_listen_socket(/*INADDR_ANY,*/ CLIENT_PORT6, client_config.interface); + else if (new_mode != LISTEN_NONE) + sockfd = d6_raw_socket(client_config.ifindex); + /* else LISTEN_NONE: sockfd stays closed */ +} + +/* Called only on SIGUSR1 */ +static void perform_renew(void) +{ + bb_info_msg("Performing a DHCP renew"); + switch (state) { + case BOUND: + change_listen_mode(LISTEN_KERNEL); + case RENEWING: + case REBINDING: + state = RENEW_REQUESTED; + break; + case RENEW_REQUESTED: /* impatient are we? fine, square 1 */ + d6_run_script(NULL, "deconfig"); + case REQUESTING: + case RELEASED: + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + break; + case INIT_SELECTING: + break; + } +} + +static void perform_d6_release(struct in6_addr *server_ipv6, struct in6_addr *our_cur_ipv6) +{ + /* send release packet */ + if (state == BOUND || state == RENEWING || state == REBINDING) { + bb_info_msg("Unicasting a release"); + send_d6_release(server_ipv6, our_cur_ipv6); /* unicast */ + d6_run_script(NULL, "deconfig"); + } + bb_info_msg("Entering released state"); + + change_listen_mode(LISTEN_NONE); + state = RELEASED; +} + +///static uint8_t* alloc_dhcp_option(int code, const char *str, int extra) +///{ +/// uint8_t *storage; +/// int len = strnlen(str, 255); +/// storage = xzalloc(len + extra + OPT_DATA); +/// storage[OPT_CODE] = code; +/// storage[OPT_LEN] = len + extra; +/// memcpy(storage + extra + OPT_DATA, str, len); +/// return storage; +///} + +#if BB_MMU +static void client_background(void) +{ + bb_daemonize(0); + logmode &= ~LOGMODE_STDIO; + /* rewrite pidfile, as our pid is different now */ + write_pidfile(client_config.pidfile); +} +#endif + +//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_UDHCP_VERBOSE(...) +//usage:#endif +//usage:#define udhcpc6_trivial_usage +//usage: "[-fbnq"IF_UDHCP_VERBOSE("v")"oR] [-i IFACE] [-r IP] [-s PROG] [-p PIDFILE]\n" +//usage: " [-x OPT:VAL]... [-O OPT]..." IF_FEATURE_UDHCP_PORT(" [-P N]") +//usage:#define udhcpc6_full_usage "\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--interface IFACE Interface to use (default eth0)" +//usage: "\n -p,--pidfile FILE Create pidfile" +//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B,--broadcast Request broadcast replies" +//usage: "\n -t,--retries N Send up to N discover packets" +//usage: "\n -T,--timeout N Pause between packets (default 3 seconds)" +//usage: "\n -A,--tryagain N Wait N seconds after failure (default 20)" +//usage: "\n -f,--foreground Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b,--background Background if lease is not obtained" +//usage: ) +//usage: "\n -n,--now Exit if lease is not obtained" +//usage: "\n -q,--quit Exit after obtaining lease" +//usage: "\n -R,--release Release IP on exit" +//usage: "\n -S,--syslog Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P,--client-port N Use port N (default 546)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a,--arping Use arping to validate offered address" +////usage: ) +//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" +//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" +//usage: "\n -r,--request IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i IFACE Interface to use (default eth0)" +//usage: "\n -p FILE Create pidfile" +//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -B Request broadcast replies" +//usage: "\n -t N Send up to N discover packets" +//usage: "\n -T N Pause between packets (default 3 seconds)" +//usage: "\n -A N Wait N seconds (default 20) after failure" +//usage: "\n -f Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b Background if lease is not obtained" +//usage: ) +//usage: "\n -n Exit if lease is not obtained" +//usage: "\n -q Exit after obtaining lease" +//usage: "\n -R Release IP on exit" +//usage: "\n -S Log to syslog too" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P N Use port N (default 546)" +//usage: ) +////usage: IF_FEATURE_UDHCPC_ARPING( +////usage: "\n -a Use arping to validate offered address" +////usage: ) +//usage: "\n -O OPT Request option OPT from server (cumulative)" +//usage: "\n -o Don't request any options (unless -O is given)" +//usage: "\n -r IP Request this IP address" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: "\nSignals:" +//usage: "\n USR1 Renew lease" +//usage: "\n USR2 Release lease" + + +int udhcpc6_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int udhcpc6_main(int argc UNUSED_PARAM, char **argv) +{ + const char *str_r; + IF_FEATURE_UDHCP_PORT(char *str_P;) + void *clientid_mac_ptr; + llist_t *list_O = NULL; + llist_t *list_x = NULL; + int tryagain_timeout = 20; + int discover_timeout = 3; + int discover_retries = 3; + struct in6_addr srv6_buf; + struct in6_addr ipv6_buf; + struct in6_addr *requested_ipv6; + uint32_t xid = 0; + int packet_num; + int timeout; /* must be signed */ + unsigned already_waited_sec; + unsigned opt; + int max_fd; + int retval; + fd_set rfds; + + /* Default options */ + IF_FEATURE_UDHCP_PORT(SERVER_PORT6 = 547;) + IF_FEATURE_UDHCP_PORT(CLIENT_PORT6 = 546;) + client_config.interface = "eth0"; + client_config.script = CONFIG_UDHCPC_DEFAULT_SCRIPT; + + /* Parse command line */ + /* O,x: list; -T,-t,-A take numeric param */ + opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; + IF_LONG_OPTS(applet_long_options = udhcpc6_longopts;) + opt = getopt32(argv, "i:np:qRr:s:T:t:SA:O:ox:f" + USE_FOR_MMU("b") + ///IF_FEATURE_UDHCPC_ARPING("a") + IF_FEATURE_UDHCP_PORT("P:") + "v" + , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ + , &client_config.script /* s */ + , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ + , &list_O + , &list_x + IF_FEATURE_UDHCP_PORT(, &str_P) + IF_UDHCP_VERBOSE(, &dhcp_verbose) + ); + requested_ipv6 = NULL; + if (opt & OPT_r) { + if (inet_pton(AF_INET6, str_r, &ipv6_buf) <= 0) + bb_error_msg_and_die("bad IPv6 address '%s'", str_r); + requested_ipv6 = &ipv6_buf; + } +#if ENABLE_FEATURE_UDHCP_PORT + if (opt & OPT_P) { + CLIENT_PORT6 = xatou16(str_P); + SERVER_PORT6 = CLIENT_PORT6 + 1; + } +#endif + while (list_O) { + char *optstr = llist_pop(&list_O); + unsigned n = bb_strtou(optstr, NULL, 0); + if (errno || n > 254) { + n = udhcp_option_idx(optstr); + n = dhcp_optflags[n].code; + } + client_config.opt_mask[n >> 3] |= 1 << (n & 7); + } + if (!(opt & OPT_o)) { + /* + unsigned i, n; + for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) { + if (dhcp_optflags[i].flags & OPTION_REQ) { + client_config.opt_mask[n >> 3] |= 1 << (n & 7); + } + } + */ + } + while (list_x) { + char *optstr = llist_pop(&list_x); + char *colon = strchr(optstr, ':'); + if (colon) + *colon = ' '; + /* now it looks similar to udhcpd's config file line: + * "optname optval", using the common routine: */ + udhcp_str2optset(optstr, &client_config.options); + } + + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + return 1; + } + + /* Create client ID based on mac, set clientid_mac_ptr */ + { + struct d6_option *clientid; + clientid = xzalloc(2+2+2+2+6); + clientid->code = D6_OPT_CLIENTID; + clientid->len = 2+2+6; + clientid->data[1] = 3; /* DUID-LL */ + clientid->data[3] = 1; /* ethernet */ + clientid_mac_ptr = clientid->data + 2+2; + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + client_config.clientid = (void*)clientid; + } + +#if !BB_MMU + /* on NOMMU reexec (i.e., background) early */ + if (!(opt & OPT_f)) { + bb_daemonize_or_rexec(0 /* flags */, argv); + logmode = LOGMODE_NONE; + } +#endif + if (opt & OPT_S) { + openlog(applet_name, LOG_PID, LOG_DAEMON); + logmode |= LOGMODE_SYSLOG; + } + + /* Make sure fd 0,1,2 are open */ + bb_sanitize_stdio(); + /* Equivalent of doing a fflush after every \n */ + setlinebuf(stdout); + /* Create pidfile */ + write_pidfile(client_config.pidfile); + /* Goes to stdout (unless NOMMU) and possibly syslog */ + bb_info_msg("%s (v"BB_VER") started", applet_name); + /* Set up the signal pipe */ + udhcp_sp_setup(); + /* We want random_xid to be random... */ + srand(monotonic_us()); + + state = INIT_SELECTING; + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + packet_num = 0; + timeout = 0; + already_waited_sec = 0; + + /* Main event loop. select() waits on signal pipe and possibly + * on sockfd. + * "continue" statements in code below jump to the top of the loop. + */ + for (;;) { + struct timeval tv; + struct d6_packet packet; + uint8_t *packet_end; + /* silence "uninitialized!" warning */ + unsigned timestamp_before_wait = timestamp_before_wait; + + //bb_error_msg("sockfd:%d, listen_mode:%d", sockfd, listen_mode); + + /* Was opening raw or udp socket here + * if (listen_mode != LISTEN_NONE && sockfd < 0), + * but on fast network renew responses return faster + * than we open sockets. Thus this code is moved + * to change_listen_mode(). Thus we open listen socket + * BEFORE we send renew request (see "case BOUND:"). */ + + max_fd = udhcp_sp_fd_set(&rfds, sockfd); + + tv.tv_sec = timeout - already_waited_sec; + tv.tv_usec = 0; + retval = 0; + /* If we already timed out, fall through with retval = 0, else... */ + if ((int)tv.tv_sec > 0) { + log1("Waiting on select %u seconds", (int)tv.tv_sec); + timestamp_before_wait = (unsigned)monotonic_sec(); + retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); + if (retval < 0) { + /* EINTR? A signal was caught, don't panic */ + if (errno == EINTR) { + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + continue; + } + /* Else: an error occured, panic! */ + bb_perror_msg_and_die("select"); + } + } + + /* If timeout dropped to zero, time to become active: + * resend discover/renew/whatever + */ + if (retval == 0) { + /* When running on a bridge, the ifindex may have changed + * (e.g. if member interfaces were added/removed + * or if the status of the bridge changed). + * Refresh ifindex and client_mac: + */ + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + goto ret0; /* iface is gone? */ + } + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + + /* We will restart the wait in any case */ + already_waited_sec = 0; + + switch (state) { + case INIT_SELECTING: + if (!discover_retries || packet_num < discover_retries) { + if (packet_num == 0) + xid = random_xid(); + /* multicast */ + send_d6_discover(xid, requested_ipv6); + timeout = discover_timeout; + packet_num++; + continue; + } + leasefail: + d6_run_script(NULL, "leasefail"); +#if BB_MMU /* -b is not supported on NOMMU */ + if (opt & OPT_b) { /* background if no lease */ + bb_info_msg("No lease, forking to background"); + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } else +#endif + if (opt & OPT_n) { /* abort if no lease */ + bb_info_msg("No lease, failing"); + retval = 1; + goto ret; + } + /* wait before trying again */ + timeout = tryagain_timeout; + packet_num = 0; + continue; + case REQUESTING: + if (!discover_retries || packet_num < discover_retries) { + /* send multicast select packet */ + send_d6_select(xid); + timeout = discover_timeout; + packet_num++; + continue; + } + /* Timed out, go back to init state. + * "discover...select...discover..." loops + * were seen in the wild. Treat them similarly + * to "no response to discover" case */ + change_listen_mode(LISTEN_RAW); + state = INIT_SELECTING; + goto leasefail; + case BOUND: + /* 1/2 lease passed, enter renewing state */ + state = RENEWING; + client_config.first_secs = 0; /* make secs field count from 0 */ + change_listen_mode(LISTEN_KERNEL); + log1("Entering renew state"); + /* fall right through */ + case RENEW_REQUESTED: /* manual (SIGUSR1) renew */ + case_RENEW_REQUESTED: + case RENEWING: + if (timeout > 60) { + /* send an unicast renew request */ + /* Sometimes observed to fail (EADDRNOTAVAIL) to bind + * a new UDP socket for sending inside send_renew. + * I hazard to guess existing listening socket + * is somehow conflicting with it, but why is it + * not deterministic then?! Strange. + * Anyway, it does recover by eventually failing through + * into INIT_SELECTING state. + */ + send_d6_renew(xid, &srv6_buf, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter rebinding state */ + log1("Entering rebinding state"); + state = REBINDING; + /* fall right through */ + case REBINDING: + /* Switch to bcast receive */ + change_listen_mode(LISTEN_RAW); + /* Lease is *really* about to run out, + * try to find DHCP server using broadcast */ + if (timeout > 0) { + /* send a broadcast renew request */ + send_d6_renew(xid, /*server_ipv6:*/ NULL, requested_ipv6); + timeout >>= 1; + continue; + } + /* Timed out, enter init state */ + bb_info_msg("Lease lost, entering init state"); + d6_run_script(NULL, "deconfig"); + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + /*timeout = 0; - already is */ + packet_num = 0; + continue; + /* case RELEASED: */ + } + /* yah, I know, *you* say it would never happen */ + timeout = INT_MAX; + continue; /* back to main loop */ + } /* if select timed out */ + + /* select() didn't timeout, something happened */ + + /* Is it a signal? */ + /* note: udhcp_sp_read checks FD_ISSET before reading */ + switch (udhcp_sp_read(&rfds)) { + case SIGUSR1: + client_config.first_secs = 0; /* make secs field count from 0 */ + already_waited_sec = 0; + perform_renew(); + if (state == RENEW_REQUESTED) { + /* We might be either on the same network + * (in which case renew might work), + * or we might be on a completely different one + * (in which case renew won't ever succeed). + * For the second case, must make sure timeout + * is not too big, or else we can send + * futile renew requests for hours. + * (Ab)use -A TIMEOUT value (usually 20 sec) + * as a cap on the timeout. + */ + if (timeout > tryagain_timeout) + timeout = tryagain_timeout; + goto case_RENEW_REQUESTED; + } + /* Start things over */ + packet_num = 0; + /* Kill any timeouts, user wants this to hurry along */ + timeout = 0; + continue; + case SIGUSR2: + perform_d6_release(&srv6_buf, requested_ipv6); + timeout = INT_MAX; + continue; + case SIGTERM: + bb_info_msg("Received SIGTERM"); + goto ret0; + } + + /* Is it a packet? */ + if (listen_mode == LISTEN_NONE || !FD_ISSET(sockfd, &rfds)) + continue; /* no */ + + { + int len; + + /* A packet is ready, read it */ + if (listen_mode == LISTEN_KERNEL) + len = d6_recv_kernel_packet(&srv6_buf, &packet, sockfd); + else + len = d6_recv_raw_packet(&srv6_buf, &packet, sockfd); + if (len == -1) { + /* Error is severe, reopen socket */ + bb_info_msg("Read error: %s, reopening socket", strerror(errno)); + sleep(discover_timeout); /* 3 seconds by default */ + change_listen_mode(listen_mode); /* just close and reopen */ + } + /* If this packet will turn out to be unrelated/bogus, + * we will go back and wait for next one. + * Be sure timeout is properly decreased. */ + already_waited_sec += (unsigned)monotonic_sec() - timestamp_before_wait; + if (len < 0) + continue; + packet_end = (uint8_t*)&packet + len; + } + + if ((packet.d6_xid32 & htonl(0x00ffffff)) != xid) { + log1("xid %x (our is %x), ignoring packet", + (unsigned)(packet.d6_xid32 & htonl(0x00ffffff)), (unsigned)xid); + continue; + } + + switch (state) { + case INIT_SELECTING: + if (packet.d6_msg_type == D6_MSG_ADVERTISE) + goto type_is_ok; + /* DHCPv6 has "Rapid Commit", when instead of Advertise, + * server sends Reply right away. + * Fall through to check for this case. + */ + case REQUESTING: + case RENEWING: + case RENEW_REQUESTED: + case REBINDING: + if (packet.d6_msg_type == D6_MSG_REPLY) { + uint32_t lease_seconds; + struct d6_option *option, *iaaddr; + type_is_ok: + option = d6_find_option(packet.d6_options, packet_end, D6_OPT_STATUS_CODE); + if (option && option->data[4] != 0) { + /* return to init state */ + bb_info_msg("Received DHCP NAK (%u)", option->data[4]); + d6_run_script(&packet, "nak"); + if (state != REQUESTING) + d6_run_script(NULL, "deconfig"); + change_listen_mode(LISTEN_RAW); + sleep(3); /* avoid excessive network traffic */ + state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ + requested_ipv6 = NULL; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + option = d6_copy_option(packet.d6_options, packet_end, D6_OPT_SERVERID); + if (!option) { + bb_error_msg("no server ID, ignoring packet"); + continue; + /* still selecting - this server looks bad */ + } +//Note: we do not bother comparing server IDs in Advertise and Reply msgs. +//server_id variable is used solely for creation of proper server_id option +//in outgoing packets. (why DHCPv6 even introduced it is a mystery). + free(client6_data.server_id); + client6_data.server_id = option; + if (packet.d6_msg_type == D6_MSG_ADVERTISE) { + /* enter requesting state */ + state = REQUESTING; + timeout = 0; + packet_num = 0; + already_waited_sec = 0; + continue; + } + /* It's a D6_MSG_REPLY */ +/* + * RFC 3315 18.1.8. Receipt of Reply Messages + * + * Upon the receipt of a valid Reply message in response to a Solicit + * (with a Rapid Commit option), Request, Confirm, Renew, Rebind or + * Information-request message, the client extracts the configuration + * information contained in the Reply. The client MAY choose to report + * any status code or message from the status code option in the Reply + * message. + * + * The client SHOULD perform duplicate address detection [17] on each of + * the addresses in any IAs it receives in the Reply message before + * using that address for traffic. If any of the addresses are found to + * be in use on the link, the client sends a Decline message to the + * server as described in section 18.1.7. + * + * If the Reply was received in response to a Solicit (with a Rapid + * Commit option), Request, Renew or Rebind message, the client updates + * the information it has recorded about IAs from the IA options + * contained in the Reply message: + * + * - Record T1 and T2 times. + * + * - Add any new addresses in the IA option to the IA as recorded by + * the client. + * + * - Update lifetimes for any addresses in the IA option that the + * client already has recorded in the IA. + * + * - Discard any addresses from the IA, as recorded by the client, that + * have a valid lifetime of 0 in the IA Address option. + * + * - Leave unchanged any information about addresses the client has + * recorded in the IA but that were not included in the IA from the + * server. + * + * Management of the specific configuration information is detailed in + * the definition of each option in section 22. + * + * If the client receives a Reply message with a Status Code containing + * UnspecFail, the server is indicating that it was unable to process + * the message due to an unspecified failure condition. If the client + * retransmits the original message to the same server to retry the + * desired operation, the client MUST limit the rate at which it + * retransmits the message and limit the duration of the time during + * which it retransmits the message. + * + * When the client receives a Reply message with a Status Code option + * with the value UseMulticast, the client records the receipt of the + * message and sends subsequent messages to the server through the + * interface on which the message was received using multicast. The + * client resends the original message using multicast. + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IA_NA | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | IAID (4 octets) | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T1 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | T2 | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * . IA_NA-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * + * + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_IAADDR | option-len | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | | + * | IPv6 address | + * | | + * | | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | preferred-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | valid-lifetime | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * . . + * . IAaddr-options . + * . . + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + */ + free(client6_data.ia_na); + client6_data.ia_na = d6_copy_option(packet.d6_options, packet_end, D6_OPT_IA_NA); + if (!client6_data.ia_na) { + bb_error_msg("no %s option, ignoring packet", "IA_NA"); + continue; + } + if (client6_data.ia_na->len < (4 + 4 + 4) + (2 + 2 + 16 + 4 + 4)) { + bb_error_msg("IA_NA option is too short:%d bytes", client6_data.ia_na->len); + continue; + } + iaaddr = d6_find_option(client6_data.ia_na->data + 4 + 4 + 4, + client6_data.ia_na->data + client6_data.ia_na->len, + D6_OPT_IAADDR + ); + if (!iaaddr) { + bb_error_msg("no %s option, ignoring packet", "IAADDR"); + continue; + } + if (iaaddr->len < (16 + 4 + 4)) { + bb_error_msg("IAADDR option is too short:%d bytes", iaaddr->len); + continue; + } + /* Note: the address is sufficiently aligned for cast: + * we _copied_ IA-NA, and copy is always well-aligned. + */ + requested_ipv6 = (struct in6_addr*) iaaddr->data; + move_from_unaligned32(lease_seconds, iaaddr->data + 16 + 4); + lease_seconds = ntohl(lease_seconds); + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; +/// TODO: check for 0 lease time? + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; + /* enter bound state */ + timeout = lease_seconds / 2; + bb_info_msg("Lease obtained, lease time %u", + /*inet_ntoa(temp_addr),*/ (unsigned)lease_seconds); + d6_run_script(&packet, state == REQUESTING ? "bound" : "renew"); + + state = BOUND; + change_listen_mode(LISTEN_NONE); + if (opt & OPT_q) { /* quit after lease */ + goto ret0; + } + /* future renew failures should not exit (JM) */ + opt &= ~OPT_n; +#if BB_MMU /* NOMMU case backgrounded earlier */ + if (!(opt & OPT_f)) { + client_background(); + /* do not background again! */ + opt = ((opt & ~OPT_b) | OPT_f); + } +#endif + already_waited_sec = 0; + continue; /* back to main loop */ + } + continue; + /* case BOUND: - ignore all packets */ + /* case RELEASED: - ignore all packets */ + } + /* back to main loop */ + } /* for (;;) - main loop ends */ + + ret0: + if (opt & OPT_R) /* release on quit */ + perform_d6_release(&srv6_buf, requested_ipv6); + retval = 0; + ret: + /*if (client_config.pidfile) - remove_pidfile has its own check */ + remove_pidfile(client_config.pidfile); + return retval; +} diff --git a/networking/udhcp/d6_packet.c b/networking/udhcp/d6_packet.c new file mode 100644 index 0000000..79b2946 --- /dev/null +++ b/networking/udhcp/d6_packet.c @@ -0,0 +1,172 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include "dhcpd.h" +#include +#include +#include + +#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 2 +void FAST_FUNC d6_dump_packet(struct d6_packet *packet) +{ + if (dhcp_verbose < 2) + return; + + bb_info_msg( + " xid %x" + , packet->d6_xid32 + ); + //*bin2hex(buf, (void *) packet->chaddr, sizeof(packet->chaddr)) = '\0'; + //bb_info_msg(" chaddr %s", buf); +} +#endif + +int FAST_FUNC d6_recv_kernel_packet(struct in6_addr *peer_ipv6 + UNUSED_PARAM + , struct d6_packet *packet, int fd) +{ + int bytes; + + memset(packet, 0, sizeof(*packet)); + bytes = safe_read(fd, packet, sizeof(*packet)); + if (bytes < 0) { + log1("Packet read error, ignoring"); + return bytes; /* returns -1 */ + } + + if (bytes < offsetof(struct d6_packet, d6_options)) { + bb_info_msg("Packet with bad magic, ignoring"); + return -2; + } + log1("Received a packet"); + d6_dump_packet(packet); + + return bytes; +} + +/* Construct a ipv6+udp header for a packet, send packet */ +int FAST_FUNC d6_send_raw_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port, const uint8_t *dest_arp, + int ifindex) +{ + struct sockaddr_ll dest_sll; + struct ip6_udp_d6_packet packet; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IPV6)); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + + memset(&dest_sll, 0, sizeof(dest_sll)); + memset(&packet, 0, offsetof(struct ip6_udp_d6_packet, data)); + packet.data = *d6_pkt; /* struct copy */ + + dest_sll.sll_family = AF_PACKET; + dest_sll.sll_protocol = htons(ETH_P_IPV6); + dest_sll.sll_ifindex = ifindex; + dest_sll.sll_halen = 6; + memcpy(dest_sll.sll_addr, dest_arp, 6); + + if (bind(fd, (struct sockaddr *)&dest_sll, sizeof(dest_sll)) < 0) { + msg = "bind(%s)"; + goto ret_close; + } + + packet.ip6.ip6_vfc = (6 << 4); /* 4 bits version, top 4 bits of tclass */ + if (src_ipv6) + packet.ip6.ip6_src = *src_ipv6; /* struct copy */ + packet.ip6.ip6_dst = *dst_ipv6; /* struct copy */ + packet.udp.source = htons(source_port); + packet.udp.dest = htons(dest_port); + /* size, excluding IP header: */ + packet.udp.len = htons(sizeof(struct udphdr) + d6_pkt_size); + packet.ip6.ip6_plen = packet.udp.len; + /* + * Someone was smoking weed (at least) while inventing UDP checksumming: + * UDP checksum skips first four bytes of IPv6 header. + * 'next header' field should be summed as if it is one more byte + * to the right, therefore we write its value (IPPROTO_UDP) + * into ip6_hlim, and its 'real' location remains zero-filled for now. + */ + packet.ip6.ip6_hlim = IPPROTO_UDP; + packet.udp.check = inet_cksum( + (uint16_t *)&packet + 2, + offsetof(struct ip6_udp_d6_packet, data) - 4 + d6_pkt_size + ); + /* fix 'hop limit' and 'next header' after UDP checksumming */ + packet.ip6.ip6_hlim = 1; /* observed Windows machines to use hlim=1 */ + packet.ip6.ip6_nxt = IPPROTO_UDP; + + d6_dump_packet(d6_pkt); + result = sendto(fd, &packet, offsetof(struct ip6_udp_d6_packet, data) + d6_pkt_size, + /*flags:*/ 0, + (struct sockaddr *) &dest_sll, sizeof(dest_sll) + ); + msg = "sendto"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "PACKET"); + } + return result; +} + +/* Let the kernel do all the work for packet generation */ +int FAST_FUNC d6_send_kernel_packet( + struct d6_packet *d6_pkt, unsigned d6_pkt_size, + struct in6_addr *src_ipv6, int source_port, + struct in6_addr *dst_ipv6, int dest_port) +{ + struct sockaddr_in6 sa; + int fd; + int result = -1; + const char *msg; + + fd = socket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + if (fd < 0) { + msg = "socket(%s)"; + goto ret_msg; + } + setsockopt_reuseaddr(fd); + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(source_port); + sa.sin6_addr = *src_ipv6; /* struct copy */ + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "bind(%s)"; + goto ret_close; + } + + memset(&sa, 0, sizeof(sa)); + sa.sin6_family = AF_INET6; + sa.sin6_port = htons(dest_port); + sa.sin6_addr = *dst_ipv6; /* struct copy */ + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + msg = "connect"; + goto ret_close; + } + + d6_dump_packet(d6_pkt); + result = safe_write(fd, d6_pkt, d6_pkt_size); + msg = "write"; + ret_close: + close(fd); + if (result < 0) { + ret_msg: + bb_perror_msg(msg, "UDP"); + } + return result; +} diff --git a/networking/udhcp/d6_socket.c b/networking/udhcp/d6_socket.c new file mode 100644 index 0000000..56f69f6 --- /dev/null +++ b/networking/udhcp/d6_socket.c @@ -0,0 +1,34 @@ +/* vi: set sw=4 ts=4: */ +/* + * Copyright (C) 2011 Denys Vlasenko. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +#include "common.h" +#include "d6_common.h" +#include + +int FAST_FUNC d6_listen_socket(int port, const char *inf) +{ + int fd; + struct sockaddr_in6 addr; + + log1("Opening listen socket on *:%d %s", port, inf); + fd = xsocket(PF_INET6, SOCK_DGRAM, IPPROTO_UDP); + + setsockopt_reuseaddr(fd); + if (setsockopt_broadcast(fd) == -1) + bb_perror_msg_and_die("SO_BROADCAST"); + + /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ + if (setsockopt_bindtodevice(fd, inf)) + xfunc_die(); /* warning is already printed */ + + memset(&addr, 0, sizeof(addr)); + addr.sin6_family = AF_INET6; + addr.sin6_port = htons(port); + /* addr.sin6_addr is all-zeros */ + xbind(fd, (struct sockaddr *)&addr, sizeof(addr)); + + return fd; +} diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c index de1b798..8dee916 100644 --- a/networking/udhcp/dhcpc.c +++ b/networking/udhcp/dhcpc.c @@ -25,17 +25,71 @@ #include "dhcpd.h" #include "dhcpc.h" -#include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined(_NEWLIB_VERSION) -# include -# include -#else -# include -# include -#endif +#include #include +#include + +/* "struct client_config_t client_config" is in bb_common_bufsiz1 */ -/* struct client_config_t client_config is in bb_common_bufsiz1 */ + +#if ENABLE_LONG_OPTS +static const char udhcpc_longopts[] ALIGN1 = + "clientid-none\0" No_argument "C" + "vendorclass\0" Required_argument "V" + "hostname\0" Required_argument "H" + "fqdn\0" Required_argument "F" + "interface\0" Required_argument "i" + "now\0" No_argument "n" + "pidfile\0" Required_argument "p" + "quit\0" No_argument "q" + "release\0" No_argument "R" + "request\0" Required_argument "r" + "script\0" Required_argument "s" + "timeout\0" Required_argument "T" + "retries\0" Required_argument "t" + "tryagain\0" Required_argument "A" + "syslog\0" No_argument "S" + "request-option\0" Required_argument "O" + "no-default-options\0" No_argument "o" + "foreground\0" No_argument "f" + "background\0" No_argument "b" + "broadcast\0" No_argument "B" + IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") + IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") + ; +#endif +/* Must match getopt32 option string order */ +enum { + OPT_C = 1 << 0, + OPT_V = 1 << 1, + OPT_H = 1 << 2, + OPT_h = 1 << 3, + OPT_F = 1 << 4, + OPT_i = 1 << 5, + OPT_n = 1 << 6, + OPT_p = 1 << 7, + OPT_q = 1 << 8, + OPT_R = 1 << 9, + OPT_r = 1 << 10, + OPT_s = 1 << 11, + OPT_T = 1 << 12, + OPT_t = 1 << 13, + OPT_S = 1 << 14, + OPT_A = 1 << 15, + OPT_O = 1 << 16, + OPT_o = 1 << 17, + OPT_x = 1 << 18, + OPT_f = 1 << 19, + OPT_B = 1 << 20, +/* The rest has variable bit positions, need to be clever */ + OPTBIT_B = 20, + USE_FOR_MMU( OPTBIT_b,) + IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPTBIT_P,) + USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) + IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) + IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) +}; /*** Script execution code ***/ @@ -45,7 +99,9 @@ static const uint8_t len_of_option_as_string[] = { [OPTION_IP ] = sizeof("255.255.255.255 "), [OPTION_IP_PAIR ] = sizeof("255.255.255.255 ") * 2, [OPTION_STATIC_ROUTES ] = sizeof("255.255.255.255/32 255.255.255.255 "), + [OPTION_6RD ] = sizeof("32 128 ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff 255.255.255.255 "), [OPTION_STRING ] = 1, + [OPTION_STRING_HOST ] = 1, #if ENABLE_FEATURE_UDHCP_RFC3397 [OPTION_DNS_STRING ] = 1, /* unused */ /* Hmmm, this severely overestimates size if SIP_SERVERS option @@ -80,6 +136,63 @@ static int mton(uint32_t mask) return i; } +/* Check if a given label represents a valid DNS label + * Return pointer to the first character after the label upon success, + * NULL otherwise. + * See RFC1035, 2.3.1 + */ +/* We don't need to be particularly anal. For example, allowing _, hyphen + * at the end, or leading and trailing dots would be ok, since it + * can't be used for attacks. (Leading hyphen can be, if someone uses + * cmd "$hostname" + * in the script: then hostname may be treated as an option) + */ +static const char *valid_domain_label(const char *label) +{ + unsigned char ch; + unsigned pos = 0; + + for (;;) { + ch = *label; + if ((ch|0x20) < 'a' || (ch|0x20) > 'z') { + if (pos == 0) { + /* label must begin with letter */ + return NULL; + } + if (ch < '0' || ch > '9') { + if (ch == '\0' || ch == '.') + return label; + /* DNS allows only '-', but we are more permissive */ + if (ch != '-' && ch != '_') + return NULL; + } + } + label++; + pos++; + //Do we want this? + //if (pos > 63) /* NS_MAXLABEL; labels must be 63 chars or less */ + // return NULL; + } +} + +/* Check if a given name represents a valid DNS name */ +/* See RFC1035, 2.3.1 */ +static int good_hostname(const char *name) +{ + //const char *start = name; + + for (;;) { + name = valid_domain_label(name); + if (!name) + return 0; + if (!name[0]) + return 1; + //Do we want this? + //return ((name - start) < 1025); /* NS_MAXDNAME */ + name++; + } +} + /* Create "opt_name=opt_value" string */ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_optflag *optflag, const char *opt_name) { @@ -87,27 +200,25 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ int len, type, optlen; char *dest, *ret; - /* option points to OPT_DATA, need to go back and get OPT_LEN */ - len = option[OPT_LEN - OPT_DATA]; + /* option points to OPT_DATA, need to go back to get OPT_LEN */ + len = option[-OPT_DATA + OPT_LEN]; + type = optflag->flags & OPTION_TYPE_MASK; optlen = dhcp_option_lengths[type]; - upper_length = len_of_option_as_string[type] * ((unsigned)len / (unsigned)optlen); + upper_length = len_of_option_as_string[type] + * ((unsigned)(len + optlen - 1) / (unsigned)optlen); dest = ret = xmalloc(upper_length + strlen(opt_name) + 2); dest += sprintf(ret, "%s=", opt_name); while (len >= optlen) { switch (type) { - case OPTION_IP_PAIR: - dest += sprint_nip(dest, "", option); - *dest++ = '/'; - option += 4; - optlen = 4; case OPTION_IP: + case OPTION_IP_PAIR: dest += sprint_nip(dest, "", option); -// TODO: it can be a list only if (optflag->flags & OPTION_LIST). -// Should we bail out/warn if we see multi-ip option which is -// not allowed to be such? For example, DHCP_BROADCAST... + if (type == OPTION_IP) + break; + dest += sprint_nip(dest, "/", option + 4); break; // case OPTION_BOOLEAN: // dest += sprintf(dest, *option ? "yes" : "no"); @@ -129,10 +240,17 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ dest += sprintf(dest, type == OPTION_U32 ? "%lu" : "%ld", (unsigned long) ntohl(val_u32)); break; } + /* Note: options which use 'return' instead of 'break' + * (for example, OPTION_STRING) skip the code which handles + * the case of list of options. + */ case OPTION_STRING: + case OPTION_STRING_HOST: memcpy(dest, option, len); dest[len] = '\0'; - return ret; /* Short circuit this case */ + if (type == OPTION_STRING_HOST && !good_hostname(dest)) + safe_strncpy(dest, "bad", len); + return ret; case OPTION_STATIC_ROUTES: { /* Option binary format: * mask [one byte, 0..32] @@ -177,6 +295,53 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ return ret; } + case OPTION_6RD: + /* Option binary format (see RFC 5969): + * 0 1 2 3 + * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | OPTION_6RD | option-length | IPv4MaskLen | 6rdPrefixLen | + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * | 6rdPrefix | + * ... (16 octets) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * ... 6rdBRIPv4Address(es) ... + * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + * We convert it to a string + * "IPv4MaskLen 6rdPrefixLen 6rdPrefix 6rdBRIPv4Address..." + * + * Sanity check: ensure that our length is at least 22 bytes, that + * IPv4MaskLen <= 32, + * 6rdPrefixLen <= 128, + * 6rdPrefixLen + (32 - IPv4MaskLen) <= 128 + * (2nd condition need no check - it follows from 1st and 3rd). + * Else, return envvar with empty value ("optname=") + */ + if (len >= (1 + 1 + 16 + 4) + && option[0] <= 32 + && (option[1] + 32 - option[0]) <= 128 + ) { + /* IPv4MaskLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefixLen */ + dest += sprintf(dest, "%u ", *option++); + /* 6rdPrefix */ + dest += sprint_nip6(dest, /* "", */ option); + option += 16; + len -= 1 + 1 + 16 + 4; + /* "+ 4" above corresponds to the length of IPv4 addr + * we consume in the loop below */ + while (1) { + /* 6rdBRIPv4Address(es) */ + dest += sprint_nip(dest, " ", option); + option += 4; + len -= 4; /* do we have yet another 4+ bytes? */ + if (len < 0) + break; /* no */ + } + } + + return ret; #if ENABLE_FEATURE_UDHCP_RFC3397 case OPTION_DNS_STRING: /* unpack option into dest; use ret for prefix (i.e., "optname=") */ @@ -216,13 +381,21 @@ static NOINLINE char *xmalloc_optname_optval(uint8_t *option, const struct dhcp_ return ret; #endif } /* switch */ + + /* If we are here, try to format any remaining data + * in the option as another, similarly-formatted option + */ option += optlen; len -= optlen; - if (len <= 0) +// TODO: it can be a list only if (optflag->flags & OPTION_LIST). +// Should we bail out/warn if we see multi-ip option which is +// not allowed to be such (for example, DHCP_BROADCAST)? - + if (len < optlen /* || !(optflag->flags & OPTION_LIST) */) break; *dest++ = ' '; *dest = '\0'; - } + } /* while */ + return ret; } @@ -236,6 +409,14 @@ static char **fill_envp(struct dhcp_packet *packet) uint8_t *temp; uint8_t overload = 0; +#define BITMAP unsigned +#define BBITS (sizeof(BITMAP) * 8) +#define BMASK(i) (1 << (i & (sizeof(BITMAP) * 8 - 1))) +#define FOUND_OPTS(i) (found_opts[(unsigned)i / BBITS]) + BITMAP found_opts[256 / BBITS]; + + memset(found_opts, 0, sizeof(found_opts)); + /* We need 6 elements for: * "interface=IFACE" * "ip=N.N.N.N" from packet->yiaddr @@ -247,18 +428,22 @@ static char **fill_envp(struct dhcp_packet *packet) envc = 6; /* +1 element for each option, +2 for subnet option: */ if (packet) { - for (i = 0; dhcp_optflags[i].code; i++) { - if (udhcp_get_option(packet, dhcp_optflags[i].code)) { - if (dhcp_optflags[i].code == DHCP_SUBNET) - envc++; /* for mton */ + /* note: do not search for "pad" (0) and "end" (255) options */ +//TODO: change logic to scan packet _once_ + for (i = 1; i < 255; i++) { + temp = udhcp_get_option(packet, i); + if (temp) { + if (i == DHCP_OPTION_OVERLOAD) + overload = *temp; + else if (i == DHCP_SUBNET) + envc++; /* for $mask */ envc++; + /*if (i != DHCP_MESSAGE_TYPE)*/ + FOUND_OPTS(i) |= BMASK(i); } } - temp = udhcp_get_option(packet, DHCP_OPTION_OVERLOAD); - if (temp) - overload = *temp; } - curr = envp = xzalloc(sizeof(char *) * envc); + curr = envp = xzalloc(sizeof(envp[0]) * envc); *curr = xasprintf("interface=%s", client_config.interface); putenv(*curr++); @@ -266,44 +451,88 @@ static char **fill_envp(struct dhcp_packet *packet) if (!packet) return envp; + /* Export BOOTP fields. Fields we don't (yet?) export: + * uint8_t op; // always BOOTREPLY + * uint8_t htype; // hardware address type. 1 = 10mb ethernet + * uint8_t hlen; // hardware address length + * uint8_t hops; // used by relay agents only + * uint32_t xid; + * uint16_t secs; // elapsed since client began acquisition/renewal + * uint16_t flags; // only one flag so far: bcast. Never set by server + * uint32_t ciaddr; // client IP (usually == yiaddr. can it be different + * // if during renew server wants to give us differn IP?) + * uint32_t gateway_nip; // relay agent IP address + * uint8_t chaddr[16]; // link-layer client hardware address (MAC) + * TODO: export gateway_nip as $giaddr? + */ + /* Most important one: yiaddr as $ip */ *curr = xmalloc(sizeof("ip=255.255.255.255")); sprint_nip(*curr, "ip=", (uint8_t *) &packet->yiaddr); putenv(*curr++); + if (packet->siaddr_nip) { + /* IP address of next server to use in bootstrap */ + *curr = xmalloc(sizeof("siaddr=255.255.255.255")); + sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); + putenv(*curr++); + } + if (!(overload & FILE_FIELD) && packet->file[0]) { + /* watch out for invalid packets */ + *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); + putenv(*curr++); + } + if (!(overload & SNAME_FIELD) && packet->sname[0]) { + /* watch out for invalid packets */ + *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); + putenv(*curr++); + } + /* Export known DHCP options */ opt_name = dhcp_option_strings; i = 0; while (*opt_name) { - temp = udhcp_get_option(packet, dhcp_optflags[i].code); - if (!temp) + uint8_t code = dhcp_optflags[i].code; + BITMAP *found_ptr = &FOUND_OPTS(code); + BITMAP found_mask = BMASK(code); + if (!(*found_ptr & found_mask)) goto next; + *found_ptr &= ~found_mask; /* leave only unknown options */ + temp = udhcp_get_option(packet, code); *curr = xmalloc_optname_optval(temp, &dhcp_optflags[i], opt_name); putenv(*curr++); - if (dhcp_optflags[i].code == DHCP_SUBNET) { + if (code == DHCP_SUBNET) { /* Subnet option: make things like "$ip/$mask" possible */ uint32_t subnet; move_from_unaligned32(subnet, temp); - *curr = xasprintf("mask=%d", mton(subnet)); + *curr = xasprintf("mask=%u", mton(subnet)); putenv(*curr++); } next: opt_name += strlen(opt_name) + 1; i++; } - if (packet->siaddr_nip) { - *curr = xmalloc(sizeof("siaddr=255.255.255.255")); - sprint_nip(*curr, "siaddr=", (uint8_t *) &packet->siaddr_nip); - putenv(*curr++); - } - if (!(overload & FILE_FIELD) && packet->file[0]) { - /* watch out for invalid packets */ - *curr = xasprintf("boot_file=%."DHCP_PKT_FILE_LEN_STR"s", packet->file); - putenv(*curr++); - } - if (!(overload & SNAME_FIELD) && packet->sname[0]) { - /* watch out for invalid packets */ - *curr = xasprintf("sname=%."DHCP_PKT_SNAME_LEN_STR"s", packet->sname); - putenv(*curr++); + /* Export unknown options */ + for (i = 0; i < 256;) { + BITMAP bitmap = FOUND_OPTS(i); + if (!bitmap) { + i += BBITS; + continue; + } + if (bitmap & BMASK(i)) { + unsigned len, ofs; + + temp = udhcp_get_option(packet, i); + /* udhcp_get_option returns ptr to data portion, + * need to go back to get len + */ + len = temp[-OPT_DATA + OPT_LEN]; + *curr = xmalloc(sizeof("optNNN=") + 1 + len*2); + ofs = sprintf(*curr, "opt%u=", i); + *bin2hex(*curr + ofs, (void*) temp, len) = '\0'; + putenv(*curr++); + } + i++; } + return envp; } @@ -313,9 +542,6 @@ static void udhcp_run_script(struct dhcp_packet *packet, const char *name) char **envp, **curr; char *argv[3]; - if (client_config.script == NULL) - return; - envp = fill_envp(packet); /* call script */ @@ -343,38 +569,38 @@ static ALWAYS_INLINE uint32_t random_xid(void) /* Initialize the packet with the proper defaults */ static void init_packet(struct dhcp_packet *packet, char type) { + uint16_t secs; + + /* Fill in: op, htype, hlen, cookie fields; message type option: */ udhcp_init_header(packet, type); + + packet->xid = random_xid(); + + client_config.last_secs = monotonic_sec(); + if (client_config.first_secs == 0) + client_config.first_secs = client_config.last_secs; + secs = client_config.last_secs - client_config.first_secs; + packet->secs = htons(secs); + memcpy(packet->chaddr, client_config.client_mac, 6); if (client_config.clientid) udhcp_add_binary_option(packet, client_config.clientid); - if (client_config.hostname) - udhcp_add_binary_option(packet, client_config.hostname); - if (client_config.fqdn) - udhcp_add_binary_option(packet, client_config.fqdn); - if (type != DHCPDECLINE - && type != DHCPRELEASE - && client_config.vendorclass - ) { - udhcp_add_binary_option(packet, client_config.vendorclass); - } } static void add_client_options(struct dhcp_packet *packet) { + int i, end, len; + + udhcp_add_simple_option(packet, DHCP_MAX_SIZE, htons(IP_UDP_DHCP_SIZE)); + /* Add a "param req" option with the list of options we'd like to have * from stubborn DHCP servers. Pull the data from the struct in common.c. * No bounds checking because it goes towards the head of the packet. */ - uint8_t c; - int end = udhcp_end_option(packet->options); - int i, len = 0; - - for (i = 0; (c = dhcp_optflags[i].code) != 0; i++) { - if (( (dhcp_optflags[i].flags & OPTION_REQ) - && !client_config.no_default_options - ) - || (client_config.opt_mask[c >> 3] & (1 << (c & 7))) - ) { - packet->options[end + OPT_DATA + len] = c; + end = udhcp_end_option(packet->options); + len = 0; + for (i = 1; i < DHCP_END; i++) { + if (client_config.opt_mask[i >> 3] & (1 << (i & 7))) { + packet->options[end + OPT_DATA + len] = i; len++; } } @@ -384,6 +610,17 @@ static void add_client_options(struct dhcp_packet *packet) packet->options[end + OPT_DATA + len] = DHCP_END; } + if (client_config.vendorclass) + udhcp_add_binary_option(packet, client_config.vendorclass); + if (client_config.hostname) + udhcp_add_binary_option(packet, client_config.hostname); + if (client_config.fqdn) + udhcp_add_binary_option(packet, client_config.fqdn); + + /* Request broadcast replies if we have no IP addr */ + if ((option_mask32 & OPT_B) && packet->ciaddr == 0) + packet->flags |= htons(BROADCAST_FLAG); + /* Add -x options if any */ { struct option_set *curr = client_config.options; @@ -396,6 +633,12 @@ static void add_client_options(struct dhcp_packet *packet) // if (client_config.boot_file) // strncpy((char*)packet->file, client_config.boot_file, sizeof(packet->file) - 1); } + + // This will be needed if we remove -V VENDOR_STR in favor of + // -x vendor:VENDOR_STR + //if (!udhcp_find_option(packet.options, DHCP_VENDOR)) + // /* not set, set the default vendor ID */ + // ...add (DHCP_VENDOR, "udhcp "BB_VER) opt... } /* RFC 2131 @@ -424,18 +667,35 @@ static int raw_bcast_from_client_config_ifindex(struct dhcp_packet *packet) client_config.ifindex); } +static int bcast_or_ucast(struct dhcp_packet *packet, uint32_t ciaddr, uint32_t server) +{ + if (server) + return udhcp_send_kernel_packet(packet, + ciaddr, CLIENT_PORT, + server, SERVER_PORT); + return raw_bcast_from_client_config_ifindex(packet); +} + /* Broadcast a DHCP discover packet to the network, with an optionally requested IP */ -static int send_discover(uint32_t xid, uint32_t requested) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_discover(uint32_t xid, uint32_t requested) { struct dhcp_packet packet; + /* Fill in: op, htype, hlen, cookie, chaddr fields, + * random xid field (we override it below), + * client-id option (unless -C), message type option: + */ init_packet(&packet, DHCPDISCOVER); + packet.xid = xid; if (requested) udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); - /* Explicitly saying that we want RFC-compliant packets helps - * some buggy DHCP servers to NOT send bigger packets */ - udhcp_add_simple_option(&packet, DHCP_MAX_SIZE, htons(576)); + + /* Add options: maxsize, + * optionally: hostname, fqdn, vendorclass, + * "param req" option according to -O, options specified with -x + */ add_client_options(&packet); bb_info_msg("Sending discover..."); @@ -446,15 +706,39 @@ static int send_discover(uint32_t xid, uint32_t requested) /* RFC 2131 3.1 paragraph 3: * "The client _broadcasts_ a DHCPREQUEST message..." */ -static int send_select(uint32_t xid, uint32_t server, uint32_t requested) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_select(uint32_t xid, uint32_t server, uint32_t requested) { struct dhcp_packet packet; struct in_addr addr; +/* + * RFC 2131 4.3.2 DHCPREQUEST message + * ... + * If the DHCPREQUEST message contains a 'server identifier' + * option, the message is in response to a DHCPOFFER message. + * Otherwise, the message is a request to verify or extend an + * existing lease. If the client uses a 'client identifier' + * in a DHCPREQUEST message, it MUST use that same 'client identifier' + * in all subsequent messages. If the client included a list + * of requested parameters in a DHCPDISCOVER message, it MUST + * include that list in all subsequent messages. + */ + /* Fill in: op, htype, hlen, cookie, chaddr fields, + * random xid field (we override it below), + * client-id option (unless -C), message type option: + */ init_packet(&packet, DHCPREQUEST); + packet.xid = xid; udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); + udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); + + /* Add options: maxsize, + * optionally: hostname, fqdn, vendorclass, + * "param req" option according to -O, and options specified with -x + */ add_client_options(&packet); addr.s_addr = requested; @@ -463,32 +747,67 @@ static int send_select(uint32_t xid, uint32_t server, uint32_t requested) } /* Unicast or broadcast a DHCP renew message */ -static int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_renew(uint32_t xid, uint32_t server, uint32_t ciaddr) { struct dhcp_packet packet; +/* + * RFC 2131 4.3.2 DHCPREQUEST message + * ... + * DHCPREQUEST generated during RENEWING state: + * + * 'server identifier' MUST NOT be filled in, 'requested IP address' + * option MUST NOT be filled in, 'ciaddr' MUST be filled in with + * client's IP address. In this situation, the client is completely + * configured, and is trying to extend its lease. This message will + * be unicast, so no relay agents will be involved in its + * transmission. Because 'giaddr' is therefore not filled in, the + * DHCP server will trust the value in 'ciaddr', and use it when + * replying to the client. + */ + /* Fill in: op, htype, hlen, cookie, chaddr fields, + * random xid field (we override it below), + * client-id option (unless -C), message type option: + */ init_packet(&packet, DHCPREQUEST); + packet.xid = xid; packet.ciaddr = ciaddr; + + /* Add options: maxsize, + * optionally: hostname, fqdn, vendorclass, + * "param req" option according to -O, and options specified with -x + */ add_client_options(&packet); bb_info_msg("Sending renew..."); - if (server) - return udhcp_send_kernel_packet(&packet, - ciaddr, CLIENT_PORT, - server, SERVER_PORT); - return raw_bcast_from_client_config_ifindex(&packet); + return bcast_or_ucast(&packet, ciaddr, server); } #if ENABLE_FEATURE_UDHCPC_ARPING /* Broadcast a DHCP decline message */ -static int send_decline(uint32_t xid, uint32_t server, uint32_t requested) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE int send_decline(/*uint32_t xid,*/ uint32_t server, uint32_t requested) { struct dhcp_packet packet; + /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, + * client-id option (unless -C), message type option: + */ init_packet(&packet, DHCPDECLINE); + +#if 0 + /* RFC 2131 says DHCPDECLINE's xid is randomly selected by client, + * but in case the server is buggy and wants DHCPDECLINE's xid + * to match the xid which started entire handshake, + * we use the same xid we used in initial DHCPDISCOVER: + */ packet.xid = xid; +#endif + /* DHCPDECLINE uses "requested ip", not ciaddr, to store offered IP */ udhcp_add_simple_option(&packet, DHCP_REQUESTED_IP, requested); + udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); bb_info_msg("Sending decline..."); @@ -501,29 +820,56 @@ static int send_release(uint32_t server, uint32_t ciaddr) { struct dhcp_packet packet; + /* Fill in: op, htype, hlen, cookie, chaddr, random xid fields, + * client-id option (unless -C), message type option: + */ init_packet(&packet, DHCPRELEASE); - packet.xid = random_xid(); + + /* DHCPRELEASE uses ciaddr, not "requested ip", to store IP being released */ packet.ciaddr = ciaddr; udhcp_add_simple_option(&packet, DHCP_SERVER_ID, server); bb_info_msg("Sending release..."); - return udhcp_send_kernel_packet(&packet, ciaddr, CLIENT_PORT, server, SERVER_PORT); + /* Note: normally we unicast here since "server" is not zero. + * However, there _are_ people who run "address-less" DHCP servers, + * and reportedly ISC dhcp client and Windows allow that. + */ + return bcast_or_ucast(&packet, ciaddr, server); } /* Returns -1 on errors that are fatal for the socket, -2 for those that aren't */ +/* NOINLINE: limit stack usage in caller */ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) { int bytes; struct ip_udp_dhcp_packet packet; uint16_t check; + unsigned char cmsgbuf[CMSG_LEN(sizeof(struct tpacket_auxdata))]; + struct iovec iov; + struct msghdr msg; + struct cmsghdr *cmsg; - memset(&packet, 0, sizeof(packet)); - bytes = safe_read(fd, &packet, sizeof(packet)); - if (bytes < 0) { - log1("Packet read error, ignoring"); - /* NB: possible down interface, etc. Caller should pause. */ - return bytes; /* returns -1 */ + /* used to use just safe_read(fd, &packet, sizeof(packet)) + * but we need to check for TP_STATUS_CSUMNOTREADY :( + */ + iov.iov_base = &packet; + iov.iov_len = sizeof(packet); + memset(&msg, 0, sizeof(msg)); + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = sizeof(cmsgbuf); + for (;;) { + bytes = recvmsg(fd, &msg, 0); + if (bytes < 0) { + if (errno == EINTR) + continue; + log1("Packet read error, ignoring"); + /* NB: possible down interface, etc. Caller should pause. */ + return bytes; /* returns -1 */ + } + break; } if (bytes < (int) (sizeof(packet.ip) + sizeof(packet.udp))) { @@ -541,7 +887,8 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) bytes = ntohs(packet.ip.tot_len); /* make sure its the right packet for us, and that it passes sanity checks */ - if (packet.ip.protocol != IPPROTO_UDP || packet.ip.version != IPVERSION + if (packet.ip.protocol != IPPROTO_UDP + || packet.ip.version != IPVERSION || packet.ip.ihl != (sizeof(packet.ip) >> 2) || packet.udp.dest != htons(CLIENT_PORT) /* || bytes > (int) sizeof(packet) - can't happen */ @@ -554,31 +901,48 @@ static NOINLINE int udhcp_recv_raw_packet(struct dhcp_packet *dhcp_pkt, int fd) /* verify IP checksum */ check = packet.ip.check; packet.ip.check = 0; - if (check != udhcp_checksum(&packet.ip, sizeof(packet.ip))) { + if (check != inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip))) { log1("Bad IP header checksum, ignoring"); return -2; } + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == SOL_PACKET + && cmsg->cmsg_type == PACKET_AUXDATA + ) { + /* some VMs don't checksum UDP and TCP data + * they send to the same physical machine, + * here we detect this case: + */ + struct tpacket_auxdata *aux = (void *)CMSG_DATA(cmsg); + if (aux->tp_status & TP_STATUS_CSUMNOTREADY) + goto skip_udp_sum_check; + } + } + /* verify UDP checksum. IP header has to be modified for this */ memset(&packet.ip, 0, offsetof(struct iphdr, protocol)); /* ip.xx fields which are not memset: protocol, check, saddr, daddr */ packet.ip.tot_len = packet.udp.len; /* yes, this is needed */ check = packet.udp.check; packet.udp.check = 0; - if (check && check != udhcp_checksum(&packet, bytes)) { + if (check && check != inet_cksum((uint16_t *)&packet, bytes)) { log1("Packet with bad UDP checksum received, ignoring"); return -2; } + skip_udp_sum_check: - memcpy(dhcp_pkt, &packet.data, bytes - (sizeof(packet.ip) + sizeof(packet.udp))); - - if (dhcp_pkt->cookie != htonl(DHCP_MAGIC)) { + if (packet.data.cookie != htonl(DHCP_MAGIC)) { bb_info_msg("Packet with bad magic, ignoring"); return -2; } - log1("Got valid DHCP packet"); - udhcp_dump_packet(dhcp_pkt); - return bytes - (sizeof(packet.ip) + sizeof(packet.udp)); + + log1("Received a packet"); + udhcp_dump_packet(&packet.data); + + bytes -= sizeof(packet.ip) + sizeof(packet.udp); + memcpy(dhcp_pkt, &packet.data, bytes); + return bytes; } @@ -633,22 +997,25 @@ static int udhcp_raw_socket(int ifindex) * * TODO: make conditional? */ -#define SERVER_AND_CLIENT_PORTS ((67 << 16) + 68) static const struct sock_filter filter_instr[] = { - /* check for udp */ + /* load 9th byte (protocol) */ BPF_STMT(BPF_LD|BPF_B|BPF_ABS, 9), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 2, 0), /* L5, L1, is UDP? */ - /* ugly check for arp on ethernet-like and IPv4 */ - BPF_STMT(BPF_LD|BPF_W|BPF_ABS, 2), /* L1: */ - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 0x08000604, 3, 4), /* L3, L4 */ - /* skip IP header */ - BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), /* L5: */ - /* check udp source and destination ports */ - BPF_STMT(BPF_LD|BPF_W|BPF_IND, 0), - BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, SERVER_AND_CLIENT_PORTS, 0, 1), /* L3, L4 */ - /* returns */ - BPF_STMT(BPF_RET|BPF_K, 0x0fffffff ), /* L3: pass */ - BPF_STMT(BPF_RET|BPF_K, 0), /* L4: reject */ + /* jump to L1 if it is IPPROTO_UDP, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, IPPROTO_UDP, 0, 6), + /* L1: load halfword from offset 6 (flags and frag offset) */ + BPF_STMT(BPF_LD|BPF_H|BPF_ABS, 6), + /* jump to L4 if any bits in frag offset field are set, else to L2 */ + BPF_JUMP(BPF_JMP|BPF_JSET|BPF_K, 0x1fff, 4, 0), + /* L2: skip IP header (load index reg with header len) */ + BPF_STMT(BPF_LDX|BPF_B|BPF_MSH, 0), + /* load udp destination port from halfword[header_len + 2] */ + BPF_STMT(BPF_LD|BPF_H|BPF_IND, 2), + /* jump to L3 if udp dport is CLIENT_PORT, else to L4 */ + BPF_JUMP(BPF_JMP|BPF_JEQ|BPF_K, 68, 0, 1), + /* L3: accept packet */ + BPF_STMT(BPF_RET|BPF_K, 0xffffffff), + /* L4: discard packet */ + BPF_STMT(BPF_RET|BPF_K, 0), }; static const struct sock_fprog filter_prog = { .len = sizeof(filter_instr) / sizeof(filter_instr[0]), @@ -659,20 +1026,28 @@ static int udhcp_raw_socket(int ifindex) log1("Opening raw socket on ifindex %d", ifindex); //log2? fd = xsocket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_IP)); - log1("Got raw socket fd %d", fd); //log2? + log1("Got raw socket fd"); //log2? - if (SERVER_PORT == 67 && CLIENT_PORT == 68) { - /* Use only if standard ports are in use */ + sock.sll_family = AF_PACKET; + sock.sll_protocol = htons(ETH_P_IP); + sock.sll_ifindex = ifindex; + xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); + + if (CLIENT_PORT == 68) { + /* Use only if standard port is in use */ /* Ignoring error (kernel may lack support for this) */ if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter_prog, sizeof(filter_prog)) >= 0) - log1("Attached filter to raw socket fd %d", fd); // log? + log1("Attached filter to raw socket fd"); // log? + } + + if (setsockopt(fd, SOL_PACKET, PACKET_AUXDATA, + &const_int_1, sizeof(int)) < 0 + ) { + if (errno != ENOPROTOOPT) + log1("Can't set PACKET_AUXDATA on raw socket"); } - sock.sll_family = AF_PACKET; - sock.sll_protocol = htons(ETH_P_IP); - sock.sll_ifindex = ifindex; - xbind(fd, (struct sockaddr *) &sock, sizeof(sock)); log1("Created raw socket"); return fd; @@ -698,6 +1073,7 @@ static void change_listen_mode(int new_mode) /* else LISTEN_NONE: sockfd stays closed */ } +/* Called only on SIGUSR1 */ static void perform_renew(void) { bb_info_msg("Performing a DHCP renew"); @@ -720,7 +1096,7 @@ static void perform_renew(void) } } -static void perform_release(uint32_t requested_ip, uint32_t server_addr) +static void perform_release(uint32_t server_addr, uint32_t requested_ip) { char buffer[sizeof("255.255.255.255")]; struct in_addr temp_addr; @@ -762,12 +1138,102 @@ static void client_background(void) } #endif +//usage:#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 +//usage:# define IF_UDHCP_VERBOSE(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_UDHCP_VERBOSE(...) +//usage:#endif +//usage:#define udhcpc_trivial_usage +//usage: "[-fbq"IF_UDHCP_VERBOSE("v")IF_FEATURE_UDHCPC_ARPING("a")"RB] [-t N] [-T SEC] [-A SEC/-n]\n" +//usage: " [-i IFACE]"IF_FEATURE_UDHCP_PORT(" [-P PORT]")" [-s PROG] [-p PIDFILE]\n" +//usage: " [-oC] [-r IP] [-V VENDOR] [-F NAME] [-x OPT:VAL]... [-O OPT]..." +//usage:#define udhcpc_full_usage "\n" +//usage: IF_LONG_OPTS( +//usage: "\n -i,--interface IFACE Interface to use (default eth0)" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P,--client-port PORT Use PORT (default 68)" +//usage: ) +//usage: "\n -s,--script PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -p,--pidfile FILE Create pidfile" +//usage: "\n -B,--broadcast Request broadcast replies" +//usage: "\n -t,--retries N Send up to N discover packets (default 3)" +//usage: "\n -T,--timeout SEC Pause between packets (default 3)" +//usage: "\n -A,--tryagain SEC Wait if lease is not obtained (default 20)" +//usage: "\n -n,--now Exit if lease is not obtained" +//usage: "\n -q,--quit Exit after obtaining lease" +//usage: "\n -R,--release Release IP on exit" +//usage: "\n -f,--foreground Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b,--background Background if lease is not obtained" +//usage: ) +//usage: "\n -S,--syslog Log to syslog too" +//usage: IF_FEATURE_UDHCPC_ARPING( +//usage: "\n -a,--arping Use arping to validate offered address" +//usage: ) +//usage: "\n -r,--request IP Request this IP address" +//usage: "\n -o,--no-default-options Don't request any options (unless -O is given)" +//usage: "\n -O,--request-option OPT Request option OPT from server (cumulative)" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: "\n -F,--fqdn NAME Ask server to update DNS mapping for NAME" +//usage: "\n -V,--vendorclass VENDOR Vendor identifier (default 'udhcp VERSION')" +//usage: "\n -C,--clientid-none Don't send MAC as client identifier" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -i IFACE Interface to use (default eth0)" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P PORT Use PORT (default 68)" +//usage: ) +//usage: "\n -s PROG Run PROG at DHCP events (default "CONFIG_UDHCPC_DEFAULT_SCRIPT")" +//usage: "\n -p FILE Create pidfile" +//usage: "\n -B Request broadcast replies" +//usage: "\n -t N Send up to N discover packets (default 3)" +//usage: "\n -T SEC Pause between packets (default 3)" +//usage: "\n -A SEC Wait if lease is not obtained (default 20)" +//usage: "\n -n Exit if lease is not obtained" +//usage: "\n -q Exit after obtaining lease" +//usage: "\n -R Release IP on exit" +//usage: "\n -f Run in foreground" +//usage: USE_FOR_MMU( +//usage: "\n -b Background if lease is not obtained" +//usage: ) +//usage: "\n -S Log to syslog too" +//usage: IF_FEATURE_UDHCPC_ARPING( +//usage: "\n -a Use arping to validate offered address" +//usage: ) +//usage: "\n -r IP Request this IP address" +//usage: "\n -o Don't request any options (unless -O is given)" +//usage: "\n -O OPT Request option OPT from server (cumulative)" +//usage: "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" +//usage: "\n Examples of string, numeric, and hex byte opts:" +//usage: "\n -x hostname:bbox - option 12" +//usage: "\n -x lease:3600 - option 51 (lease time)" +//usage: "\n -x 0x3d:0100BEEFC0FFEE - option 61 (client id)" +//usage: "\n -F NAME Ask server to update DNS mapping for NAME" +//usage: "\n -V VENDOR Vendor identifier (default 'udhcp VERSION')" +//usage: "\n -C Don't send MAC as client identifier" +//usage: IF_UDHCP_VERBOSE( +//usage: "\n -v Verbose" +//usage: ) +//usage: ) +//usage: "\nSignals:" +//usage: "\n USR1 Renew lease" +//usage: "\n USR2 Release lease" + + int udhcpc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpc_main(int argc UNUSED_PARAM, char **argv) { uint8_t *temp, *message; - const char *str_c, *str_V, *str_h, *str_F, *str_r; + const char *str_V, *str_h, *str_F, *str_r; IF_FEATURE_UDHCP_PORT(char *str_P;) + void *clientid_mac_ptr; llist_t *list_O = NULL; llist_t *list_x = NULL; int tryagain_timeout = 20; @@ -775,78 +1241,16 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) int discover_retries = 3; uint32_t server_addr = server_addr; /* for compiler */ uint32_t requested_ip = 0; - uint32_t xid = 0; - uint32_t lease_seconds = 0; /* can be given as 32-bit quantity */ + uint32_t xid = xid; /* for compiler */ int packet_num; int timeout; /* must be signed */ unsigned already_waited_sec; unsigned opt; int max_fd; int retval; - struct timeval tv; - struct dhcp_packet packet; fd_set rfds; -#if ENABLE_LONG_OPTS - static const char udhcpc_longopts[] ALIGN1 = - "clientid\0" Required_argument "c" - "clientid-none\0" No_argument "C" - "vendorclass\0" Required_argument "V" - "hostname\0" Required_argument "H" - "fqdn\0" Required_argument "F" - "interface\0" Required_argument "i" - "now\0" No_argument "n" - "pidfile\0" Required_argument "p" - "quit\0" No_argument "q" - "release\0" No_argument "R" - "request\0" Required_argument "r" - "script\0" Required_argument "s" - "timeout\0" Required_argument "T" - "version\0" No_argument "v" - "retries\0" Required_argument "t" - "tryagain\0" Required_argument "A" - "syslog\0" No_argument "S" - "request-option\0" Required_argument "O" - "no-default-options\0" No_argument "o" - "foreground\0" No_argument "f" - "background\0" No_argument "b" - IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") - IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") - ; -#endif - enum { - OPT_c = 1 << 0, - OPT_C = 1 << 1, - OPT_V = 1 << 2, - OPT_H = 1 << 3, - OPT_h = 1 << 4, - OPT_F = 1 << 5, - OPT_i = 1 << 6, - OPT_n = 1 << 7, - OPT_p = 1 << 8, - OPT_q = 1 << 9, - OPT_R = 1 << 10, - OPT_r = 1 << 11, - OPT_s = 1 << 12, - OPT_T = 1 << 13, - OPT_t = 1 << 14, - OPT_S = 1 << 15, - OPT_A = 1 << 16, - OPT_O = 1 << 17, - OPT_o = 1 << 18, - OPT_x = 1 << 19, - OPT_f = 1 << 20, -/* The rest has variable bit positions, need to be clever */ - OPTBIT_f = 20, - USE_FOR_MMU( OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPTBIT_P,) - USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) - }; - - /* Default options. */ + /* Default options */ IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;) IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;) client_config.interface = "eth0"; @@ -854,31 +1258,28 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) str_V = "udhcp "BB_VER; /* Parse command line */ - /* Cc: mutually exclusive; O,x: list; -T,-t,-A take numeric param */ - opt_complementary = "c--C:C--c:O::x::T+:t+:A+" -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - ":vv" -#endif - ; + /* O,x: list; -T,-t,-A take numeric param */ + opt_complementary = "O::x::T+:t+:A+" IF_UDHCP_VERBOSE(":vv") ; IF_LONG_OPTS(applet_long_options = udhcpc_longopts;) - opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:f" + opt = getopt32(argv, "CV:H:h:F:i:np:qRr:s:T:t:SA:O:ox:fB" USE_FOR_MMU("b") IF_FEATURE_UDHCPC_ARPING("a") IF_FEATURE_UDHCP_PORT("P:") "v" - , &str_c, &str_V, &str_h, &str_h, &str_F + , &str_V, &str_h, &str_h, &str_F , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ , &client_config.script /* s */ , &discover_timeout, &discover_retries, &tryagain_timeout /* T,t,A */ , &list_O , &list_x IF_FEATURE_UDHCP_PORT(, &str_P) -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose -#endif - ); - if (opt & (OPT_h|OPT_H)) + IF_UDHCP_VERBOSE(, &dhcp_verbose) + ); + if (opt & (OPT_h|OPT_H)) { + //msg added 2011-11 + bb_error_msg("option -h NAME is deprecated, use -x hostname:NAME"); client_config.hostname = alloc_dhcp_option(DHCP_HOST_NAME, str_h, 0); + } if (opt & OPT_F) { /* FQDN option format: [0x51][len][flags][0][0] */ client_config.fqdn = alloc_dhcp_option(DHCP_FQDN, str_F, 3); @@ -902,14 +1303,23 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) SERVER_PORT = CLIENT_PORT - 1; } #endif - if (opt & OPT_o) - client_config.no_default_options = 1; while (list_O) { char *optstr = llist_pop(&list_O); - unsigned n = udhcp_option_idx(optstr); - n = dhcp_optflags[n].code; + unsigned n = bb_strtou(optstr, NULL, 0); + if (errno || n > 254) { + n = udhcp_option_idx(optstr); + n = dhcp_optflags[n].code; + } client_config.opt_mask[n >> 3] |= 1 << (n & 7); } + if (!(opt & OPT_o)) { + unsigned i, n; + for (i = 0; (n = dhcp_optflags[i].code) != 0; i++) { + if (dhcp_optflags[i].flags & OPTION_REQ) { + client_config.opt_mask[n >> 3] |= 1 << (n & 7); + } + } + } while (list_x) { char *optstr = llist_pop(&list_x); char *colon = strchr(optstr, ':'); @@ -928,16 +1338,24 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) return 1; } - if (opt & OPT_c) { - client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0); - } else if (!(opt & OPT_C)) { - /* not set and not suppressed, set the default client ID */ + clientid_mac_ptr = NULL; + if (!(opt & OPT_C) && !udhcp_find_option(client_config.options, DHCP_CLIENT_ID)) { + /* not suppressed and not set, set the default client ID */ client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, "", 7); client_config.clientid[OPT_DATA] = 1; /* type: ethernet */ - memcpy(client_config.clientid + OPT_DATA+1, client_config.client_mac, 6); + clientid_mac_ptr = client_config.clientid + OPT_DATA+1; + memcpy(clientid_mac_ptr, client_config.client_mac, 6); } - if (str_V[0] != '\0') + if (str_V[0] != '\0') { + // can drop -V, str_V, client_config.vendorclass, + // but need to add "vendor" to the list of recognized + // string opts for this to work; + // and need to tweak add_client_options() too... + // ...so the question is, should we? + //bb_error_msg("option -V VENDOR is deprecated, use -x vendor:VENDOR"); client_config.vendorclass = alloc_dhcp_option(DHCP_VENDOR, str_V, 0); + } + #if !BB_MMU /* on NOMMU reexec (i.e., background) early */ if (!(opt & OPT_f)) { @@ -975,6 +1393,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * "continue" statements in code below jump to the top of the loop. */ for (;;) { + struct timeval tv; + struct dhcp_packet packet; /* silence "uninitialized!" warning */ unsigned timestamp_before_wait = timestamp_before_wait; @@ -994,8 +1414,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) retval = 0; /* If we already timed out, fall through with retval = 0, else... */ if ((int)tv.tv_sec > 0) { + log1("Waiting on select %u seconds", (int)tv.tv_sec); timestamp_before_wait = (unsigned)monotonic_sec(); - log1("Waiting on select..."); retval = select(max_fd + 1, &rfds, NULL, NULL, &tv); if (retval < 0) { /* EINTR? A signal was caught, don't panic */ @@ -1012,12 +1432,27 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) * resend discover/renew/whatever */ if (retval == 0) { + /* When running on a bridge, the ifindex may have changed + * (e.g. if member interfaces were added/removed + * or if the status of the bridge changed). + * Refresh ifindex and client_mac: + */ + if (udhcp_read_interface(client_config.interface, + &client_config.ifindex, + NULL, + client_config.client_mac) + ) { + goto ret0; /* iface is gone? */ + } + if (clientid_mac_ptr) + memcpy(clientid_mac_ptr, client_config.client_mac, 6); + /* We will restart the wait in any case */ already_waited_sec = 0; switch (state) { case INIT_SELECTING: - if (packet_num < discover_retries) { + if (!discover_retries || packet_num < discover_retries) { if (packet_num == 0) xid = random_xid(); /* broadcast */ @@ -1046,7 +1481,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) packet_num = 0; continue; case REQUESTING: - if (packet_num < discover_retries) { + if (!discover_retries || packet_num < discover_retries) { /* send broadcast select packet */ send_select(xid, server_addr, requested_ip); timeout = discover_timeout; @@ -1063,6 +1498,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case BOUND: /* 1/2 lease passed, enter renewing state */ state = RENEWING; + client_config.first_secs = 0; /* make secs field count from 0 */ change_listen_mode(LISTEN_KERNEL); log1("Entering renew state"); /* fall right through */ @@ -1102,6 +1538,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) bb_info_msg("Lease lost, entering init state"); udhcp_run_script(NULL, "deconfig"); state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ /*timeout = 0; - already is */ packet_num = 0; continue; @@ -1118,22 +1555,35 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* note: udhcp_sp_read checks FD_ISSET before reading */ switch (udhcp_sp_read(&rfds)) { case SIGUSR1: + client_config.first_secs = 0; /* make secs field count from 0 */ + already_waited_sec = 0; perform_renew(); - if (state == RENEW_REQUESTED) + if (state == RENEW_REQUESTED) { + /* We might be either on the same network + * (in which case renew might work), + * or we might be on a completely different one + * (in which case renew won't ever succeed). + * For the second case, must make sure timeout + * is not too big, or else we can send + * futile renew requests for hours. + * (Ab)use -A TIMEOUT value (usually 20 sec) + * as a cap on the timeout. + */ + if (timeout > tryagain_timeout) + timeout = tryagain_timeout; goto case_RENEW_REQUESTED; + } /* Start things over */ packet_num = 0; /* Kill any timeouts, user wants this to hurry along */ timeout = 0; continue; case SIGUSR2: - perform_release(requested_ip, server_addr); + perform_release(server_addr, requested_ip); timeout = INT_MAX; continue; case SIGTERM: bb_info_msg("Received SIGTERM"); - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } @@ -1171,7 +1621,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* Ignore packets that aren't for us */ if (packet.hlen != 6 - || memcmp(packet.chaddr, client_config.client_mac, 6) + || memcmp(packet.chaddr, client_config.client_mac, 6) != 0 ) { //FIXME: need to also check that last 10 bytes are zero log1("chaddr does not match, ignoring packet"); // log2? @@ -1186,18 +1636,41 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) switch (state) { case INIT_SELECTING: - /* Must be a DHCPOFFER to one of our xid's */ + /* Must be a DHCPOFFER */ if (*message == DHCPOFFER) { - /* TODO: why we don't just fetch server's IP from IP header? */ +/* What exactly is server's IP? There are several values. + * Example DHCP offer captured with tchdump: + * + * 10.34.25.254:67 > 10.34.25.202:68 // IP header's src + * BOOTP fields: + * Your-IP 10.34.25.202 + * Server-IP 10.34.32.125 // "next server" IP + * Gateway-IP 10.34.25.254 // relay's address (if DHCP relays are in use) + * DHCP options: + * DHCP-Message Option 53, length 1: Offer + * Server-ID Option 54, length 4: 10.34.255.7 // "server ID" + * Default-Gateway Option 3, length 4: 10.34.25.254 // router + * + * We think that real server IP (one to use in renew/release) + * is one in Server-ID option. But I am not 100% sure. + * IP header's src and Gateway-IP (same in this example) + * might work too. + * "Next server" and router are definitely wrong ones to use, though... + */ +/* We used to ignore pcakets without DHCP_SERVER_ID. + * I've got user reports from people who run "address-less" servers. + * They either supply DHCP_SERVER_ID of 0.0.0.0 or don't supply it at all. + * They say ISC DHCP client supports this case. + */ + server_addr = 0; temp = udhcp_get_option(&packet, DHCP_SERVER_ID); if (!temp) { - bb_error_msg("no server ID in message"); - continue; - /* still selecting - this server looks bad */ + bb_error_msg("no server ID, using 0.0.0.0"); + } else { + /* it IS unaligned sometimes, don't "optimize" */ + move_from_unaligned32(server_addr, temp); } - /* it IS unaligned sometimes, don't "optimize" */ - move_from_unaligned32(server_addr, temp); - xid = packet.xid; + /*xid = packet.xid; - already is */ requested_ip = packet.yiaddr; /* enter requesting state */ @@ -1212,6 +1685,9 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) case RENEW_REQUESTED: case REBINDING: if (*message == DHCPACK) { + uint32_t lease_seconds; + struct in_addr temp_addr; + temp = udhcp_get_option(&packet, DHCP_LEASE_TIME); if (!temp) { bb_error_msg("no lease time with ACK, using 1 hour lease"); @@ -1220,9 +1696,11 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) /* it IS unaligned sometimes, don't "optimize" */ move_from_unaligned32(lease_seconds, temp); lease_seconds = ntohl(lease_seconds); - lease_seconds &= 0x0fffffff; /* paranoia: must not be prone to overflows */ - if (lease_seconds < 10) /* and not too small */ - lease_seconds = 10; + /* paranoia: must not be too small and not prone to overflows */ + if (lease_seconds < 0x10) + lease_seconds = 0x10; + if (lease_seconds >= 0x10000000) + lease_seconds = 0x0fffffff; } #if ENABLE_FEATURE_UDHCPC_ARPING if (opt & OPT_a) { @@ -1243,12 +1721,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) ) { bb_info_msg("Offered address is in use " "(got ARP reply), declining"); - send_decline(xid, server_addr, packet.yiaddr); + send_decline(/*xid,*/ server_addr, packet.yiaddr); if (state != REQUESTING) udhcp_run_script(NULL, "deconfig"); change_listen_mode(LISTEN_RAW); state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ requested_ip = 0; timeout = tryagain_timeout; packet_num = 0; @@ -1259,20 +1738,15 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) #endif /* enter bound state */ timeout = lease_seconds / 2; - { - struct in_addr temp_addr; - temp_addr.s_addr = packet.yiaddr; - bb_info_msg("Lease of %s obtained, lease time %u", - inet_ntoa(temp_addr), (unsigned)lease_seconds); - } + temp_addr.s_addr = packet.yiaddr; + bb_info_msg("Lease of %s obtained, lease time %u", + inet_ntoa(temp_addr), (unsigned)lease_seconds); requested_ip = packet.yiaddr; udhcp_run_script(&packet, state == REQUESTING ? "bound" : "renew"); state = BOUND; change_listen_mode(LISTEN_NONE); if (opt & OPT_q) { /* quit after lease */ - if (opt & OPT_R) /* release on quit */ - perform_release(requested_ip, server_addr); goto ret0; } /* future renew failures should not exit (JM) */ @@ -1284,6 +1758,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) opt = ((opt & ~OPT_b) | OPT_f); } #endif + /* make future renew packets use different xid */ + /* xid = random_xid(); ...but why bother? */ already_waited_sec = 0; continue; /* back to main loop */ } @@ -1296,6 +1772,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) change_listen_mode(LISTEN_RAW); sleep(3); /* avoid excessive network traffic */ state = INIT_SELECTING; + client_config.first_secs = 0; /* make secs field count from 0 */ requested_ip = 0; timeout = 0; packet_num = 0; @@ -1309,6 +1786,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) } /* for (;;) - main loop ends */ ret0: + if (opt & OPT_R) /* release on quit */ + perform_release(server_addr, requested_ip); retval = 0; ret: /*if (client_config.pidfile) - remove_pidfile has its own check */ diff --git a/networking/udhcp/dhcpc.h b/networking/udhcp/dhcpc.h index 6bef562..9f423a5 100644 --- a/networking/udhcp/dhcpc.h +++ b/networking/udhcp/dhcpc.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #ifndef UDHCP_DHCPC_H #define UDHCP_DHCPC_H 1 @@ -9,7 +9,6 @@ PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN struct client_config_t { uint8_t client_mac[6]; /* Our mac address */ - char no_default_options; /* Do not include default options in request */ IF_FEATURE_UDHCP_PORT(uint16_t port;) int ifindex; /* Index number of the interface to use */ uint8_t opt_mask[256 / 8]; /* Bitmask of options to send (-O option) */ @@ -21,15 +20,20 @@ struct client_config_t { uint8_t *vendorclass; /* Optional vendor class-id to use */ uint8_t *hostname; /* Optional hostname to use */ uint8_t *fqdn; /* Optional fully qualified domain name to use */ + + uint16_t first_secs; + uint16_t last_secs; } FIX_ALIASING; /* server_config sits in 1st half of bb_common_bufsiz1 */ #define client_config (*(struct client_config_t*)(&bb_common_bufsiz1[COMMON_BUFSIZE / 2])) #if ENABLE_FEATURE_UDHCP_PORT -#define CLIENT_PORT (client_config.port) +#define CLIENT_PORT (client_config.port) +#define CLIENT_PORT6 (client_config.port) #else -#define CLIENT_PORT 68 +#define CLIENT_PORT 68 +#define CLIENT_PORT6 546 #endif POP_SAVED_FUNCTION_VISIBILITY diff --git a/networking/udhcp/dhcpd.c b/networking/udhcp/dhcpd.c index 043220d..a1a7f6b 100644 --- a/networking/udhcp/dhcpd.c +++ b/networking/udhcp/dhcpd.c @@ -20,6 +20,18 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +//usage:#define udhcpd_trivial_usage +//usage: "[-fS] [-I ADDR]" IF_FEATURE_UDHCP_PORT(" [-P N]") " [CONFFILE]" +//usage:#define udhcpd_full_usage "\n\n" +//usage: "DHCP server\n" +//usage: "\n -f Run in foreground" +//usage: "\n -S Log to syslog too" +//usage: "\n -I ADDR Local address" +//usage: IF_FEATURE_UDHCP_PORT( +//usage: "\n -P N Use port N (default 67)" +//usage: ) + #include #include "common.h" #include "dhcpc.h" @@ -132,7 +144,11 @@ static uint32_t select_lease_time(struct dhcp_packet *packet) } /* We got a DHCP DISCOVER. Send an OFFER. */ -static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, struct dyn_lease *lease) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE void send_offer(struct dhcp_packet *oldpacket, + uint32_t static_lease_nip, + struct dyn_lease *lease, + uint8_t *requested_ip_opt) { struct dhcp_packet packet; uint32_t lease_time_sec; @@ -146,7 +162,6 @@ static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, if (!static_lease_nip) { /* We have no static lease for client's chaddr */ uint32_t req_nip; - uint8_t *req_ip_opt; const char *p_host_name; if (lease) { @@ -157,9 +172,9 @@ static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, packet.yiaddr = lease->lease_nip; } /* Or: if client has requested an IP */ - else if ((req_ip_opt = udhcp_get_option(oldpacket, DHCP_REQUESTED_IP)) != NULL + else if (requested_ip_opt != NULL /* (read IP) */ - && (move_from_unaligned32(req_nip, req_ip_opt), 1) + && (move_from_unaligned32(req_nip, requested_ip_opt), 1) /* and the IP is in the lease range */ && ntohl(req_nip) >= server_config.start_ip && ntohl(req_nip) <= server_config.end_ip @@ -202,7 +217,8 @@ static void send_offer(struct dhcp_packet *oldpacket, uint32_t static_lease_nip, send_packet(&packet, /*force_bcast:*/ 0); } -static void send_NAK(struct dhcp_packet *oldpacket) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE void send_NAK(struct dhcp_packet *oldpacket) { struct dhcp_packet packet; @@ -212,7 +228,8 @@ static void send_NAK(struct dhcp_packet *oldpacket) send_packet(&packet, /*force_bcast:*/ 1); } -static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) { struct dhcp_packet packet; uint32_t lease_time_sec; @@ -243,7 +260,8 @@ static void send_ACK(struct dhcp_packet *oldpacket, uint32_t yiaddr) } } -static void send_inform(struct dhcp_packet *oldpacket) +/* NOINLINE: limit stack usage in caller */ +static NOINLINE void send_inform(struct dhcp_packet *oldpacket) { struct dhcp_packet packet; @@ -279,16 +297,13 @@ struct dyn_lease *g_leases; int udhcpd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int udhcpd_main(int argc UNUSED_PARAM, char **argv) { - fd_set rfds; int server_socket = -1, retval, max_sock; - struct dhcp_packet packet; uint8_t *state; - uint32_t static_lease_nip; unsigned timeout_end; unsigned num_ips; unsigned opt; struct option_set *option; - struct dyn_lease *lease, fake_lease; + char *str_I = str_I; IF_FEATURE_UDHCP_PORT(char *str_P;) #if ENABLE_FEATURE_UDHCP_PORT @@ -299,11 +314,11 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 opt_complementary = "vv"; #endif - opt = getopt32(argv, "fSv" - IF_FEATURE_UDHCP_PORT("P:", &str_P) -#if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose -#endif + opt = getopt32(argv, "fSI:v" + IF_FEATURE_UDHCP_PORT("P:") + , &str_I + IF_FEATURE_UDHCP_PORT(, &str_P) + IF_UDHCP_VERBOSE(, &dhcp_verbose) ); if (!(opt & 1)) { /* no -f */ bb_daemonize_or_rexec(0, argv); @@ -315,8 +330,13 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) openlog(applet_name, LOG_PID, LOG_DAEMON); logmode |= LOGMODE_SYSLOG; } + if (opt & 4) { /* -I */ + len_and_sockaddr *lsa = xhost_and_af2sockaddr(str_I, 0, AF_INET); + server_config.server_nip = lsa->u.sin.sin_addr.s_addr; + free(lsa); + } #if ENABLE_FEATURE_UDHCP_PORT - if (opt & 8) { /* -P */ + if (opt & 16) { /* -P */ SERVER_PORT = xatou16(str_P); CLIENT_PORT = SERVER_PORT + 1; } @@ -356,7 +376,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) if (udhcp_read_interface(server_config.interface, &server_config.ifindex, - &server_config.server_nip, + (server_config.server_nip == 0 ? &server_config.server_nip : NULL), server_config.server_mac) ) { retval = 1; @@ -366,13 +386,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) /* Setup the signal pipe */ udhcp_sp_setup(); + continue_with_autotime: timeout_end = monotonic_sec() + server_config.auto_time; while (1) { /* loop until universe collapses */ + fd_set rfds; + struct dhcp_packet packet; int bytes; struct timeval tv; uint8_t *server_id_opt; - uint8_t *requested_opt; + uint8_t *requested_ip_opt; uint32_t requested_nip = requested_nip; /* for compiler */ + uint32_t static_lease_nip; + struct dyn_lease *lease, fake_lease; if (server_socket < 0) { server_socket = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, @@ -391,8 +416,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) } if (retval == 0) { write_leases(); - timeout_end = monotonic_sec() + server_config.auto_time; - continue; + goto continue_with_autotime; } if (retval < 0 && errno != EINTR) { log1("Error on select"); @@ -404,12 +428,12 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) bb_info_msg("Received SIGUSR1"); write_leases(); /* why not just reset the timeout, eh */ - timeout_end = monotonic_sec() + server_config.auto_time; - continue; + goto continue_with_autotime; case SIGTERM: bb_info_msg("Received SIGTERM"); + write_leases(); goto ret0; - case 0: /* no signal: read a packet */ + case 0: /* no signal: read a packet */ break; default: /* signal or error (probably EINTR): back to select */ continue; @@ -439,6 +463,18 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) continue; } + /* Get SERVER_ID if present */ + server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); + if (server_id_opt) { + uint32_t server_id_network_order; + move_from_unaligned32(server_id_network_order, server_id_opt); + if (server_id_network_order != server_config.server_nip) { + /* client talks to somebody else */ + log1("server ID doesn't match, ignoring"); + continue; + } + } + /* Look for a static/dynamic lease */ static_lease_nip = get_static_nip_by_mac(server_config.static_leases, &packet.chaddr); if (static_lease_nip) { @@ -451,20 +487,10 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) lease = find_lease_by_mac(packet.chaddr); } - /* Get REQUESTED_IP and SERVER_ID if present */ - server_id_opt = udhcp_get_option(&packet, DHCP_SERVER_ID); - if (server_id_opt) { - uint32_t server_id_net; - move_from_unaligned32(server_id_net, server_id_opt); - if (server_id_net != server_config.server_nip) { - /* client talks to somebody else */ - log1("server ID doesn't match, ignoring"); - continue; - } - } - requested_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); - if (requested_opt) { - move_from_unaligned32(requested_nip, requested_opt); + /* Get REQUESTED_IP if present */ + requested_ip_opt = udhcp_get_option(&packet, DHCP_REQUESTED_IP); + if (requested_ip_opt) { + move_from_unaligned32(requested_nip, requested_ip_opt); } switch (state[0]) { @@ -472,7 +498,7 @@ int udhcpd_main(int argc UNUSED_PARAM, char **argv) case DHCPDISCOVER: log1("Received DISCOVER"); - send_offer(&packet, static_lease_nip, lease); + send_offer(&packet, static_lease_nip, lease, requested_ip_opt); break; case DHCPREQUEST: @@ -563,7 +589,7 @@ o DHCPREQUEST generated during REBINDING state: A DHCP server MAY extend a client's lease only if it has local administrative authority to do so. */ - if (!requested_opt) { + if (!requested_ip_opt) { requested_nip = packet.ciaddr; if (requested_nip == 0) { log1("no requested IP and no ciaddr, ignoring"); @@ -576,11 +602,15 @@ o DHCPREQUEST generated during REBINDING state: send_ACK(&packet, lease->lease_nip); break; } - if (server_id_opt) { - /* client was talking specifically to us. - * "No, we don't have this IP for you". */ + /* No lease for this MAC, or lease IP != requested IP */ + + if (server_id_opt /* client is in SELECTING state */ + || requested_ip_opt /* client is in INIT-REBOOT state */ + ) { + /* "No, we don't have this IP for you" */ send_NAK(&packet); - } + } /* else: client is in RENEWING or REBINDING, do not answer */ + break; case DHCPDECLINE: @@ -599,7 +629,7 @@ o DHCPREQUEST generated during REBINDING state: */ log1("Received DECLINE"); if (server_id_opt - && requested_opt + && requested_ip_opt && lease /* chaddr matches this lease */ && requested_nip == lease->lease_nip ) { diff --git a/networking/udhcp/dhcpd.h b/networking/udhcp/dhcpd.h index eea9017..a77724f 100644 --- a/networking/udhcp/dhcpd.h +++ b/networking/udhcp/dhcpd.h @@ -1,6 +1,6 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #ifndef UDHCP_DHCPD_H #define UDHCP_DHCPD_H 1 @@ -61,9 +61,11 @@ struct server_config_t { /* client_config sits in 2nd half of bb_common_bufsiz1 */ #if ENABLE_FEATURE_UDHCP_PORT -#define SERVER_PORT (server_config.port) +#define SERVER_PORT (server_config.port) +#define SERVER_PORT6 (server_config.port) #else -#define SERVER_PORT 67 +#define SERVER_PORT 67 +#define SERVER_PORT6 547 #endif diff --git a/networking/udhcp/dhcprelay.c b/networking/udhcp/dhcprelay.c index d194a98..f82ac05 100644 --- a/networking/udhcp/dhcprelay.c +++ b/networking/udhcp/dhcprelay.c @@ -1,7 +1,7 @@ /* vi: set sw=4 ts=4: */ /* Port to Busybox Copyright (C) 2006 Jesse Dutton * - * Licensed under GPL v2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * * DHCP Relay for 'DHCPv4 Configuration of IPSec Tunnel Mode' support * Copyright (C) 2002 Mario Strasser , @@ -9,11 +9,20 @@ * Netbeat AG * Upstream has GPL v2 or later */ + +//usage:#define dhcprelay_trivial_usage +//usage: "CLIENT_IFACE[,CLIENT_IFACE2]... SERVER_IFACE [SERVER_IP]" +//usage:#define dhcprelay_full_usage "\n\n" +//usage: "Relay DHCP requests between clients and server" + #include "common.h" -#define SERVER_PORT 67 -#define SELECT_TIMEOUT 5 /* select timeout in sec. */ -#define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ +#define SERVER_PORT 67 + +/* lifetime of an xid entry in sec. */ +#define MAX_LIFETIME 2*60 +/* select timeout in sec. */ +#define SELECT_TIMEOUT (MAX_LIFETIME / 8) /* This list holds information about clients. The xid_* functions manipulate this list. */ struct xid_item { @@ -22,7 +31,7 @@ struct xid_item { uint32_t xid; struct sockaddr_in ip; struct xid_item *next; -}; +} FIX_ALIASING; #define dhcprelay_xid_list (*(struct xid_item*)&bb_common_bufsiz1) @@ -67,11 +76,11 @@ static struct xid_item *xid_find(uint32_t xid) struct xid_item *item = dhcprelay_xid_list.next; while (item != NULL) { if (item->xid == xid) { - return item; + break; } item = item->next; } - return NULL; + return item; } static void xid_del(uint32_t xid) @@ -110,62 +119,72 @@ static int get_dhcp_packet_type(struct dhcp_packet *p) } /** - * get_client_devices - parses the devices list - * dev_list - comma separated list of devices + * make_iface_list - parses client/server interface names * returns array */ -static char **get_client_devices(char *dev_list, int *client_number) +static char **make_iface_list(char **client_and_server_ifaces, int *client_number) { - char *s, **client_dev; + char *s, **iface_list; int i, cn; - /* copy list */ - dev_list = xstrdup(dev_list); - - /* get number of items, replace ',' with NULs */ - s = dev_list; - cn = 1; + /* get number of items */ + cn = 2; /* 1 server iface + at least 1 client one */ + s = client_and_server_ifaces[0]; /* list of client ifaces */ while (*s) { - if (*s == ',') { - *s = '\0'; + if (*s == ',') cn++; - } s++; } *client_number = cn; /* create vector of pointers */ - client_dev = xzalloc(cn * sizeof(*client_dev)); - client_dev[0] = dev_list; + iface_list = xzalloc(cn * sizeof(iface_list[0])); + + iface_list[0] = client_and_server_ifaces[1]; /* server iface */ + i = 1; - while (i != cn) { - client_dev[i] = client_dev[i - 1] + strlen(client_dev[i - 1]) + 1; - i++; + s = xstrdup(client_and_server_ifaces[0]); /* list of client ifaces */ + goto store_client_iface_name; + + while (i < cn) { + if (*s++ == ',') { + s[-1] = '\0'; + store_client_iface_name: + iface_list[i++] = s; + } } - return client_dev; + + return iface_list; } /* Creates listen sockets (in fds) bound to client and server ifaces, * and returns numerically max fd. */ -static int init_sockets(char **client_ifaces, int num_clients, - char *server_iface, int *fds) +static int init_sockets(char **iface_list, int num_clients, int *fds) { int i, n; - /* talk to real server on bootps */ - fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server_iface); - n = fds[0]; - - for (i = 1; i < num_clients; i++) { - /* listen for clients on bootps */ - fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]); - if (fds[i] > n) + n = 0; + for (i = 0; i < num_clients; i++) { + fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, iface_list[i]); + if (n < fds[i]) n = fds[i]; } return n; } +static int sendto_ip4(int sock, const void *msg, int msg_len, struct sockaddr_in *to) +{ + int err; + + errno = 0; + err = sendto(sock, msg, msg_len, 0, (struct sockaddr*) to, sizeof(*to)); + err -= msg_len; + if (err) + bb_perror_msg("sendto"); + return err; +} + /** * pass_to_server() - forwards dhcp packets from client to server * p - packet to send @@ -174,7 +193,7 @@ static int init_sockets(char **client_ifaces, int num_clients, static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, int *fds, struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) { - int res, type; + int type; /* check packet_type */ type = get_dhcp_packet_type(p); @@ -188,13 +207,12 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in /* create new xid entry */ xid_add(p->xid, client_addr, client); - /* forward request to LAN (server) */ - errno = 0; - res = sendto(fds[0], p, packet_len, 0, (struct sockaddr*)server_addr, - sizeof(struct sockaddr_in)); - if (res != packet_len) { - bb_perror_msg("sendto"); - } + /* forward request to server */ + /* note that we send from fds[0] which is bound to SERVER_PORT (67). + * IOW: we send _from_ SERVER_PORT! Although this may look strange, + * RFC 1542 not only allows, but prescribes this for BOOTP relays. + */ + sendto_ip4(fds[0], p, packet_len, server_addr); } /** @@ -203,7 +221,7 @@ static void pass_to_server(struct dhcp_packet *p, int packet_len, int client, in */ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) { - int res, type; + int type; struct xid_item *item; /* check xid */ @@ -218,14 +236,12 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) return; } +//TODO: also do it if (p->flags & htons(BROADCAST_FLAG)) is set! if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); - errno = 0; - res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*) &(item->ip), - sizeof(item->ip)); - if (res != packet_len) { - bb_perror_msg("sendto"); - return; + + if (sendto_ip4(fds[item->client], p, packet_len, &item->ip) != 0) { + return; /* send error occurred */ } /* remove xid entry */ @@ -235,36 +251,30 @@ static void pass_to_client(struct dhcp_packet *p, int packet_len, int *fds) int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dhcprelay_main(int argc, char **argv) { - struct dhcp_packet dhcp_msg; struct sockaddr_in server_addr; - struct sockaddr_in client_addr; - fd_set rfds; - char **client_ifaces; + char **iface_list; int *fds; int num_sockets, max_socket; uint32_t our_nip; server_addr.sin_family = AF_INET; + server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); server_addr.sin_port = htons(SERVER_PORT); - /* dhcprelay client_iface1,client_iface2,... server_iface [server_IP] */ + /* dhcprelay CLIENT_IFACE1[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP] */ if (argc == 4) { if (!inet_aton(argv[3], &server_addr.sin_addr)) bb_perror_msg_and_die("bad server IP"); - } else if (argc == 3) { - server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); - } else { + } else if (argc != 3) { bb_show_usage(); } - /* Produce list of client ifaces */ - client_ifaces = get_client_devices(argv[1], &num_sockets); + iface_list = make_iface_list(argv + 1, &num_sockets); - num_sockets++; /* for server socket at fds[0] */ fds = xmalloc(num_sockets * sizeof(fds[0])); /* Create sockets and bind one to every iface */ - max_socket = init_sockets(client_ifaces, num_sockets, argv[2], fds); + max_socket = init_sockets(iface_list, num_sockets, fds); /* Get our IP on server_iface */ if (udhcp_read_interface(argv[2], NULL, &our_nip, NULL)) @@ -272,11 +282,10 @@ int dhcprelay_main(int argc, char **argv) /* Main loop */ while (1) { -//reinit stuff from time to time? go back to get_client_devices -//every N minutes? +// reinit stuff from time to time? go back to make_iface_list +// every N minutes? + fd_set rfds; struct timeval tv; - size_t packlen; - socklen_t addr_size; int i; FD_ZERO(&rfds); @@ -285,6 +294,9 @@ int dhcprelay_main(int argc, char **argv) tv.tv_sec = SELECT_TIMEOUT; tv.tv_usec = 0; if (select(max_socket + 1, &rfds, NULL, NULL, &tv) > 0) { + int packlen; + struct dhcp_packet dhcp_msg; + /* server */ if (FD_ISSET(fds[0], &rfds)) { packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); @@ -292,24 +304,65 @@ int dhcprelay_main(int argc, char **argv) pass_to_client(&dhcp_msg, packlen, fds); } } + /* clients */ for (i = 1; i < num_sockets; i++) { + struct sockaddr_in client_addr; + socklen_t addr_size; + if (!FD_ISSET(fds[i], &rfds)) continue; - addr_size = sizeof(struct sockaddr_in); + + addr_size = sizeof(client_addr); packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, (struct sockaddr *)(&client_addr), &addr_size); if (packlen <= 0) continue; /* Get our IP on corresponding client_iface */ -//why? what if server can't route such IP? - if (udhcp_read_interface(client_ifaces[i-1], NULL, &dhcp_msg.gateway_nip, NULL)) { - /* Fall back to our server_iface's IP */ -//this makes more sense! +// RFC 1542 +// 4.1 General BOOTP Processing for Relay Agents +// 4.1.1 BOOTREQUEST Messages +// If the relay agent does decide to relay the request, it MUST examine +// the 'giaddr' ("gateway" IP address) field. If this field is zero, +// the relay agent MUST fill this field with the IP address of the +// interface on which the request was received. If the interface has +// more than one IP address logically associated with it, the relay +// agent SHOULD choose one IP address associated with that interface and +// use it consistently for all BOOTP messages it relays. If the +// 'giaddr' field contains some non-zero value, the 'giaddr' field MUST +// NOT be modified. The relay agent MUST NOT, under any circumstances, +// fill the 'giaddr' field with a broadcast address as is suggested in +// [1] (Section 8, sixth paragraph). + +// but why? what if server can't route such IP? Client ifaces may be, say, NATed! + +// 4.1.2 BOOTREPLY Messages +// BOOTP relay agents relay BOOTREPLY messages only to BOOTP clients. +// It is the responsibility of BOOTP servers to send BOOTREPLY messages +// directly to the relay agent identified in the 'giaddr' field. +// (yeah right, unless it is impossible... see comment above) +// Therefore, a relay agent may assume that all BOOTREPLY messages it +// receives are intended for BOOTP clients on its directly-connected +// networks. +// +// When a relay agent receives a BOOTREPLY message, it should examine +// the BOOTP 'giaddr', 'yiaddr', 'chaddr', 'htype', and 'hlen' fields. +// These fields should provide adequate information for the relay agent +// to deliver the BOOTREPLY message to the client. +// +// The 'giaddr' field can be used to identify the logical interface from +// which the reply must be sent (i.e., the host or router interface +// connected to the same network as the BOOTP client). If the content +// of the 'giaddr' field does not match one of the relay agent's +// directly-connected logical interfaces, the BOOTREPLY messsage MUST be +// silently discarded. + if (udhcp_read_interface(iface_list[i], NULL, &dhcp_msg.gateway_nip, NULL)) { + /* Fall back to our IP on server iface */ +// this makes more sense! dhcp_msg.gateway_nip = our_nip; } -//maybe set dhcp_msg.flags |= BROADCAST_FLAG too? +// maybe dhcp_msg.hops++? drop packets with too many hops (RFC 1542 says 4 or 16)? pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); } } diff --git a/networking/udhcp/domain_codec.c b/networking/udhcp/domain_codec.c index 2dd5347..c1325d8 100644 --- a/networking/udhcp/domain_codec.c +++ b/networking/udhcp/domain_codec.c @@ -4,7 +4,7 @@ * * Loosely based on the isc-dhcpd implementation by dhankins@isc.org * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ #ifdef DNS_COMPR_TESTING # define FAST_FUNC /* nothing */ diff --git a/networking/udhcp/dumpleases.c b/networking/udhcp/dumpleases.c index fb6219f..64cd73e 100644 --- a/networking/udhcp/dumpleases.c +++ b/networking/udhcp/dumpleases.c @@ -1,22 +1,27 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define dumpleases_trivial_usage +//usage: "[-r|-a] [-f LEASEFILE]" +//usage:#define dumpleases_full_usage "\n\n" +//usage: "Display DHCP leases granted by udhcpd\n" +//usage: IF_LONG_OPTS( +//usage: "\n -f,--file=FILE Lease file" +//usage: "\n -r,--remaining Show remaining time" +//usage: "\n -a,--absolute Show expiration time" +//usage: ) +//usage: IF_NOT_LONG_OPTS( +//usage: "\n -f FILE Lease file" +//usage: "\n -r Show remaining time" +//usage: "\n -a Show expiration time" +//usage: ) + #include "common.h" #include "dhcpd.h" #include "unicode.h" -#if BB_LITTLE_ENDIAN -static inline uint64_t hton64(uint64_t v) -{ - return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); -} -#else -#define hton64(v) (v) -#endif -#define ntoh64(v) hton64(v) - - int dumpleases_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int dumpleases_main(int argc UNUSED_PARAM, char **argv) { @@ -29,9 +34,9 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) struct in_addr addr; enum { - OPT_a = 0x1, // -a - OPT_r = 0x2, // -r - OPT_f = 0x4, // -f + OPT_a = 0x1, // -a + OPT_r = 0x2, // -r + OPT_f = 0x4, // -f }; #if ENABLE_LONG_OPTS static const char dumpleases_longopts[] ALIGN1 = @@ -54,7 +59,7 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) /* "123456789 123456789 123456789 123456789 123456789 123456789 123456789 123456789 */ xread(fd, &written_at, sizeof(written_at)); - written_at = ntoh64(written_at); + written_at = SWAP_BE64(written_at); curr = time(NULL); if (curr < written_at) written_at = curr; /* lease file from future! :) */ @@ -68,7 +73,7 @@ int dumpleases_main(int argc UNUSED_PARAM, char **argv) addr.s_addr = lease.lease_nip; #if ENABLE_UNICODE_SUPPORT { - char *uni_name = unicode_conv_to_printable_fixedwidth(NULL, lease.hostname, 19); + char *uni_name = unicode_conv_to_printable_fixedwidth(/*NULL,*/ lease.hostname, 19); printf(" %-16s%s ", inet_ntoa(addr), uni_name); free(uni_name); } diff --git a/networking/udhcp/files.c b/networking/udhcp/files.c index ff63111..6840f3c 100644 --- a/networking/udhcp/files.c +++ b/networking/udhcp/files.c @@ -4,23 +4,13 @@ * * Rewrite by Russ Dill July 2001 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include #include "common.h" #include "dhcpd.h" -#if BB_LITTLE_ENDIAN -static inline uint64_t hton64(uint64_t v) -{ - return (((uint64_t)htonl(v)) << 32) | htonl(v >> 32); -} -#else -#define hton64(v) (v) -#endif -#define ntoh64(v) hton64(v) - /* on these functions, make sure your datatype matches */ static int FAST_FUNC read_str(const char *line, void *arg) { @@ -90,9 +80,9 @@ static const struct config_keyword keywords[] = { /* keywords with no defaults must be last! */ {"option" , udhcp_str2optset, &server_config.options , ""}, {"opt" , udhcp_str2optset, &server_config.options , ""}, - {"notify_file" , read_str , &server_config.notify_file , ""}, - {"sname" , read_str , &server_config.sname , ""}, - {"boot_file" , read_str , &server_config.boot_file , ""}, + {"notify_file" , read_str , &server_config.notify_file , NULL}, + {"sname" , read_str , &server_config.sname , NULL}, + {"boot_file" , read_str , &server_config.boot_file , NULL}, {"static_lease" , read_staticlease, &server_config.static_leases, ""}, }; enum { KWS_WITH_DEFAULTS = ARRAY_SIZE(keywords) - 6 }; @@ -140,7 +130,7 @@ void FAST_FUNC write_leases(void) curr = written_at = time(NULL); - written_at = hton64(written_at); + written_at = SWAP_BE64(written_at); full_write(fd, &written_at, sizeof(written_at)); for (i = 0; i < server_config.max_leases; i++) { @@ -190,7 +180,7 @@ void FAST_FUNC read_leases(const char *file) if (full_read(fd, &written_at, sizeof(written_at)) != sizeof(written_at)) goto ret; - written_at = ntoh64(written_at); + written_at = SWAP_BE64(written_at); time_passed = time(NULL) - written_at; /* Strange written_at, or lease file from old version of udhcpd diff --git a/networking/udhcp/leases.c b/networking/udhcp/leases.c index fad71ec..c5b60b1 100644 --- a/networking/udhcp/leases.c +++ b/networking/udhcp/leases.c @@ -2,7 +2,7 @@ /* * Russ Dill July 2001 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "common.h" #include "dhcpd.h" @@ -137,21 +137,42 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) uint32_t addr; struct dyn_lease *oldest_lease = NULL; - addr = server_config.start_ip; /* addr is in host order here */ - for (; addr <= server_config.end_ip; addr++) { +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + uint32_t stop; + unsigned i, hash; + + /* hash hwaddr: use the SDBM hashing algorithm. Seems to give good + * dispersal even with similarly-valued "strings". + */ + hash = 0; + for (i = 0; i < 6; i++) + hash += safe_mac[i] + (hash << 6) + (hash << 16) - hash; + + /* pick a seed based on hwaddr then iterate until we find a free address. */ + addr = server_config.start_ip + + (hash % (1 + server_config.end_ip - server_config.start_ip)); + stop = addr; +#else + addr = server_config.start_ip; +#define stop (server_config.end_ip + 1) +#endif + do { uint32_t nip; struct dyn_lease *lease; /* ie, 192.168.55.0 */ if ((addr & 0xff) == 0) - continue; + goto next_addr; /* ie, 192.168.55.255 */ if ((addr & 0xff) == 0xff) - continue; + goto next_addr; nip = htonl(addr); + /* skip our own address */ + if (nip == server_config.server_nip) + goto next_addr; /* is this a static lease addr? */ if (is_nip_reserved(server_config.static_leases, nip)) - continue; + goto next_addr; lease = find_lease_by_nip(nip); if (!lease) { @@ -162,7 +183,14 @@ uint32_t FAST_FUNC find_free_or_expired_nip(const uint8_t *safe_mac) if (!oldest_lease || lease->expires < oldest_lease->expires) oldest_lease = lease; } - } + + next_addr: + addr++; +#if ENABLE_FEATURE_UDHCPD_BASE_IP_ON_MAC + if (addr > server_config.end_ip) + addr = server_config.start_ip; +#endif + } while (addr != stop); if (oldest_lease && is_expired_lease(oldest_lease) diff --git a/networking/udhcp/packet.c b/networking/udhcp/packet.c index 4badc9c..148f525 100644 --- a/networking/udhcp/packet.c +++ b/networking/udhcp/packet.c @@ -4,20 +4,13 @@ * * Rewrite by Russ Dill July 2001 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION -# include -# include -#else -# include -# include -# include -#endif - #include "common.h" #include "dhcpd.h" +#include +#include +#include void FAST_FUNC udhcp_init_header(struct dhcp_packet *packet, char type) { @@ -88,7 +81,6 @@ void FAST_FUNC udhcp_dump_packet(struct dhcp_packet *packet) int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) { int bytes; - unsigned char *vendor; memset(packet, 0, sizeof(*packet)); bytes = safe_read(fd, packet, sizeof(*packet)); @@ -97,74 +89,18 @@ int FAST_FUNC udhcp_recv_kernel_packet(struct dhcp_packet *packet, int fd) return bytes; /* returns -1 */ } - if (packet->cookie != htonl(DHCP_MAGIC)) { + if (bytes < offsetof(struct dhcp_packet, options) + || packet->cookie != htonl(DHCP_MAGIC) + ) { bb_info_msg("Packet with bad magic, ignoring"); return -2; } log1("Received a packet"); udhcp_dump_packet(packet); - if (packet->op == BOOTREQUEST) { - vendor = udhcp_get_option(packet, DHCP_VENDOR); - if (vendor) { -#if 0 - static const char broken_vendors[][8] = { - "MSFT 98", - "" - }; - int i; - for (i = 0; broken_vendors[i][0]; i++) { - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)strlen(broken_vendors[i]) - && strncmp((char*)vendor, broken_vendors[i], vendor[OPT_LEN - OPT_DATA]) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", - broken_vendors[i]); - packet->flags |= htons(BROADCAST_FLAG); - } - } -#else - if (vendor[OPT_LEN - OPT_DATA] == (uint8_t)(sizeof("MSFT 98")-1) - && memcmp(vendor, "MSFT 98", sizeof("MSFT 98")-1) == 0 - ) { - log1("Broken client (%s), forcing broadcast replies", "MSFT 98"); - packet->flags |= htons(BROADCAST_FLAG); - } -#endif - } - } - return bytes; } -uint16_t FAST_FUNC udhcp_checksum(void *addr, int count) -{ - /* Compute Internet Checksum for "count" bytes - * beginning at location "addr". - */ - int32_t sum = 0; - uint16_t *source = (uint16_t *) addr; - - while (count > 1) { - /* This is the inner loop */ - sum += *source++; - count -= 2; - } - - /* Add left-over byte, if any */ - if (count > 0) { - /* Make sure that the left-over byte is added correctly both - * with little and big endian hosts */ - uint16_t tmp = 0; - *(uint8_t*)&tmp = *(uint8_t*)source; - sum += tmp; - } - /* Fold 32-bit sum to 16 bits */ - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - /* Construct a ip/udp header for a packet, send packet */ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, uint32_t source_nip, int source_port, @@ -207,8 +143,15 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, * * In order to work with those buggy servers, * we truncate packets after end option byte. + * + * However, RFC 1542 says "The IP Total Length and UDP Length + * must be large enough to contain the minimal BOOTP header of 300 octets". + * Thus, we retain enough padding to not go below 300 BOOTP bytes. + * Some devices have filters which drop DHCP packets shorter than that. */ padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(packet.data.options); + if (padding > DHCP_SIZE - 300) + padding = DHCP_SIZE - 300; packet.ip.protocol = IPPROTO_UDP; packet.ip.saddr = source_nip; @@ -216,19 +159,20 @@ int FAST_FUNC udhcp_send_raw_packet(struct dhcp_packet *dhcp_pkt, packet.udp.source = htons(source_port); packet.udp.dest = htons(dest_port); /* size, excluding IP header: */ - packet.udp.len = htons(UPD_DHCP_SIZE - padding); + packet.udp.len = htons(UDP_DHCP_SIZE - padding); /* for UDP checksumming, ip.len is set to UDP packet len */ packet.ip.tot_len = packet.udp.len; - packet.udp.check = udhcp_checksum(&packet, IP_UPD_DHCP_SIZE - padding); + packet.udp.check = inet_cksum((uint16_t *)&packet, + IP_UDP_DHCP_SIZE - padding); /* but for sending, it is set to IP packet len */ - packet.ip.tot_len = htons(IP_UPD_DHCP_SIZE - padding); + packet.ip.tot_len = htons(IP_UDP_DHCP_SIZE - padding); packet.ip.ihl = sizeof(packet.ip) >> 2; packet.ip.version = IPVERSION; packet.ip.ttl = IPDEFTTL; - packet.ip.check = udhcp_checksum(&packet.ip, sizeof(packet.ip)); + packet.ip.check = inet_cksum((uint16_t *)&packet.ip, sizeof(packet.ip)); udhcp_dump_packet(dhcp_pkt); - result = sendto(fd, &packet, IP_UPD_DHCP_SIZE - padding, /*flags:*/ 0, + result = sendto(fd, &packet, IP_UDP_DHCP_SIZE - padding, /*flags:*/ 0, (struct sockaddr *) &dest_sll, sizeof(dest_sll)); msg = "sendto"; ret_close: @@ -245,7 +189,7 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, uint32_t source_nip, int source_port, uint32_t dest_nip, int dest_port) { - struct sockaddr_in client; + struct sockaddr_in sa; unsigned padding; int fd; int result = -1; @@ -258,27 +202,28 @@ int FAST_FUNC udhcp_send_kernel_packet(struct dhcp_packet *dhcp_pkt, } setsockopt_reuseaddr(fd); - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(source_port); - client.sin_addr.s_addr = source_nip; - if (bind(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(source_port); + sa.sin_addr.s_addr = source_nip; + if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "bind(%s)"; goto ret_close; } - memset(&client, 0, sizeof(client)); - client.sin_family = AF_INET; - client.sin_port = htons(dest_port); - client.sin_addr.s_addr = dest_nip; - if (connect(fd, (struct sockaddr *)&client, sizeof(client)) == -1) { + memset(&sa, 0, sizeof(sa)); + sa.sin_family = AF_INET; + sa.sin_port = htons(dest_port); + sa.sin_addr.s_addr = dest_nip; + if (connect(fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { msg = "connect"; goto ret_close; } udhcp_dump_packet(dhcp_pkt); - padding = DHCP_OPTIONS_BUFSIZE - 1 - udhcp_end_option(dhcp_pkt->options); + if (padding > DHCP_SIZE - 300) + padding = DHCP_SIZE - 300; result = safe_write(fd, dhcp_pkt, DHCP_SIZE - padding); msg = "write"; ret_close: diff --git a/networking/udhcp/socket.c b/networking/udhcp/socket.c index 0ed7ad1..a421069 100644 --- a/networking/udhcp/socket.c +++ b/networking/udhcp/socket.c @@ -22,56 +22,50 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#include -#if (defined(__GLIBC__) && __GLIBC__ >= 2 && __GLIBC_MINOR__ >= 1) || defined _NEWLIB_VERSION -# include -# include -#else -# include -# include -# include -#endif - #include "common.h" +#include int FAST_FUNC udhcp_read_interface(const char *interface, int *ifindex, uint32_t *nip, uint8_t *mac) { + /* char buffer instead of bona-fide struct avoids aliasing warning */ + char ifr_buf[sizeof(struct ifreq)]; + struct ifreq *const ifr = (void *)ifr_buf; + int fd; - struct ifreq ifr; struct sockaddr_in *our_ip; - memset(&ifr, 0, sizeof(ifr)); + memset(ifr, 0, sizeof(*ifr)); fd = xsocket(AF_INET, SOCK_RAW, IPPROTO_RAW); - ifr.ifr_addr.sa_family = AF_INET; - strncpy_IFNAMSIZ(ifr.ifr_name, interface); + ifr->ifr_addr.sa_family = AF_INET; + strncpy_IFNAMSIZ(ifr->ifr_name, interface); if (nip) { - if (ioctl_or_perror(fd, SIOCGIFADDR, &ifr, + if (ioctl_or_perror(fd, SIOCGIFADDR, ifr, "is interface %s up and configured?", interface) ) { close(fd); return -1; } - our_ip = (struct sockaddr_in *) &ifr.ifr_addr; + our_ip = (struct sockaddr_in *) &ifr->ifr_addr; *nip = our_ip->sin_addr.s_addr; log1("IP %s", inet_ntoa(our_ip->sin_addr)); } if (ifindex) { - if (ioctl_or_warn(fd, SIOCGIFINDEX, &ifr) != 0) { + if (ioctl_or_warn(fd, SIOCGIFINDEX, ifr) != 0) { close(fd); return -1; } - log1("Adapter index %d", ifr.ifr_ifindex); - *ifindex = ifr.ifr_ifindex; + log1("Adapter index %d", ifr->ifr_ifindex); + *ifindex = ifr->ifr_ifindex; } if (mac) { - if (ioctl_or_warn(fd, SIOCGIFHWADDR, &ifr) != 0) { + if (ioctl_or_warn(fd, SIOCGIFHWADDR, ifr) != 0) { close(fd); return -1; } - memcpy(mac, ifr.ifr_hwaddr.sa_data, 6); + memcpy(mac, ifr->ifr_hwaddr.sa_data, 6); log1("MAC %02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); } @@ -86,6 +80,7 @@ int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) { int fd; struct sockaddr_in addr; + char *colon; log1("Opening listen socket on *:%d %s", port, inf); fd = xsocket(PF_INET, SOCK_DGRAM, IPPROTO_UDP); @@ -94,10 +89,17 @@ int FAST_FUNC udhcp_listen_socket(/*uint32_t ip,*/ int port, const char *inf) if (setsockopt_broadcast(fd) == -1) bb_perror_msg_and_die("SO_BROADCAST"); - /* NB: bug 1032 says this doesn't work on ethernet aliases (ethN:M) */ + /* SO_BINDTODEVICE doesn't work on ethernet aliases (ethN:M) */ + colon = strrchr(inf, ':'); + if (colon) + *colon = '\0'; + if (setsockopt_bindtodevice(fd, inf)) xfunc_die(); /* warning is already printed */ + if (colon) + *colon = ':'; + memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_port = htons(port); diff --git a/networking/udhcp/static_leases.c b/networking/udhcp/static_leases.c index b334a58..f4a24ab 100644 --- a/networking/udhcp/static_leases.c +++ b/networking/udhcp/static_leases.c @@ -4,7 +4,7 @@ * * Wade Berrier September 2004 * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "common.h" #include "dhcpd.h" diff --git a/networking/vconfig.c b/networking/vconfig.c index 00379fc..924b2f0 100644 --- a/networking/vconfig.c +++ b/networking/vconfig.c @@ -4,11 +4,22 @@ * * Copyright (C) 2001 Manuel Novoa III * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A */ +//usage:#define vconfig_trivial_usage +//usage: "COMMAND [OPTIONS]" +//usage:#define vconfig_full_usage "\n\n" +//usage: "Create and remove virtual ethernet devices\n" +//usage: "\n add IFACE VLAN_ID" +//usage: "\n rem VLAN_NAME" +//usage: "\n set_flag IFACE 0|1 VLAN_QOS" +//usage: "\n set_egress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_ingress_map VLAN_NAME SKB_PRIO VLAN_QOS" +//usage: "\n set_name_type NAME_TYPE" + #include "libbb.h" #include @@ -47,66 +58,48 @@ struct vlan_ioctl_args { short vlan_qos; }; -#define VLAN_GROUP_ARRAY_LEN 4096 -#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ +#define VLAN_GROUP_ARRAY_LEN 4096 +#define SIOCSIFVLAN 0x8983 /* Set 802.1Q VLAN options */ /* On entry, table points to the length of the current string * plus NUL terminator plus data length for the subsequent entry. * The return value is the last data entry for the matching string. */ static const char *xfind_str(const char *table, const char *str) { - while (strcasecmp(str, table+1) != 0) { - table += table[0]; - if (!*table) { + while (strcasecmp(str, table + 1) != 0) { + if (!table[0]) bb_show_usage(); - } + table += table[0]; } return table - 1; } static const char cmds[] ALIGN1 = { 4, ADD_VLAN_CMD, 7, - 'a', 'd', 'd', 0, + 'a','d','d',0, 3, DEL_VLAN_CMD, 7, - 'r', 'e', 'm', 0, + 'r','e','m',0, 3, SET_VLAN_NAME_TYPE_CMD, 17, - 's', 'e', 't', '_', - 'n', 'a', 'm', 'e', '_', - 't', 'y', 'p', 'e', 0, + 's','e','t','_','n','a','m','e','_','t','y','p','e',0, 5, SET_VLAN_FLAG_CMD, 12, - 's', 'e', 't', '_', - 'f', 'l', 'a', 'g', 0, + 's','e','t','_','f','l','a','g',0, 5, SET_VLAN_EGRESS_PRIORITY_CMD, 18, - 's', 'e', 't', '_', - 'e', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, - 5, SET_VLAN_INGRESS_PRIORITY_CMD, 16, - 's', 'e', 't', '_', - 'i', 'n', 'g', 'r', 'e', 's', 's', '_', - 'm', 'a', 'p', 0, + 's','e','t','_','e','g','r','e','s','s','_','m','a','p',0, + 5, SET_VLAN_INGRESS_PRIORITY_CMD, 0, + 's','e','t','_','i','n','g','r','e','s','s','_','m','a','p',0, }; static const char name_types[] ALIGN1 = { VLAN_NAME_TYPE_PLUS_VID, 16, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D',0, VLAN_NAME_TYPE_PLUS_VID_NO_PAD, 22, - 'V', 'L', 'A', 'N', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'V','L','A','N','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, VLAN_NAME_TYPE_RAW_PLUS_VID, 15, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - 0, - VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 20, - 'D', 'E', 'V', - '_', 'P', 'L', 'U', 'S', '_', 'V', 'I', 'D', - '_', 'N', 'O', '_', 'P', 'A', 'D', 0, + 'D','E','V','_','P','L','U','S','_','V','I','D',0, + VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD, 0, + 'D','E','V','_','P','L','U','S','_','V','I','D','_','N','O','_','P','A','D',0, }; -static const char conf_file_name[] ALIGN1 = "/proc/net/vlan/config"; - int vconfig_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int vconfig_main(int argc, char **argv) { @@ -114,25 +107,19 @@ int vconfig_main(int argc, char **argv) const char *p; int fd; - if (argc < 3) { - bb_show_usage(); - } - - /* Don't bother closing the filedes. It will be closed on cleanup. */ - /* Will die if 802.1q is not present */ - xopen(conf_file_name, O_RDONLY); - memset(&ifr, 0, sizeof(ifr)); ++argv; - p = xfind_str(cmds+2, *argv); + if (!argv[0]) + bb_show_usage(); + p = xfind_str(cmds + 2, argv[0]); ifr.cmd = *p; - if (argc != p[-1]) { + if (argc != p[-1]) bb_show_usage(); - } - if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { /* set_name_type */ - ifr.u.name_type = *xfind_str(name_types+1, argv[1]); + if (ifr.cmd == SET_VLAN_NAME_TYPE_CMD) { + /* set_name_type */ + ifr.u.name_type = *xfind_str(name_types + 1, argv[1]); } else { strncpy_IFNAMSIZ(ifr.device1, argv[1]); p = argv[2]; @@ -141,22 +128,26 @@ int vconfig_main(int argc, char **argv) * since ifr.u.flag, ifr.u.VID, and ifr.u.skb_priority are all same-sized * (unsigned) int members of a unions. But because of the range checking, * doing so wouldn't save that much space and would also make maintainence - * more of a pain. */ - if (ifr.cmd == SET_VLAN_FLAG_CMD) { /* set_flag */ - ifr.u.flag = xatoul_range(p, 0, 1); + * more of a pain. + */ + if (ifr.cmd == SET_VLAN_FLAG_CMD) { + /* set_flag */ + ifr.u.flag = xatou_range(p, 0, 1); /* DM: in order to set reorder header, qos must be set */ - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); - } else if (ifr.cmd == ADD_VLAN_CMD) { /* add */ - ifr.u.VID = xatoul_range(p, 0, VLAN_GROUP_ARRAY_LEN-1); - } else if (ifr.cmd != DEL_VLAN_CMD) { /* set_{egress|ingress}_map */ + ifr.vlan_qos = xatou_range(argv[3], 0, 7); + } else if (ifr.cmd == ADD_VLAN_CMD) { + /* add */ + ifr.u.VID = xatou_range(p, 0, VLAN_GROUP_ARRAY_LEN - 1); + } else if (ifr.cmd != DEL_VLAN_CMD) { + /* set_{egress|ingress}_map */ ifr.u.skb_priority = xatou(p); - ifr.vlan_qos = xatoul_range(argv[3], 0, 7); + ifr.vlan_qos = xatou_range(argv[3], 0, 7); } } fd = xsocket(AF_INET, SOCK_STREAM, 0); ioctl_or_perror_and_die(fd, SIOCSIFVLAN, &ifr, - "ioctl error for %s", *argv); + "ioctl error for %s", argv[0]); return 0; } diff --git a/networking/wget.c b/networking/wget.c index 1f35f8b..d6c509e 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -3,14 +3,48 @@ * wget - retrieve a file using HTTP or FTP * * Chip Rosenthal Covad Communications + * Licensed under GPLv2, see file LICENSE in this source tree. * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Copyright (C) 2010 Bradley M. Kuhn + * Kuhn's copyrights are licensed GPLv2-or-later. File as a whole remains GPLv2. */ + +//usage:#define wget_trivial_usage +//usage: IF_FEATURE_WGET_LONG_OPTIONS( +//usage: "[-c|--continue] [-s|--spider] [-q|--quiet] [-O|--output-document FILE]\n" +//usage: " [--header 'header: value'] [-Y|--proxy on/off] [-P DIR]\n" +/* Since we ignore these opts, we don't show them in --help */ +/* //usage: " [--no-check-certificate] [--no-cache]" */ +//usage: " [-U|--user-agent AGENT]" IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." +//usage: ) +//usage: IF_NOT_FEATURE_WGET_LONG_OPTIONS( +//usage: "[-csq] [-O FILE] [-Y on/off] [-P DIR] [-U AGENT]" +//usage: IF_FEATURE_WGET_TIMEOUT(" [-T SEC]") " URL..." +//usage: ) +//usage:#define wget_full_usage "\n\n" +//usage: "Retrieve files via HTTP or FTP\n" +//usage: "\n -s Spider mode - only check file existence" +//usage: "\n -c Continue retrieval of aborted transfer" +//usage: "\n -q Quiet" +//usage: "\n -P DIR Save to DIR (default .)" +//usage: IF_FEATURE_WGET_TIMEOUT( +//usage: "\n -T SEC Network read timeout is SEC seconds" +//usage: ) +//usage: "\n -O FILE Save to FILE ('-' for stdout)" +//usage: "\n -U STR Use STR for User-Agent header" +//usage: "\n -Y Use proxy ('on' or 'off')" + #include "libbb.h" +#if 0 +# define log_io(...) bb_error_msg(__VA_ARGS__) +#else +# define log_io(...) ((void)0) +#endif + + struct host_info { - // May be used if we ever will want to free() all xstrdup()s... - /* char *allocated; */ + char *allocated; const char *path; const char *user; char *host; @@ -19,7 +53,7 @@ struct host_info { }; -/* Globals (can be accessed from signal handlers) */ +/* Globals */ struct globals { off_t content_len; /* Content-length of the file */ off_t beg_range; /* Range at which continue begins */ @@ -28,49 +62,82 @@ struct globals { const char *curfile; /* Name of current file being transferred */ bb_progress_t pmt; #endif + char *dir_prefix; +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + char *post_data; + char *extra_headers; +#endif + char *fname_out; /* where to direct output (-O) */ + const char *proxy_flag; /* Use proxies if env vars are set */ + const char *user_agent; /* "User-Agent" header field */ +#if ENABLE_FEATURE_WGET_TIMEOUT + unsigned timeout_seconds; + bool connecting; +#endif + int output_fd; + int o_flags; smallint chunked; /* chunked transfer encoding */ smallint got_clen; /* got content-length: from server */ + /* Local downloads do benefit from big buffer. + * With 512 byte buffer, it was measured to be + * an order of magnitude slower than with big one. + */ + uint64_t just_to_align_next_member; + char wget_buf[CONFIG_FEATURE_COPYBUF_KB*1024]; } FIX_ALIASING; -#define G (*(struct globals*)&bb_common_bufsiz1) -struct BUG_G_too_big { - char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; -}; -#define INIT_G() do { } while (0) +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) +#define FINI_G() do { \ + FREE_PTR_TO_GLOBALS(); \ +} while (0) -#if ENABLE_FEATURE_WGET_STATUSBAR +/* Must match option string! */ +enum { + WGET_OPT_CONTINUE = (1 << 0), + WGET_OPT_SPIDER = (1 << 1), + WGET_OPT_QUIET = (1 << 2), + WGET_OPT_OUTNAME = (1 << 3), + WGET_OPT_PREFIX = (1 << 4), + WGET_OPT_PROXY = (1 << 5), + WGET_OPT_USER_AGENT = (1 << 6), + WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 7), + WGET_OPT_RETRIES = (1 << 8), + WGET_OPT_PASSIVE = (1 << 9), + WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, + WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, +}; +enum { + PROGRESS_START = -1, + PROGRESS_END = 0, + PROGRESS_BUMP = 1, +}; +#if ENABLE_FEATURE_WGET_STATUSBAR static void progress_meter(int flag) { - /* We can be called from signal handler */ - int save_errno = errno; + if (option_mask32 & WGET_OPT_QUIET) + return; - if (flag == -1) { /* first call to progress_meter */ - bb_progress_init(&G.pmt); - } + if (flag == PROGRESS_START) + bb_progress_init(&G.pmt, G.curfile); - bb_progress_update(&G.pmt, G.curfile, G.beg_range, G.transferred, - G.chunked ? 0 : G.beg_range + G.transferred + G.content_len); + bb_progress_update(&G.pmt, + G.beg_range, + G.transferred, + (G.chunked || !G.got_clen) ? 0 : G.beg_range + G.transferred + G.content_len + ); - if (flag == 0) { - /* last call to progress_meter */ - alarm(0); + if (flag == PROGRESS_END) { + bb_progress_free(&G.pmt); bb_putchar_stderr('\n'); G.transferred = 0; - } else { - if (flag == -1) { /* first call to progress_meter */ - signal_SA_RESTART_empty_mask(SIGALRM, progress_meter); - } - alarm(1); } - - errno = save_errno; } - -#else /* FEATURE_WGET_STATUSBAR */ - +#else static ALWAYS_INLINE void progress_meter(int flag UNUSED_PARAM) { } - #endif @@ -110,48 +177,15 @@ static void strip_ipv6_scope_id(char *host) overlapping_strcpy(scope, cp); } -/* Read NMEMB bytes into PTR from STREAM. Returns the number of bytes read, - * and a short count if an eof or non-interrupt error is encountered. */ -static size_t safe_fread(void *ptr, size_t nmemb, FILE *stream) -{ - size_t ret; - char *p = (char*)ptr; - - do { - clearerr(stream); - errno = 0; - ret = fread(p, 1, nmemb, stream); - p += ret; - nmemb -= ret; - } while (nmemb && ferror(stream) && errno == EINTR); - - return p - (char*)ptr; -} - -/* Read a line or SIZE-1 bytes into S, whichever is less, from STREAM. - * Returns S, or NULL if an eof or non-interrupt error is encountered. */ -static char *safe_fgets(char *s, int size, FILE *stream) -{ - char *ret; - - do { - clearerr(stream); - errno = 0; - ret = fgets(s, size, stream); - } while (ret == NULL && ferror(stream) && errno == EINTR); - - return ret; -} - #if ENABLE_FEATURE_WGET_AUTHENTICATION -/* Base64-encode character string. buf is assumed to be char buf[512]. */ -static char *base64enc_512(char buf[512], const char *str) +/* Base64-encode character string. */ +static char *base64enc(const char *str) { unsigned len = strlen(str); - if (len > 512/4*3 - 10) /* paranoia */ - len = 512/4*3 - 10; - bb_uuencode(buf, str, len, bb_uuenc_tbl_base64); - return buf; + if (len > sizeof(G.wget_buf)/4*3 - 10) /* paranoia */ + len = sizeof(G.wget_buf)/4*3 - 10; + bb_uuencode(G.wget_buf, str, len, bb_uuenc_tbl_base64); + return G.wget_buf; } #endif @@ -164,61 +198,98 @@ static char* sanitize_string(char *s) return s; } +#if ENABLE_FEATURE_WGET_TIMEOUT +static void alarm_handler(int sig UNUSED_PARAM) +{ + /* This is theoretically unsafe (uses stdio and malloc in signal handler) */ + if (G.connecting) + bb_error_msg_and_die("download timed out"); +} +#endif + static FILE *open_socket(len_and_sockaddr *lsa) { + int fd; FILE *fp; + IF_FEATURE_WGET_TIMEOUT(alarm(G.timeout_seconds); G.connecting = 1;) + fd = xconnect_stream(lsa); + IF_FEATURE_WGET_TIMEOUT(G.connecting = 0;) + /* glibc 2.4 seems to try seeking on it - ??! */ /* hopefully it understands what ESPIPE means... */ - fp = fdopen(xconnect_stream(lsa), "r+"); + fp = fdopen(fd, "r+"); if (fp == NULL) - bb_perror_msg_and_die("fdopen"); + bb_perror_msg_and_die(bb_msg_memory_exhausted); return fp; } -static int ftpcmd(const char *s1, const char *s2, FILE *fp, char *buf) +/* Returns '\n' if it was seen, else '\0'. Trims at first '\r' or '\n' */ +/* FIXME: does not respect FEATURE_WGET_TIMEOUT and -T N: */ +static char fgets_and_trim(FILE *fp) +{ + char c; + char *buf_ptr; + + if (fgets(G.wget_buf, sizeof(G.wget_buf) - 1, fp) == NULL) + bb_perror_msg_and_die("error getting response"); + + buf_ptr = strchrnul(G.wget_buf, '\n'); + c = *buf_ptr; + *buf_ptr = '\0'; + buf_ptr = strchrnul(G.wget_buf, '\r'); + *buf_ptr = '\0'; + + log_io("< %s", G.wget_buf); + + return c; +} + +static int ftpcmd(const char *s1, const char *s2, FILE *fp) { int result; if (s1) { - if (!s2) s2 = ""; + if (!s2) + s2 = ""; fprintf(fp, "%s%s\r\n", s1, s2); fflush(fp); + log_io("> %s%s", s1, s2); } do { - char *buf_ptr; - - if (fgets(buf, 510, fp) == NULL) { - bb_perror_msg_and_die("error getting response"); - } - buf_ptr = strstr(buf, "\r\n"); - if (buf_ptr) { - *buf_ptr = '\0'; - } - } while (!isdigit(buf[0]) || buf[3] != ' '); + fgets_and_trim(fp); + } while (!isdigit(G.wget_buf[0]) || G.wget_buf[3] != ' '); - buf[3] = '\0'; - result = xatoi_u(buf); - buf[3] = ' '; + G.wget_buf[3] = '\0'; + result = xatoi_positive(G.wget_buf); + G.wget_buf[3] = ' '; return result; } -static void parse_url(char *src_url, struct host_info *h) +static void parse_url(const char *src_url, struct host_info *h) { char *url, *p, *sp; - /* h->allocated = */ url = xstrdup(src_url); + free(h->allocated); + h->allocated = url = xstrdup(src_url); - if (strncmp(url, "http://", 7) == 0) { - h->port = bb_lookup_port("http", "tcp", 80); - h->host = url + 7; - h->is_ftp = 0; - } else if (strncmp(url, "ftp://", 6) == 0) { + if (strncmp(url, "ftp://", 6) == 0) { h->port = bb_lookup_port("ftp", "tcp", 21); h->host = url + 6; h->is_ftp = 1; } else + if (strncmp(url, "http://", 7) == 0) { + h->host = url + 7; + http: + h->port = bb_lookup_port("http", "tcp", 80); + h->is_ftp = 0; + } else + if (!strstr(url, "//")) { + // GNU wget is user-friendly and falls back to http:// + h->host = url; + goto http; + } else bb_error_msg_and_die("not an http or ftp url: %s", sanitize_string(url)); // FYI: @@ -256,103 +327,73 @@ static void parse_url(char *src_url, struct host_info *h) sp = strrchr(h->host, '@'); if (sp != NULL) { - h->user = h->host; + // URL-decode "user:password" string before base64-encoding: + // wget http://test:my%20pass@example.com should send + // Authorization: Basic dGVzdDpteSBwYXNz + // which decodes to "test:my pass". + // Standard wget and curl do this too. *sp = '\0'; + h->user = percent_decode_in_place(h->host, /*strict:*/ 0); h->host = sp + 1; } sp = h->host; } -static char *gethdr(char *buf, size_t bufsiz, FILE *fp /*, int *istrunc*/) +static char *gethdr(FILE *fp) { char *s, *hdrval; int c; - /* *istrunc = 0; */ - /* retrieve header line */ - if (fgets(buf, bufsiz, fp) == NULL) - return NULL; + c = fgets_and_trim(fp); - /* see if we are at the end of the headers */ - for (s = buf; *s == '\r'; ++s) - continue; - if (*s == '\n') + /* end of the headers? */ + if (G.wget_buf[0] == '\0') return NULL; /* convert the header name to lower case */ - for (s = buf; isalnum(*s) || *s == '-' || *s == '.'; ++s) { - /* tolower for "A-Z", no-op for "0-9a-z-." */ - *s = (*s | 0x20); + for (s = G.wget_buf; isalnum(*s) || *s == '-' || *s == '.' || *s == '_'; ++s) { + /* + * No-op for 20-3f and 60-7f. "0-9a-z-." are in these ranges. + * 40-5f range ("@A-Z[\]^_") maps to 60-7f. + * "A-Z" maps to "a-z". + * "@[\]" can't occur in header names. + * "^_" maps to "~,DEL" (which is wrong). + * "^" was never seen yet, "_" was seen from web.archive.org + * (x-archive-orig-x_commoncrawl_Signature: HEXSTRING). + */ + *s |= 0x20; } /* verify we are at the end of the header name */ if (*s != ':') - bb_error_msg_and_die("bad header line: %s", sanitize_string(buf)); + bb_error_msg_and_die("bad header line: %s", sanitize_string(G.wget_buf)); /* locate the start of the header value */ *s++ = '\0'; hdrval = skip_whitespace(s); - /* locate the end of header */ - while (*s && *s != '\r' && *s != '\n') - ++s; - - /* end of header found */ - if (*s) { - *s = '\0'; - return hdrval; + if (c != '\n') { + /* Rats! The buffer isn't big enough to hold the entire header value */ + while (c = getc(fp), c != EOF && c != '\n') + continue; } - /* Rats! The buffer isn't big enough to hold the entire header value */ - while (c = getc(fp), c != EOF && c != '\n') - continue; - /* *istrunc = 1; */ return hdrval; } -#if ENABLE_FEATURE_WGET_LONG_OPTIONS -static char *URL_escape(const char *str) +static void reset_beg_range_to_zero(void) { - /* URL encode, see RFC 2396 */ - char *dst; - char *res = dst = xmalloc(strlen(str) * 3 + 1); - unsigned char c; - - while (1) { - c = *str++; - if (c == '\0' - /* || strchr("!&'()*-.=_~", c) - more code */ - || c == '!' - || c == '&' - || c == '\'' - || c == '(' - || c == ')' - || c == '*' - || c == '-' - || c == '.' - || c == '=' - || c == '_' - || c == '~' - || (c >= '0' && c <= '9') - || ((c|0x20) >= 'a' && (c|0x20) <= 'z') - ) { - *dst++ = c; - if (c == '\0') - return res; - } else { - *dst++ = '%'; - *dst++ = bb_hexdigits_upcase[c >> 4]; - *dst++ = bb_hexdigits_upcase[c & 0xf]; - } - } + bb_error_msg("restart failed"); + G.beg_range = 0; + xlseek(G.output_fd, 0, SEEK_SET); + /* Done at the end instead: */ + /* ftruncate(G.output_fd, 0); */ } -#endif static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_sockaddr *lsa) { - char buf[512]; FILE *sfp; char *str; int port; @@ -361,8 +402,8 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ target->user = xstrdup("anonymous:busybox@"); sfp = open_socket(lsa); - if (ftpcmd(NULL, NULL, sfp, buf) != 220) - bb_error_msg_and_die("%s", sanitize_string(buf+4)); + if (ftpcmd(NULL, NULL, sfp) != 220) + bb_error_msg_and_die("%s", sanitize_string(G.wget_buf + 4)); /* * Splitting username:password pair, @@ -371,24 +412,24 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ str = strchr(target->user, ':'); if (str) *str++ = '\0'; - switch (ftpcmd("USER ", target->user, sfp, buf)) { + switch (ftpcmd("USER ", target->user, sfp)) { case 230: break; case 331: - if (ftpcmd("PASS ", str, sfp, buf) == 230) + if (ftpcmd("PASS ", str, sfp) == 230) break; /* fall through (failed login) */ default: - bb_error_msg_and_die("ftp login: %s", sanitize_string(buf+4)); + bb_error_msg_and_die("ftp login: %s", sanitize_string(G.wget_buf + 4)); } - ftpcmd("TYPE I", NULL, sfp, buf); + ftpcmd("TYPE I", NULL, sfp); /* * Querying file size */ - if (ftpcmd("SIZE ", target->path, sfp, buf) == 213) { - G.content_len = BB_STRTOOFF(buf+4, NULL, 10); + if (ftpcmd("SIZE ", target->path, sfp) == 213) { + G.content_len = BB_STRTOOFF(G.wget_buf + 4, NULL, 10); if (G.content_len < 0 || errno) { bb_error_msg_and_die("SIZE value is garbage"); } @@ -398,212 +439,222 @@ static FILE* prepare_ftp_session(FILE **dfpp, struct host_info *target, len_and_ /* * Entering passive mode */ - if (ftpcmd("PASV", NULL, sfp, buf) != 227) { + if (ftpcmd("PASV", NULL, sfp) != 227) { pasv_error: - bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(buf)); + bb_error_msg_and_die("bad response to %s: %s", "PASV", sanitize_string(G.wget_buf)); } // Response is "227 garbageN1,N2,N3,N4,P1,P2[)garbage] // Server's IP is N1.N2.N3.N4 (we ignore it) // Server's port for data connection is P1*256+P2 - str = strrchr(buf, ')'); + str = strrchr(G.wget_buf, ')'); if (str) str[0] = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port = xatou_range(str+1, 0, 255); *str = '\0'; - str = strrchr(buf, ','); + str = strrchr(G.wget_buf, ','); if (!str) goto pasv_error; port += xatou_range(str+1, 0, 255) * 256; - set_nport(lsa, htons(port)); + set_nport(&lsa->u.sa, htons(port)); *dfpp = open_socket(lsa); - if (G.beg_range) { - sprintf(buf, "REST %"OFF_FMT"u", G.beg_range); - if (ftpcmd(buf, NULL, sfp, buf) == 350) + if (G.beg_range != 0) { + sprintf(G.wget_buf, "REST %"OFF_FMT"u", G.beg_range); + if (ftpcmd(G.wget_buf, NULL, sfp) == 350) G.content_len -= G.beg_range; + else + reset_beg_range_to_zero(); } - if (ftpcmd("RETR ", target->path, sfp, buf) > 150) - bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(buf)); + if (ftpcmd("RETR ", target->path, sfp) > 150) + bb_error_msg_and_die("bad response to %s: %s", "RETR", sanitize_string(G.wget_buf)); return sfp; } -/* Must match option string! */ -enum { - WGET_OPT_CONTINUE = (1 << 0), - WGET_OPT_SPIDER = (1 << 1), - WGET_OPT_QUIET = (1 << 2), - WGET_OPT_OUTNAME = (1 << 3), - WGET_OPT_PREFIX = (1 << 4), - WGET_OPT_PROXY = (1 << 5), - WGET_OPT_USER_AGENT = (1 << 6), - WGET_OPT_RETRIES = (1 << 7), - WGET_OPT_NETWORK_READ_TIMEOUT = (1 << 8), - WGET_OPT_PASSIVE = (1 << 9), - WGET_OPT_HEADER = (1 << 10) * ENABLE_FEATURE_WGET_LONG_OPTIONS, - WGET_OPT_POST_DATA = (1 << 11) * ENABLE_FEATURE_WGET_LONG_OPTIONS, -}; - -static void NOINLINE retrieve_file_data(FILE *dfp, int output_fd) +static void NOINLINE retrieve_file_data(FILE *dfp) { - char buf[512]; - - if (!(option_mask32 & WGET_OPT_QUIET)) - progress_meter(-1); +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT +# if ENABLE_FEATURE_WGET_TIMEOUT + unsigned second_cnt = G.timeout_seconds; +# endif + struct pollfd polldata; + + polldata.fd = fileno(dfp); + polldata.events = POLLIN | POLLPRI; +#endif + progress_meter(PROGRESS_START); if (G.chunked) goto get_clen; /* Loops only if chunked */ while (1) { + +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + /* Must use nonblocking I/O, otherwise fread will loop + * and *block* until it reads full buffer, + * which messes up progress bar and/or timeout logic. + * Because of nonblocking I/O, we need to dance + * very carefully around EAGAIN. See explanation at + * clearerr() calls. + */ + ndelay_on(polldata.fd); +#endif while (1) { int n; unsigned rdsz; - rdsz = sizeof(buf); +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + /* fread internally uses read loop, which in our case + * is usually exited when we get EAGAIN. + * In this case, libc sets error marker on the stream. + * Need to clear it before next fread to avoid possible + * rare false positive ferror below. Rare because usually + * fread gets more than zero bytes, and we don't fall + * into if (n <= 0) ... + */ + clearerr(dfp); +#endif + errno = 0; + rdsz = sizeof(G.wget_buf); if (G.got_clen) { - if (G.content_len < (off_t)sizeof(buf)) { + if (G.content_len < (off_t)sizeof(G.wget_buf)) { if ((int)G.content_len <= 0) break; rdsz = (unsigned)G.content_len; } } - n = safe_fread(buf, rdsz, dfp); - if (n <= 0) { + n = fread(G.wget_buf, 1, rdsz, dfp); + + if (n > 0) { + xwrite(G.output_fd, G.wget_buf, n); +#if ENABLE_FEATURE_WGET_STATUSBAR + G.transferred += n; +#endif + if (G.got_clen) { + G.content_len -= n; + if (G.content_len == 0) + break; + } +#if ENABLE_FEATURE_WGET_TIMEOUT + second_cnt = G.timeout_seconds; +#endif + continue; + } + + /* n <= 0. + * man fread: + * If error occurs, or EOF is reached, the return value + * is a short item count (or zero). + * fread does not distinguish between EOF and error. + */ + if (errno != EAGAIN) { if (ferror(dfp)) { - /* perror will not work: ferror doesn't set errno */ - bb_error_msg_and_die(bb_msg_read_error); + progress_meter(PROGRESS_END); + bb_perror_msg_and_die(bb_msg_read_error); } - break; + break; /* EOF, not error */ } - xwrite(output_fd, buf, n); -#if ENABLE_FEATURE_WGET_STATUSBAR - G.transferred += n; + +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + /* It was EAGAIN. There is no data. Wait up to one second + * then abort if timed out, or update the bar and try reading again. + */ + if (safe_poll(&polldata, 1, 1000) == 0) { +# if ENABLE_FEATURE_WGET_TIMEOUT + if (second_cnt != 0 && --second_cnt == 0) { + progress_meter(PROGRESS_END); + bb_error_msg_and_die("download timed out"); + } +# endif + /* We used to loop back to poll here, + * but there is no great harm in letting fread + * to try reading anyway. + */ + } + /* Need to do it _every_ second for "stalled" indicator + * to be shown properly. + */ + progress_meter(PROGRESS_BUMP); #endif - if (G.got_clen) - G.content_len -= n; - } + } /* while (reading data) */ +#if ENABLE_FEATURE_WGET_STATUSBAR || ENABLE_FEATURE_WGET_TIMEOUT + clearerr(dfp); + ndelay_off(polldata.fd); /* else fgets can get very unhappy */ +#endif if (!G.chunked) break; - safe_fgets(buf, sizeof(buf), dfp); /* This is a newline */ + fgets_and_trim(dfp); /* Eat empty line */ get_clen: - safe_fgets(buf, sizeof(buf), dfp); - G.content_len = STRTOOFF(buf, NULL, 16); + fgets_and_trim(dfp); + G.content_len = STRTOOFF(G.wget_buf, NULL, 16); /* FIXME: error check? */ if (G.content_len == 0) break; /* all done! */ G.got_clen = 1; + /* + * Note that fgets may result in some data being buffered in dfp. + * We loop back to fread, which will retrieve this data. + * Also note that code has to be arranged so that fread + * is done _before_ one-second poll wait - poll doesn't know + * about stdio buffering and can result in spurious one second waits! + */ + } + + /* If -c failed, we restart from the beginning, + * but we do not truncate file then, we do it only now, at the end. + * This lets user to ^C if his 99% complete 10 GB file download + * failed to restart *without* losing the almost complete file. + */ + { + off_t pos = lseek(G.output_fd, 0, SEEK_CUR); + if (pos != (off_t)-1) + ftruncate(G.output_fd, pos); } - if (!(option_mask32 & WGET_OPT_QUIET)) - progress_meter(0); + /* Draw full bar and free its resources */ + G.chunked = 0; /* makes it show 100% even for chunked download */ + G.got_clen = 1; /* makes it show 100% even for download of (formerly) unknown size */ + progress_meter(PROGRESS_END); } -int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int wget_main(int argc UNUSED_PARAM, char **argv) +static void download_one_url(const char *url) { - char buf[512]; - struct host_info server, target; - len_and_sockaddr *lsa; - unsigned opt; + bool use_proxy; /* Use proxies if env vars are set */ int redir_limit; - char *proxy = NULL; - char *dir_prefix = NULL; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - char *post_data; - char *extra_headers = NULL; - llist_t *headers_llist = NULL; -#endif + len_and_sockaddr *lsa; FILE *sfp; /* socket to web/ftp server */ FILE *dfp; /* socket to ftp server (data) */ - char *fname_out; /* where to direct output (-O) */ - int output_fd = -1; - bool use_proxy; /* Use proxies if env vars are set */ - const char *proxy_flag = "on"; /* Use proxies if env vars are set */ - const char *user_agent = "Wget";/* "User-Agent" header field */ - - static const char keywords[] ALIGN1 = - "content-length\0""transfer-encoding\0""chunked\0""location\0"; - enum { - KEY_content_length = 1, KEY_transfer_encoding, KEY_chunked, KEY_location - }; -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - static const char wget_longopts[] ALIGN1 = - /* name, has_arg, val */ - "continue\0" No_argument "c" - "spider\0" No_argument "s" - "quiet\0" No_argument "q" - "output-document\0" Required_argument "O" - "directory-prefix\0" Required_argument "P" - "proxy\0" Required_argument "Y" - "user-agent\0" Required_argument "U" - /* Ignored: */ - // "tries\0" Required_argument "t" - // "timeout\0" Required_argument "T" - /* Ignored (we always use PASV): */ - "passive-ftp\0" No_argument "\xff" - "header\0" Required_argument "\xfe" - "post-data\0" Required_argument "\xfd" - /* Ignored (we don't do ssl) */ - "no-check-certificate\0" No_argument "\xfc" - ; -#endif - - INIT_G(); - -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - applet_long_options = wget_longopts; -#endif - /* server.allocated = target.allocated = NULL; */ - opt_complementary = "-1" IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); - opt = getopt32(argv, "csqO:P:Y:U:" /*ignored:*/ "t:T:", - &fname_out, &dir_prefix, - &proxy_flag, &user_agent, - NULL, /* -t RETRIES */ - NULL /* -T NETWORK_READ_TIMEOUT */ - IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) - IF_FEATURE_WGET_LONG_OPTIONS(, &post_data) - ); -#if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (headers_llist) { - int size = 1; - char *cp; - llist_t *ll = headers_llist; - while (ll) { - size += strlen(ll->data) + 2; - ll = ll->link; - } - extra_headers = cp = xmalloc(size); - while (headers_llist) { - cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); - } - } -#endif - - /* TODO: compat issue: should handle "wget URL1 URL2..." */ - + char *proxy = NULL; + char *fname_out_alloc; + char *redirected_path = NULL; + struct host_info server; + struct host_info target; + + server.allocated = NULL; + target.allocated = NULL; + server.user = NULL; target.user = NULL; - parse_url(argv[optind], &target); + + parse_url(url, &target); /* Use the proxy if necessary */ - use_proxy = (strcmp(proxy_flag, "off") != 0); + use_proxy = (strcmp(G.proxy_flag, "off") != 0); if (use_proxy) { proxy = getenv(target.is_ftp ? "ftp_proxy" : "http_proxy"); - if (proxy && proxy[0]) { - server.user = NULL; + use_proxy = (proxy && proxy[0]); + if (use_proxy) parse_url(proxy, &server); - } else { - use_proxy = 0; - } } if (!use_proxy) { server.port = target.port; if (ENABLE_FEATURE_IPV6) { - server.host = xstrdup(target.host); + //free(server.allocated); - can't be non-NULL + server.host = server.allocated = xstrdup(target.host); } else { server.host = target.host; } @@ -612,50 +663,48 @@ int wget_main(int argc UNUSED_PARAM, char **argv) if (ENABLE_FEATURE_IPV6) strip_ipv6_scope_id(target.host); - /* Guess an output filename, if there was no -O FILE */ - if (!(opt & WGET_OPT_OUTNAME)) { - fname_out = bb_get_last_path_component_nostrip(target.path); + /* If there was no -O FILE, guess output filename */ + fname_out_alloc = NULL; + if (!(option_mask32 & WGET_OPT_OUTNAME)) { + G.fname_out = bb_get_last_path_component_nostrip(target.path); /* handle "wget http://kernel.org//" */ - if (fname_out[0] == '/' || !fname_out[0]) - fname_out = (char*)"index.html"; + if (G.fname_out[0] == '/' || !G.fname_out[0]) + G.fname_out = (char*)"index.html"; /* -P DIR is considered only if there was no -O FILE */ - if (dir_prefix) - fname_out = concat_path_file(dir_prefix, fname_out); - } else { - if (LONE_DASH(fname_out)) { - /* -O - */ - output_fd = 1; - opt &= ~WGET_OPT_CONTINUE; + if (G.dir_prefix) + G.fname_out = fname_out_alloc = concat_path_file(G.dir_prefix, G.fname_out); + else { + /* redirects may free target.path later, need to make a copy */ + G.fname_out = fname_out_alloc = xstrdup(G.fname_out); } } #if ENABLE_FEATURE_WGET_STATUSBAR - G.curfile = bb_get_last_path_component_nostrip(fname_out); + G.curfile = bb_get_last_path_component_nostrip(G.fname_out); #endif - /* Impossible? - if ((opt & WGET_OPT_CONTINUE) && !fname_out) - bb_error_msg_and_die("can't specify continue (-c) without a filename (-O)"); - */ - /* Determine where to start transfer */ - if (opt & WGET_OPT_CONTINUE) { - output_fd = open(fname_out, O_WRONLY); - if (output_fd >= 0) { - G.beg_range = xlseek(output_fd, 0, SEEK_END); + G.beg_range = 0; + if (option_mask32 & WGET_OPT_CONTINUE) { + G.output_fd = open(G.fname_out, O_WRONLY); + if (G.output_fd >= 0) { + G.beg_range = xlseek(G.output_fd, 0, SEEK_END); } /* File doesn't exist. We do not create file here yet. - * We are not sure it exists on remove side */ + * We are not sure it exists on remote side */ } redir_limit = 5; resolve_lsa: lsa = xhost2sockaddr(server.host, server.port); - if (!(opt & WGET_OPT_QUIET)) { + if (!(option_mask32 & WGET_OPT_QUIET)) { char *s = xmalloc_sockaddr2dotted(&lsa->u.sa); fprintf(stderr, "Connecting to %s (%s)\n", server.host, s); free(s); } establish_session: + /*G.content_len = 0; - redundant, got_clen = 0 is enough */ + G.got_clen = 0; + G.chunked = 0; if (use_proxy || !target.is_ftp) { /* * HTTP session @@ -663,6 +712,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) char *str; int status; + /* Open socket to http server */ sfp = open_socket(lsa); @@ -672,54 +722,61 @@ int wget_main(int argc UNUSED_PARAM, char **argv) target.is_ftp ? "f" : "ht", target.host, target.path); } else { - if (opt & WGET_OPT_POST_DATA) + if (option_mask32 & WGET_OPT_POST_DATA) fprintf(sfp, "POST /%s HTTP/1.1\r\n", target.path); else fprintf(sfp, "GET /%s HTTP/1.1\r\n", target.path); } fprintf(sfp, "Host: %s\r\nUser-Agent: %s\r\n", - target.host, user_agent); + target.host, G.user_agent); + + /* Ask server to close the connection as soon as we are done + * (IOW: we do not intend to send more requests) + */ + fprintf(sfp, "Connection: close\r\n"); #if ENABLE_FEATURE_WGET_AUTHENTICATION if (target.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n"+6, - base64enc_512(buf, target.user)); + base64enc(target.user)); } if (use_proxy && server.user) { fprintf(sfp, "Proxy-Authorization: Basic %s\r\n", - base64enc_512(buf, server.user)); + base64enc(server.user)); } #endif - if (G.beg_range) + if (G.beg_range != 0) fprintf(sfp, "Range: bytes=%"OFF_FMT"u-\r\n", G.beg_range); + #if ENABLE_FEATURE_WGET_LONG_OPTIONS - if (extra_headers) - fputs(extra_headers, sfp); - - if (opt & WGET_OPT_POST_DATA) { - char *estr = URL_escape(post_data); - fprintf(sfp, "Content-Type: application/x-www-form-urlencoded\r\n"); - fprintf(sfp, "Content-Length: %u\r\n" "\r\n" "%s", - (int) strlen(estr), estr); - /*fprintf(sfp, "Connection: Keep-Alive\r\n\r\n");*/ - /*fprintf(sfp, "%s\r\n", estr);*/ - free(estr); + if (G.extra_headers) + fputs(G.extra_headers, sfp); + + if (option_mask32 & WGET_OPT_POST_DATA) { + fprintf(sfp, + "Content-Type: application/x-www-form-urlencoded\r\n" + "Content-Length: %u\r\n" + "\r\n" + "%s", + (int) strlen(G.post_data), G.post_data + ); } else #endif - { /* If "Connection:" is needed, document why */ - fprintf(sfp, /* "Connection: close\r\n" */ "\r\n"); + { + fprintf(sfp, "\r\n"); } + fflush(sfp); + /* * Retrieve HTTP response line and check for "200" status code. */ read_response: - if (fgets(buf, sizeof(buf), sfp) == NULL) - bb_error_msg_and_die("no response from server"); + fgets_and_trim(sfp); - str = buf; + str = G.wget_buf; str = skip_non_whitespace(str); str = skip_whitespace(str); // FIXME: no error check @@ -728,7 +785,7 @@ int wget_main(int argc UNUSED_PARAM, char **argv) switch (status) { case 0: case 100: - while (gethdr(buf, sizeof(buf), sfp /*, &n*/) != NULL) + while (gethdr(sfp) != NULL) /* eat all remaining headers */; goto read_response; case 200: @@ -757,33 +814,48 @@ However, in real world it was observed that some web servers (e.g. Boa/0.94.14rc21) simply use code 204 when file size is zero. */ case 204: + if (G.beg_range != 0) { + /* "Range:..." was not honored by the server. + * Restart download from the beginning. + */ + reset_beg_range_to_zero(); + } break; - case 300: /* redirection */ + case 300: /* redirection */ case 301: case 302: case 303: break; - case 206: - if (G.beg_range) + case 206: /* Partial Content */ + if (G.beg_range != 0) + /* "Range:..." worked. Good. */ break; + /* Partial Content even though we did not ask for it??? */ /* fall through */ default: - bb_error_msg_and_die("server returned error: %s", sanitize_string(buf)); + bb_error_msg_and_die("server returned error: %s", sanitize_string(G.wget_buf)); } /* * Retrieve HTTP headers. */ - while ((str = gethdr(buf, sizeof(buf), sfp /*, &n*/)) != NULL) { - /* gethdr converted "FOO:" string to lowercase */ + while ((str = gethdr(sfp)) != NULL) { + static const char keywords[] ALIGN1 = + "content-length\0""transfer-encoding\0""location\0"; + enum { + KEY_content_length = 1, KEY_transfer_encoding, KEY_location + }; smalluint key; + + /* gethdr converted "FOO:" string to lowercase */ + /* strip trailing whitespace */ char *s = strchrnul(str, '\0') - 1; while (s >= str && (*s == ' ' || *s == '\t')) { *s = '\0'; s--; } - key = index_in_strings(keywords, buf) + 1; + key = index_in_strings(keywords, G.wget_buf) + 1; if (key == KEY_content_length) { G.content_len = BB_STRTOOFF(str, NULL, 10); if (G.content_len < 0 || errno) { @@ -793,23 +865,23 @@ However, in real world it was observed that some web servers continue; } if (key == KEY_transfer_encoding) { - if (index_in_strings(keywords, str_tolower(str)) + 1 != KEY_chunked) + if (strcmp(str_tolower(str), "chunked") != 0) bb_error_msg_and_die("transfer encoding '%s' is not supported", sanitize_string(str)); - G.chunked = G.got_clen = 1; + G.chunked = 1; } if (key == KEY_location && status >= 300) { if (--redir_limit == 0) bb_error_msg_and_die("too many redirections"); fclose(sfp); - G.got_clen = 0; - G.chunked = 0; - if (str[0] == '/') - /* free(target.allocated); */ - target.path = /* target.allocated = */ xstrdup(str+1); + if (str[0] == '/') { + free(redirected_path); + target.path = redirected_path = xstrdup(str+1); /* lsa stays the same: it's on the same server */ - else { + } else { parse_url(str, &target); if (!use_proxy) { + free(server.allocated); + server.allocated = NULL; server.host = target.host; /* strip_ipv6_scope_id(target.host); - no! */ /* we assume remote never gives us IPv6 addr with scope id */ @@ -834,30 +906,127 @@ However, in real world it was observed that some web servers sfp = prepare_ftp_session(&dfp, &target, lsa); } - if (opt & WGET_OPT_SPIDER) { - if (ENABLE_FEATURE_CLEAN_UP) - fclose(sfp); - return EXIT_SUCCESS; - } + free(lsa); - if (output_fd < 0) { - int o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; - /* compat with wget: -O FILE can overwrite */ - if (opt & WGET_OPT_OUTNAME) - o_flags = O_WRONLY | O_CREAT | O_TRUNC; - output_fd = xopen(fname_out, o_flags); + if (!(option_mask32 & WGET_OPT_SPIDER)) { + if (G.output_fd < 0) + G.output_fd = xopen(G.fname_out, G.o_flags); + retrieve_file_data(dfp); + if (!(option_mask32 & WGET_OPT_OUTNAME)) { + xclose(G.output_fd); + G.output_fd = -1; + } } - retrieve_file_data(dfp, output_fd); - xclose(output_fd); - if (dfp != sfp) { - /* It's ftp. Close it properly */ + /* It's ftp. Close data connection properly */ fclose(dfp); - if (ftpcmd(NULL, NULL, sfp, buf) != 226) - bb_error_msg_and_die("ftp error: %s", sanitize_string(buf+4)); - /* ftpcmd("QUIT", NULL, sfp, buf); - why bother? */ + if (ftpcmd(NULL, NULL, sfp) != 226) + bb_error_msg_and_die("ftp error: %s", sanitize_string(G.wget_buf + 4)); + /* ftpcmd("QUIT", NULL, sfp); - why bother? */ + } + fclose(sfp); + + free(server.allocated); + free(target.allocated); + free(fname_out_alloc); + free(redirected_path); +} + +int wget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int wget_main(int argc UNUSED_PARAM, char **argv) +{ +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + static const char wget_longopts[] ALIGN1 = + /* name, has_arg, val */ + "continue\0" No_argument "c" +//FIXME: -s isn't --spider, it's --save-headers! + "spider\0" No_argument "s" + "quiet\0" No_argument "q" + "output-document\0" Required_argument "O" + "directory-prefix\0" Required_argument "P" + "proxy\0" Required_argument "Y" + "user-agent\0" Required_argument "U" +#if ENABLE_FEATURE_WGET_TIMEOUT + "timeout\0" Required_argument "T" +#endif + /* Ignored: */ + // "tries\0" Required_argument "t" + /* Ignored (we always use PASV): */ + "passive-ftp\0" No_argument "\xff" + "header\0" Required_argument "\xfe" + "post-data\0" Required_argument "\xfd" + /* Ignored (we don't do ssl) */ + "no-check-certificate\0" No_argument "\xfc" + /* Ignored (we don't support caching) */ + "no-cache\0" No_argument "\xfb" + ; +#endif + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + llist_t *headers_llist = NULL; +#endif + + INIT_G(); + +#if ENABLE_FEATURE_WGET_TIMEOUT + G.timeout_seconds = 900; + signal(SIGALRM, alarm_handler); +#endif + G.proxy_flag = "on"; /* use proxies if env vars are set */ + G.user_agent = "Wget"; /* "User-Agent" header field */ + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + applet_long_options = wget_longopts; +#endif + opt_complementary = "-1" IF_FEATURE_WGET_TIMEOUT(":T+") IF_FEATURE_WGET_LONG_OPTIONS(":\xfe::"); + getopt32(argv, "csqO:P:Y:U:T:" /*ignored:*/ "t:", + &G.fname_out, &G.dir_prefix, + &G.proxy_flag, &G.user_agent, + IF_FEATURE_WGET_TIMEOUT(&G.timeout_seconds) IF_NOT_FEATURE_WGET_TIMEOUT(NULL), + NULL /* -t RETRIES */ + IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist) + IF_FEATURE_WGET_LONG_OPTIONS(, &G.post_data) + ); + argv += optind; + +#if ENABLE_FEATURE_WGET_LONG_OPTIONS + if (headers_llist) { + int size = 1; + char *cp; + llist_t *ll = headers_llist; + while (ll) { + size += strlen(ll->data) + 2; + ll = ll->link; + } + G.extra_headers = cp = xmalloc(size); + while (headers_llist) { + cp += sprintf(cp, "%s\r\n", (char*)llist_pop(&headers_llist)); + } + } +#endif + + G.output_fd = -1; + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC | O_EXCL; + if (G.fname_out) { /* -O FILE ? */ + if (LONE_DASH(G.fname_out)) { /* -O - ? */ + G.output_fd = 1; + option_mask32 &= ~WGET_OPT_CONTINUE; + } + /* compat with wget: -O FILE can overwrite */ + G.o_flags = O_WRONLY | O_CREAT | O_TRUNC; } + while (*argv) + download_one_url(*argv++); + + if (G.output_fd >= 0) + xclose(G.output_fd); + +#if ENABLE_FEATURE_CLEAN_UP && ENABLE_FEATURE_WGET_LONG_OPTIONS + free(G.extra_headers); +#endif + FINI_G(); + return EXIT_SUCCESS; } diff --git a/networking/whois.c b/networking/whois.c new file mode 100644 index 0000000..bf33033 --- /dev/null +++ b/networking/whois.c @@ -0,0 +1,65 @@ +/* vi: set sw=4 ts=4: */ +/* + * whois - tiny client for the whois directory service + * + * Copyright (c) 2011 Pere Orga + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + */ +/* TODO + * Add ipv6 support + * Add proxy support + */ + +//config:config WHOIS +//config: bool "whois" +//config: default y +//config: help +//config: whois is a client for the whois directory service + +//applet:IF_WHOIS(APPLET(whois, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_WHOIS) += whois.o + +//usage:#define whois_trivial_usage +//usage: "[-h SERVER] [-p PORT] NAME..." +//usage:#define whois_full_usage "\n\n" +//usage: "Query WHOIS info about NAME\n" +//usage: "\n -h,-p Server to query" + +#include "libbb.h" + +static void pipe_out(int fd) +{ + FILE *fp; + char buf[1024]; + + fp = xfdopen_for_read(fd); + while (fgets(buf, sizeof(buf), fp)) { + char *p = strpbrk(buf, "\r\n"); + if (p) + *p = '\0'; + puts(buf); + } + + fclose(fp); /* closes fd too */ +} + +int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int whois_main(int argc UNUSED_PARAM, char **argv) +{ + int port = 43; + const char *host = "whois-servers.net"; + + opt_complementary = "-1:p+"; + getopt32(argv, "h:p:", &host, &port); + + argv += optind; + do { + int fd = create_and_connect_stream_or_die(host, port); + fdprintf(fd, "%s\r\n", *argv); + pipe_out(fd); + } + while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/networking/zcip.c b/networking/zcip.c index 6b0b1c4..7314ff8 100644 --- a/networking/zcip.c +++ b/networking/zcip.c @@ -6,7 +6,7 @@ * Copyright (C) 2003 by Arthur van Hoff (avh@strangeberry.com) * Copyright (C) 2004 by David Brownell * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -23,14 +23,24 @@ // - avoid silent script failures, especially under load... // - link status monitoring (restart on link-up; stop on link-down) +//usage:#define zcip_trivial_usage +//usage: "[OPTIONS] IFACE SCRIPT" +//usage:#define zcip_full_usage "\n\n" +//usage: "Manage a ZeroConf IPv4 link-local address\n" +//usage: "\n -f Run in foreground" +//usage: "\n -q Quit after obtaining address" +//usage: "\n -r 169.254.x.x Request this address first" +//usage: "\n -v Verbose" +//usage: "\n" +//usage: "\nWith no -q, runs continuously monitoring for ARP conflicts," +//usage: "\nexits only on I/O errors (link down etc)" + +#include "libbb.h" #include -#include #include #include -#include #include -#include "libbb.h" #include /* We don't need more than 32 bits of the counter */ @@ -81,6 +91,7 @@ struct globals { #define G (*(struct globals*)&bb_common_bufsiz1) #define saddr (G.saddr ) #define eth_addr (G.eth_addr) +#define INIT_G() do { } while (0) /** @@ -213,6 +224,7 @@ int zcip_main(int argc UNUSED_PARAM, char **argv) #define verbose (L.verbose ) memset(&L, 0, sizeof(L)); + INIT_G(); #define FOREGROUND (opts & 1) #define QUIT (opts & 2) diff --git a/packaging/06ls.patch b/packaging/06ls.patch deleted file mode 100644 index b953d77..0000000 --- a/packaging/06ls.patch +++ /dev/null @@ -1,19 +0,0 @@ -#! /bin/sh /usr/share/dpatch/dpatch-run -## 99-unnamed.dpatch by Yauheni Kaliuta -## -## All lines beginning with `## DP:' are a description of the patch. -## DP: No description. - -@DPATCH@ -diff --git a/coreutils/ls.c b/coreutils/ls.c -index 067e463..39aa63e 100644 ---- a/coreutils/ls.c -+++ b/coreutils/ls.c -@@ -431,6 +431,7 @@ static void showfiles(struct dnode **dn, int nfiles) - } - } - putchar('\n'); -+ fflush(NULL); - column = 0; - } - } diff --git a/packaging/applets-fallback.patch b/packaging/applets-fallback.patch deleted file mode 100644 index 880cbe5..0000000 --- a/packaging/applets-fallback.patch +++ /dev/null @@ -1,197 +0,0 @@ ---- a/shell/ash.c -+++ b/shell/ash.c -@@ -7241,25 +7241,10 @@ - - - static void --tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) -+tryexec(IF_FEATURE_SH_STANDALONE(int applet_no UNUSED_PARAM,) char *cmd, char **argv, char **envp) - { - int repeated = 0; - --#if ENABLE_FEATURE_SH_STANDALONE -- if (applet_no >= 0) { -- if (APPLET_IS_NOEXEC(applet_no)) { -- clearenv(); -- while (*envp) -- putenv(*envp++); -- run_applet_no_and_exit(applet_no, argv); -- } -- /* re-exec ourselves with the new arguments */ -- execve(bb_busybox_exec_path, argv, envp); -- /* If they called chroot or otherwise made the binary no longer -- * executable, fall through */ -- } --#endif -- - repeat: - #ifdef SYSV - do { -@@ -7309,14 +7294,14 @@ - - clearredir(/*drop:*/ 1); - envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); -- if (strchr(argv[0], '/') != NULL --#if ENABLE_FEATURE_SH_STANDALONE -- || (applet_no = find_applet_by_name(argv[0])) >= 0 --#endif -- ) { -+ if (strchr(argv[0], '/') != NULL) { - tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); - e = errno; - } else { -+#if ENABLE_FEATURE_SH_STANDALONE -+ bb_execv_applet(argv[0], argv, envp); -+#endif -+ - e = ENOENT; - while ((cmdname = path_advance(&path, argv[0])) != NULL) { - if (--idx < 0 && pathopt == NULL) { ---- a/libbb/execable.c -+++ b/libbb/execable.c -@@ -9,6 +9,9 @@ - - #include "libbb.h" - -+#include -+#include -+ - /* check if path points to an executable file; - * return 1 if found; - * return 0 otherwise; -@@ -68,12 +71,60 @@ - } - - #if ENABLE_FEATURE_PREFER_APPLETS -+int FAST_FUNC bb_execv_applet(const char *name, char *const argv[], char *const envp[]) -+{ -+ const char **path = bb_busybox_exec_paths; -+ -+ errno = ENOENT; -+ -+ if (find_applet_by_name(name) < 0) -+ return -1; -+ -+ for (; *path; ++path) -+ execve(*path, argv, envp); -+ -+ return -1; -+} -+ - /* just like the real execvp, but try to launch an applet named 'file' first - */ - int FAST_FUNC bb_execvp(const char *file, char *const argv[]) - { -- return execvp(find_applet_by_name(file) >= 0 ? bb_busybox_exec_path : file, -- argv); -+ int ret = bb_execv_applet(file, argv, environ); -+ if (errno != ENOENT) -+ return ret; -+ -+ return execvp(file, argv); -+} -+ -+int FAST_FUNC bb_execlp(const char *file, const char *arg, ...) -+{ -+#define INITIAL_ARGV_MAX 16 -+ size_t argv_max = INITIAL_ARGV_MAX; -+ const char **argv = malloc(argv_max * sizeof (const char *)); -+ va_list args; -+ unsigned int i = 0; -+ int ret; -+ -+ va_start (args, arg); -+ while (argv[i++] != NULL) { -+ if (i == argv_max) { -+ const char **nptr; -+ argv_max *= 2; -+ nptr = realloc (argv, argv_max * sizeof (const char *)); -+ if (nptr == NULL) -+ return -1; -+ argv = nptr; -+ } -+ -+ argv[i] = va_arg (args, const char *); -+ } -+ va_end (args); -+ -+ ret = bb_execvp(file, (char *const *)argv); -+ free(argv); -+ -+ return ret; - } - #endif - ---- a/libbb/messages.c -+++ b/libbb/messages.c -@@ -45,6 +45,15 @@ - const char bb_path_motd_file[] ALIGN1 = "/etc/motd"; - const char bb_dev_null[] ALIGN1 = "/dev/null"; - const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; -+const char *bb_busybox_exec_paths[] ALIGN1 = { -+#ifdef __linux__ -+ "/proc/self/exe", -+#endif -+#ifdef CONFIG_BUSYBOX_EXEC_PATH -+ CONFIG_BUSYBOX_EXEC_PATH, -+#endif -+ NULL -+}; - const char bb_default_login_shell[] ALIGN1 = LIBBB_DEFAULT_LOGIN_SHELL; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, - * but I want to save a few bytes here. Check libbb.h before changing! */ ---- a/include/libbb.h -+++ b/include/libbb.h -@@ -830,11 +830,11 @@ - * but it may exec busybox and call applet instead of searching PATH. - */ - #if ENABLE_FEATURE_PREFER_APPLETS -+int bb_execv_applet(const char *name, char *const argv[], char *const envp[]) FAST_FUNC; - int bb_execvp(const char *file, char *const argv[]) FAST_FUNC; --#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) --#define BB_EXECLP(prog,cmd,...) \ -- execlp((find_applet_by_name(prog) >= 0) ? CONFIG_BUSYBOX_EXEC_PATH : prog, \ -- cmd, __VA_ARGS__) -+int bb_execlp(const char *file, const char *arg, ...) FAST_FUNC; -+#define BB_EXECVP(prog,cmd) bb_execvp(prog,cmd) -+#define BB_EXECLP(prog,cmd,...) bb_execlp(prog,cmd, __VA_ARGS__) - #else - #define BB_EXECVP(prog,cmd) execvp(prog,cmd) - #define BB_EXECLP(prog,cmd,...) execlp(prog,cmd, __VA_ARGS__) -@@ -1575,6 +1575,7 @@ - extern const char bb_path_wtmp_file[]; - extern const char bb_dev_null[]; - extern const char bb_busybox_exec_path[]; -+extern const char *bb_busybox_exec_paths[]; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, - * but I want to save a few bytes here */ - extern const char bb_PATH_root_path[]; /* "PATH=/sbin:/usr/sbin:/bin:/usr/bin" */ ---- a/Config.in -+++ b/Config.in -@@ -386,13 +386,10 @@ - - config BUSYBOX_EXEC_PATH - string "Path to BusyBox executable" -- default "/proc/self/exe" -+ default "/bin/busybox" - help - When Busybox applets need to run other busybox applets, BusyBox -- sometimes needs to exec() itself. When the /proc filesystem is -- mounted, /proc/self/exe always points to the currently running -- executable. If you haven't got /proc, set this to wherever you -- want to run BusyBox from. -+ sometimes needs to exec() itself. - - # These are auto-selected by other options - ---- a/coreutils/chroot.c -+++ b/coreutils/chroot.c -@@ -30,5 +30,7 @@ - argv[1] = (char *) "-i"; - } - -- BB_EXECVP_or_die(argv); -+ execvp(argv[0], argv); -+ xfunc_error_retval = (errno == ENOENT) ? 127 : 126; -+ bb_perror_msg_and_die("can't execute '%s'", argv[0]); - } diff --git a/packaging/bin.links b/packaging/bin.links deleted file mode 100644 index acf3d14..0000000 --- a/packaging/bin.links +++ /dev/null @@ -1,65 +0,0 @@ -ash -mktemp -bunzip2 -bzcat -bzip2 -cat -chgrp -chmod -chown -cp -cpio -date -dd -df -dmesg -dnsdomainname -dumpkmap -echo -ed -egrep -false -fbset -fdflush -fgconsole -fgrep -fsync -fuser -grep -gunzip -gzip -hostname -ip -ipaddr -iplink -iproute -iprule -kill -ln -ls -mkdir -mknod -more -mount -mountpoint -mv -netstat -ping -ping6 -ps -pwd -readlink -rm -rmdir -sed -sleep -stty -sync -tar -touch -true -umount -uname -uncompress -usleep -zcat diff --git a/packaging/blockdev.patch b/packaging/blockdev.patch deleted file mode 100644 index 46f57b7..0000000 --- a/packaging/blockdev.patch +++ /dev/null @@ -1,210 +0,0 @@ -Description: Backport blockdev applet from upstream - This allows os-prober to avoid replaying journals when mounting block - devices read-only. -Origin: http://git.busybox.net/busybox/tree/util-linux/blockdev.c -Bug-Debian: http://bugs.debian.org/418163 -Author: Sergey Naumov -Author: Denys Vlasenko -Forwarded: not-needed -Last-Update: 2010-11-09 - -Index: b/util-linux/blockdev.c -=================================================================== ---- /dev/null -+++ b/util-linux/blockdev.c -@@ -0,0 +1,195 @@ -+/* -+ * blockdev implementation for busybox -+ * -+ * Copyright (C) 2010 Sergey Naumov -+ * -+ * Licensed under GPLv2, see file LICENSE in this source tree. -+ */ -+ -+//applet:IF_BLOCKDEV(APPLET(blockdev, _BB_DIR_SBIN, _BB_SUID_DROP)) -+ -+//kbuild:lib-$(CONFIG_BLOCKDEV) += blockdev.o -+ -+//config:config BLOCKDEV -+//config: bool "blockdev" -+//config: default y -+//config: help -+//config: Performs some ioctls with block devices. -+ -+//usage:#define blockdev_trivial_usage -+//usage: "OPTION BLOCKDEV" -+//usage:#define blockdev_full_usage "\n\n" -+//usage: "Options:" -+//usage: "\n --setro Set ro" -+//usage: "\n --setrw Set rw" -+//usage: "\n --getro Get ro" -+//usage: "\n --getss Get sector size" -+//usage: "\n --getbsz Get block size" -+//usage: "\n --setbsz BYTES Set block size" -+//usage: "\n --getsize Get device size in 512-byte sectors" -+//usage: "\n --getsize64 Get device size in bytes" -+//usage: "\n --flushbufs Flush buffers" -+//usage: "\n --rereadpt Reread partition table" -+ -+ -+#include "libbb.h" -+#include -+ -+enum { -+ ARG_NONE = 0, -+ ARG_INT = 1, -+ ARG_ULONG = 2, -+ /* Yes, BLKGETSIZE64 takes pointer to uint64_t, not ullong! */ -+ ARG_U64 = 3, -+ ARG_MASK = 3, -+ -+ FL_USRARG = 4, /* argument is provided by user */ -+ FL_NORESULT = 8, -+}; -+ -+struct bdc { -+ uint32_t ioc; /* ioctl code */ -+ const char name[sizeof("flushbufs")]; /* "--setfoo" wothout "--" */ -+ uint8_t flags; -+ int8_t argval; /* default argument value */ -+}; -+ -+static const struct bdc bdcommands[] = { -+ { -+ .ioc = BLKROSET, -+ .name = "setro", -+ .flags = ARG_INT + FL_NORESULT, -+ .argval = 1, -+ },{ -+ .ioc = BLKROSET, -+ .name = "setrw", -+ .flags = ARG_INT + FL_NORESULT, -+ .argval = 0, -+ },{ -+ .ioc = BLKROGET, -+ .name = "getro", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKSSZGET, -+ .name = "getss", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKBSZGET, -+ .name = "getbsz", -+ .flags = ARG_INT, -+ .argval = -1, -+ },{ -+ .ioc = BLKBSZSET, -+ .name = "setbsz", -+ .flags = ARG_INT + FL_NORESULT + FL_USRARG, -+ .argval = 0, -+ },{ -+ .ioc = BLKGETSIZE, -+ .name = "getsize", -+ .flags = ARG_ULONG, -+ .argval = -1, -+ },{ -+ .ioc = BLKGETSIZE64, -+ .name = "getsize64", -+ .flags = ARG_U64, -+ .argval = -1, -+ },{ -+ .ioc = BLKFLSBUF, -+ .name = "flushbufs", -+ .flags = ARG_NONE + FL_NORESULT, -+ .argval = 0, -+ },{ -+ .ioc = BLKRRPART, -+ .name = "rereadpt", -+ .flags = ARG_NONE + FL_NORESULT, -+ .argval = 0, -+ } -+}; -+ -+static const struct bdc *find_cmd(const char *s) -+{ -+ const struct bdc *bdcmd = bdcommands; -+ if (s[0] == '-' && s[1] == '-') { -+ s += 2; -+ do { -+ if (strcmp(s, bdcmd->name) == 0) -+ return bdcmd; -+ bdcmd++; -+ } while (bdcmd != bdcommands + ARRAY_SIZE(bdcommands)); -+ } -+ bb_show_usage(); -+} -+ -+int blockdev_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -+int blockdev_main(int argc, char **argv) -+{ -+ const struct bdc *bdcmd; -+ int fd; -+ uint64_t u64; -+ union { -+ int i; -+ unsigned long lu; -+ uint64_t u64; -+ } ioctl_val_on_stack; -+ -+ if ((unsigned)(argc - 3) > 1) /* must have 2 or 3 args */ -+ bb_show_usage(); -+ -+ bdcmd = find_cmd(*++argv); -+ -+ u64 = (int)bdcmd->argval; -+ if (bdcmd->flags & FL_USRARG) -+ u64 = xatoi_u(*++argv); -+ -+ if (!*++argv || argv[1]) -+ bb_show_usage(); -+ fd = xopen(*argv, O_RDONLY); -+ -+ ioctl_val_on_stack.u64 = u64; -+#if BB_BIG_ENDIAN -+ /* Store data properly wrt data size. -+ * (1) It's no-op for little-endian. -+ * (2) it's no-op for 0 and -1. Only --setro uses arg != 0 and != -1, -+ * and it is ARG_INT. --setbsz USER_VAL is also ARG_INT. -+ * Thus, we don't need to handle ARG_ULONG. -+ */ -+ switch (bdcmd->flags & ARG_MASK) { -+ case ARG_INT: -+ ioctl_val_on_stack.i = (int)u64; -+ break; -+# if 0 /* unused */ -+ case ARG_ULONG: -+ ioctl_val_on_stack.lu = (unsigned long)u64; -+ break; -+# endif -+ } -+#endif -+ -+ if (ioctl(fd, bdcmd->ioc, &ioctl_val_on_stack.u64) == -1) -+ bb_simple_perror_msg_and_die(*argv); -+ -+ /* Fetch it into register(s) */ -+ u64 = ioctl_val_on_stack.u64; -+ -+ /* Zero- or one-extend the value if needed, then print */ -+ switch (bdcmd->flags & (ARG_MASK+FL_NORESULT)) { -+ case ARG_INT: -+ /* Smaller code when we use long long -+ * (gcc tail-merges printf call) -+ */ -+ printf("%lld\n", (long long)(int)u64); -+ break; -+ case ARG_ULONG: -+ u64 = (unsigned long)u64; -+ /* FALLTHROUGH */ -+ case ARG_U64: -+ printf("%llu\n", (unsigned long long)u64); -+ break; -+ } -+ -+ if (ENABLE_FEATURE_CLEAN_UP) -+ close(fd); -+ return EXIT_SUCCESS; -+} diff --git a/packaging/bootchartd-mounting-tmpfs-is-Linux-specific.patch b/packaging/bootchartd-mounting-tmpfs-is-Linux-specific.patch deleted file mode 100644 index aafbed2..0000000 --- a/packaging/bootchartd-mounting-tmpfs-is-Linux-specific.patch +++ /dev/null @@ -1,66 +0,0 @@ -From e7a0632b7b38f635853a08c276dad2fbd395ba92 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:53 +0200 -Subject: [PATCH 11/12] bootchartd: mounting tmpfs is Linux-specific - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/bootchartd.c | 20 +++++++++++++------- - 1 files changed, 13 insertions(+), 7 deletions(-) - -diff --git a/init/bootchartd.c b/init/bootchartd.c -index a1c0164..465a349 100644 ---- a/init/bootchartd.c -+++ b/init/bootchartd.c -@@ -6,7 +6,6 @@ - //config:config BOOTCHARTD - //config: bool "bootchartd" - //config: default y --//config: depends on PLATFORM_LINUX - //config: help - //config: bootchartd is commonly used to profile the boot process - //config: for the purpose of speeding it up. In this case, it is started -@@ -46,12 +45,15 @@ - #include "libbb.h" - /* After libbb.h, since it needs sys/types.h on some systems */ - #include --#include --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --#ifndef MNT_DETACH --# define MNT_DETACH 0x00000002 -+ -+#ifdef __linux__ -+# include -+# ifndef MS_SILENT -+# define MS_SILENT (1 << 15) -+# endif -+# ifndef MNT_DETACH -+# define MNT_DETACH 0x00000002 -+# endif - #endif - - #define BC_VERSION_STR "0.8" -@@ -175,6 +177,7 @@ static char *make_tempdir(void) - char template[] = "/tmp/bootchart.XXXXXX"; - char *tempdir = xstrdup(mkdtemp(template)); - if (!tempdir) { -+#ifdef __linux__ - /* /tmp is not writable (happens when we are used as init). - * Try to mount a tmpfs, them cd and lazily unmount it. - * Since we unmount it at once, we can mount it anywhere. -@@ -192,6 +195,9 @@ static char *make_tempdir(void) - if (umount2(try_dir, MNT_DETACH) != 0) { - bb_perror_msg_and_die("can't %smount tmpfs", "un"); - } -+#else -+ bb_perror_msg_and_die("can't create temporary directory"); -+#endif - } else { - xchdir(tempdir); - } --- -1.7.1 - diff --git a/packaging/busybox-1.17.1-make.patch b/packaging/busybox-1.17.1-make.patch deleted file mode 100644 index 96da2e4..0000000 --- a/packaging/busybox-1.17.1-make.patch +++ /dev/null @@ -1,32 +0,0 @@ ---- Makefile.orig 2012-08-03 13:24:05.328363736 +0900 -+++ busybox-1.17.1/Makefile 2012-08-03 13:28:35.568351822 +0900 -@@ -433,7 +433,12 @@ - -include $(srctree)/arch/$(ARCH)/Makefile - export KBUILD_DEFCONFIG - --config %config: scripts_basic outputmakefile gen_build_files FORCE -+%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 -@@ -1285,9 +1290,14 @@ - $(Q)$(MAKE) $(build)=$(build-dir) $(target-dir)$(notdir $@) - - # Modules --/ %/: prepare scripts FORCE -+%/: 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) diff --git a/packaging/busybox-1.20.2-fix-resource-h-failure.patch b/packaging/busybox-1.20.2-fix-resource-h-failure.patch deleted file mode 100755 index a081e25..0000000 --- a/packaging/busybox-1.20.2-fix-resource-h-failure.patch +++ /dev/null @@ -1,10 +0,0 @@ ---- busybox-1.17.1/include/libbb.h.org 2012-11-07 16:17:30.000000000 +0900 -+++ busybox-1.17.1/include/libbb.h 2012-11-21 14:58:48.000000000 +0900 -@@ -29,6 +29,7 @@ - #include - #include - #include -+#include - #include - #include - #include diff --git a/packaging/busybox-zero-ifr.ifr_hwaddr.sa_data.patch b/packaging/busybox-zero-ifr.ifr_hwaddr.sa_data.patch deleted file mode 100644 index 9fc6f7d..0000000 --- a/packaging/busybox-zero-ifr.ifr_hwaddr.sa_data.patch +++ /dev/null @@ -1,12 +0,0 @@ -diff --git a/networking/interface.c b/networking/interface.c -index ef187be..6cb1afa 100644 ---- a/networking/interface.c -+++ b/networking/interface.c -@@ -623,6 +623,7 @@ static int if_fetch(struct interface *ife) - - strncpy_IFNAMSIZ(ifr.ifr_name, ifname); - memset(ife->hwaddr, 0, 32); -+ memset(ifr.ifr_hwaddr.sa_data, 0, 8); - if (ioctl(skfd, SIOCGIFHWADDR, &ifr) >= 0) - memcpy(ife->hwaddr, ifr.ifr_hwaddr.sa_data, 8); - diff --git a/debian/config/pkg/slp b/packaging/busybox.config similarity index 68% rename from debian/config/pkg/slp rename to packaging/busybox.config index a003f21..91440b3 100644 --- a/debian/config/pkg/slp +++ b/packaging/busybox.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Tue Jan 17 11:38:38 2012 +# Busybox version: 1.17.2 +# Wed Oct 6 16:34:52 2010 # CONFIG_HAVE_DOT_CONFIG=y @@ -12,11 +12,10 @@ CONFIG_HAVE_DOT_CONFIG=y # # General Configuration # -# CONFIG_DESKTOP is not set -CONFIG_EXTRA_COMPAT=y +CONFIG_DESKTOP=y +# CONFIG_EXTRA_COMPAT is not set CONFIG_INCLUDE_SUSv2=y # CONFIG_USE_PORTABLE_CODE is not set -CONFIG_PLATFORM_LINUX=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 @@ -27,7 +26,7 @@ CONFIG_FEATURE_COMPRESS_USAGE=y # 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_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=63 CONFIG_LAST_SUPPORTED_WCHAR=767 # CONFIG_UNICODE_COMBINING_WCHARS is not set @@ -45,7 +44,6 @@ CONFIG_FEATURE_SUID=y # CONFIG_FEATURE_SUID_CONFIG is not set # CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set -CONFIG_SMACK=y # CONFIG_FEATURE_PREFER_APPLETS is not set CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" CONFIG_FEATURE_SYSLOG=y @@ -85,26 +83,26 @@ CONFIG_INSTALL_APPLET_SYMLINKS=y # 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" +CONFIG_PREFIX="/usr" # # Busybox Library Tuning # CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=0 +CONFIG_MD5_SIZE_VS_SPEED=2 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_HISTORY=666 CONFIG_FEATURE_EDITING_SAVEHISTORY=y CONFIG_FEATURE_TAB_COMPLETION=y # CONFIG_FEATURE_USERNAME_COMPLETION is not set -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y -CONFIG_FEATURE_EDITING_ASK_TERMINAL=y -# CONFIG_FEATURE_NON_POSIX_CP is not set -CONFIG_FEATURE_VERBOSE_CP_MESSAGE=y +# 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=y CONFIG_IOCTL_HEX2STR_ERROR=y @@ -118,18 +116,18 @@ CONFIG_FEATURE_HWIB=y # 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_FEATURE_SEAMLESS_LZMA is not set +# CONFIG_FEATURE_SEAMLESS_BZ2 is not set +# CONFIG_FEATURE_SEAMLESS_GZ is not set +# CONFIG_FEATURE_SEAMLESS_Z is not set 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_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_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set @@ -137,27 +135,27 @@ CONFIG_GUNZIP=y CONFIG_GZIP=y CONFIG_FEATURE_GZIP_LONG_OPTIONS=y CONFIG_LZOP=y -CONFIG_LZOP_COMPR_HIGH=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_AUTODETECT is not set CONFIG_FEATURE_TAR_FROM=y -CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY=y -CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY=y +# CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set +# CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set 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_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_FEATURE_LZMA_FAST is not set CONFIG_LZMA=y -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set +CONFIG_UNXZ=y +CONFIG_XZ=y CONFIG_UNZIP=y # @@ -167,7 +165,7 @@ CONFIG_BASENAME=y CONFIG_CAT=y CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y -CONFIG_FEATURE_DATE_NANO=y +# CONFIG_FEATURE_DATE_NANO is not set CONFIG_FEATURE_DATE_COMPAT=y CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y @@ -201,8 +199,8 @@ 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_EXPAND is not set +# CONFIG_FEATURE_EXPAND_LONG_OPTIONS is not set CONFIG_EXPR=y CONFIG_EXPR_MATH_SUPPORT_64=y CONFIG_FALSE=y @@ -224,7 +222,7 @@ 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 not set # CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set CONFIG_MD5SUM=y CONFIG_MKDIR=y @@ -240,18 +238,18 @@ CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y CONFIG_READLINK=y -CONFIG_FEATURE_READLINK_FOLLOW=y +# CONFIG_FEATURE_READLINK_FOLLOW is not set CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y -CONFIG_FEATURE_RMDIR_LONG_OPTIONS=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_FEATURE_FANCY_SLEEP is not set +# CONFIG_FEATURE_FLOAT_SLEEP is not set CONFIG_SORT=y CONFIG_FEATURE_SORT_BIG=y CONFIG_SPLIT=y @@ -261,17 +259,17 @@ CONFIG_FEATURE_STAT_FORMAT=y CONFIG_STTY=y CONFIG_SUM=y CONFIG_SYNC=y -CONFIG_TAC=y +# CONFIG_TAC is not set CONFIG_TAIL=y -CONFIG_FEATURE_FANCY_TAIL=y +# CONFIG_FEATURE_FANCY_TAIL is not set CONFIG_TEE=y -CONFIG_FEATURE_TEE_USE_BLOCK_IO=y +# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set CONFIG_TOUCH=y CONFIG_TRUE=y CONFIG_TTY=y CONFIG_UNAME=y -CONFIG_UNEXPAND=y -CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +# CONFIG_UNEXPAND is not set +# CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS is not set CONFIG_UNIQ=y CONFIG_USLEEP=y CONFIG_UUDECODE=y @@ -285,7 +283,7 @@ CONFIG_YES=y # # Common options for cp and mv # -CONFIG_FEATURE_PRESERVE_HARDLINKS=y +# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set # # Common options for ls, more and telnet @@ -307,20 +305,20 @@ CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # CONFIG_CHVT=y CONFIG_FGCONSOLE=y -# CONFIG_CLEAR is not set +CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y -CONFIG_KBD_MODE=y +# CONFIG_KBD_MODE is not set CONFIG_LOADFONT=y CONFIG_LOADKMAP=y CONFIG_OPENVT=y -# CONFIG_RESET is not set +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_FEATURE_SETCONSOLE_LONG_OPTIONS is not set +CONFIG_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y CONFIG_DEFAULT_SETFONT_DIR="" CONFIG_SETKEYCODES=y CONFIG_SETLOGCONS=y @@ -337,19 +335,19 @@ CONFIG_FEATURE_LOADFONT_RAW=y # CONFIG_MKTEMP=y # CONFIG_PIPE_PROGRESS is not set -# CONFIG_RUN_PARTS is not set -# CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS is not set -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set +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 is not set +CONFIG_WHICH=y # # Editors # CONFIG_AWK=y -CONFIG_FEATURE_AWK_LIBM=y +# CONFIG_FEATURE_AWK_LIBM is not set CONFIG_CMP=y CONFIG_DIFF=y CONFIG_FEATURE_DIFF_LONG_OPTIONS=y @@ -358,7 +356,7 @@ CONFIG_ED=y CONFIG_PATCH=y CONFIG_SED=y CONFIG_VI=y -CONFIG_FEATURE_VI_MAX_LEN=4096 +CONFIG_FEATURE_VI_MAX_LEN=1024 CONFIG_FEATURE_VI_8BIT=y CONFIG_FEATURE_VI_COLON=y CONFIG_FEATURE_VI_YANKMARK=y @@ -394,11 +392,10 @@ 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_DELETE is not set CONFIG_FEATURE_FIND_PATH=y CONFIG_FEATURE_FIND_REGEX=y # CONFIG_FEATURE_FIND_CONTEXT is not set -CONFIG_FEATURE_FIND_SMACK=y CONFIG_FEATURE_FIND_LINKS=y CONFIG_GREP=y CONFIG_FEATURE_GREP_EGREP_ALIAS=y @@ -413,65 +410,64 @@ 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_INIT is not set -# CONFIG_FEATURE_USE_INITTAB is not set -# CONFIG_FEATURE_KILL_REMOVED is not set +CONFIG_BOOTCHARTD=y +CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER=y +CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE=y +CONFIG_INIT=y +CONFIG_FEATURE_USE_INITTAB=y +CONFIG_FEATURE_KILL_REMOVED=y CONFIG_FEATURE_KILL_DELAY=0 -# CONFIG_FEATURE_INIT_SCTTY is not set -# CONFIG_FEATURE_INIT_SYSLOG is not set -# CONFIG_FEATURE_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -CONFIG_INIT_TERMINAL_TYPE="" -# CONFIG_HALT is not set +CONFIG_FEATURE_INIT_SCTTY=y +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y +CONFIG_FEATURE_INITRD=y +CONFIG_HALT=y # CONFIG_FEATURE_CALL_TELINIT is not set CONFIG_TELINIT_PATH="" -# CONFIG_MESG is not set +CONFIG_MESG=y # # Login/Password Management Utilities # CONFIG_FEATURE_SHADOWPASSWDS=y -# 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_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_FEATURE_ADDUSER_TO_GROUP is not set CONFIG_DELGROUP=y -CONFIG_FEATURE_DEL_USER_FROM_GROUP=y -CONFIG_FEATURE_CHECK_NAMES=y +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set +# CONFIG_FEATURE_CHECK_NAMES is not set CONFIG_ADDUSER=y -CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y -CONFIG_FIRST_SYSTEM_ID=0 -CONFIG_LAST_SYSTEM_ID=64900 +# CONFIG_FEATURE_ADDUSER_LONG_OPTIONS is not set +CONFIG_FIRST_SYSTEM_ID=100 +CONFIG_LAST_SYSTEM_ID=999 CONFIG_DELUSER=y CONFIG_GETTY=y -# CONFIG_LOGIN is not set +CONFIG_LOGIN=y # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set # CONFIG_FEATURE_NOLOGIN is not set -# CONFIG_FEATURE_SECURETTY is not set +CONFIG_FEATURE_SECURETTY=y CONFIG_PASSWD=y -CONFIG_FEATURE_PASSWD_WEAK_CHECK=y -# CONFIG_CRYPTPW is not set -CONFIG_CHPASSWD=y -# 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_FEATURE_PASSWD_WEAK_CHECK is not set +CONFIG_CRYPTPW=y +# CONFIG_CHPASSWD is not set +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 is not set -# CONFIG_FSCK is not set -# CONFIG_LSATTR is not set +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y # CONFIG_TUNE2FS is not set # @@ -486,8 +482,8 @@ CONFIG_RMMOD=y CONFIG_LSMOD=y CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y CONFIG_MODPROBE=y -CONFIG_FEATURE_MODPROBE_BLACKLIST=y -CONFIG_DEPMOD=y +# CONFIG_FEATURE_MODPROBE_BLACKLIST is not set +# CONFIG_DEPMOD is not set # # Options common to multiple modutils @@ -508,18 +504,17 @@ 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_ACPID=y +CONFIG_FEATURE_ACPID_COMPAT=y 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_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=y CONFIG_FDISK_SUPPORT_LARGE_DISKS=y CONFIG_FEATURE_FDISK_WRITABLE=y @@ -527,33 +522,33 @@ CONFIG_FEATURE_FDISK_WRITABLE=y # 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_FEATURE_FDISK_ADVANCED is not set # CONFIG_FINDFS is not set CONFIG_FLOCK=y -CONFIG_FREERAMDISK=y -CONFIG_FSCK_MINIX=y -# CONFIG_MKFS_EXT2 is not set -CONFIG_MKFS_MINIX=y -CONFIG_FEATURE_MINIX2=y +# CONFIG_FREERAMDISK is not set +# 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_FEATURE_HEXDUMP_REVERSE is not set +# CONFIG_HD is not set 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 is not set -# CONFIG_LSUSB is not set +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_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set CONFIG_FEATURE_MDEV_EXEC=y CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y CONFIG_MKSWAP=y @@ -562,23 +557,23 @@ CONFIG_MORE=y CONFIG_FEATURE_USE_TERMIOS=y CONFIG_MOUNT=y CONFIG_FEATURE_MOUNT_FAKE=y -CONFIG_FEATURE_MOUNT_VERBOSE=y +# CONFIG_FEATURE_MOUNT_VERBOSE is not set CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# CONFIG_FEATURE_MOUNT_LABEL is not set 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_PIVOT_ROOT is not set CONFIG_RDATE=y -CONFIG_RDEV=y +# CONFIG_RDEV is not set CONFIG_READPROFILE=y -CONFIG_RTCWAKE=y -CONFIG_SCRIPT=y +# CONFIG_RTCWAKE is not set +# CONFIG_SCRIPT is not set CONFIG_SCRIPTREPLAY=y -CONFIG_SETARCH=y +# CONFIG_SETARCH is not set CONFIG_SWAPONOFF=y -CONFIG_FEATURE_SWAPON_PRI=y +# CONFIG_FEATURE_SWAPON_PRI is not set CONFIG_SWITCH_ROOT=y CONFIG_UMOUNT=y CONFIG_FEATURE_UMOUNT_ALL=y @@ -588,41 +583,41 @@ CONFIG_FEATURE_UMOUNT_ALL=y # CONFIG_FEATURE_MOUNT_LOOP=y CONFIG_FEATURE_MOUNT_LOOP_CREATE=y -# CONFIG_FEATURE_MTAB_SUPPORT is not set +CONFIG_FEATURE_MTAB_SUPPORT=y CONFIG_VOLUMEID=y # # Filesystem/Volume identification # -CONFIG_FEATURE_VOLUMEID_EXT=y +# CONFIG_FEATURE_VOLUMEID_EXT is not set 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_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_UBIATTACH=y -CONFIG_UBIDETACH=y +# CONFIG_UBIATTACH is not set +# CONFIG_UBIDETACH is not set CONFIG_ADJTIMEX=y # CONFIG_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 # CONFIG_CHAT is not set # CONFIG_FEATURE_CHAT_NOFAIL is not set # CONFIG_FEATURE_CHAT_TTY_HIFI is not set @@ -637,25 +632,25 @@ 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_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_DEVMEM=y CONFIG_EJECT=y -CONFIG_FEATURE_EJECT_SCSI=y -CONFIG_FBSPLASH=y -CONFIG_FLASHCP=y -CONFIG_FLASH_LOCK=y -CONFIG_FLASH_UNLOCK=y -CONFIG_FLASH_ERASEALL=y +# 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=y -CONFIG_INOTIFYD=y -# CONFIG_LAST is not set -# CONFIG_FEATURE_LAST_SMALL is not set +# CONFIG_INOTIFYD is not set +CONFIG_LAST=y +CONFIG_FEATURE_LAST_SMALL=y # CONFIG_FEATURE_LAST_FANCY is not set CONFIG_LESS=y CONFIG_FEATURE_LESS_MAXLINES=9999999 @@ -677,13 +672,13 @@ CONFIG_MAKEDEVS=y # CONFIG_FEATURE_MAKEDEVS_LEAF is not set CONFIG_FEATURE_MAKEDEVS_TABLE=y CONFIG_MAN=y -CONFIG_MICROCOM=y +# CONFIG_MICROCOM is not set CONFIG_MOUNTPOINT=y CONFIG_MT=y CONFIG_RAIDAUTORUN=y -CONFIG_READAHEAD=y +# CONFIG_READAHEAD is not set # CONFIG_RFKILL is not set -# CONFIG_RUNLEVEL is not set +CONFIG_RUNLEVEL=y CONFIG_RX=y CONFIG_SETSID=y CONFIG_STRINGS=y @@ -699,49 +694,49 @@ CONFIG_WATCHDOG=y # # Networking Utilities # -# CONFIG_NC is not set -# CONFIG_NC_SERVER is not set -# CONFIG_NC_EXTRA is not set +CONFIG_NC=y +CONFIG_NC_SERVER=y +CONFIG_NC_EXTRA=y # CONFIG_NC_110_COMPAT is not set CONFIG_FEATURE_IPV6=y # CONFIG_FEATURE_UNIX_LOCAL is not set -# CONFIG_FEATURE_PREFER_IPV4_ADDRESS is not set -# CONFIG_VERBOSE_RESOLUTION_ERRORS is not set +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_BRCTL is not set +# CONFIG_FEATURE_BRCTL_FANCY is not set +# CONFIG_FEATURE_BRCTL_SHOW is not set CONFIG_DNSD=y CONFIG_ETHER_WAKE=y CONFIG_FAKEIDENTD=y -# CONFIG_FTPD is not set -# CONFIG_FEATURE_FTP_WRITE is not set -# CONFIG_FEATURE_FTPD_ACCEPT_BROKEN_LIST is not set +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_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=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 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 @@ -751,13 +746,13 @@ 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_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 @@ -765,7 +760,7 @@ 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_FEATURE_IP_RARE_PROTOCOLS is not set CONFIG_IPADDR=y CONFIG_IPLINK=y CONFIG_IPROUTE=y @@ -775,20 +770,20 @@ CONFIG_IPCALC=y CONFIG_FEATURE_IPCALC_FANCY=y CONFIG_FEATURE_IPCALC_LONG_OPTIONS=y CONFIG_NAMEIF=y -CONFIG_FEATURE_NAMEIF_EXTENDED=y +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set CONFIG_NETSTAT=y CONFIG_FEATURE_NETSTAT_WIDE=y -CONFIG_FEATURE_NETSTAT_PRG=y +# CONFIG_FEATURE_NETSTAT_PRG is not set CONFIG_NSLOOKUP=y -# CONFIG_NTPD is not set -# CONFIG_FEATURE_NTPD_SERVER is not set +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_SLATTACH is not set +# CONFIG_TCPSVD is not set CONFIG_TELNET=y CONFIG_FEATURE_TELNET_TTYPE=y CONFIG_FEATURE_TELNET_AUTOLOGIN=y @@ -805,35 +800,34 @@ 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_TFTP_DEBUG is not set CONFIG_TRACEROUTE=y -# CONFIG_TRACEROUTE6 is not set +CONFIG_TRACEROUTE6=y CONFIG_FEATURE_TRACEROUTE_VERBOSE=y CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y -# CONFIG_TUNCTL is not set -# CONFIG_FEATURE_TUNCTL_UG 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_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set +CONFIG_DHCPD_LEASES_FILE="" CONFIG_UDHCPC=y CONFIG_FEATURE_UDHCPC_ARPING=y -CONFIG_FEATURE_UDHCP_PORT=y -CONFIG_UDHCP_DEBUG=0 +# CONFIG_FEATURE_UDHCP_PORT is not set +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_FEATURE_UDHCPC_FAST_REQUEST=y CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" -CONFIG_UDPSVD=y +# CONFIG_UDPSVD is not set 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_ZCIP is not set # # Print Utilities @@ -845,33 +839,33 @@ CONFIG_ZCIP=y # # Mail Utilities # -# CONFIG_MAKEMIME is not set +CONFIG_MAKEMIME=y CONFIG_FEATURE_MIME_CHARSET="us-ascii" -# 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=y +CONFIG_POPMAILDIR=y +CONFIG_FEATURE_POPMAILDIR_DELIVERY=y +CONFIG_REFORMIME=y +CONFIG_FEATURE_REFORMIME_COMPAT=y +# CONFIG_SENDMAIL is not set # # Process Utilities # -# CONFIG_SMEMCAP is not set +CONFIG_SMEMCAP=y CONFIG_FREE=y CONFIG_FUSER=y CONFIG_KILL=y CONFIG_KILLALL=y -# CONFIG_KILLALL5 is not set -CONFIG_NMETER=y -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_KILLALL5=y +# CONFIG_NMETER 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=y # CONFIG_FEATURE_PS_TIME is not set -# CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS is not set +CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set CONFIG_RENICE=y CONFIG_BB_SYSCTL=y @@ -879,7 +873,7 @@ 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_DECIMALS is not set CONFIG_FEATURE_TOP_SMP_PROCESS=y CONFIG_FEATURE_TOPMEM=y CONFIG_FEATURE_SHOW_THREADS=y @@ -889,17 +883,17 @@ 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_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=y -CONFIG_CHPST=y -CONFIG_SETUIDGID=y -CONFIG_ENVUIDGID=y -CONFIG_ENVDIR=y -CONFIG_SOFTLIMIT=y +# 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 @@ -927,11 +921,11 @@ CONFIG_ASH_GETOPTS=y CONFIG_ASH_BUILTIN_ECHO=y CONFIG_ASH_BUILTIN_PRINTF=y CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y +# CONFIG_ASH_CMDCMD is not set # CONFIG_ASH_MAIL is not set CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -CONFIG_ASH_RANDOM_SUPPORT=y -CONFIG_ASH_EXPAND_PRMT=y +# 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 @@ -955,31 +949,22 @@ CONFIG_FEATURE_BASH_IS_NONE=y # CONFIG_MSH is not set CONFIG_SH_MATH_SUPPORT=y CONFIG_SH_MATH_SUPPORT_64=y -CONFIG_FEATURE_SH_EXTRA_QUIET=y +# 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 - -# -# Smack Utilities -# -CONFIG_SMACKLOAD=y -CONFIG_SMACKCIPSO=y -CONFIG_NEWSMACK=y -CONFIG_SMACKENABLED=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_REMOTE_LOG is not set +# 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_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=y diff --git a/packaging/busybox.manifest b/packaging/busybox.manifest index c922afb..017d22d 100644 --- a/packaging/busybox.manifest +++ b/packaging/busybox.manifest @@ -1,8 +1,5 @@ - - - - - - + + + diff --git a/packaging/busybox.spec b/packaging/busybox.spec old mode 100755 new mode 100644 index f84fb1a..e1d6d85 --- a/packaging/busybox.spec +++ b/packaging/busybox.spec @@ -1,1077 +1,51 @@ -#sbs-git:slp/pkgs/b/busybox busybox 1.17.1 2af797aea95edf3accab73b53dd8075b78e75ddd -Summary: Single binary providing simplified versions of system commands -Name: busybox -Version: 1.17.1 -Release: 28 -License: GPLv2 -Group: System/Shells -Source: http://www.busybox.net/downloads/%{name}-%{version}.tar.gz -Source1: busybox-dahlia.config -Source2: bin.links -Source3: sbin.links -Source4: usrbin.links -Source5: usrsbin.links -Source101: tizen.config -Source201: klogd.service -Source202: syslogd.service -Source1001: %{name}.manifest -Source1002: syslogd.manifest - -Patch0: 06ls.patch -Patch1: doc-man-name.patch -Patch2: shell-ash-export-HOME.patch -Patch3: applets-fallback.patch -Patch4: version.patch -Patch5: init-console.patch -#Patch6: 05thumb.dpatch -#Patch7: 06ls.patch -Patch8: busybox-zero-ifr.ifr_hwaddr.sa_data.patch -Patch9: top-display-rss.patch -Patch10: strip.patch -Patch11: make_gen_build_files_skip_quilt.patch - -# The following patches have been merged upstream and will be in version 1.18 -Patch12: readlink-use-xmalloc_realpath.patch -Patch13: mark-Linux-specific-configuration-options.patch -Patch14: init-loginutils-termios-portability-fixes.patch -Patch15: init-halt-portability-improvements.patch -Patch16: init-make-the-initial-TERM-value-configurable.patch -Patch17: libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch -Patch18: mkdir-fix-p-on-FreeBSD.patch -Patch19: libbb-conditionalize-AF_-usage-in-error-reporting.patch -Patch20: tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch -Patch21: less-remove-misguided-dependency-on-PLATFORM_LINUX.patch -Patch22: bootchartd-mounting-tmpfs-is-Linux-specific.patch -Patch23: vlock-disable-linux-console-calls-on-other-systems.patch -Patch24: cttyhack-serial-console-detection-is-Linux-specific.patch -Patch25: klogd-make-it-work-on-non-linux-systems.patch -Patch26: stty-sort-out-preprocessor-conditionals.patch -Patch27: update-scripts-kconfig-_shipped.patch -Patch28: blockdev.patch - -# The following patches will likely be merged soon -Patch29: u-mount-FreeBSD-support.patch -Patch30: swaponoff-FreeBSD-support.patch - -# not sent upstream -Patch31: init-console-CRTSCTS.patch -Patch32: debian-changes-1.17.1-10 - -# SLP -Patch33: udhcpc-fast-request.patch -Patch34: smack-busybox-1.17.1.patch -Patch35: smack-conflict-with-selinux.patch -Patch36: make_unicode_printable.patch - -# The following patches have been merged upstream and will be in version 1.20 -Patch37: busybox-1.20.2-fix-resource-h-failure.patch - -Patch100: busybox-1.17.1-make.patch -Patch101: sysinfo-multiple-define-error-fix.patch - -Patch999: syslogd-disable-systemd-sa.patch - -URL: http://www.busybox.net - -BuildRequires: pkgconfig(libsystemd-daemon) +Name: busybox +Version: 1.22.1 +Release: 0 +License: GPL-2.0+ +Summary: The Swiss Army Knife of Embedded Linux +Url: http://www.busybox.net/ +Group: System/Utilities +Source: http://busybox.net/downloads/%{name}-%{version}.tar.bz2 +Source2: busybox.tizen.config +Source1001: busybox.manifest %description -Busybox is a single binary which includes versions of a large number -of system commands, including a shell. This package can be very -useful for recovering from certain types of system failures, -particularly those involving broken shared libraries. - -%package docs -Group: Documentation -Summary: Busybox Documentation - -%description docs -Busybox documentation and user guides - -%package symlinks-busybox -Group: tools -Summary: BusyBox specific symlinks -Requires: %{name} = %{version}-%{release} - -%description symlinks-busybox - BusyBox symlinks for utilities without counterparts in Debian. - These are in separate package because they aren't essentials - (e.g. needed for system package upgrades). - -%package symlinks-adduser -Group: tools -Summary: BusyBox symlinks to provide 'adduser' -Requires: %{name} = %{version}-%{release} - -%description symlinks-adduser -BusyBox symlinks for utilities corresponding to 'adduser' package. - -%package symlinks-adjtimex -Group: tools -Summary: BusyBox symlinks to provide 'adjtimex' -Requires: %{name} = %{version}-%{release} - -%description symlinks-adjtimex -BusyBox symlinks for utilities corresponding to 'adjtimex' package. - -%package symlinks-binutils -Group: tools -Summary: BusyBox symlinks to provide 'binutils' -Requires: %{name} = %{version}-%{release} - -%description symlinks-binutils -BusyBox symlinks for utilities corresponding to 'binutils' package. - -%package symlinks-bridge-utils -Group: tools -Summary: BusyBox symlinks to provide 'bridge-utils' - -%description symlinks-bridge-utils -BusyBox symlinks for utilities corresponding to 'bridge-utils' package. - -%package symlinks-bsdmainutils -Group: tools -Summary: BusyBox symlinks to provide 'bsdmainutils' -Requires: %{name} = %{version}-%{release} - -%description symlinks-bsdmainutils -BusyBox symlinks for utilities corresponding to 'bsdmainutils' package. - -%package symlinks-bzip2 -Group: tools -Summary: BusyBox symlinks to provide 'bzip2' -Requires: %{name} = %{version}-%{release} - -%description symlinks-bzip2 -BusyBox symlinks for utilities corresponding to 'bzip2' package. - -%package symlinks-console-tools -Group: tools -Summary: BusyBox symlinks to provide 'console-tools' -Requires: %{name} = %{version}-%{release} - -%description symlinks-console-tools -BusyBox symlinks for utilities corresponding to 'console-tools' package. - -%package symlinks-cpio -Group: tools -Summary: BusyBox symlinks to provide 'cpio' -Requires: %{name} = %{version}-%{release} - -%description symlinks-cpio -BusyBox symlinks for utilities corresponding to 'cpio' package. - -%package symlinks-cron -Group: tools -Summary: BusyBox symlinks to provide 'cron' -Requires: %{name} = %{version}-%{release} - -%description symlinks-cron -BusyBox symlinks for utilities corresponding to 'cron' package. - -%package symlinks-daemontools -Group: tools -Summary: BusyBox symlinks to provide 'daemontools' -Requires: %{name} = %{version}-%{release} - -%description symlinks-daemontools -BusyBox symlinks for utilities corresponding to 'daemontools' package. - -%package symlinks-dc -Group: tools -Summary: BusyBox symlinks to provide 'dc' -Requires: %{name} = %{version}-%{release} - -%description symlinks-dc -BusyBox symlinks for utilities corresponding to 'dc' package. - -%package symlinks-dnsutils -Group: tools -Summary: BusyBox symlinks to provide 'dnsutils' -Requires: %{name} = %{version}-%{release} - -%description symlinks-dnsutils -BusyBox symlinks for utilities corresponding to 'dnsutils' package. - -%package symlinks-dosfstools -Group: tools -Summary: BusyBox symlinks to provide 'dosfstools' -Requires: %{name} = %{version}-%{release} - -%description symlinks-dosfstools -BusyBox symlinks for utilities corresponding to 'dosfstools' package. - -%package symlinks-ed -Group: tools -Summary: BusyBox symlinks to provide 'ed' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ed -BusyBox symlinks for utilities corresponding to 'ed' package. - -%package symlinks-eject -Group: tools -Summary: BusyBox symlinks to provide 'eject' -Requires: %{name} = %{version}-%{release} - -%description symlinks-eject -BusyBox symlinks for utilities corresponding to 'eject' package. - -%package symlinks-fbset -Group: tools -Summary: BusyBox symlinks to provide 'fbset' -Requires: %{name} = %{version}-%{release} - -%description symlinks-fbset -BusyBox symlinks for utilities corresponding to 'fbset' package. - -%package symlinks-fdflush -Group: tools -Summary: BusyBox symlinks to provide 'fdflush' -Requires: %{name} = %{version}-%{release} - -%description symlinks-fdflush -BusyBox symlinks for utilities corresponding to 'fdflush' package. - -%package symlinks-hdparm -Group: tools -Summary: BusyBox symlinks to provide 'hdparm' -Requires: %{name} = %{version}-%{release} - -%description symlinks-hdparm -BusyBox symlinks for utilities corresponding to 'hdparm' package. - -%package symlinks-ifupdown -Group: tools -Summary: BusyBox symlinks to provide 'ifupdown' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ifupdown -BusyBox symlinks for utilities corresponding to 'ifupdown' package. - -%package symlinks-initscripts -Group: tools -Summary: BusyBox symlinks to provide 'initscripts' -Requires: %{name} = %{version}-%{release} - -%description symlinks-initscripts -BusyBox symlinks for utilities corresponding to 'initscripts' package. - -%package symlinks-ipcalc -Group: tools -Summary: BusyBox symlinks to provide 'ipcalc' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ipcalc -BusyBox symlinks for utilities corresponding to 'ipcalc' package. - -%package symlinks-iproute -Group: tools -Summary: BusyBox symlinks to provide 'iproute' -Requires: %{name} = %{version}-%{release} - -%description symlinks-iproute -BusyBox symlinks for utilities corresponding to 'iproute' package. - -%package symlinks-ipsvd -Group: tools -Summary: BusyBox symlinks to provide 'ipsvd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ipsvd -BusyBox symlinks for utilities corresponding to 'ipsvd' package. - -%package symlinks-iputils-arping -Group: tools -Summary: BusyBox symlinks to provide 'iputils-arping' -Requires: %{name} = %{version}-%{release} - -%description symlinks-iputils-arping -BusyBox symlinks for utilities corresponding to 'iputils-arping' package. - -%package symlinks-iputils-ping -Group: tools -Summary: BusyBox symlinks to provide 'iputils-ping' -Requires: %{name} = %{version}-%{release} - -%description symlinks-iputils-ping -BusyBox symlinks for utilities corresponding to 'iputils-ping' package. - -%package symlinks-klogd -Group: tools -Summary: BusyBox symlinks to provide 'klogd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-klogd -BusyBox symlinks for utilities corresponding to 'klogd' package. - -%package symlinks-loadlin -Group: tools -Summary: BusyBox symlinks to provide 'loadlin' -Requires: %{name} = %{version}-%{release} - -%description symlinks-loadlin -BusyBox symlinks for utilities corresponding to 'loadlin' package. - -%package symlinks-lrzsz -Group: tools -Summary: BusyBox symlinks to provide 'lrzsz' -Requires: %{name} = %{version}-%{release} - -%description symlinks-lrzsz -BusyBox symlinks for utilities corresponding to 'lrzsz' package. - -%package symlinks-lzma -Group: tools -Summary: BusyBox symlinks to provide 'lzma' -Requires: %{name} = %{version}-%{release} - -%description symlinks-lzma -BusyBox symlinks for utilities corresponding to 'lzma' package. - -%package symlinks-lzop -Group: tools -Summary: BusyBox symlinks to provide 'lzop' -Requires: %{name} = %{version}-%{release} - -%description symlinks-lzop -BusyBox symlinks for utilities corresponding to 'lzop' package. - -%package symlinks-module-init-tools -Group: tools -Summary: BusyBox symlinks to provide 'module-init-tools' -Requires: %{name} = %{version}-%{release} - -%description symlinks-module-init-tools -BusyBox symlinks for utilities corresponding to 'module-init-tools' package. - -%package symlinks-mtd-utils -Group: tools -Summary: BusyBox symlinks to provide 'mtd-utils' -Requires: %{name} = %{version}-%{release} - -%description symlinks-mtd-utils -BusyBox symlinks for utilities corresponding to 'mtd-utils' package. - -%package symlinks-net-tools -Group: tools -Summary: BusyBox symlinks to provide 'net-tools' -Requires: %{name} = %{version}-%{release} - -%description symlinks-net-tools -BusyBox symlinks for utilities corresponding to 'net-tools' package. - -%package symlinks-openbsd-inetd -Group: tools -Summary: BusyBox symlinks to provide 'openbsd-inetd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-openbsd-inetd -BusyBox symlinks for utilities corresponding to 'openbsd-inetd' package. - -%package symlinks-passwd -Group: tools -Summary: BusyBox symlinks to provide 'passwd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-passwd -BusyBox symlinks for utilities corresponding to 'passwd' package. - -%package symlinks-patch -Group: tools -Summary: BusyBox symlinks to provide 'patch' -Requires: %{name} = %{version}-%{release} - -%description symlinks-patch -BusyBox symlinks for utilities corresponding to 'patch' package. - -%package symlinks-ppp -Group: tools -Summary: BusyBox symlinks to provide 'ppp' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ppp -BusyBox symlinks for utilities corresponding to 'ppp' package. - -%package symlinks-procps -Group: tools -Summary: BusyBox symlinks to provide 'procps' -Requires: %{name} = %{version}-%{release} - -%description symlinks-procps -BusyBox symlinks for utilities corresponding to 'procps' package. - -%package symlinks-psmisc -Group: tools -Summary: BusyBox symlinks to provide 'psmisc' -Requires: %{name} = %{version}-%{release} - -%description symlinks-psmisc -BusyBox symlinks for utilities corresponding to 'psmisc' package. - -%package symlinks-rdate -Group: tools -Summary: BusyBox symlinks to provide 'rdate' -Requires: %{name} = %{version}-%{release} - -%description symlinks-rdate -BusyBox symlinks for utilities corresponding to 'rdate' package. - -%package symlinks-realpath -Group: tools -Summary: BusyBox symlinks to provide 'realpath' -Requires: %{name} = %{version}-%{release} - -%description symlinks-realpath -BusyBox symlinks for utilities corresponding to 'realpath' package. - -%package symlinks-runit -Group: tools -Summary: BusyBox symlinks to provide 'runit' -Requires: %{name} = %{version}-%{release} - -%description symlinks-runit -BusyBox symlinks for utilities corresponding to 'runit' package. - -%package symlinks-sharutils -Group: tools -Summary: BusyBox symlinks to provide 'sharutils' -Requires: %{name} = %{version}-%{release} - -%description symlinks-sharutils -BusyBox symlinks for utilities corresponding to 'sharutils' package. - -%package symlinks-ssmtp -Group: tools -Summary: BusyBox symlinks to provide 'ssmtp' -Requires: %{name} = %{version}-%{release} - -%description symlinks-ssmtp -BusyBox symlinks for utilities corresponding to 'ssmtp' package. - -%package symlinks-sysklogd -Group: tools -Summary: BusyBox symlinks to provide 'sysklogd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-sysklogd -BusyBox symlinks for utilities corresponding to 'sysklogd' package. - -%package symlinks-telnetd -Group: tools -Summary: BusyBox symlinks to provide 'telnetd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-telnetd -BusyBox symlinks for utilities corresponding to 'telnetd' package. - -%package symlinks-tftp -Group: tools -Summary: BusyBox symlinks to provide 'tftp' -Requires: %{name} = %{version}-%{release} - -%description symlinks-tftp -BusyBox symlinks for utilities corresponding to 'tftp' package. - -%package symlinks-time -Group: tools -Summary: BusyBox symlinks to provide 'time' -Requires: %{name} = %{version}-%{release} - -%description symlinks-time -BusyBox symlinks for utilities corresponding to 'time' package. - -%package symlinks-tofrodos -Group: tools -Summary: BusyBox symlinks to provide 'tofrodos' -Requires: %{name} = %{version}-%{release} - -%description symlinks-tofrodos -BusyBox symlinks for utilities corresponding to 'tofrodos' package. - -%package symlinks-udhcpc -Group: tools -Summary: BusyBox symlinks to provide 'udhcpc' -Requires: %{name} = %{version}-%{release} - -%description symlinks-udhcpc -BusyBox symlinks for utilities corresponding to 'udhcpc' package. - -%package symlinks-udhcpd -Group: tools -Summary: BusyBox symlinks to provide 'udhcpd' -Requires: %{name} = %{version}-%{release} - -%description symlinks-udhcpd -BusyBox symlinks for utilities corresponding to 'udhcpd' package. - -%package symlinks-unzip -Group: tools -Summary: BusyBox symlinks to provide 'unzip' -Requires: %{name} = %{version}-%{release} - -%description symlinks-unzip -BusyBox symlinks for utilities corresponding to 'unzip' package. - -%package symlinks-vlan -Group: tools -Summary: BusyBox symlinks to provide 'vlan' -Requires: %{name} = %{version}-%{release} - -%description symlinks-vlan -BusyBox symlinks for utilities corresponding to 'vlan' package. - -%package symlinks-vlock -Group: tools -Summary: BusyBox symlinks to provide 'vlock' -Requires: %{name} = %{version}-%{release} - -%description symlinks-vlock -BusyBox symlinks for utilities corresponding to 'vlock' package. - -%package symlinks-watchdog -Group: tools -Summary: BusyBox symlinks to provide 'watchdog' -Requires: %{name} = %{version}-%{release} - -%description symlinks-watchdog -BusyBox symlinks for utilities corresponding to 'watchdog' package. - -%package symlinks-wget -Group: tools -Summary: BusyBox symlinks to provide 'wget' -Requires: %{name} = %{version}-%{release} - -%description symlinks-wget -BusyBox symlinks for utilities corresponding to 'wget' package. - -%package symlinks-xterm -Group: tools -Summary: BusyBox symlinks to provide 'xterm' -Requires: %{name} = %{version}-%{release} - -%description symlinks-xterm -BusyBox symlinks for utilities corresponding to 'xterm' package. - -%package symlinks-zcip -Group: tools -Summary: BusyBox symlinks to provide 'zcip' -Requires: %{name} = %{version}-%{release} - -%description symlinks-zcip -BusyBox symlinks for utilities corresponding to 'zcip' package. - +BusyBox combines tiny versions of many common UNIX utilities into a +small single executable. It provides minimalist replacements for most +of the utilities usually found in fileutils, shellutils, findutils, +textutils, grep, gzip, tar, and more. BusyBox provides a fairly +complete POSIX environment for any small or embedded system. The +utilities in BusyBox generally have fewer options than their +full-featured GNU cousins. The options that are included provide the +expected functionality and behave very much like their GNU +counterparts. %prep %setup -q -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -#%patch6 -p1 -#%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch27 -p1 -%patch28 -p1 -%patch29 -p1 -%patch30 -p1 -%patch31 -p1 -%patch32 -p1 -%patch33 -p1 -%patch36 -p1 -%patch37 -p1 - -%patch100 -p1 -%patch101 -p1 - -%patch999 -p1 +cp %{SOURCE1001} . +cp -a %{SOURCE2} .config %build -cp %{SOURCE1001} . -cp %{SOURCE1002} . -# create dynamic busybox - the executable is busybox -cp %{SOURCE101} .config -make oldconfig -make CC="gcc $RPM_OPT_FLAGS" -cp busybox busybox-dynamic +export VERBOSE=-v +export BUILD_VERBOSE=2 +export CFLAGS="%{optflags} -fno-strict-aliasing" +export CC="gcc" +export HOSTCC=gcc +%__make -e oldconfig +%__make -e %{?_smp_mflags} +%__make -e doc busybox.links %{?_smp_mflags} %install -rm -rf $RPM_BUILD_ROOT -mkdir -p $RPM_BUILD_ROOT/bin -install -m 755 busybox-dynamic $RPM_BUILD_ROOT/bin/busybox - -# debian/busybox.links -pushd %{buildroot} -mkdir -p usr/bin usr/sbin sbin -cd bin -for f in `cat %SOURCE2` ; do ln -s busybox $f ; done -cd ../sbin -for f in `cat %SOURCE3` ; do ln -s ../bin/busybox $f ; done -cd ../usr/bin -for f in `cat %SOURCE4` ; do ln -s ../../bin/busybox $f ; done -cd ../../usr/sbin -for f in `cat %SOURCE5` ; do ln -s ../../bin/busybox $f ; done -popd - -# install systemd service files for syslogd and klogd -mkdir -p %{buildroot}%{_libdir}/systemd/system -mkdir -p %{buildroot}%{_libdir}/systemd/system/basic.target.wants -install -m 644 %SOURCE201 %{buildroot}%{_libdir}/systemd/system/klogd.service -ln -s ../klogd.service %{buildroot}%{_libdir}/systemd/system/basic.target.wants/klogd.service -install -m 644 %SOURCE202 %{buildroot}%{_libdir}/systemd/system/syslogd.service -ln -s ../syslogd.service %{buildroot}%{_libdir}/systemd/system/basic.target.wants/syslogd.service - -rm -rf $RPM_BUILD_ROOT/sbin/syslogd -cp -f $RPM_BUILD_ROOT/bin/busybox $RPM_BUILD_ROOT/sbin/syslogd - -mkdir -p $RPM_BUILD_ROOT%{_datadir}/license -for keyword in LICENSE COPYING COPYRIGHT; -do - for file in `find %{_builddir} -name $keyword`; - do - cat $file >> $RPM_BUILD_ROOT%{_datadir}/license/%{name}; - echo ""; - done; -done +install -d %{buildroot}%{_prefix}/bin +install -d %{buildroot}%{_datadir}/busybox +install busybox.links %{buildroot}%{_datadir}/busybox +install applets/install.sh %{buildroot}%{_bindir}/busybox.install +install busybox %{buildroot}%{_prefix}/bin %files -%defattr(-,root,root,-) -%manifest %{name}.manifest -%doc LICENSE -%{_datadir}/license/%{name} -%exclude /bin/mktemp -/bin/busybox -%exclude /bin/ash -%exclude /bin/cat -%exclude /bin/chgrp -%exclude /bin/chmod -%exclude /bin/chown -%exclude /bin/cp -%exclude /bin/date -%exclude /bin/dd -%exclude /bin/df -%exclude /bin/dmesg -%exclude /bin/dnsdomainname -%exclude /bin/echo -%exclude /bin/egrep -%exclude /bin/false -%exclude /bin/fgrep -%exclude /bin/grep -%exclude /bin/gunzip -%exclude /bin/gzip -%exclude /bin/hostname -%exclude /bin/ln -%exclude /bin/ls -%exclude /bin/mkdir -%exclude /bin/mknod -%exclude /bin/more -%exclude /bin/mount -%exclude /bin/mv -%exclude /bin/pwd -%exclude /bin/readlink -%exclude /bin/rm -%exclude /bin/rmdir -%exclude /bin/sed -#/bin/sh -%exclude /bin/sleep -%exclude /bin/stty -%exclude /bin/sync -%exclude /bin/tar -%exclude /bin/touch -%exclude /bin/true -%exclude /bin/umount -%exclude /bin/uname -%exclude /bin/uncompress -%exclude /bin/zcat -%exclude /sbin/blkid -%exclude /sbin/blockdev -%exclude /sbin/fdisk -%exclude /sbin/fsck.minix -%exclude /sbin/getty -%exclude /sbin/hwclock -%exclude /sbin/losetup -%exclude /sbin/mkfs.minix -%exclude /sbin/mkswap -%exclude /sbin/pivot_root -%exclude /sbin/swapoff -%exclude /sbin/swapon -%exclude /sbin/switch_root -%exclude /usr/bin/[ -%exclude /usr/bin/basename -%exclude /usr/bin/chrt -%exclude /usr/bin/cksum -%exclude /usr/bin/cmp -%exclude /usr/bin/comm -%exclude /usr/bin/cut -%exclude /usr/bin/diff -%exclude /usr/bin/dirname -%exclude /usr/bin/du -%exclude /usr/bin/env -%exclude /usr/bin/expand -%exclude /usr/bin/expr -%exclude /usr/bin/fdformat -%exclude /usr/bin/find -%exclude /usr/bin/flock -%exclude /usr/bin/fold -%exclude /usr/bin/getopt -%exclude /usr/bin/head -%exclude /usr/bin/hostid -%exclude /usr/bin/id -%exclude /usr/bin/install -%exclude /usr/bin/ionice -%exclude /usr/bin/ipcrm -%exclude /usr/bin/ipcs -%exclude /usr/bin/less -%exclude /usr/bin/linux32 -%exclude /usr/bin/linux64 -%exclude /usr/bin/logger -%exclude /usr/bin/logname -%exclude /usr/bin/md5sum -%exclude /usr/bin/mkfifo -%exclude /usr/bin/nice -%exclude /usr/bin/nohup -%exclude /usr/bin/od -%exclude /usr/bin/printenv -%exclude /usr/bin/printf -%exclude /usr/bin/renice -%exclude /usr/bin/rev -%exclude /usr/bin/rtcwake -%exclude /usr/bin/script -%exclude /usr/bin/scriptreplay -%exclude /usr/bin/seq -%exclude /usr/bin/setarch -%exclude /usr/bin/setsid -%exclude /usr/bin/sha1sum -%exclude /usr/bin/sha256sum -%exclude /usr/bin/sha512sum -%exclude /usr/bin/sort -%exclude /usr/bin/split -%exclude /usr/bin/stat -%exclude /usr/bin/sum -%exclude /usr/bin/tac -%exclude /usr/bin/tail -%exclude /usr/bin/taskset -%exclude /usr/bin/tee -%exclude /usr/bin/test -%exclude /usr/bin/timeout -%exclude /usr/bin/tr -%exclude /usr/bin/tty -%exclude /usr/bin/unexpand -%exclude /usr/bin/uniq -%exclude /usr/bin/wall -%exclude /usr/bin/wc -%exclude /usr/bin/who -%exclude /usr/bin/whoami -/usr/bin/vi -%exclude /usr/bin/xargs -%exclude /usr/bin/yes -%exclude /usr/sbin/chroot -%exclude /usr/sbin/rdev -%exclude /usr/sbin/readprofile - -%files docs -%doc LICENSE docs/busybox.net/*.html - -%files symlinks-adduser -%exclude /usr/sbin/addgroup -%exclude /usr/sbin/adduser -%exclude /usr/sbin/delgroup -%exclude /usr/sbin/deluser - -%files symlinks-adjtimex -%exclude /usr/bin/adjtimex - -%files symlinks-binutils -%exclude /usr/bin/ar -%exclude /usr/bin/strings - -%files symlinks-bridge-utils -%exclude /usr/bin/brctl - -%files symlinks-bsdmainutils -%exclude /usr/bin/cal -%exclude /usr/bin/hd -%exclude /usr/bin/hexdump - -%files symlinks-busybox -%manifest %{name}.manifest -%exclude /usr/bin/[[ -%exclude /usr/bin/catv -%exclude /usr/sbin/crond -%exclude /usr/sbin/dhcprelay -%exclude /usr/sbin/dnsd -%exclude /bin/dumpkmap -%exclude /usr/bin/ether-wake -%exclude /usr/sbin/fakeidentd -%exclude /sbin/fbsplash -%exclude /bin/fsync -%exclude /usr/bin/ftpget -%exclude /usr/bin/ftpput -%exclude /usr/sbin/httpd -%exclude /sbin/ifenslave -%exclude /sbin/inotifyd -%exclude /bin/ipaddr -%exclude /bin/iplink -%exclude /bin/iproute -%exclude /bin/iprule -%exclude /usr/bin/length -%exclude /usr/bin/loadfont -%exclude /sbin/loadkmap -%exclude /sbin/logread -%exclude /sbin/makedevs -%exclude /sbin/mdev -%exclude /usr/bin/microcom -%exclude /usr/bin/nmeter -%exclude /usr/bin/pscan -%exclude /sbin/raidautorun -%exclude /usr/bin/readahead -%exclude /sbin/setconsole -%exclude /usr/sbin/tftpd -%exclude /usr/bin/ttysize -%exclude /bin/usleep -%exclude /usr/bin/volname - -%files symlinks-bzip2 -%exclude /bin/bunzip2 -%exclude /bin/bzcat -%exclude /bin/bzip2 - -%files symlinks-console-tools -%exclude /usr/bin/chvt -%exclude /usr/bin/deallocvt -%exclude /bin/fgconsole -%exclude /usr/bin/kbd_mode -%exclude /usr/bin/openvt -%exclude /usr/bin/setkeycodes -%exclude /usr/bin/setlogcons -%exclude /usr/bin/showkey - -%files symlinks-cpio -%exclude /bin/cpio - -%files symlinks-cron -%exclude /usr/bin/crontab - -%files symlinks-daemontools -%exclude /usr/bin/envdir -%exclude /usr/bin/envuidgid -%exclude /usr/bin/setuidgid -%exclude /usr/bin/softlimit - -%files symlinks-dc -%exclude /usr/bin/dc - -%files symlinks-dnsutils -%manifest %{name}.manifest -%exclude /usr/bin/nslookup - -%files symlinks-dosfstools -%exclude /sbin/mkdosfs -%exclude /sbin/mkfs.vfat - -%files symlinks-ed -%exclude /bin/ed - -%files symlinks-eject -%exclude /usr/bin/eject - -%files symlinks-fbset -%exclude /bin/fbset - -%files symlinks-fdflush -%exclude /bin/fdflush - -%files symlinks-hdparm -%exclude /sbin/hdparm - -%files symlinks-ifupdown -%manifest %{name}.manifest -%exclude /sbin/ifdown -%exclude /sbin/ifup - -%files symlinks-initscripts -%exclude /bin/mountpoint - -%files symlinks-ipcalc -%exclude /usr/bin/ipcalc - -%files symlinks-iproute -%exclude /bin/ip -%exclude /sbin/ip - -%files symlinks-ipsvd -%exclude /usr/bin/tcpsvd -%exclude /usr/bin/udpsvd - -%files symlinks-iputils-arping -%exclude /usr/bin/arping - -%files symlinks-iputils-ping %manifest %{name}.manifest -%exclude /bin/ping -%exclude /bin/ping6 - -%files symlinks-klogd -%manifest %{name}.manifest -%exclude /sbin/klogd -%exclude %{_libdir}/systemd/system/klogd.service -%exclude %{_libdir}/systemd/system/basic.target.wants/klogd.service - -%files symlinks-loadlin -%exclude /usr/bin/freeramdisk - -%files symlinks-lrzsz -%exclude /usr/bin/rx - -%files symlinks-lzma -%exclude /usr/bin/lzcat -%exclude /usr/bin/lzma -%exclude /usr/bin/unlzma - -%files symlinks-lzop -%exclude /usr/bin/lzop -%exclude /usr/bin/lzopcat -%exclude /usr/bin/unlzop - -%files symlinks-module-init-tools -%exclude /sbin/depmod -%exclude /sbin/insmod -%exclude /sbin/lsmod -%exclude /sbin/modinfo -%exclude /sbin/modprobe -%exclude /sbin/rmmod - -%files symlinks-mtd-utils -%exclude /usr/sbin/flash_eraseall -%exclude /usr/sbin/flash_lock -%exclude /usr/sbin/flash_unlock -%exclude /usr/sbin/flashcp -%exclude /usr/sbin/ubiattach -%exclude /usr/sbin/ubidetach - -%files symlinks-net-tools -%exclude /usr/sbin/arp -%exclude /sbin/ifconfig -%exclude /sbin/iptunnel -%exclude /sbin/nameif -%exclude /bin/netstat -%exclude /sbin/route -%exclude /sbin/slattach - -%files symlinks-openbsd-inetd -%exclude /usr/sbin/inetd - -%files symlinks-passwd -%exclude /usr/sbin/chpasswd -%exclude /usr/bin/passwd - -%files symlinks-patch -%exclude /usr/bin/patch - -%files symlinks-ppp -%exclude /usr/sbin/chat - -%files symlinks-procps -%exclude /usr/bin/free -%exclude /bin/kill -%exclude /usr/bin/pgrep -%exclude /usr/bin/pkill -%exclude /bin/ps -%exclude /sbin/sysctl -%exclude /usr/bin/top -%exclude /usr/bin/uptime -%exclude /usr/bin/watch - -%files symlinks-psmisc -%exclude /bin/fuser -%exclude /usr/bin/killall - -%files symlinks-rdate -%exclude /usr/sbin/rdate - -%files symlinks-realpath -%exclude /usr/bin/realpath - -#%files symlinks-rpm -#/usr/bin/rpm -#/usr/bin/rpm2cpio - -%files symlinks-runit -%exclude /usr/bin/chpst -%exclude /usr/bin/runsv -%exclude /usr/bin/runsvdir -%exclude /usr/bin/sv -%exclude /usr/bin/svlogd - -%files symlinks-sharutils -%exclude /usr/bin/uudecode -%exclude /usr/bin/uuencode - -%files symlinks-ssmtp -%exclude /usr/sbin/sendmail - -%files symlinks-sysklogd -%exclude /sbin/syslogd -%exclude %{_libdir}/systemd/system/syslogd.service -%exclude %{_libdir}/systemd/system/basic.target.wants/syslogd.service - -%files symlinks-telnetd -%exclude /usr/sbin/telnetd - -%files symlinks-tftp -%exclude /usr/bin/tftp - -%files symlinks-time -%exclude /usr/bin/time - -%files symlinks-tofrodos -%exclude /usr/bin/dos2unix -%exclude /usr/bin/unix2dos - -%files symlinks-udhcpc -%exclude /usr/bin/udhcpc - -%files symlinks-udhcpd -%exclude /usr/bin/dumpleases -%exclude /usr/sbin/udhcpd - -%files symlinks-unzip -%exclude /usr/bin/unzip - -%files symlinks-vlan -%exclude /sbin/vconfig - -%files symlinks-vlock -%exclude /usr/bin/vlock - -%files symlinks-watchdog -%exclude /usr/sbin/watchdog - -%files symlinks-wget -%exclude /usr/bin/wget - -%files symlinks-xterm -%exclude /usr/bin/resize - -%files symlinks-zcip -%exclude /usr/bin/zcip +%defattr(-,root,root) +%license LICENSE +%{_bindir}/busybox +%{_bindir}/busybox.install +%config %{_datadir}/busybox/busybox.links diff --git a/debian/config/pkg/static b/packaging/busybox.tizen.config similarity index 63% rename from debian/config/pkg/static rename to packaging/busybox.tizen.config index 45d0b90..aea41b0 100644 --- a/debian/config/pkg/static +++ b/packaging/busybox.tizen.config @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Tue Nov 9 10:36:06 2010 +# Busybox version: 1.20.2 +# Tue Aug 6 16:59:06 2013 # CONFIG_HAVE_DOT_CONFIG=y @@ -13,24 +13,26 @@ CONFIG_HAVE_DOT_CONFIG=y # General Configuration # CONFIG_DESKTOP=y -CONFIG_EXTRA_COMPAT=y +# CONFIG_EXTRA_COMPAT is not set CONFIG_INCLUDE_SUSv2=y # CONFIG_USE_PORTABLE_CODE is not set +CONFIG_PLATFORM_LINUX=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_FEATURE_INSTALLER is not set +# 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=y +# CONFIG_FEATURE_CHECK_UNICODE_IN_ENV is not set CONFIG_SUBST_WCHAR=63 CONFIG_LAST_SUPPORTED_WCHAR=767 -CONFIG_UNICODE_COMBINING_WCHARS=y -CONFIG_UNICODE_WIDE_WCHARS=y +# 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 @@ -41,18 +43,18 @@ 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_FEATURE_SUID_CONFIG is not set +# CONFIG_FEATURE_SUID_CONFIG_QUIET is not set # CONFIG_SELINUX is not set -CONFIG_FEATURE_PREFER_APPLETS=y -CONFIG_BUSYBOX_EXEC_PATH="/bin/busybox" +# CONFIG_FEATURE_PREFER_APPLETS is not set +CONFIG_BUSYBOX_EXEC_PATH="/proc/self/exe" CONFIG_FEATURE_SYSLOG=y -# CONFIG_FEATURE_HAVE_RPC is not set +CONFIG_FEATURE_HAVE_RPC=y # # Build Options # -CONFIG_STATIC=y +# CONFIG_STATIC is not set # CONFIG_PIE is not set # CONFIG_NOMMU is not set # CONFIG_BUILD_LIBBUSYBOX is not set @@ -60,7 +62,10 @@ CONFIG_STATIC=y # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_SYSROOT="" CONFIG_EXTRA_CFLAGS="" +CONFIG_EXTRA_LDFLAGS="" +CONFIG_EXTRA_LDLIBS="" # # Debugging Options @@ -73,37 +78,42 @@ CONFIG_NO_DEBUG_LIB=y # CONFIG_EFENCE is not set # -# Installation Options +# Installation Options ("make install" behavior) # -# CONFIG_INSTALL_NO_USR is not set -# CONFIG_INSTALL_APPLET_SYMLINKS 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=y +# 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" +CONFIG_PREFIX="/usr" # # Busybox Library Tuning # +CONFIG_FEATURE_SYSTEMD=y +CONFIG_FEATURE_RTMINMAX=y CONFIG_PASSWORD_MINLEN=6 -CONFIG_MD5_SIZE_VS_SPEED=1 -# CONFIG_FEATURE_FAST_TOP is not set +CONFIG_MD5_SMALL=1 +CONFIG_FEATURE_FAST_TOP=y # CONFIG_FEATURE_ETC_NETWORKS is not set +CONFIG_FEATURE_USE_TERMIOS=y 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 is not set +CONFIG_FEATURE_EDITING_HISTORY=666 +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=y -CONFIG_FEATURE_EDITING_FANCY_PROMPT=y -CONFIG_FEATURE_EDITING_ASK_TERMINAL=y -# CONFIG_FEATURE_NON_POSIX_CP is not set -CONFIG_FEATURE_VERBOSE_CP_MESSAGE=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_FEATURE_SKIP_ROOTFS=y CONFIG_MONOTONIC_SYSCALL=y CONFIG_IOCTL_HEX2STR_ERROR=y CONFIG_FEATURE_HWIB=y @@ -115,47 +125,48 @@ CONFIG_FEATURE_HWIB=y # # Archival Utilities # -# CONFIG_FEATURE_SEAMLESS_XZ is not set -CONFIG_FEATURE_SEAMLESS_LZMA=y -CONFIG_FEATURE_SEAMLESS_BZ2=y -CONFIG_FEATURE_SEAMLESS_GZ=y -CONFIG_FEATURE_SEAMLESS_Z=y +CONFIG_FEATURE_SEAMLESS_XZ=y +# CONFIG_FEATURE_SEAMLESS_LZMA is not set +# CONFIG_FEATURE_SEAMLESS_BZ2 is not set +# CONFIG_FEATURE_SEAMLESS_GZ is not set +# CONFIG_FEATURE_SEAMLESS_Z is not set CONFIG_AR=y CONFIG_FEATURE_AR_LONG_FILENAMES=y -# CONFIG_FEATURE_AR_CREATE is not set +CONFIG_FEATURE_AR_CREATE=y CONFIG_BUNZIP2=y CONFIG_BZIP2=y CONFIG_CPIO=y -CONFIG_FEATURE_CPIO_O=y +# CONFIG_FEATURE_CPIO_O is not set # CONFIG_FEATURE_CPIO_P is not set -CONFIG_DPKG=y -CONFIG_DPKG_DEB=y +# CONFIG_DPKG is not set +# CONFIG_DPKG_DEB is not set # CONFIG_FEATURE_DPKG_DEB_EXTRACT_ONLY is not set CONFIG_GUNZIP=y CONFIG_GZIP=y CONFIG_FEATURE_GZIP_LONG_OPTIONS=y -# CONFIG_LZOP is not set +CONFIG_GZIP_FAST=0 +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 is not set -# CONFIG_FEATURE_TAR_FROM is not set +CONFIG_FEATURE_TAR_FROM=y # CONFIG_FEATURE_TAR_OLDGNU_COMPATIBILITY is not set # CONFIG_FEATURE_TAR_OLDSUN_COMPATIBILITY is not set CONFIG_FEATURE_TAR_GNU_EXTENSIONS=y CONFIG_FEATURE_TAR_LONG_OPTIONS=y -# CONFIG_FEATURE_TAR_TO_COMMAND is not set -CONFIG_FEATURE_TAR_UNAME_GNAME=y -# CONFIG_FEATURE_TAR_NOPRESERVE_TIME is not set +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 is not set -# CONFIG_LZMA is not set -# CONFIG_UNXZ is not set -# CONFIG_XZ is not set +CONFIG_LZMA=y +CONFIG_UNXZ=y +CONFIG_XZ=y CONFIG_UNZIP=y # @@ -167,27 +178,35 @@ CONFIG_DATE=y CONFIG_FEATURE_DATE_ISOFMT=y # CONFIG_FEATURE_DATE_NANO is not set CONFIG_FEATURE_DATE_COMPAT=y +CONFIG_HOSTID=y +CONFIG_ID=y +CONFIG_GROUPS=y CONFIG_TEST=y CONFIG_FEATURE_TEST_64=y +CONFIG_TOUCH=y +CONFIG_FEATURE_TOUCH_SUSV3=y CONFIG_TR=y -# CONFIG_FEATURE_TR_CLASSES is not set -# CONFIG_FEATURE_TR_EQUIV is not set +CONFIG_FEATURE_TR_CLASSES=y +CONFIG_FEATURE_TR_EQUIV=y +CONFIG_BASE64=y +CONFIG_WHO=y +CONFIG_USERS=y CONFIG_CAL=y -# CONFIG_CATV is not set +CONFIG_CATV=y CONFIG_CHGRP=y CONFIG_CHMOD=y CONFIG_CHOWN=y CONFIG_FEATURE_CHOWN_LONG_OPTIONS=y CONFIG_CHROOT=y -# CONFIG_CKSUM is not set -# CONFIG_COMM is not set +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 is not set -# CONFIG_FEATURE_DD_IBS_OBS is not set +CONFIG_FEATURE_DD_THIRD_STATUS_LINE=y +CONFIG_FEATURE_DD_IBS_OBS=y CONFIG_DF=y CONFIG_FEATURE_DF_FANCY=y CONFIG_DIRNAME=y @@ -199,20 +218,17 @@ 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_EXPAND is not set +# 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 is not set +CONFIG_FSYNC=y CONFIG_HEAD=y CONFIG_FEATURE_FANCY_HEAD=y -CONFIG_HOSTID=y -CONFIG_ID=y -# CONFIG_INSTALL is not set -# CONFIG_FEATURE_INSTALL_LONG_OPTIONS is not set -CONFIG_LENGTH=y +CONFIG_INSTALL=y +CONFIG_FEATURE_INSTALL_LONG_OPTIONS=y CONFIG_LN=y CONFIG_LOGNAME=y CONFIG_LS=y @@ -222,7 +238,7 @@ 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 not set # CONFIG_FEATURE_LS_COLOR_IS_DEFAULT is not set CONFIG_MD5SUM=y CONFIG_MKDIR=y @@ -231,59 +247,57 @@ CONFIG_MKFIFO=y CONFIG_MKNOD=y CONFIG_MV=y CONFIG_FEATURE_MV_LONG_OPTIONS=y -# CONFIG_NICE is not set -# CONFIG_NOHUP is not set +CONFIG_NICE=y +CONFIG_NOHUP=y CONFIG_OD=y -# CONFIG_PRINTENV is not set +CONFIG_PRINTENV=y CONFIG_PRINTF=y CONFIG_PWD=y CONFIG_READLINK=y -CONFIG_FEATURE_READLINK_FOLLOW=y +# CONFIG_FEATURE_READLINK_FOLLOW is not set CONFIG_REALPATH=y CONFIG_RM=y CONFIG_RMDIR=y -CONFIG_FEATURE_RMDIR_LONG_OPTIONS=y -# CONFIG_SEQ is not set +# 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_FANCY_SLEEP is not set # CONFIG_FEATURE_FLOAT_SLEEP is not set CONFIG_SORT=y CONFIG_FEATURE_SORT_BIG=y -# 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_SPLIT=y +CONFIG_FEATURE_SPLIT_FANCY=y +CONFIG_STAT=y +CONFIG_FEATURE_STAT_FORMAT=y CONFIG_STTY=y -# CONFIG_SUM is not set +CONFIG_SUM=y CONFIG_SYNC=y -CONFIG_TAC=y +# CONFIG_TAC is not set CONFIG_TAIL=y -CONFIG_FEATURE_FANCY_TAIL=y +# CONFIG_FEATURE_FANCY_TAIL is not set CONFIG_TEE=y -CONFIG_FEATURE_TEE_USE_BLOCK_IO=y -CONFIG_TOUCH=y +# CONFIG_FEATURE_TEE_USE_BLOCK_IO is not set CONFIG_TRUE=y CONFIG_TTY=y CONFIG_UNAME=y -CONFIG_UNEXPAND=y -CONFIG_FEATURE_UNEXPAND_LONG_OPTIONS=y +# CONFIG_UNEXPAND is not set +# 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 is not set -CONFIG_WHO=y +CONFIG_FEATURE_WC_LARGE=y CONFIG_WHOAMI=y CONFIG_YES=y # # Common options for cp and mv # -CONFIG_FEATURE_PRESERVE_HARDLINKS=y +# CONFIG_FEATURE_PRESERVE_HARDLINKS is not set # # Common options for ls, more and telnet @@ -298,13 +312,13 @@ CONFIG_FEATURE_HUMAN_READABLE=y # # Common options for md5sum, sha1sum, sha256sum, sha512sum # -# CONFIG_FEATURE_MD5_SHA1_SUM_CHECK is not set +CONFIG_FEATURE_MD5_SHA1_SUM_CHECK=y # # Console Utilities # CONFIG_CHVT=y -# CONFIG_FGCONSOLE is not set +CONFIG_FGCONSOLE=y CONFIG_CLEAR=y CONFIG_DEALLOCVT=y CONFIG_DUMPKMAP=y @@ -313,22 +327,22 @@ CONFIG_LOADFONT=y CONFIG_LOADKMAP=y CONFIG_OPENVT=y CONFIG_RESET=y -# CONFIG_RESIZE is not set -# CONFIG_FEATURE_RESIZE_PRINT is not set -# CONFIG_SETCONSOLE is not set +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_SETFONT=y +CONFIG_FEATURE_SETFONT_TEXTUAL_MAP=y CONFIG_DEFAULT_SETFONT_DIR="" CONFIG_SETKEYCODES=y -# CONFIG_SETLOGCONS is not set -# CONFIG_SHOWKEY is not set +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 +CONFIG_FEATURE_LOADFONT_PSF2=y +CONFIG_FEATURE_LOADFONT_RAW=y # # Debian Utilities @@ -337,38 +351,39 @@ CONFIG_MKTEMP=y # CONFIG_PIPE_PROGRESS is not set CONFIG_RUN_PARTS=y CONFIG_FEATURE_RUN_PARTS_LONG_OPTIONS=y -# CONFIG_FEATURE_RUN_PARTS_FANCY is not set -CONFIG_START_STOP_DAEMON=y -CONFIG_FEATURE_START_STOP_DAEMON_FANCY=y -CONFIG_FEATURE_START_STOP_DAEMON_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_AWK=y -CONFIG_FEATURE_AWK_LIBM=y -CONFIG_CMP=y -# CONFIG_DIFF is not set -# CONFIG_FEATURE_DIFF_LONG_OPTIONS is not set -# CONFIG_FEATURE_DIFF_DIR is not set -CONFIG_ED=y CONFIG_PATCH=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_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 is not set +CONFIG_FEATURE_VI_ASK_TERMINAL=y CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y +CONFIG_AWK=y +# CONFIG_FEATURE_AWK_LIBM is not set +CONFIG_CMP=y +CONFIG_DIFF=y +CONFIG_FEATURE_DIFF_LONG_OPTIONS=y +CONFIG_FEATURE_DIFF_DIR=y +CONFIG_ED=y +CONFIG_SED=y CONFIG_FEATURE_ALLOW_EXEC=y # @@ -402,61 +417,66 @@ 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 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 +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_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_REMOVED=y CONFIG_FEATURE_KILL_DELAY=0 CONFIG_FEATURE_INIT_SCTTY=y -# CONFIG_FEATURE_INIT_SYSLOG is not set -# CONFIG_FEATURE_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set +CONFIG_FEATURE_INIT_SYSLOG=y +CONFIG_FEATURE_EXTRA_QUIET=y +CONFIG_FEATURE_INIT_COREDUMPS=y CONFIG_FEATURE_INITRD=y CONFIG_INIT_TERMINAL_TYPE="linux" -CONFIG_HALT=y -# CONFIG_FEATURE_CALL_TELINIT is not set -CONFIG_TELINIT_PATH="" CONFIG_MESG=y +CONFIG_FEATURE_MESG_ENABLE_ONLY_GROUP=y # # Login/Password Management Utilities # +CONFIG_ADD_SHELL=y +CONFIG_REMOVE_SHELL=y 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 is not set -# CONFIG_FEATURE_ADDUSER_TO_GROUP is not set -CONFIG_DELGROUP=y -# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set -# CONFIG_FEATURE_CHECK_NAMES is not set CONFIG_ADDUSER=y -CONFIG_FEATURE_ADDUSER_LONG_OPTIONS=y +# 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 is not set CONFIG_DELUSER=y +CONFIG_DELGROUP=y +# CONFIG_FEATURE_DEL_USER_FROM_GROUP is not set CONFIG_GETTY=y CONFIG_LOGIN=y +# CONFIG_LOGIN_SESSION_AS_CHILD is not set # CONFIG_PAM is not set # CONFIG_LOGIN_SCRIPTS is not set -CONFIG_FEATURE_NOLOGIN=y +# CONFIG_FEATURE_NOLOGIN is not set CONFIG_FEATURE_SECURETTY=y CONFIG_PASSWD=y -CONFIG_FEATURE_PASSWD_WEAK_CHECK=y -# CONFIG_CRYPTPW is not set +# CONFIG_FEATURE_PASSWD_WEAK_CHECK is not set +CONFIG_CRYPTPW=y # CONFIG_CHPASSWD is not set +CONFIG_FEATURE_DEFAULT_PASSWD_ALGO="des" CONFIG_SU=y CONFIG_FEATURE_SU_SYSLOG=y CONFIG_FEATURE_SU_CHECKS_SHELLS=y @@ -466,23 +486,23 @@ CONFIG_VLOCK=y # # Linux Ext2 FS Progs # -# CONFIG_CHATTR is not set -# CONFIG_FSCK is not set -# CONFIG_LSATTR is not set +CONFIG_CHATTR=y +CONFIG_FSCK=y +CONFIG_LSATTR=y # CONFIG_TUNE2FS is not set # # Linux Module Utilities # -# CONFIG_MODINFO is not set +CONFIG_MODINFO=y # 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_INSMOD=y +CONFIG_RMMOD=y +CONFIG_LSMOD=y +CONFIG_FEATURE_LSMOD_PRETTY_2_6_OUTPUT=y +CONFIG_MODPROBE=y # CONFIG_FEATURE_MODPROBE_BLACKLIST is not set # CONFIG_DEPMOD is not set @@ -496,44 +516,52 @@ CONFIG_VLOCK=y # 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="" +CONFIG_FEATURE_CHECK_TAINTED_MODULE=y +CONFIG_FEATURE_MODUTILS_ALIAS=y +CONFIG_FEATURE_MODUTILS_SYMBOLS=y +CONFIG_DEFAULT_MODULES_DIR="/lib/modules" +CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" # # Linux System Utilities # CONFIG_BLOCKDEV=y -# CONFIG_REV is not set +CONFIG_MDEV=y +CONFIG_FEATURE_MDEV_CONF=y +# CONFIG_FEATURE_MDEV_RENAME is not set +# CONFIG_FEATURE_MDEV_RENAME_REGEXP is not set +CONFIG_FEATURE_MDEV_EXEC=y +CONFIG_FEATURE_MDEV_LOAD_FIRMWARE=y +CONFIG_REV=y CONFIG_ACPID=y -# CONFIG_FEATURE_ACPID_COMPAT is not set -# CONFIG_BLKID is not set +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_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=y -CONFIG_FDISK_SUPPORT_LARGE_DISKS=y +# CONFIG_FDISK_SUPPORT_LARGE_DISKS is not set 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_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 is not set -CONFIG_FREERAMDISK=y -CONFIG_FSCK_MINIX=y -# CONFIG_MKFS_EXT2 is not set -CONFIG_MKFS_MINIX=y -CONFIG_FEATURE_MINIX2=y +CONFIG_FLOCK=y +# CONFIG_FREERAMDISK is not set +# 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 is not set +CONFIG_MKFS_VFAT=y CONFIG_GETOPT=y CONFIG_FEATURE_GETOPT_LONG=y CONFIG_HEXDUMP=y @@ -542,48 +570,37 @@ CONFIG_HEXDUMP=y CONFIG_HWCLOCK=y CONFIG_FEATURE_HWCLOCK_LONG_OPTIONS=y CONFIG_FEATURE_HWCLOCK_ADJTIME_FHS=y -# CONFIG_IPCRM is not set -# CONFIG_IPCS is not set +CONFIG_IPCRM=y +CONFIG_IPCS=y CONFIG_LOSETUP=y -# CONFIG_LSPCI is not set -# CONFIG_LSUSB is not set -CONFIG_MDEV=y -# 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_LSPCI=y +CONFIG_LSUSB=y CONFIG_MKSWAP=y CONFIG_FEATURE_MKSWAP_UUID=y CONFIG_MORE=y -CONFIG_FEATURE_USE_TERMIOS=y -CONFIG_MOUNT=y +# CONFIG_MOUNT is not set # CONFIG_FEATURE_MOUNT_FAKE is not set # CONFIG_FEATURE_MOUNT_VERBOSE is not set -CONFIG_FEATURE_MOUNT_HELPERS=y -CONFIG_FEATURE_MOUNT_LABEL=y +# 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=y -CONFIG_FEATURE_MOUNT_FSTAB=y -CONFIG_PIVOT_ROOT=y +# CONFIG_FEATURE_MOUNT_FLAGS is not set +# CONFIG_FEATURE_MOUNT_FSTAB is not set +# CONFIG_PIVOT_ROOT is not set CONFIG_RDATE=y # CONFIG_RDEV is not set -# CONFIG_READPROFILE is not set +CONFIG_READPROFILE=y # CONFIG_RTCWAKE is not set # CONFIG_SCRIPT is not set -# CONFIG_SCRIPTREPLAY is not set +CONFIG_SCRIPTREPLAY=y # CONFIG_SETARCH is not set CONFIG_SWAPONOFF=y # CONFIG_FEATURE_SWAPON_PRI is not set -# CONFIG_SWITCH_ROOT is not set -CONFIG_UMOUNT=y -CONFIG_FEATURE_UMOUNT_ALL=y - -# -# Common options for mount/umount -# -CONFIG_FEATURE_MOUNT_LOOP=y +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 @@ -591,35 +608,53 @@ CONFIG_VOLUMEID=y # # Filesystem/Volume identification # -CONFIG_FEATURE_VOLUMEID_EXT=y +# CONFIG_FEATURE_VOLUMEID_EXT is not set 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_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_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=y +CONFIG_NANDDUMP=y +CONFIG_SETSERIAL=y # CONFIG_UBIATTACH is not set # CONFIG_UBIDETACH is not set +CONFIG_UBIMKVOL=y +CONFIG_UBIRMVOL=y +CONFIG_UBIRSVOL=y +CONFIG_UBIUPDATEVOL=y CONFIG_ADJTIMEX=y # CONFIG_BBCONFIG is not set -# CONFIG_BEEP is not set -CONFIG_FEATURE_BEEP_FREQ=0 -CONFIG_FEATURE_BEEP_LENGTH_MS=0 +# CONFIG_FEATURE_COMPRESS_BBCONFIG is not set +CONFIG_BEEP=y +CONFIG_FEATURE_BEEP_FREQ=4000 +CONFIG_FEATURE_BEEP_LENGTH_MS=30 # CONFIG_CHAT is not set # CONFIG_FEATURE_CHAT_NOFAIL is not set # CONFIG_FEATURE_CHAT_TTY_HIFI is not set @@ -628,22 +663,22 @@ CONFIG_FEATURE_BEEP_LENGTH_MS=0 # 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_CHRT=y CONFIG_CROND=y -# CONFIG_FEATURE_CROND_D is not set +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_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_DEVMEM=y CONFIG_EJECT=y -CONFIG_FEATURE_EJECT_SCSI=y +# CONFIG_FEATURE_EJECT_SCSI is not set # CONFIG_FBSPLASH is not set # CONFIG_FLASHCP is not set # CONFIG_FLASH_LOCK is not set @@ -654,83 +689,82 @@ CONFIG_IONICE=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 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_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 is not set -CONFIG_MICROCOM=y +CONFIG_MAN=y +# CONFIG_MICROCOM is not set # CONFIG_MOUNTPOINT is not set CONFIG_MT=y -# CONFIG_RAIDAUTORUN is not set +CONFIG_RAIDAUTORUN=y # 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_RUNLEVEL=y +CONFIG_RX=y +CONFIG_SETSID=y CONFIG_STRINGS=y -# CONFIG_TASKSET is not set -# CONFIG_FEATURE_TASKSET_FANCY is not set +CONFIG_TASKSET=y +CONFIG_FEATURE_TASKSET_FANCY=y CONFIG_TIME=y CONFIG_TIMEOUT=y -# CONFIG_TTYSIZE is not set -# CONFIG_VOLNAME is not set -# CONFIG_WALL is not set +CONFIG_TTYSIZE=y +CONFIG_VOLNAME=y +CONFIG_WALL=y CONFIG_WATCHDOG=y # # Networking Utilities # +CONFIG_NAMEIF=y +# CONFIG_FEATURE_NAMEIF_EXTENDED is not set +CONFIG_NBDCLIENT=y CONFIG_NC=y -# CONFIG_NC_SERVER is not set -# CONFIG_NC_EXTRA is not set +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_WHOIS=y CONFIG_FEATURE_IPV6=y # 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_FEATURE_PREFER_IPV4_ADDRESS=y +CONFIG_VERBOSE_RESOLUTION_ERRORS=y +CONFIG_ARP=y CONFIG_ARPING=y -CONFIG_BRCTL=y +# 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_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_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=y +# 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=y +# CONFIG_FEATURE_HTTPD_ERROR_PAGES is not set # CONFIG_FEATURE_HTTPD_PROXY is not set +# CONFIG_FEATURE_HTTPD_GZIP is not set CONFIG_IFCONFIG=y CONFIG_FEATURE_IFCONFIG_STATUS=y CONFIG_FEATURE_IFCONFIG_SLIP=y @@ -738,7 +772,7 @@ 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_IFPLUGD=y CONFIG_IFUPDOWN=y CONFIG_IFUPDOWN_IFSTATE_PATH="/var/run/ifstate" CONFIG_FEATURE_IFUPDOWN_IP=y @@ -761,28 +795,23 @@ 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 is not set +CONFIG_FEATURE_IP_SHORT_FORMS=y # 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_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 is not set CONFIG_NETSTAT=y -# CONFIG_FEATURE_NETSTAT_WIDE is not set +CONFIG_FEATURE_NETSTAT_WIDE=y # CONFIG_FEATURE_NETSTAT_PRG is not set CONFIG_NSLOOKUP=y -# CONFIG_NTPD is not set -# CONFIG_FEATURE_NTPD_SERVER is not set -CONFIG_PING=y -CONFIG_PING6=y -CONFIG_FEATURE_FANCY_PING=y -# CONFIG_PSCAN is not set +CONFIG_NTPD=y +CONFIG_FEATURE_NTPD_SERVER=y +CONFIG_PSCAN=y CONFIG_ROUTE=y # CONFIG_SLATTACH is not set # CONFIG_TCPSVD is not set @@ -790,10 +819,10 @@ CONFIG_TELNET=y CONFIG_FEATURE_TELNET_TTYPE=y CONFIG_FEATURE_TELNET_AUTOLOGIN=y CONFIG_TELNETD=y -# CONFIG_FEATURE_TELNETD_STANDALONE is not set -# CONFIG_FEATURE_TELNETD_INETD_WAIT is not set +CONFIG_FEATURE_TELNETD_STANDALONE=y +CONFIG_FEATURE_TELNETD_INETD_WAIT=y CONFIG_TFTP=y -# CONFIG_TFTPD is not set +CONFIG_TFTPD=y # # Common options for tftp/tftpd @@ -801,25 +830,28 @@ CONFIG_TFTP=y CONFIG_FEATURE_TFTP_GET=y CONFIG_FEATURE_TFTP_PUT=y CONFIG_FEATURE_TFTP_BLOCKSIZE=y -# CONFIG_FEATURE_TFTP_PROGRESS_BAR is not set +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_SOURCE_ROUTE is not set -# CONFIG_FEATURE_TRACEROUTE_USE_ICMP is not set +CONFIG_FEATURE_TRACEROUTE_SOURCE_ROUTE=y +CONFIG_FEATURE_TRACEROUTE_USE_ICMP=y CONFIG_TUNCTL=y -# CONFIG_FEATURE_TUNCTL_UG is not set +CONFIG_FEATURE_TUNCTL_UG=y +# CONFIG_UDHCPC6 is not set CONFIG_UDHCPD=y -# CONFIG_DHCPRELAY is not set +CONFIG_DHCPRELAY=y CONFIG_DUMPLEASES=y # CONFIG_FEATURE_UDHCPD_WRITE_LEASES_EARLY is not set -CONFIG_DHCPD_LEASES_FILE="/var/lib/misc/udhcpd.leases" +# 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=0 +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" @@ -829,6 +861,7 @@ 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 # @@ -841,45 +874,54 @@ CONFIG_FEATURE_WGET_LONG_OPTIONS=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_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 is not set # # Process Utilities # -# CONFIG_SMEMCAP is not set +CONFIG_IOSTAT=y +CONFIG_LSOF=y +CONFIG_MPSTAT=y +# CONFIG_NMETER is not set +CONFIG_PMAP=y +CONFIG_POWERTOP=y +CONFIG_PSTREE=y +CONFIG_PWDX=y +CONFIG_SMEMCAP=y +CONFIG_UPTIME=y +CONFIG_FEATURE_UPTIME_UTMP_SUPPORT=y CONFIG_FREE=y -# CONFIG_FUSER is not set +CONFIG_FUSER=y CONFIG_KILL=y CONFIG_KILLALL=y -# CONFIG_KILLALL5 is not set -# CONFIG_NMETER is not set +CONFIG_KILLALL5=y # CONFIG_PGREP is not set CONFIG_PIDOF=y -# CONFIG_FEATURE_PIDOF_SINGLE is not set -# CONFIG_FEATURE_PIDOF_OMIT is not set +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 is not set CONFIG_FEATURE_PS_ADDITIONAL_COLUMNS=y # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set CONFIG_RENICE=y -# CONFIG_BB_SYSCTL is not set +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 is not set +CONFIG_FEATURE_TOP_SMP_CPU=y # CONFIG_FEATURE_TOP_DECIMALS is not set -# CONFIG_FEATURE_TOP_SMP_PROCESS is not set -# CONFIG_FEATURE_TOPMEM is not set +CONFIG_FEATURE_TOP_SMP_PROCESS=y +CONFIG_FEATURE_TOPMEM=y CONFIG_FEATURE_SHOW_THREADS=y -CONFIG_UPTIME=y CONFIG_WATCH=y # @@ -890,7 +932,7 @@ CONFIG_WATCH=y # CONFIG_FEATURE_RUNSVDIR_LOG is not set # CONFIG_SV is not set CONFIG_SV_DEFAULT_SERVICE_DIR="" -# CONFIG_SVLOGD is not set +CONFIG_SVLOGD=y # CONFIG_CHPST is not set # CONFIG_SETUIDGID is not set # CONFIG_ENVUIDGID is not set @@ -917,21 +959,25 @@ CONFIG_SV_DEFAULT_SERVICE_DIR="" # 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_BUILTIN_ECHO=y CONFIG_ASH_BUILTIN_PRINTF=y CONFIG_ASH_BUILTIN_TEST=y -CONFIG_ASH_CMDCMD=y -CONFIG_ASH_MAIL=y +# CONFIG_ASH_CMDCMD is not set +# CONFIG_ASH_MAIL is not set CONFIG_ASH_OPTIMIZE_FOR_SIZE=y -CONFIG_ASH_RANDOM_SUPPORT=y -CONFIG_ASH_EXPAND_PRMT=y +# 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 @@ -939,34 +985,35 @@ CONFIG_ASH_EXPAND_PRMT=y # 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_HUSH_EXPORT_N is not set +# CONFIG_HUSH_MODE_X is not set +# CONFIG_MSH 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_LASH is not set -# CONFIG_MSH is not set CONFIG_SH_MATH_SUPPORT=y CONFIG_SH_MATH_SUPPORT_64=y # CONFIG_FEATURE_SH_EXTRA_QUIET is not set -CONFIG_FEATURE_SH_STANDALONE=y +# CONFIG_FEATURE_SH_STANDALONE is not set # CONFIG_FEATURE_SH_NOFORK is not set -# CONFIG_CTTYHACK is not set +CONFIG_FEATURE_SH_HISTFILESIZE=y # # System Logging Utilities # CONFIG_SYSLOGD=y -# CONFIG_FEATURE_ROTATE_LOGFILE is not set -CONFIG_FEATURE_REMOTE_LOG=y +CONFIG_FEATURE_ROTATE_LOGFILE=y +# CONFIG_FEATURE_REMOTE_LOG is not set # CONFIG_FEATURE_SYSLOGD_DUP is not set +CONFIG_FEATURE_SYSLOGD_CFG=y CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=256 -CONFIG_FEATURE_IPC_SYSLOG=y -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=64 -CONFIG_LOGREAD=y +# 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 diff --git a/packaging/cttyhack-serial-console-detection-is-Linux-specific.patch b/packaging/cttyhack-serial-console-detection-is-Linux-specific.patch deleted file mode 100644 index 7228615..0000000 --- a/packaging/cttyhack-serial-console-detection-is-Linux-specific.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 430ba79c39eeed4725c36e9c2ad61c438c8a5d3e Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Fri, 30 Jul 2010 06:21:21 +0200 -Subject: [PATCH 13/19] cttyhack: serial console detection is Linux-specific - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - shell/cttyhack.c | 15 ++++++++++++--- - 1 files changed, 12 insertions(+), 3 deletions(-) - -Index: busybox-1.17.1/shell/cttyhack.c -=================================================================== ---- busybox-1.17.1.orig/shell/cttyhack.c 2010-08-01 05:38:31.000000000 +0200 -+++ busybox-1.17.1/shell/cttyhack.c 2010-08-01 05:39:26.000000000 +0200 -@@ -6,6 +6,10 @@ - */ - #include "libbb.h" - -+#if !defined(__linux__) && !defined(TIOCGSERIAL) -+# warning cttyhack will not be able to detect a controlling tty on this system -+#endif -+ - /* From */ - struct vt_stat { - unsigned short v_active; /* active vt */ -@@ -59,13 +63,19 @@ - close(fd); - } else { - /* We don't have ctty (or don't have "/dev/tty" node...) */ -- if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { -+ if (0) {} -+#ifdef TIOCGSERIAL -+ else if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { - /* this is a serial console */ - sprintf(console + 8, "S%d", u.sr.line); -- } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { -+ } -+#endif -+#ifdef __linux__ -+ else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { - /* this is linux virtual tty */ - sprintf(console + 8, "S%d" + 1, u.vt.v_active); - } -+#endif - if (console[8]) { - fd = xopen(console, O_RDWR); - //bb_error_msg("switching to '%s'", console); -Index: busybox-1.17.1/shell/Config.src -=================================================================== ---- busybox-1.17.1.orig/shell/Config.src 2010-08-01 05:39:44.000000000 +0200 -+++ busybox-1.17.1/shell/Config.src 2010-08-01 05:39:49.000000000 +0200 -@@ -370,7 +370,6 @@ - config CTTYHACK - bool "cttyhack" - default y -- depends on PLATFORM_LINUX - help - One common problem reported on the mailing list is "can't access tty; - job control turned off" error message which typically appears when diff --git a/packaging/debian-changes-1.17.1-10 b/packaging/debian-changes-1.17.1-10 deleted file mode 100644 index 6bb43e4..0000000 --- a/packaging/debian-changes-1.17.1-10 +++ /dev/null @@ -1,70 +0,0 @@ -Description: Upstream changes introduced in version 1:1.17.1-10 - This patch has been created by dpkg-source during the package build. - Here's the last changelog entry, hopefully it gives details on why - those changes were made: - . - busybox (1:1.17.1-10) unstable; urgency=low - . - [ Michael Tokarev ] - * tiny build system changes: from main source to build directories: - don't copy .dotfiles, use ln instead of cp - . - [ Joey Hess ] - * Enable sha256sum in udeb, needed by debootstrap to handle Release - files w/o md5sums. - * Did not disable md5sum in udeb because eg anna still uses them to verify - md5sum fields from d-i Packages files. (Those fields are still present.. - for now.) - . - The person named in the Author field signed this changelog entry. -Author: Joey Hess - ---- -The information above should follow the Patch Tagging Guidelines, please -checkout http://dep.debian.net/deps/dep3/ to learn about the format. Here -are templates for supplementary fields that you might want to add: - -Origin: , -Bug: -Bug-Debian: http://bugs.debian.org/ -Bug-Ubuntu: https://launchpad.net/bugs/ -Forwarded: -Reviewed-By: -Last-Update: - ---- /dev/null -+++ busybox-1.17.1/busybox-1.17.1/.indent.pro -@@ -0,0 +1,33 @@ -+--blank-lines-after-declarations -+--blank-lines-after-procedures -+--break-before-boolean-operator -+--no-blank-lines-after-commas -+--braces-on-if-line -+--braces-on-struct-decl-line -+--comment-indentation25 -+--declaration-comment-column25 -+--no-comment-delimiters-on-blank-lines -+--cuddle-else -+--continuation-indentation4 -+--case-indentation0 -+--else-endif-column33 -+--space-after-cast -+--line-comments-indentation0 -+--declaration-indentation1 -+--dont-format-first-column-comments -+--dont-format-comments -+--honour-newlines -+--indent-level4 -+/* changed from 0 to 4 */ -+--parameter-indentation4 -+--line-length78 /* changed from 75 */ -+--continue-at-parentheses -+--no-space-after-function-call-names -+--dont-break-procedure-type -+--dont-star-comments -+--leave-optional-blank-lines -+--dont-space-special-semicolon -+--tab-size4 -+/* additions by Mark */ -+--case-brace-indentation0 -+--leave-preprocessor-space diff --git a/packaging/doc-man-name.patch b/packaging/doc-man-name.patch deleted file mode 100644 index d793c35..0000000 --- a/packaging/doc-man-name.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/Makefile.custom -+++ b/Makefile.custom -@@ -107,7 +107,7 @@ - - # Documentation Targets - .PHONY: doc --doc: docs/busybox.pod docs/BusyBox.txt docs/BusyBox.1 docs/BusyBox.html -+doc: docs/busybox.pod docs/BusyBox.txt docs/busybox.1 docs/BusyBox.html - - # FIXME: Doesn't belong here - cmd_doc = -@@ -134,10 +134,10 @@ - $(Q)-mkdir -p docs - $(Q)-pod2text $< > $@ - --docs/BusyBox.1: docs/busybox.pod -+docs/busybox.1: docs/busybox.pod - $(disp_doc) - $(Q)-mkdir -p docs -- $(Q)-pod2man --center=BusyBox --release="version $(KERNELVERSION)" $< > $@ -+ $(Q)-pod2man --center=busybox --release="version $(KERNELVERSION)" $< > $@ - - docs/BusyBox.html: docs/busybox.net/BusyBox.html - $(disp_doc) diff --git a/packaging/init-console-CRTSCTS.patch b/packaging/init-console-CRTSCTS.patch deleted file mode 100644 index ddc06fb..0000000 --- a/packaging/init-console-CRTSCTS.patch +++ /dev/null @@ -1,15 +0,0 @@ ---- a/init/init.c.original 2010-10-17 20:12:02.000000000 +0200 -+++ b/init/init.c 2010-10-17 20:12:17.000000000 +0200 -@@ -232,7 +232,11 @@ - #endif - - /* Make it be sane */ -- tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; -+ tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD -+#ifdef CRTSCTS -+ | CRTSCTS -+#endif -+ ; - tty.c_cflag |= CREAD | HUPCL | CLOCAL; - - /* input modes */ diff --git a/packaging/init-console.patch b/packaging/init-console.patch deleted file mode 100644 index 6845950..0000000 --- a/packaging/init-console.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/init/init.c -+++ b/init/init.c -@@ -441,6 +441,8 @@ - for (a = init_action_list; a; a = a->next) { - if (!(a->action_type & action_type)) - continue; -+ if (a->terminal[0] && access(a->terminal, R_OK | W_OK)) -+ continue; - - if (a->action_type & (SYSINIT | WAIT | ONCE | CTRLALTDEL | SHUTDOWN)) { - pid_t pid = run(a); diff --git a/packaging/init-halt-portability-improvements.patch b/packaging/init-halt-portability-improvements.patch deleted file mode 100644 index 94618c3..0000000 --- a/packaging/init-halt-portability-improvements.patch +++ /dev/null @@ -1,185 +0,0 @@ -From 714674e4da3d92c5dd14e00ab30794a895b91eb4 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:38:44 +0200 -Subject: [PATCH 4/9] init,halt: portability improvements - -* make init and halt use the same RB_* constants for reboot() -* conditionalize the Linux-specific code - -Inspired by init.init.diff from the Debian kFreeBSD patches at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/Config.src | 2 -- - init/halt.c | 14 +------------- - init/init.c | 16 ++++++++-------- - init/reboot.h | 31 +++++++++++++++++++++++++++++++ - 4 files changed, 40 insertions(+), 23 deletions(-) - create mode 100644 init/reboot.h - -Index: busybox-1.17.1/init/Config.src -=================================================================== ---- busybox-1.17.1.orig/init/Config.src 2010-08-01 05:32:43.000000000 +0200 -+++ busybox-1.17.1/init/Config.src 2010-08-01 05:36:47.000000000 +0200 -@@ -10,7 +10,6 @@ - config INIT - bool "init" - default y -- depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - init is the first program run when the system boots. -@@ -93,7 +92,6 @@ - config HALT - bool "poweroff, halt, and reboot" - default y -- depends on PLATFORM_LINUX - help - Stop all processes and either halt, reboot, or power off the system. - -Index: busybox-1.17.1/init/halt.c -=================================================================== ---- busybox-1.17.1.orig/init/halt.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/init/halt.c 2010-08-01 05:36:47.000000000 +0200 -@@ -8,7 +8,7 @@ - */ - - #include "libbb.h" --#include -+#include "reboot.h" - - #if ENABLE_FEATURE_WTMP - #include -@@ -36,18 +36,6 @@ - #define write_wtmp() ((void)0) - #endif - --#ifndef RB_HALT_SYSTEM --#define RB_HALT_SYSTEM RB_HALT --#endif -- --#ifndef RB_POWERDOWN --/* Stop system and switch power off if possible. */ --# define RB_POWERDOWN 0x4321fedc --#endif --#ifndef RB_POWER_OFF --# define RB_POWER_OFF RB_POWERDOWN --#endif -- - - int halt_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int halt_main(int argc UNUSED_PARAM, char **argv) -Index: busybox-1.17.1/init/init.c -=================================================================== ---- busybox-1.17.1.orig/init/init.c 2010-08-01 05:36:45.000000000 +0200 -+++ busybox-1.17.1/init/init.c 2010-08-01 05:36:47.000000000 +0200 -@@ -12,7 +12,6 @@ - #include "libbb.h" - #include - #include --#include - #include - #ifdef __linux__ - #include -@@ -20,6 +19,7 @@ - #if ENABLE_FEATURE_UTMP - # include /* DEAD_PROCESS */ - #endif -+#include "reboot.h" /* reboot() constants */ - - /* Used only for sanitizing purposes in set_sane_term() below. On systems where - * the baud rate is stored in a separate field, we can safely disable them. */ -@@ -97,13 +97,6 @@ - enum { - L_LOG = 0x1, - L_CONSOLE = 0x2, --#ifndef RB_HALT_SYSTEM -- RB_HALT_SYSTEM = 0xcdef0123, /* FIXME: this overflows enum */ -- RB_ENABLE_CAD = 0x89abcdef, -- RB_DISABLE_CAD = 0, -- RB_POWER_OFF = 0x4321fedc, -- RB_AUTOBOOT = 0x01234567, --#endif - }; - - /* Print a message to the specified device. -@@ -726,10 +719,12 @@ - - run_shutdown_and_kill_processes(); - -+#ifdef RB_ENABLE_CAD - /* Allow Ctrl-Alt-Del to reboot the system. - * This is how kernel sets it up for init, we follow suit. - */ - reboot(RB_ENABLE_CAD); /* misnomer */ -+#endif - - if (open_stdio_to_tty(a->terminal)) { - dbg_message(L_CONSOLE, "Trying to re-exec %s", a->command); -@@ -872,9 +867,11 @@ - ) { - bb_show_usage(); - } -+#ifdef RB_DISABLE_CAD - /* Turn off rebooting via CTL-ALT-DEL - we get a - * SIGINT on CAD so we can shut things down gracefully... */ - reboot(RB_DISABLE_CAD); /* misnomer */ -+#endif - } - - /* Figure out where the default console should be */ -@@ -897,6 +894,8 @@ - message(L_CONSOLE | L_LOG, "init started: %s", bb_banner); - #endif - -+/* struct sysinfo is linux-specific */ -+#ifdef __linux__ - /* Make sure there is enough memory to do something useful. */ - if (ENABLE_SWAPONOFF) { - struct sysinfo info; -@@ -912,6 +911,7 @@ - run_actions(SYSINIT); /* wait and removing */ - } - } -+#endif - - /* Check if we are supposed to be in single user mode */ - if (argv[1] -Index: busybox-1.17.1/init/reboot.h -=================================================================== ---- /dev/null 1970-01-01 00:00:00.000000000 +0000 -+++ busybox-1.17.1/init/reboot.h 2010-08-01 05:36:47.000000000 +0200 -@@ -0,0 +1,31 @@ -+/* -+ * Definitions related to the reboot() system call, -+ * shared between init.c and halt.c. -+ */ -+ -+#include -+ -+#ifndef RB_HALT_SYSTEM -+# if defined(__linux__) -+# define RB_HALT_SYSTEM 0xcdef0123 -+# define RB_ENABLE_CAD 0x89abcdef -+# define RB_DISABLE_CAD 0 -+# define RB_POWER_OFF 0x4321fedc -+# define RB_AUTOBOOT 0x01234567 -+# elif defined(RB_HALT) -+# define RB_HALT_SYSTEM RB_HALT -+# endif -+#endif -+ -+/* Stop system and switch power off if possible. */ -+#ifndef RB_POWER_OFF -+# if defined(RB_POWERDOWN) -+# define RB_POWER_OFF RB_POWERDOWN -+# elif defined(__linux__) -+# define RB_POWER_OFF 0x4321fedc -+# else -+# warning "poweroff unsupported, using halt as fallback" -+# define RB_POWER_OFF RB_HALT_SYSTEM -+# endif -+#endif -+ diff --git a/packaging/init-loginutils-termios-portability-fixes.patch b/packaging/init-loginutils-termios-portability-fixes.patch deleted file mode 100644 index c612263..0000000 --- a/packaging/init-loginutils-termios-portability-fixes.patch +++ /dev/null @@ -1,199 +0,0 @@ -From f812eace1863feeac64dc8af27f4ab0f98119618 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:37:32 +0200 -Subject: [PATCH 3/9] init,loginutils: termios portability fixes - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/init.c | 17 ++++++++++++++++- - loginutils/Config.src | 2 -- - loginutils/getty.c | 27 ++++++++++++++------------- - loginutils/login.c | 2 +- - 4 files changed, 31 insertions(+), 17 deletions(-) - -diff --git a/init/init.c b/init/init.c -index 2eb8f1a..1388c75 100644 ---- a/init/init.c -+++ b/init/init.c -@@ -14,11 +14,19 @@ - #include - #include - #include -+#ifdef __linux__ - #include -+#endif - #if ENABLE_FEATURE_UTMP - # include /* DEAD_PROCESS */ - #endif - -+/* Used only for sanitizing purposes in set_sane_term() below. On systems where -+ * the baud rate is stored in a separate field, we can safely disable them. */ -+#ifndef CBAUD -+# define CBAUD 0 -+# define CBAUDEX 0 -+#endif - - /* Was a CONFIG_xxx option. A lot of people were building - * not fully functional init by switching it on! */ -@@ -166,7 +174,9 @@ static void message(int where, const char *fmt, ...) - - static void console_init(void) - { -+#ifdef VT_OPENQRY - int vtno; -+#endif - char *s; - - s = getenv("CONSOLE"); -@@ -190,6 +200,7 @@ static void console_init(void) - } - - s = getenv("TERM"); -+#ifdef VT_OPENQRY - if (ioctl(STDIN_FILENO, VT_OPENQRY, &vtno) != 0) { - /* Not a linux terminal, probably serial console. - * Force the TERM setting to vt102 -@@ -198,7 +209,9 @@ static void console_init(void) - putenv((char*)"TERM=vt102"); - if (!ENABLE_FEATURE_INIT_SYSLOG) - log_console = NULL; -- } else if (!s) -+ } else -+#endif -+ if (!s) - putenv((char*)"TERM=linux"); - } - -@@ -220,8 +233,10 @@ static void set_sane_term(void) - tty.c_cc[VSTOP] = 19; /* C-s */ - tty.c_cc[VSUSP] = 26; /* C-z */ - -+#ifdef __linux__ - /* use line discipline 0 */ - tty.c_line = 0; -+#endif - - /* Make it be sane */ - tty.c_cflag &= CBAUD | CBAUDEX | CSIZE | CSTOPB | PARENB | PARODD; -diff --git a/loginutils/Config.src b/loginutils/Config.src -index 425d041..6ec2893 100644 ---- a/loginutils/Config.src -+++ b/loginutils/Config.src -@@ -179,7 +179,6 @@ config DELUSER - config GETTY - bool "getty" - default y -- depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - getty lets you log in on a tty, it is normally invoked by init. -@@ -187,7 +186,6 @@ config GETTY - config LOGIN - bool "login" - default y -- depends on PLATFORM_LINUX - select FEATURE_SUID - select FEATURE_SYSLOG - help -diff --git a/loginutils/getty.c b/loginutils/getty.c -index a5e8e90..7f04d33 100644 ---- a/loginutils/getty.c -+++ b/loginutils/getty.c -@@ -282,10 +282,8 @@ static void termios_init(struct termios *tp, int speed, struct options *op) - * reads will be done in raw mode anyway. Errors will be dealt with - * later on. - */ --#ifdef __linux__ - /* flush input and output queues, important for modems! */ -- ioctl(0, TCFLSH, TCIOFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ --#endif -+ tcflush(0, TCIOFLUSH); - ispeed = ospeed = speed; - if (speed == B0) { - /* Speed was specified as "0" on command line. -@@ -299,10 +297,13 @@ static void termios_init(struct termios *tp, int speed, struct options *op) - cfsetispeed(tp, ispeed); - cfsetospeed(tp, ospeed); - -- tp->c_iflag = tp->c_lflag = tp->c_line = 0; -+ tp->c_iflag = tp->c_lflag = 0; - tp->c_oflag = OPOST | ONLCR; - tp->c_cc[VMIN] = 1; - tp->c_cc[VTIME] = 0; -+#ifdef __linux__ -+ tp->c_line = 0; -+#endif - - /* Optionally enable hardware flow control */ - #ifdef CRTSCTS -@@ -360,10 +361,8 @@ static void auto_baud(char *buf, unsigned size_buf, struct termios *tp) - for (bp = buf; bp < buf + nread; bp++) { - if (isdigit(*bp)) { - speed = bcode(bp); -- if (speed > 0) { -- tp->c_cflag &= ~CBAUD; -- tp->c_cflag |= speed; -- } -+ if (speed > 0) -+ cfsetspeed(tp, speed); - break; - } - } -@@ -417,7 +416,7 @@ static char *get_logname(char *logname, unsigned size_logname, - - /* Flush pending input (esp. after parsing or switching the baud rate). */ - sleep(1); -- ioctl(0, TCFLSH, TCIFLUSH); /* tcflush(0, TCIOFLUSH)? - same */ -+ tcflush(0, TCIOFLUSH); - - /* Prompt for and read a login name. */ - logname[0] = '\0'; -@@ -526,7 +525,9 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat - tp->c_cc[VQUIT] = DEF_QUIT; /* default quit */ - tp->c_cc[VEOF] = DEF_EOF; /* default EOF character */ - tp->c_cc[VEOL] = DEF_EOL; -+#ifdef VSWTC - tp->c_cc[VSWTC] = DEF_SWITCH; /* default switch character */ -+#endif - - /* Account for special characters seen in input. */ - if (cp->eol == CR) { -@@ -572,8 +573,8 @@ static void termios_final(struct options *op, struct termios *tp, struct chardat - #endif - - /* Finally, make the new settings effective */ -- /* It's tcsetattr_stdin_TCSANOW() + error check */ -- ioctl_or_perror_and_die(0, TCSETS, tp, "%s: TCSETS", op->tty); -+ if (tcsetattr_stdin_TCSANOW(tp) < 0) -+ bb_perror_msg_and_die("%s: tcsetattr", op->tty); - } - - int getty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -@@ -650,8 +651,8 @@ int getty_main(int argc UNUSED_PARAM, char **argv) - * by patching the SunOS kernel variable "zsadtrlow" to a larger value; - * 5 seconds seems to be a good value. - */ -- /* tcgetattr() + error check */ -- ioctl_or_perror_and_die(0, TCGETS, &termios, "%s: TCGETS", options.tty); -+ if (tcgetattr(0, &termios) < 0) -+ bb_perror_msg_and_die("%s: tcgetattr", options.tty); - - pid = getpid(); - #ifdef __linux__ -diff --git a/loginutils/login.c b/loginutils/login.c -index 88ed0af..1001248 100644 ---- a/loginutils/login.c -+++ b/loginutils/login.c -@@ -264,7 +264,7 @@ int login_main(int argc UNUSED_PARAM, char **argv) - - while (1) { - /* flush away any type-ahead (as getty does) */ -- ioctl(0, TCFLSH, TCIFLUSH); -+ tcflush(0, TCIFLUSH); - - if (!username[0]) - get_username_or_die(username, sizeof(username)); --- -1.7.1 - diff --git a/packaging/init-make-the-initial-TERM-value-configurable.patch b/packaging/init-make-the-initial-TERM-value-configurable.patch deleted file mode 100644 index fb04a1e..0000000 --- a/packaging/init-make-the-initial-TERM-value-configurable.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 1c05303fdc302725093294eb0305adc003d52bcb Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:07 +0200 -Subject: [PATCH 5/9] init: make the initial $TERM value configurable - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - init/Config.src | 12 ++++++++++++ - init/init.c | 2 +- - 2 files changed, 13 insertions(+), 1 deletions(-) - -diff --git a/init/Config.src b/init/Config.src -index 590e298..2cac357 100644 ---- a/init/Config.src -+++ b/init/Config.src -@@ -89,6 +89,18 @@ config FEATURE_INITRD - This does not apply to initramfs, which runs /init as PID 1 and - requires no special support. - -+config INIT_TERMINAL_TYPE -+ string "Initial terminal type" -+ default "linux" -+ depends on INIT -+ help -+ This is the initial value set by init for the TERM environment -+ variable. This variable is used by programs which make use of -+ extended terminal capabilities. -+ -+ Note that on Linux, init attempts to detect serial terminal and -+ sets TERM to "vt102" if one is found. -+ - config HALT - bool "poweroff, halt, and reboot" - default y -diff --git a/init/init.c b/init/init.c -index d8bf158..fa1af6d 100644 ---- a/init/init.c -+++ b/init/init.c -@@ -205,7 +205,7 @@ static void console_init(void) - } else - #endif - if (!s) -- putenv((char*)"TERM=linux"); -+ putenv((char*)"TERM=" CONFIG_INIT_TERMINAL_TYPE); - } - - /* Set terminal settings to reasonable defaults. --- -1.7.1 - diff --git a/packaging/klogd-make-it-work-on-non-linux-systems.patch b/packaging/klogd-make-it-work-on-non-linux-systems.patch deleted file mode 100644 index 033617f..0000000 --- a/packaging/klogd-make-it-work-on-non-linux-systems.patch +++ /dev/null @@ -1,246 +0,0 @@ -From 63c2e7ecc0c7a72b2ed35475a8d18d3052039ce4 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Sun, 1 Aug 2010 03:01:44 +0200 -Subject: [PATCH 1/2] klogd: make it work on non-linux systems - -The klogctl() interface allows changing the console loglevel, but is -Linux-specific. The more portable method of reading from _PATH_KLOG is -added as an alternative. - -Adapted from the Debian kFreeBSD patch at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian/klogd.diff - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - sysklogd/Config.src | 17 ++++++- - sysklogd/klogd.c | 128 +++++++++++++++++++++++++++++++++++++++++++------- - 2 files changed, 126 insertions(+), 19 deletions(-) - -diff --git a/sysklogd/Config.src b/sysklogd/Config.src -index 41c0d28..1e59872 100644 ---- a/sysklogd/Config.src -+++ b/sysklogd/Config.src -@@ -109,7 +109,6 @@ config FEATURE_LOGREAD_REDUCED_LOCKING - config KLOGD - bool "klogd" - default y -- depends on PLATFORM_LINUX - help - klogd is a utility which intercepts and logs all - messages from the Linux kernel and sends the messages -@@ -117,6 +116,22 @@ config KLOGD - you wish to record the messages produced by the kernel, - you should enable this option. - -+config FEATURE_KLOGD_KLOGCTL -+ bool "Use the klogctl() interface" -+ default y -+ depends on KLOGD && PLATFORM_LINUX -+ help -+ The klogd applet supports two interfaces for reading -+ kernel messages. Linux provides the klogctl() interface -+ which allows reading messages from the kernel ring buffer -+ independently from the file system. -+ -+ If you answer 'N' here, klogd will use the more portable -+ approach of reading them from /proc or a device node. -+ However, this method requires the file to be available. -+ -+ If in doubt, say 'Y'. -+ - config LOGGER - bool "logger" - default y -diff --git a/sysklogd/klogd.c b/sysklogd/klogd.c -index c54e80a..3468656 100644 ---- a/sysklogd/klogd.c -+++ b/sysklogd/klogd.c -@@ -4,7 +4,7 @@ - * - * Copyright (C) 2001 by Gennady Feldman . - * Changes: Made this a standalone busybox module which uses standalone -- * syslog() client interface. -+ * syslog() client interface. - * - * Copyright (C) 1999-2004 by Erik Andersen - * -@@ -19,18 +19,93 @@ - - #include "libbb.h" - #include --#include - --static void klogd_signal(int sig) -+ -+/* The Linux-specific klogctl(3) interface does not rely on the filesystem and -+ * allows us to change the console loglevel. Alternatively, we read the -+ * messages from _PATH_KLOG. */ -+ -+#if ENABLE_FEATURE_KLOGD_KLOGCTL -+ -+# include -+ -+static void klogd_open(void) -+{ -+ /* "Open the log. Currently a NOP" */ -+ klogctl(1, NULL, 0); -+} -+ -+static void klogd_setloglevel(int lvl) -+{ -+ /* "printk() prints a message on the console only if it has a loglevel -+ * less than console_loglevel". Here we set console_loglevel = lvl. */ -+ klogctl(8, NULL, lvl); -+} -+ -+static int klogd_read(char *bufp, int len) -+{ -+ return klogctl(2, bufp, len); -+} -+# define READ_ERROR "klogctl(2) error" -+ -+static void klogd_close(void) - { - /* FYI: cmd 7 is equivalent to setting console_loglevel to 7 - * via klogctl(8, NULL, 7). */ - klogctl(7, NULL, 0); /* "7 -- Enable printk's to console" */ - klogctl(0, NULL, 0); /* "0 -- Close the log. Currently a NOP" */ -- syslog(LOG_NOTICE, "klogd: exiting"); -- kill_myself_with_sig(sig); - } - -+#else -+ -+# include -+# ifndef _PATH_KLOG -+# ifdef __GNU__ -+# define _PATH_KLOG "/dev/klog" -+# else -+# error "your system's _PATH_KLOG is unknown" -+# endif -+# endif -+# define PATH_PRINTK "/proc/sys/kernel/printk" -+ -+enum { klogfd = 3 }; -+ -+static void klogd_open(void) -+{ -+ int fd = xopen(_PATH_KLOG, O_RDONLY); -+ xmove_fd(fd, klogfd); -+} -+ -+static void klogd_setloglevel(int lvl) -+{ -+ FILE *fp = fopen_or_warn(PATH_PRINTK, "w"); -+ if (fp) { -+ /* This changes only first value: -+ * "messages with a higher priority than this -+ * [that is, with numerically lower value] -+ * will be printed to the console". -+ * The other three values in this pseudo-file aren't changed. -+ */ -+ fprintf(fp, "%u\n", lvl); -+ fclose(fp); -+ } -+} -+ -+static int klogd_read(char *bufp, int len) -+{ -+ return read(klogfd, bufp, len); -+} -+# define READ_ERROR "read error" -+ -+static void klogd_close(void) -+{ -+ klogd_setloglevel(7); -+ if (ENABLE_FEATURE_CLEAN_UP) -+ close(klogfd); -+} -+ -+#endif -+ - #define log_buffer bb_common_bufsiz1 - enum { - KLOGD_LOGBUF_SIZE = sizeof(log_buffer), -@@ -38,6 +113,19 @@ enum { - OPT_FOREGROUND = (1 << 1), - }; - -+/* TODO: glibc openlog(LOG_KERN) reverts to LOG_USER instead, -+ * because that's how they interpret word "default" -+ * in the openlog() manpage: -+ * LOG_USER (default) -+ * generic user-level messages -+ * and the fact that LOG_KERN is a constant 0. -+ * glibc interprets it as "0 in openlog() call means 'use default'". -+ * I think it means "if openlog wasn't called before syslog() is called, -+ * use default". -+ * Convincing glibc maintainers otherwise is, as usual, nearly impossible. -+ * Should we open-code syslog() here to use correct facility? -+ */ -+ - int klogd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int klogd_main(int argc UNUSED_PARAM, char **argv) - { -@@ -55,34 +143,34 @@ int klogd_main(int argc UNUSED_PARAM, char **argv) - bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv); - } - -- openlog("kernel", 0, LOG_KERN); -- -- bb_signals(BB_FATAL_SIGS, klogd_signal); -- signal(SIGHUP, SIG_IGN); -+ logmode = LOGMODE_SYSLOG; - -- /* "Open the log. Currently a NOP" */ -- klogctl(1, NULL, 0); -+ /* klogd_open() before openlog(), since it might use fixed fd 3, -+ * and openlog() also may use the same fd 3 if we swap them: -+ */ -+ klogd_open(); -+ openlog("kernel", 0, LOG_KERN); - -- /* "printk() prints a message on the console only if it has a loglevel -- * less than console_loglevel". Here we set console_loglevel = i. */ - if (i) -- klogctl(8, NULL, i); -+ klogd_setloglevel(i); -+ -+ bb_signals(BB_FATAL_SIGS, record_signo); -+ signal(SIGHUP, SIG_IGN); - - syslog(LOG_NOTICE, "klogd started: %s", bb_banner); - -- while (1) { -+ while (!bb_got_signal) { - int n; - int priority; - char *start; - - /* "2 -- Read from the log." */ - start = log_buffer + used; -- n = klogctl(2, start, KLOGD_LOGBUF_SIZE-1 - used); -+ n = klogd_read(start, KLOGD_LOGBUF_SIZE-1 - used); - if (n < 0) { - if (errno == EINTR) - continue; -- syslog(LOG_ERR, "klogd: error %d in klogctl(2): %m", -- errno); -+ bb_perror_msg(READ_ERROR); - break; - } - start[n] = '\0'; -@@ -131,5 +219,9 @@ int klogd_main(int argc UNUSED_PARAM, char **argv) - } - } - -+ klogd_close(); -+ syslog(LOG_NOTICE, "klogd: exiting"); -+ if (bb_got_signal) -+ kill_myself_with_sig(bb_got_signal); - return EXIT_FAILURE; - } --- -1.7.1 - diff --git a/packaging/klogd.service b/packaging/klogd.service deleted file mode 100644 index cce62ac..0000000 --- a/packaging/klogd.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Run syslog -After=syslogd.service - -[Service] -Type=forking -ExecStart=/sbin/klogd -OOMScoreAdjust=-1000 -Restart=always -RestartSec=0 - -[Install] -WantedBy=basic.target diff --git a/packaging/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch b/packaging/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch deleted file mode 100644 index 5bec32f..0000000 --- a/packaging/less-remove-misguided-dependency-on-PLATFORM_LINUX.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 5a71fb82025d8bbb87a2d0a0851cb4c9cc31e888 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:47 +0200 -Subject: [PATCH 10/12] less: remove misguided dependency on PLATFORM_LINUX - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - miscutils/Config.src | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) - -Index: busybox-1.17.1/miscutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/miscutils/Config.src 2010-08-01 07:33:11.000000000 +0200 -+++ busybox-1.17.1/miscutils/Config.src 2010-08-02 00:45:01.000000000 +0200 -@@ -351,11 +351,6 @@ - config LESS - bool "less" - default y -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX -- depends on PLATFORM_LINUX - help - 'less' is a pager, meaning that it displays text files. It possesses - a wide array of features, and is an improvement over 'more'. diff --git a/packaging/libbb-conditionalize-AF_-usage-in-error-reporting.patch b/packaging/libbb-conditionalize-AF_-usage-in-error-reporting.patch deleted file mode 100644 index 73c9c32..0000000 --- a/packaging/libbb-conditionalize-AF_-usage-in-error-reporting.patch +++ /dev/null @@ -1,44 +0,0 @@ -From 29885114a5e3d22ee7aa3ab0e373e00e7cff443c Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:39:24 +0200 -Subject: [PATCH 8/9] libbb: conditionalize AF_* usage in error reporting - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - libbb/xfuncs_printf.c | 4 ++++ - networking/Config.src | 1 - - 2 files changed, 4 insertions(+), 1 deletions(-) - -diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c -index 7069a7c..91f7ba2 100644 ---- a/libbb/xfuncs_printf.c -+++ b/libbb/xfuncs_printf.c -@@ -387,8 +387,12 @@ int FAST_FUNC xsocket(int domain, int type, int protocol) - /* Hijack vaguely related config option */ - #if ENABLE_VERBOSE_RESOLUTION_ERRORS - const char *s = "INET"; -+# ifdef AF_PACKET - if (domain == AF_PACKET) s = "PACKET"; -+# endif -+# ifdef AF_NETLINK - if (domain == AF_NETLINK) s = "NETLINK"; -+# endif - IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";) - bb_perror_msg_and_die("socket(AF_%s,%d,%d)", s, type, protocol); - #else -diff --git a/networking/Config.src b/networking/Config.src -index 26c59e7..fc613e8 100644 ---- a/networking/Config.src -+++ b/networking/Config.src -@@ -43,7 +43,6 @@ config FEATURE_PREFER_IPV4_ADDRESS - config VERBOSE_RESOLUTION_ERRORS - bool "Verbose resolution errors" - default n -- depends on PLATFORM_LINUX #because of xsocket() in libbb/xfuncs_prinf.c - help - Enable if you are not satisfied with simplistic - "can't resolve 'hostname.com'" and want to know more. --- -1.7.1 - diff --git a/packaging/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch b/packaging/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch deleted file mode 100644 index 91ac9bf..0000000 --- a/packaging/libbb.h-add-device-names-for-Hurd-and-FreeBSD.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 816ed971e4ce60564f7ecbdc016d268d8e936230 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:29 +0200 -Subject: [PATCH 6/9] libbb.h: add device names for Hurd and FreeBSD - -Adapted from include.libbb.diff from the Debian kFreeBSD people: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - include/libbb.h | 26 +++++++++++++++++++++----- - 1 files changed, 21 insertions(+), 5 deletions(-) - -Index: busybox-1.17.1/include/libbb.h -=================================================================== ---- busybox-1.17.1.orig/include/libbb.h 2010-08-01 05:24:36.000000000 +0200 -+++ busybox-1.17.1/include/libbb.h 2010-08-01 05:36:59.000000000 +0200 -@@ -1614,7 +1614,27 @@ - /* "sh" */ - #define DEFAULT_SHELL_SHORT_NAME (bb_default_login_shell+6) - --#if ENABLE_FEATURE_DEVFS -+/* The following devices are the same on all systems. */ -+#define CURRENT_TTY "/dev/tty" -+#define DEV_CONSOLE "/dev/console" -+ -+#if defined(__FreeBSD_kernel__) -+# define CURRENT_VC CURRENT_TTY -+# define VC_1 "/dev/ttyv0" -+# define VC_2 "/dev/ttyv1" -+# define VC_3 "/dev/ttyv2" -+# define VC_4 "/dev/ttyv3" -+# define VC_5 "/dev/ttyv4" -+# define VC_FORMAT "/dev/ttyv%d" -+#elif defined(__GNU__) -+# define CURRENT_VC CURRENT_TTY -+# define VC_1 "/dev/tty1" -+# define VC_2 "/dev/tty2" -+# define VC_3 "/dev/tty3" -+# define VC_4 "/dev/tty4" -+# define VC_5 "/dev/tty5" -+# define VC_FORMAT "/dev/tty%d" -+#elif ENABLE_FEATURE_DEVFS /* from now on, assume Linux naming */ - # define CURRENT_VC "/dev/vc/0" - # define VC_1 "/dev/vc/1" - # define VC_2 "/dev/vc/2" -@@ -1661,10 +1681,6 @@ - # define FB_0 "/dev/fb0" - #endif - --/* The following devices are the same on devfs and non-devfs systems. */ --#define CURRENT_TTY "/dev/tty" --#define DEV_CONSOLE "/dev/console" -- - - #define ARRAY_SIZE(x) ((unsigned)(sizeof(x) / sizeof((x)[0]))) - diff --git a/packaging/make_gen_build_files_skip_quilt.patch b/packaging/make_gen_build_files_skip_quilt.patch deleted file mode 100644 index d654468..0000000 --- a/packaging/make_gen_build_files_skip_quilt.patch +++ /dev/null @@ -1,13 +0,0 @@ -Index: busybox-1.17.1/scripts/gen_build_files.sh -=================================================================== ---- busybox-1.17.1.orig/scripts/gen_build_files.sh 2010-08-01 07:28:13.000000000 +0200 -+++ busybox-1.17.1/scripts/gen_build_files.sh 2010-08-01 07:31:03.000000000 +0200 -@@ -48,7 +48,7 @@ - fi - - # (Re)generate */Kbuild and */Config.in --{ cd -- "$srctree" && find -type d; } | while read -r d; do -+{ cd -- "$srctree" && find -name .\?\* -prune -or -type d -print; } | while read -r d; do - d="${d#./}" - - src="$srctree/$d/Kbuild.src" diff --git a/packaging/make_unicode_printable.patch b/packaging/make_unicode_printable.patch deleted file mode 100644 index b62ed6f..0000000 --- a/packaging/make_unicode_printable.patch +++ /dev/null @@ -1,25 +0,0 @@ -diff --git a/libbb/printable_string.c b/libbb/printable_string.c -index 83a4821..8a62725 100644 ---- a/libbb/printable_string.c -+++ b/libbb/printable_string.c -@@ -31,8 +31,8 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) - } - if (c < ' ') - break; -- if (c >= 0x7f) -- break; -+ /* if (c >= 0x7f) */ -+ /* break; */ - s++; - } - -@@ -45,7 +45,8 @@ const char* FAST_FUNC printable_string(uni_stat_t *stats, const char *str) - unsigned char c = *d; - if (c == '\0') - break; -- if (c < ' ' || c >= 0x7f) -+ /* if (c < ' ' || c >= 0x7f) */ -+ if (c < ' ') - *d = '?'; - d++; - } diff --git a/packaging/mark-Linux-specific-configuration-options.patch b/packaging/mark-Linux-specific-configuration-options.patch deleted file mode 100644 index 8f89c3e..0000000 --- a/packaging/mark-Linux-specific-configuration-options.patch +++ /dev/null @@ -1,915 +0,0 @@ -From 1d7266d3b59be361763dab61f680103bbb70f3e9 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Mon, 19 Jul 2010 00:44:56 +0200 -Subject: [PATCH 2/9] mark Linux-specific configuration options - -PLATFORM_LINUX is used as a dependency for applets or features -which require Linux-specific interfaces. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - Config.in | 12 ++++++++++++ - console-tools/Config.src | 13 +++++++++++++ - coreutils/Config.src | 2 ++ - coreutils/date.c | 2 +- - e2fsprogs/Config.src | 1 + - init/Config.src | 2 ++ - init/bootchartd.c | 1 + - libbb/Config.src | 1 + - loginutils/Config.src | 3 +++ - miscutils/Config.src | 19 ++++++++++++++++++- - miscutils/conspy.c | 1 + - miscutils/ubi_attach_detach.c | 2 ++ - modutils/Config.src | 1 + - networking/Config.src | 23 ++++++++++++++++++++++- - networking/udhcp/Config.src | 2 ++ - procps/Config.src | 4 +++- - shell/cttyhack.c | 1 + - sysklogd/Config.src | 1 + - util-linux/Config.src | 27 +++++++++++++++++++++++++++ - 19 files changed, 114 insertions(+), 4 deletions(-) - -Index: busybox-1.17.1/Config.in -=================================================================== ---- busybox-1.17.1.orig/Config.in 2010-08-01 05:24:36.000000000 +0200 -+++ busybox-1.17.1/Config.in 2010-08-01 05:32:43.000000000 +0200 -@@ -47,6 +47,17 @@ - compiler other than gcc. - If you do use gcc, this option may needlessly increase code size. - -+config PLATFORM_LINUX -+ bool "Enable Linux-specific applets and features" -+ default y -+ help -+ For the most part, busybox requires only POSIX compatibility -+ from the target system, but some applets and features use -+ Linux-specific interfaces. -+ -+ Answering 'N' here will disable such applets and hide the -+ corresponding configuration options. -+ - choice - prompt "Buffer allocation policy" - default FEATURE_BUFFERS_USE_MALLOC -@@ -353,6 +364,7 @@ - config SELINUX - bool "Support NSA Security Enhanced Linux" - default n -+ depends on PLATFORM_LINUX - help - Enable support for SELinux in applets ls, ps, and id. Also provide - the option of compiling in SELinux applets. -Index: busybox-1.17.1/console-tools/Config.src -=================================================================== ---- busybox-1.17.1.orig/console-tools/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/console-tools/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config CHVT - bool "chvt" - default y -+ depends on PLATFORM_LINUX - help - This program is used to change to another terminal. - Example: chvt 4 (change to terminal /dev/tty4) -@@ -17,6 +18,7 @@ - config FGCONSOLE - bool "fgconsole" - default y -+ depends on PLATFORM_LINUX - help - This program prints active (foreground) console number. - -@@ -29,12 +31,14 @@ - config DEALLOCVT - bool "deallocvt" - default y -+ depends on PLATFORM_LINUX - help - This program deallocates unused virtual consoles. - - config DUMPKMAP - bool "dumpkmap" - default y -+ depends on PLATFORM_LINUX - help - This program dumps the kernel's keyboard translation table to - stdout, in binary format. You can then use loadkmap to load it. -@@ -42,18 +46,21 @@ - config KBD_MODE - bool "kbd_mode" - default y -+ depends on PLATFORM_LINUX - help - This program reports and sets keyboard mode. - - config LOADFONT - bool "loadfont" - default y -+ depends on PLATFORM_LINUX - help - This program loads a console font from standard input. - - config LOADKMAP - bool "loadkmap" - default y -+ depends on PLATFORM_LINUX - help - This program loads a keyboard translation table from - standard input. -@@ -61,6 +68,7 @@ - config OPENVT - bool "openvt" - default y -+ depends on PLATFORM_LINUX - help - This program is used to start a command on an unused - virtual terminal. -@@ -92,6 +100,7 @@ - config SETCONSOLE - bool "setconsole" - default y -+ depends on PLATFORM_LINUX - help - This program redirects the system console to another device, - like the current tty while logged in via telnet. -@@ -106,6 +115,7 @@ - config SETFONT - bool "setfont" - default y -+ depends on PLATFORM_LINUX - help - Allows to load console screen map. Useful for i18n. - -@@ -127,6 +137,7 @@ - config SETKEYCODES - bool "setkeycodes" - default y -+ depends on PLATFORM_LINUX - help - This program loads entries into the kernel's scancode-to-keycode - map, allowing unusual keyboards to generate usable keycodes. -@@ -134,12 +145,14 @@ - config SETLOGCONS - bool "setlogcons" - default y -+ depends on PLATFORM_LINUX - help - This program redirects the output console of kernel messages. - - config SHOWKEY - bool "showkey" - default y -+ depends on PLATFORM_LINUX - help - Shows keys pressed. - -Index: busybox-1.17.1/coreutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/coreutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/coreutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -591,6 +591,7 @@ - config STAT - bool "stat" - default y -+ depends on PLATFORM_LINUX # statfs() - help - display file or filesystem status. - -@@ -606,6 +607,7 @@ - config STTY - bool "stty" - default y -+ depends on PLATFORM_LINUX - help - stty is used to change and print terminal line settings. - -Index: busybox-1.17.1/coreutils/date.c -=================================================================== ---- busybox-1.17.1.orig/coreutils/date.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/coreutils/date.c 2010-08-01 05:32:43.000000000 +0200 -@@ -72,7 +72,7 @@ - //config:config FEATURE_DATE_NANO - //config: bool "Support %[num]N nanosecond format specifier" - //config: default n --//config: depends on DATE -+//config: depends on DATE && PLATFORM_LINUX # syscall(__NR_clock_gettime) - //config: help - //config: Support %[num]N format specifier. Adds ~250 bytes of code. - //config: -Index: busybox-1.17.1/e2fsprogs/Config.src -=================================================================== ---- busybox-1.17.1.orig/e2fsprogs/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/e2fsprogs/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -33,6 +33,7 @@ - config LSATTR - bool "lsattr" - default y -+ depends on PLATFORM_LINUX - help - lsattr lists the file attributes on a second extended file system. - -Index: busybox-1.17.1/init/Config.src -=================================================================== ---- busybox-1.17.1.orig/init/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/init/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config INIT - bool "init" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - init is the first program run when the system boots. -@@ -92,6 +93,7 @@ - config HALT - bool "poweroff, halt, and reboot" - default y -+ depends on PLATFORM_LINUX - help - Stop all processes and either halt, reboot, or power off the system. - -Index: busybox-1.17.1/init/bootchartd.c -=================================================================== ---- busybox-1.17.1.orig/init/bootchartd.c 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/init/bootchartd.c 2010-08-01 05:32:43.000000000 +0200 -@@ -6,6 +6,7 @@ - //config:config BOOTCHARTD - //config: bool "bootchartd" - //config: default y -+//config: depends on PLATFORM_LINUX - //config: help - //config: bootchartd is commonly used to profile the boot process - //config: for the purpose of speeding it up. In this case, it is started -Index: busybox-1.17.1/libbb/Config.src -=================================================================== ---- busybox-1.17.1.orig/libbb/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/libbb/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -153,6 +153,7 @@ - config MONOTONIC_SYSCALL - bool "Use clock_gettime(CLOCK_MONOTONIC) syscall" - default n -+ depends on PLATFORM_LINUX - help - Use clock_gettime(CLOCK_MONOTONIC) syscall for measuring - time intervals (time, ping, traceroute etc need this). -Index: busybox-1.17.1/loginutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/loginutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/loginutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -179,6 +179,7 @@ - config GETTY - bool "getty" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - getty lets you log in on a tty, it is normally invoked by init. -@@ -186,6 +187,7 @@ - config LOGIN - bool "login" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - select FEATURE_SYSLOG - help -@@ -295,6 +297,7 @@ - config VLOCK - bool "vlock" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - help - Build the "vlock" applet which allows you to lock (virtual) terminals. -Index: busybox-1.17.1/miscutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/miscutils/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/miscutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config ADJTIMEX - bool "adjtimex" - default y -+ depends on PLATFORM_LINUX - help - Adjtimex reads and optionally sets adjustment parameters for - the Linux clock adjustment algorithm. -@@ -24,6 +25,7 @@ - config BEEP - bool "beep" - default y -+ depends on PLATFORM_LINUX - help - The beep applets beeps in a given freq/Hz. - -@@ -180,6 +182,7 @@ - config DEVFSD - bool "devfsd (obsolete)" - default n -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - This is deprecated and should NOT be used anymore. -@@ -223,6 +226,7 @@ - config FEATURE_DEVFS - bool "Use devfs names for all devices (obsolete)" - default n -+ depends on PLATFORM_LINUX - help - This is obsolete and should NOT be used anymore. - Use linux >= 2.6 (optionally with hotplug) and mdev instead! -@@ -242,6 +246,7 @@ - config EJECT - bool "eject" - default y -+ depends on PLATFORM_LINUX - help - Used to eject cdroms. (defaults to /dev/cdrom) - -@@ -256,6 +261,7 @@ - config FBSPLASH - bool "fbsplash" - default y -+ depends on PLATFORM_LINUX - help - Shows splash image and progress bar on framebuffer device. - Can be used during boot phase of an embedded device. ~2kb. -@@ -305,6 +311,7 @@ - config IONICE - bool "ionice" - default y -+ depends on PLATFORM_LINUX - help - Set/set program io scheduling class and priority - Requires kernel >= 2.6.13 -@@ -344,6 +351,11 @@ - config LESS - bool "less" - default y -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX -+ depends on PLATFORM_LINUX - help - 'less' is a pager, meaning that it displays text files. It possesses - a wide array of features, and is an improvement over 'more'. -@@ -410,6 +422,7 @@ - config HDPARM - bool "hdparm" - default y -+ depends on PLATFORM_LINUX - help - Get/Set hard drive parameters. Primarily intended for ATA - drives. Adds about 13k (or around 30k if you enable the -@@ -526,6 +539,7 @@ - config RAIDAUTORUN - bool "raidautorun" - default y -+ depends on PLATFORM_LINUX - help - raidautorun tells the kernel md driver to - search and start RAID arrays. -@@ -533,7 +547,7 @@ - config READAHEAD - bool "readahead" - default y -- depends on LFS -+ depends on LFS && PLATFORM_LINUX - help - Preload the files listed on the command line into RAM cache so that - subsequent reads on these files will not block on disk I/O. -@@ -550,6 +564,7 @@ - config RFKILL - bool "rfkill" - default n # doesn't build on Ubuntu 9.04 -+ depends on PLATFORM_LINUX - help - Enable/disable wireless devices. - -@@ -570,6 +585,7 @@ - config RX - bool "rx" - default y -+ depends on PLATFORM_LINUX - help - Receive files using the Xmodem protocol. - -@@ -641,6 +657,7 @@ - config WATCHDOG - bool "watchdog" - default y -+ depends on PLATFORM_LINUX - help - The watchdog utility is used with hardware or software watchdog - device drivers. It opens the specified watchdog device special file -Index: busybox-1.17.1/miscutils/conspy.c -=================================================================== ---- busybox-1.17.1.orig/miscutils/conspy.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/miscutils/conspy.c 2010-08-01 05:32:43.000000000 +0200 -@@ -17,6 +17,7 @@ - //config:config CONSPY - //config: bool "conspy" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: A text-mode VNC like program for Linux virtual terminals. - //config: example: conspy NUM shared access to console num -Index: busybox-1.17.1/miscutils/ubi_attach_detach.c -=================================================================== ---- busybox-1.17.1.orig/miscutils/ubi_attach_detach.c 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/miscutils/ubi_attach_detach.c 2010-08-01 05:32:43.000000000 +0200 -@@ -12,12 +12,14 @@ - //config:config UBIATTACH - //config: bool "ubiattach" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: Attach MTD device to an UBI device. - //config: - //config:config UBIDETACH - //config: bool "ubidetach" - //config: default n -+//config: depends on PLATFORM_LINUX - //config: help - //config: Detach MTD device from an UBI device. - -Index: busybox-1.17.1/modutils/Config.src -=================================================================== ---- busybox-1.17.1.orig/modutils/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/modutils/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -4,6 +4,7 @@ - # - - menu "Linux Module Utilities" -+depends on PLATFORM_LINUX - - INSERT - -Index: busybox-1.17.1/networking/Config.src -=================================================================== ---- busybox-1.17.1.orig/networking/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/networking/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -43,6 +43,7 @@ - config VERBOSE_RESOLUTION_ERRORS - bool "Verbose resolution errors" - default n -+ depends on PLATFORM_LINUX #because of xsocket() in libbb/xfuncs_prinf.c - help - Enable if you are not satisfied with simplistic - "can't resolve 'hostname.com'" and want to know more. -@@ -51,18 +52,21 @@ - config ARP - bool "arp" - default y -+ depends on PLATFORM_LINUX - help - Manipulate the system ARP cache. - - config ARPING - bool "arping" - default y -+ depends on PLATFORM_LINUX - help - Ping hosts by ARP packets. - - config BRCTL - bool "brctl" - default y -+ depends on PLATFORM_LINUX - help - Manage ethernet bridges. - Supports addbr/delbr and addif/delif. -@@ -95,6 +99,7 @@ - config ETHER_WAKE - bool "ether-wake" - default y -+ depends on PLATFORM_LINUX - help - Send a magic packet to wake up sleeping machines. - -@@ -269,6 +274,7 @@ - config IFCONFIG - bool "ifconfig" - default y -+ depends on PLATFORM_LINUX - help - Ifconfig is used to configure the kernel-resident network interfaces. - -@@ -316,6 +322,7 @@ - config IFENSLAVE - bool "ifenslave" - default y -+ depends on PLATFORM_LINUX - help - Userspace application to bind several interfaces - to a logical interface (use with kernel bonding driver). -@@ -323,6 +330,7 @@ - config IFPLUGD - bool "ifplugd" - default y -+ depends on PLATFORM_LINUX - help - Network interface plug detection daemon. - -@@ -364,7 +372,7 @@ - config FEATURE_IFUPDOWN_IP_BUILTIN - bool "Use busybox ip applet" - default y -- depends on FEATURE_IFUPDOWN_IP -+ depends on FEATURE_IFUPDOWN_IP && PLATFORM_LINUX - select IP - select FEATURE_IP_ADDRESS - select FEATURE_IP_LINK -@@ -483,6 +491,7 @@ - config IP - bool "ip" - default y -+ depends on PLATFORM_LINUX - help - The "ip" applet is a TCP/IP interface configuration and routing - utility. You generally don't need "ip" to use busybox with -@@ -598,6 +607,7 @@ - config NAMEIF - bool "nameif" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - nameif is used to rename network interface by its MAC address. -@@ -626,6 +636,7 @@ - config NETSTAT - bool "netstat" - default y -+ depends on PLATFORM_LINUX - help - netstat prints information about the Linux networking subsystem. - -@@ -654,6 +665,7 @@ - config NTPD - bool "ntpd" - default y -+ depends on PLATFORM_LINUX - help - The NTP client/server daemon. - -@@ -668,6 +680,7 @@ - config PING - bool "ping" - default y -+ depends on PLATFORM_LINUX - help - ping uses the ICMP protocol's mandatory ECHO_REQUEST datagram to - elicit an ICMP ECHO_RESPONSE from a host or gateway. -@@ -696,12 +709,14 @@ - config ROUTE - bool "route" - default y -+ depends on PLATFORM_LINUX - help - Route displays or manipulates the kernel's IP routing tables. - - config SLATTACH - bool "slattach" - default y -+ depends on PLATFORM_LINUX - help - slattach is a small utility to attach network interfaces to serial - lines. -@@ -719,6 +734,7 @@ - config TCPSVD - bool "tcpsvd" - default y -+ depends on PLATFORM_LINUX - help - tcpsvd listens on a TCP port and runs a program for each new - connection. -@@ -888,6 +904,7 @@ - config TRACEROUTE - bool "traceroute" - default y -+ depends on PLATFORM_LINUX - help - Utility to trace the route of IP packets. - -@@ -924,6 +941,7 @@ - config TUNCTL - bool "tunctl" - default y -+ depends on PLATFORM_LINUX - help - tunctl creates or deletes tun devices. - -@@ -949,6 +967,7 @@ - config UDPSVD - bool "udpsvd" - default y -+ depends on PLATFORM_LINUX - help - udpsvd listens on an UDP port and runs a program for each new - connection. -@@ -956,6 +975,7 @@ - config VCONFIG - bool "vconfig" - default y -+ depends on PLATFORM_LINUX - help - Creates, removes, and configures VLAN interfaces - -@@ -990,6 +1010,7 @@ - config ZCIP - bool "zcip" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SYSLOG - help - ZCIP provides ZeroConf IPv4 address selection, according to RFC 3927. -Index: busybox-1.17.1/networking/udhcp/Config.src -=================================================================== ---- busybox-1.17.1.orig/networking/udhcp/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/networking/udhcp/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -8,6 +8,7 @@ - config UDHCPD - bool "udhcp server (udhcpd)" - default y -+ depends on PLATFORM_LINUX - help - udhcpd is a DHCP server geared primarily toward embedded systems, - while striving to be fully functional and RFC compliant. -@@ -51,6 +52,7 @@ - config UDHCPC - bool "udhcp client (udhcpc)" - default y -+ depends on PLATFORM_LINUX - help - udhcpc is a DHCP client geared primarily toward embedded systems, - while striving to be fully functional and RFC compliant. -Index: busybox-1.17.1/procps/Config.src -=================================================================== ---- busybox-1.17.1.orig/procps/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/procps/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config FREE - bool "free" - default y -+ depends on PLATFORM_LINUX #sysinfo() - help - free displays the total amount of free and used physical and swap - memory in the system, as well as the buffers used by the kernel. -@@ -104,7 +105,7 @@ - config FEATURE_PS_TIME - bool "Enable time and elapsed time output" - default y -- depends on PS && DESKTOP -+ depends on PS && DESKTOP && PLATFORM_LINUX #sysinfo() - help - Support -o time and -o etime output specifiers. - -@@ -200,6 +201,7 @@ - config UPTIME - bool "uptime" - default y -+ depends on PLATFORM_LINUX #sysinfo() - help - uptime gives a one line display of the current time, how long - the system has been running, how many users are currently logged -Index: busybox-1.17.1/sysklogd/Config.src -=================================================================== ---- busybox-1.17.1.orig/sysklogd/Config.src 2010-07-25 00:12:43.000000000 +0200 -+++ busybox-1.17.1/sysklogd/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -109,6 +109,7 @@ - config KLOGD - bool "klogd" - default y -+ depends on PLATFORM_LINUX - help - klogd is a utility which intercepts and logs all - messages from the Linux kernel and sends the messages -Index: busybox-1.17.1/util-linux/Config.src -=================================================================== ---- busybox-1.17.1.orig/util-linux/Config.src 2010-07-25 00:12:56.000000000 +0200 -+++ busybox-1.17.1/util-linux/Config.src 2010-08-01 05:32:43.000000000 +0200 -@@ -10,6 +10,7 @@ - config ACPID - bool "acpid" - default y -+ depends on PLATFORM_LINUX - help - acpid listens to ACPI events coming either in textual form from - /proc/acpi/event (though it is marked deprecated it is still widely -@@ -32,6 +33,7 @@ - config BLKID - bool "blkid" - default y -+ depends on PLATFORM_LINUX - select VOLUMEID - help - Lists labels and UUIDs of all filesystems. -@@ -41,6 +43,7 @@ - config DMESG - bool "dmesg" - default y -+ depends on PLATFORM_LINUX - help - dmesg is used to examine or control the kernel ring buffer. When the - Linux kernel prints messages to the system log, they are stored in -@@ -74,6 +77,7 @@ - config FBSET - bool "fbset" - default y -+ depends on PLATFORM_LINUX - help - fbset is used to show or change the settings of a Linux frame buffer - device. The frame buffer device provides a simple and unique -@@ -102,6 +106,7 @@ - config FDFLUSH - bool "fdflush" - default y -+ depends on PLATFORM_LINUX - help - fdflush is only needed when changing media on slightly-broken - removable media drives. It is used to make Linux believe that a -@@ -114,12 +119,14 @@ - config FDFORMAT - bool "fdformat" - default y -+ depends on PLATFORM_LINUX - help - fdformat is used to low-level format a floppy disk. - - config FDISK - bool "fdisk" - default y -+ depends on PLATFORM_LINUX - help - The fdisk utility is used to divide hard disks into one or more - logical disks, which are generally called partitions. This utility -@@ -187,6 +194,7 @@ - config FINDFS - bool "findfs" - default y -+ depends on PLATFORM_LINUX - select VOLUMEID - help - Prints the name of a filesystem with given label or UUID. -@@ -202,6 +210,7 @@ - config FREERAMDISK - bool "freeramdisk" - default y -+ depends on PLATFORM_LINUX - help - Linux allows you to create ramdisks. This utility allows you to - delete them and completely free all memory that was used for the -@@ -224,12 +233,14 @@ - config MKFS_EXT2 - bool "mkfs_ext2" - default y -+ depends on PLATFORM_LINUX - help - Utility to create EXT2 filesystems. - - config MKFS_MINIX - bool "mkfs_minix" - default y -+ depends on PLATFORM_LINUX - help - The minix filesystem is a nice, small, compact, read-write filesystem - with little overhead. If you wish to be able to create minix -@@ -247,6 +258,7 @@ - config MKFS_REISER - bool "mkfs_reiser" - default n -+ depends on PLATFORM_LINUX - help - Utility to create ReiserFS filesystems. - Note: this applet needs a lot of testing and polishing. -@@ -254,6 +266,7 @@ - config MKFS_VFAT - bool "mkfs_vfat" - default y -+ depends on PLATFORM_LINUX - help - Utility to create FAT32 filesystems. - -@@ -302,6 +315,7 @@ - config HWCLOCK - bool "hwclock" - default y -+ depends on PLATFORM_LINUX - help - The hwclock utility is used to read and set the hardware clock - on a system. This is primarily used to set the current time on -@@ -341,6 +355,7 @@ - config IPCS - bool "ipcs" - default y -+ depends on PLATFORM_LINUX - select FEATURE_SUID - help - The ipcs utility is used to provide information on the currently -@@ -349,6 +364,7 @@ - config LOSETUP - bool "losetup" - default y -+ depends on PLATFORM_LINUX - help - losetup is used to associate or detach a loop device with a regular - file or block device, and to query the status of a loop device. This -@@ -357,6 +373,7 @@ - config LSPCI - bool "lspci" - default y -+ #depends on PLATFORM_LINUX - help - lspci is a utility for displaying information about PCI buses in the - system and devices connected to them. -@@ -366,6 +383,7 @@ - config LSUSB - bool "lsusb" - default y -+ #depends on PLATFORM_LINUX - help - lsusb is a utility for displaying information about USB buses in the - system and devices connected to them. -@@ -375,6 +393,7 @@ - config MDEV - bool "mdev" - default y -+ depends on PLATFORM_LINUX - help - mdev is a mini-udev implementation for dynamically creating device - nodes in the /dev directory. -@@ -473,6 +492,7 @@ - config MOUNT - bool "mount" - default y -+ depends on PLATFORM_LINUX - help - All files and filesystems in Unix are arranged into one big directory - tree. The 'mount' utility is used to graft a filesystem onto a -@@ -555,6 +575,7 @@ - config PIVOT_ROOT - bool "pivot_root" - default y -+ depends on PLATFORM_LINUX - help - The pivot_root utility swaps the mount points for the root filesystem - with some other mounted filesystem. This allows you to do all sorts -@@ -582,12 +603,14 @@ - config READPROFILE - bool "readprofile" - default y -+ #depends on PLATFORM_LINUX - help - This allows you to parse /proc/profile for basic profiling. - - config RTCWAKE - bool "rtcwake" - default y -+ depends on PLATFORM_LINUX - help - Enter a system sleep state until specified wakeup time. - -@@ -607,6 +630,7 @@ - config SETARCH - bool "setarch" - default y -+ depends on PLATFORM_LINUX - help - The linux32 utility is used to create a 32bit environment for the - specified program (usually a shell). It only makes sense to have -@@ -616,6 +640,7 @@ - config SWAPONOFF - bool "swaponoff" - default y -+ depends on PLATFORM_LINUX - help - This option enables both the 'swapon' and the 'swapoff' utilities. - Once you have created some swap space using 'mkswap', you also need -@@ -634,6 +659,7 @@ - config SWITCH_ROOT - bool "switch_root" - default y -+ depends on PLATFORM_LINUX - help - The switch_root utility is used from initramfs to select a new - root device. Under initramfs, you have to use this instead of -@@ -653,6 +679,7 @@ - config UMOUNT - bool "umount" - default y -+ depends on PLATFORM_LINUX - help - When you want to remove a mounted filesystem from its current mount - point, for example when you are shutting down the system, the -Index: busybox-1.17.1/shell/Config.src -=================================================================== ---- busybox-1.17.1.orig/shell/Config.src 2010-08-01 05:33:24.000000000 +0200 -+++ busybox-1.17.1/shell/Config.src 2010-08-01 05:33:34.000000000 +0200 -@@ -370,6 +370,7 @@ - config CTTYHACK - bool "cttyhack" - default y -+ depends on PLATFORM_LINUX - help - One common problem reported on the mailing list is "can't access tty; - job control turned off" error message which typically appears when diff --git a/packaging/mkdir-fix-p-on-FreeBSD.patch b/packaging/mkdir-fix-p-on-FreeBSD.patch deleted file mode 100644 index fc5bf7f..0000000 --- a/packaging/mkdir-fix-p-on-FreeBSD.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 84b01d5afc8230c79a1b8469c222d940c0d4e792 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:33 +0200 -Subject: [PATCH 7/9] mkdir: fix -p on FreeBSD - -This patch is libbb.make_directory.diff from Debian kFreeBSD at: -http://svn.debian.org/viewsvn/d-i/people/slackydeb/kfreebsd/busybox/1.14/debian - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - libbb/make_directory.c | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) - -diff --git a/libbb/make_directory.c b/libbb/make_directory.c -index 4486eb1..6dd04cf 100644 ---- a/libbb/make_directory.c -+++ b/libbb/make_directory.c -@@ -86,7 +86,7 @@ int FAST_FUNC bb_make_directory(char *path, long mode, int flags) - if (mkdir(path, 0777) < 0) { - /* If we failed for any other reason than the directory - * already exists, output a diagnostic and return -1 */ -- if (errno != EEXIST -+ if ((errno != EEXIST && errno != EISDIR) - || !(flags & FILEUTILS_RECUR) - || ((stat(path, &st) < 0) || !S_ISDIR(st.st_mode)) - ) { --- -1.7.1 - diff --git a/packaging/readlink-use-xmalloc_realpath.patch b/packaging/readlink-use-xmalloc_realpath.patch deleted file mode 100644 index e1103ec..0000000 --- a/packaging/readlink-use-xmalloc_realpath.patch +++ /dev/null @@ -1,50 +0,0 @@ -From b175462422f02a159a14dc5561d8bef6f84b2b66 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:32:19 +0200 -Subject: [PATCH 1/9] readlink: use xmalloc_realpath() - -Using realpath() directly with a non-NULL output buffer is unsafe because its -behavior is unspecified on systems which don't have PATH_MAX (ie. Hurd) - -I beleive this also fixes a small bug whereby 'buf' would not be freed -on 'readlink -v' with ENABLE_FEATURE_CLEANUP. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - coreutils/readlink.c | 5 ++--- - 1 files changed, 2 insertions(+), 3 deletions(-) - -diff --git a/coreutils/readlink.c b/coreutils/readlink.c -index 20df38b..2ed5e2c 100644 ---- a/coreutils/readlink.c -+++ b/coreutils/readlink.c -@@ -36,7 +36,6 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - { - char *buf; - char *fname; -- char pathbuf[PATH_MAX]; - - IF_FEATURE_READLINK_FOLLOW( - unsigned opt; -@@ -56,7 +55,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - logmode = LOGMODE_NONE; - - if (opt & 1) { /* -f */ -- buf = realpath(fname, pathbuf); -+ buf = xmalloc_realpath(fname); - } else { - buf = xmalloc_readlink_or_warn(fname); - } -@@ -65,7 +64,7 @@ int readlink_main(int argc UNUSED_PARAM, char **argv) - return EXIT_FAILURE; - printf((opt & 2) ? "%s" : "%s\n", buf); - -- if (ENABLE_FEATURE_CLEAN_UP && !opt) -+ if (ENABLE_FEATURE_CLEAN_UP) - free(buf); - - fflush_stdout_and_exit(EXIT_SUCCESS); --- -1.7.1 - diff --git a/packaging/sbin.links b/packaging/sbin.links deleted file mode 100644 index a56bbea..0000000 --- a/packaging/sbin.links +++ /dev/null @@ -1,43 +0,0 @@ -blkid -blockdev -depmod -fbsplash -fdisk -fsck.minix -getty -hdparm -hwclock -ifconfig -ifdown -ifenslave -ifup -inotifyd -insmod -ip -iptunnel -klogd -loadkmap -logread -losetup -lsmod -makedevs -mdev -mkdosfs -mkfs.minix -mkfs.vfat -mkswap -modinfo -modprobe -nameif -pivot_root -raidautorun -rmmod -route -setconsole -slattach -swapoff -swapon -switch_root -sysctl -syslogd -vconfig diff --git a/packaging/shell-ash-export-HOME.patch b/packaging/shell-ash-export-HOME.patch deleted file mode 100644 index 0d3c5ab..0000000 --- a/packaging/shell-ash-export-HOME.patch +++ /dev/null @@ -1,11 +0,0 @@ ---- a/shell/ash.c -+++ b/shell/ash.c -@@ -1774,7 +1774,7 @@ - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, - { VSTRFIXED|VTEXTFIXED|VUNSET, "MAILPATH" , changemail }, - #endif -- { VSTRFIXED|VTEXTFIXED , bb_PATH_root_path, changepath }, -+ { VSTRFIXED|VTEXTFIXED|VEXPORT, bb_PATH_root_path, changepath }, - { VSTRFIXED|VTEXTFIXED , "PS1=$ " , NULL }, - { VSTRFIXED|VTEXTFIXED , "PS2=> " , NULL }, - { VSTRFIXED|VTEXTFIXED , "PS4=+ " , NULL }, diff --git a/packaging/shell-hist.patch b/packaging/shell-hist.patch deleted file mode 100644 index 889785a..0000000 --- a/packaging/shell-hist.patch +++ /dev/null @@ -1,117 +0,0 @@ ---- a/libbb/lineedit.c 2009-03-30 17:15:10.000000000 +0300 -+++ b/libbb/lineedit.c 2009-03-31 17:52:48.000000000 +0300 -@@ -959,49 +959,48 @@ - static void load_history(const char *fromfile) - { - FILE *fp; -- int hi; -+ int hi = 0; - -- /* cleanup old */ -- for (hi = state->cnt_history; hi > 0;) { -- hi--; -- free(state->history[hi]); -- } -- -- fp = fopen(fromfile, "r"); -- if (fp) { -- for (hi = 0; hi < MAX_HISTORY;) { -- char *hl = xmalloc_getline(fp); -- int l; -- -- if (!hl) -- break; -- l = strlen(hl); -- if (l >= MAX_LINELEN) -- hl[MAX_LINELEN-1] = '\0'; -- if (l == 0 || hl[0] == ' ') { -- free(hl); -- continue; -+ if (!state->cnt_history) { -+ fp = fopen(fromfile, "r"); -+ if (fp) { -+ for (hi = 0; hi < MAX_HISTORY;) { -+ char *hl = xmalloc_getline(fp); -+ int l; -+ -+ if (!hl) -+ break; -+ l = strlen(hl); -+ if (l >= MAX_LINELEN) -+ hl[MAX_LINELEN-1] = '\0'; -+ if (l == 0 || hl[0] == ' ') { -+ free(hl); -+ continue; -+ } -+ state->history[hi++] = hl; - } -- state->history[hi++] = hl; -+ fclose(fp); - } -- fclose(fp); -+ state->cur_history = state->cnt_history = hi; - } -- state->cur_history = state->cnt_history = hi; - } - - /* state->flags is already checked to be nonzero */ --static void save_history(const char *tofile) -+void save_history(line_input_t *); -+void save_history(line_input_t *st) - { - FILE *fp; - -- fp = fopen(tofile, "w"); -- if (fp) { -- int i; -+ if (st->cnt_history) { -+ fp = fopen(st->hist_file, "w"); -+ if (fp) { -+ int i; - -- for (i = 0; i < state->cnt_history; i++) { -- fprintf(fp, "%s\n", state->history[i]); -+ for (i = 0; i < st->cnt_history; i++) { -+ fprintf(fp, "%s\n", st->history[i]); -+ } -+ fclose(fp); - } -- fclose(fp); - } - } - #else -@@ -1030,10 +1029,6 @@ - state->history[i++] = xstrdup(str); - state->cur_history = i; - state->cnt_history = i; --#if ENABLE_FEATURE_EDITING_SAVEHISTORY -- if ((state->flags & SAVE_HISTORY) && state->hist_file) -- save_history(state->hist_file); --#endif - USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;) - } - -diff -r -u busybox-1.10.2.legal.orig/shell/ash.c busybox-1.10.2.legal/shell/ash.c ---- busybox-1.10.2.legal.orig/shell/ash.c 2008-07-24 10:16:00.000000000 +0100 -+++ busybox-1.10.2.legal/shell/ash.c 2009-03-23 17:09:11.000000000 +0000 -@@ -1733,6 +1733,9 @@ - #if ENABLE_ASH_RANDOM_SUPPORT - static void change_random(const char *); - #endif -+#if ENABLE_FEATURE_EDITING_SAVEHISTORY -+void save_history(line_input_t *); -+#endif - - static const struct { - int flags; -@@ -12815,6 +12818,10 @@ - char *p; - int status; - -+ if (iflag && (line_input_state->flags & SAVE_HISTORY) -+ && line_input_state->hist_file && !shlvl) { -+ save_history(line_input_state); -+ } - status = exitstatus; - TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); - if (setjmp(loc.loc)) { diff --git a/packaging/smack-busybox-1.17.1.patch b/packaging/smack-busybox-1.17.1.patch deleted file mode 100644 index a95697f..0000000 --- a/packaging/smack-busybox-1.17.1.patch +++ /dev/null @@ -1,1604 +0,0 @@ - -Smack updates for busybox-1.17.1 - ---- - - Config.in | 9 ++ - Makefile | 1 - coreutils/id.c | 26 +++++- - coreutils/ls.c | 28 ++++++ - coreutils/stat.c | 87 ++++++++++++++++---- - findutils/find.c | 31 +++++++ - include/applets.src.h | 4 - include/libbb.h | 21 ++++ - include/usage.src.h | 30 ++++++- - libbb/Kbuild.src | 1 - libbb/messages.c | 3 - libbb/procps.c | 6 + - libbb/smack_common.c | 178 ++++++++++++++++++++++++++++++++++++++++++ - loginutils/adduser.c | 13 ++- - loginutils/login.c | 8 + - loginutils/su.c | 8 + - loginutils/sulogin.c | 6 + - miscutils/crond.c | 11 ++ - miscutils/crontab.c | 13 +++ - procps/ps.c | 48 +++++++++-- - smack/Config.src | 40 +++++++++ - smack/Kbuild.src | 14 +++ - smack/newsmack.c | 61 ++++++++++++++ - smack/smackcipso.c | 119 ++++++++++++++++++++++++++++ - smack/smackenabled.c | 17 ++++ - smack/smackload.c | 93 +++++++++++++++++++++ - 26 files changed, 844 insertions(+), 32 deletions(-) - -diff -uprN busybox-1.17.1/Config.in busybox-1.17.1-smack/Config.in ---- busybox-1.17.1/Config.in 2010-07-24 15:12:56.000000000 -0700 -+++ busybox-1.17.1-smack/Config.in 2011-08-17 15:27:12.889107702 -0700 -@@ -370,6 +370,14 @@ config SELINUX - - Most people will leave this set to 'N'. - -+config SMACK -+ bool "Support Smack" -+ default n -+ help -+ Enable support for Smack in applets ls, ps, and id. Also provide -+ the option of compiling in Smack applets. -+ -+ - config FEATURE_PREFER_APPLETS - bool "exec prefers applets" - default n -@@ -739,4 +747,5 @@ source procps/Config.in - source runit/Config.in - source selinux/Config.in - source shell/Config.in -+source smack/Config.in - source sysklogd/Config.in -diff -uprN busybox-1.17.1/coreutils/id.c busybox-1.17.1-smack/coreutils/id.c ---- busybox-1.17.1/coreutils/id.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/id.c 2011-08-17 15:27:12.889107702 -0700 -@@ -34,6 +34,9 @@ enum { - #if ENABLE_SELINUX - JUST_CONTEXT = (1 << 5), - #endif -+#if ENABLE_SMACK -+ JUST_LABEL = (1 << 5), -+#endif - }; - - static int print_common(unsigned id, const char *name, const char *prefix) -@@ -116,11 +119,15 @@ int id_main(int argc UNUSED_PARAM, char - #if ENABLE_SELINUX - security_context_t scontext = NULL; - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+#endif - /* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/ - /* Don't allow more than one username */ - opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG" -- IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); -- opt = getopt32(argv, "rnugG" IF_SELINUX("Z")); -+ IF_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G") -+ IF_SMACK(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G"); -+ opt = getopt32(argv, "rnugG" IF_SELINUX("Z") IF_SMACK("Z")); - - username = argv[optind]; - if (username) { -@@ -187,6 +194,10 @@ int id_main(int argc UNUSED_PARAM, char - printf(" context=%s", scontext); - } - #endif -+#if ENABLE_SMACK -+ if (smack_from_proc(-1, smack, sizeof(smack)) == 0) -+ printf(" label=%s", smack); -+#endif - } else if (opt & PRINT_REAL) { - euid = ruid; - egid = rgid; -@@ -205,6 +216,17 @@ int id_main(int argc UNUSED_PARAM, char - } - fputs(scontext, stdout); - } -+#endif -+#if ENABLE_SMACK -+ else if (opt & JUST_LABEL) { -+ if (username || smack_from_proc(-1, smack, sizeof(smack)) < 0) { -+ bb_error_msg_and_die("can't get process label%s", -+ username ? " for a different user" : ""); -+ } -+ fputs(smack, stdout); -+ } -+#endif -+#if ENABLE_SELINUX - /* freecon(NULL) seems to be harmless */ - if (ENABLE_FEATURE_CLEAN_UP) - freecon(scontext); -diff -uprN busybox-1.17.1/coreutils/ls.c busybox-1.17.1-smack/coreutils/ls.c ---- busybox-1.17.1/coreutils/ls.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/ls.c 2011-08-17 16:23:44.839147638 -0700 -@@ -141,6 +141,7 @@ static const char ls_options[] ALIGN1 = - IF_FEATURE_LS_RECURSIVE("R") /* 1, 25 */ - IF_FEATURE_HUMAN_READABLE("h") /* 1, 26 */ - IF_SELINUX("KZ") /* 2, 28 */ -+ IF_SMACK("KZ") /* 2, 28 */ - IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */ - ; - enum { -@@ -165,6 +166,7 @@ enum { - + 1 * ENABLE_FEATURE_LS_RECURSIVE - + 1 * ENABLE_FEATURE_HUMAN_READABLE - + 2 * ENABLE_SELINUX -+ + 2 * ENABLE_SMACK - + 2 * ENABLE_FEATURE_AUTOWIDTH, - OPT_color = 1 << OPTBIT_color, - }; -@@ -191,6 +193,7 @@ static const unsigned opt_flags[] = { - 0, /* Q (quote filename) - handled via OPT_Q */ - DISP_HIDDEN, /* A */ - ENABLE_SELINUX * LIST_CONTEXT, /* k (ignored if !SELINUX) */ -+ ENABLE_SMACK * LIST_CONTEXT, /* k (ignored if !SMACK) */ - #if ENABLE_FEATURE_LS_TIMESTAMPS - TIME_CHANGE | (ENABLE_FEATURE_LS_SORTFILES * SORT_CTIME), /* c */ - LIST_FULLTIME, /* e */ -@@ -216,10 +219,10 @@ static const unsigned opt_flags[] = { - #if ENABLE_FEATURE_HUMAN_READABLE - LS_DISP_HR, /* h */ - #endif --#if ENABLE_SELINUX -+#if ENABLE_SELINUX || ENABLE_SMACK - LIST_MODEBITS|LIST_NLINKS|LIST_CONTEXT|LIST_SIZE|LIST_DATE_TIME, /* K */ - #endif --#if ENABLE_SELINUX -+#if ENABLE_SELINUX || ENABLE_SMACK - LIST_MODEBITS|LIST_ID_NAME|LIST_CONTEXT, /* Z */ - #endif - (1U<<31) -@@ -239,6 +242,7 @@ struct dnode { - smallint fname_allocated; - struct stat dstat; /* the file stat info */ - IF_SELINUX(security_context_t sid;) -+ IF_SMACK(char xattr[SMACKBUFFSIZE];) - }; - - struct globals { -@@ -288,6 +292,10 @@ static struct dnode *my_stat(const char - struct stat dstat; - struct dnode *cur; - IF_SELINUX(security_context_t sid = NULL;) -+#if ENABLE_SMACK -+ char xattr[SMACKBUFFSIZE]; -+ int i; -+#endif - - if ((all_fmt & FOLLOW_LINKS) || force_follow) { - #if ENABLE_SELINUX -@@ -295,6 +303,11 @@ static struct dnode *my_stat(const char - getfilecon(fullname, &sid); - } - #endif -+#if ENABLE_SMACK -+ i = smack_from_file(fullname, xattr, sizeof(xattr), 1); -+ if (i < 0) -+ xattr[0] = '\0'; -+#endif - if (stat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; -@@ -306,6 +319,11 @@ static struct dnode *my_stat(const char - lgetfilecon(fullname, &sid); - } - #endif -+#if ENABLE_SMACK -+ i = smack_from_file(fullname, xattr, sizeof(xattr), 0); -+ if (i < 0) -+ xattr[0] = '\0'; -+#endif - if (lstat(fullname, &dstat)) { - bb_simple_perror_msg(fullname); - exit_code = EXIT_FAILURE; -@@ -318,6 +336,7 @@ static struct dnode *my_stat(const char - cur->name = name; - cur->dstat = dstat; - IF_SELINUX(cur->sid = sid;) -+ IF_SMACK(strncpy(cur->xattr, xattr, sizeof(xattr));) - return cur; - } - -@@ -685,6 +704,10 @@ static NOINLINE unsigned list_single(con - freecon(dn->sid); - } - #endif -+#if ENABLE_SMACK -+ if (all_fmt & LIST_CONTEXT) -+ column += printf("%-23s ", dn->xattr); -+#endif - if (all_fmt & LIST_FILENAME) { - #if ENABLE_FEATURE_LS_COLOR - if (show_color) { -@@ -753,6 +776,7 @@ static void showfiles(struct dnode **dn, - } - column_width += tabstops + - IF_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + ) -+ IF_SMACK( ((all_fmt & LIST_CONTEXT) ? 24 : 0) + ) - ((all_fmt & LIST_INO) ? 8 : 0) + - ((all_fmt & LIST_BLOCKS) ? 5 : 0); - ncols = (int) (terminal_width / column_width); -diff -uprN busybox-1.17.1/coreutils/stat.c busybox-1.17.1-smack/coreutils/stat.c ---- busybox-1.17.1/coreutils/stat.c 2010-07-05 19:25:53.000000000 -0700 -+++ busybox-1.17.1-smack/coreutils/stat.c 2011-08-18 17:01:04.060191320 -0700 -@@ -18,6 +18,7 @@ - #define OPT_TERSE (1 << 1) - #define OPT_DEREFERENCE (1 << 2) - #define OPT_SELINUX (1 << 3) -+#define OPT_SMACK (1 << 4) - - #if ENABLE_FEATURE_STAT_FORMAT - typedef bool (*statfunc_ptr)(const char *, const char *); -@@ -154,7 +155,8 @@ static void printfs(char *pformat, const - /* 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)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack)) - { - const struct statfs *statfsbuf = data; - if (m == 'n') { -@@ -192,6 +194,10 @@ static void FAST_FUNC print_statfs(char - } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { - printfs(pformat, scontext); - # endif -+#if ENABLE_SMACK -+ } else if (m == 'C' && (option_mask32 & OPT_SMACK)) { -+ printfs(pformat, smack); -+#endif - } else { - strcatc(pformat, 'c'); - printf(pformat, m); -@@ -201,7 +207,8 @@ static void FAST_FUNC print_statfs(char - /* 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)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack)) - { - #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1)) - struct stat *statbuf = (struct stat *) data; -@@ -296,6 +303,10 @@ static void FAST_FUNC print_stat(char *p - } else if (m == 'C' && (option_mask32 & OPT_SELINUX)) { - printfs(pformat, scontext); - # endif -+#if ENABLE_SMACK -+ } else if (m == 'C' && (option_mask32 & OPT_SMACK)) { -+ printfs(pformat, smack); -+#endif - } else { - strcatc(pformat, 'c'); - printf(pformat, m); -@@ -304,9 +315,10 @@ static void FAST_FUNC print_stat(char *p - - 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)), -+ void FAST_FUNC (*print_func)(char*, char, const char*, const void* IF_SELINUX(, security_context_t scontext) IF_SMACK(, char *smack)), - const void *data -- IF_SELINUX(, security_context_t scontext)) -+ IF_SELINUX(, security_context_t scontext) -+ IF_SMACK(, char *smack) ) - { - /* Create a working copy of the format string */ - char *format = xstrdup(masterformat); -@@ -349,7 +361,7 @@ static void print_it(const char *masterf - break; - default: - /* Completes "%" with specifier and printfs */ -- print_func(dest, *p, filename, data IF_SELINUX(,scontext)); -+ print_func(dest, *p, filename, data IF_SELINUX(,scontext) IF_SMACK(,smack) ); - break; - } - } -@@ -383,6 +395,18 @@ static bool do_statfs(const char *filena - } - } - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+ -+ if (option_mask32 & OPT_SMACK) { -+ int i = option_mask32 & OPT_DEREFERENCE; -+ -+ if (smack_from_file(filename, smack, sizeof(smack), i) < 0) { -+ bb_perror_msg("%s", filename); -+ return 0; -+ } -+ } -+#endif - if (statfs(filename, &statfsbuf) != 0) { - bb_perror_msg("can't read file system information for '%s'", filename); - return 0; -@@ -390,7 +414,7 @@ static bool do_statfs(const char *filena - - #if ENABLE_FEATURE_STAT_FORMAT - if (format == NULL) { --# if !ENABLE_SELINUX -+# if !ENABLE_SELINUX && !ENABLE_SMACK - format = (option_mask32 & OPT_TERSE - ? "%n %i %l %t %s %b %f %a %c %d\n" - : " File: \"%n\"\n" -@@ -400,9 +424,9 @@ static bool do_statfs(const char *filena - "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": -+ ? (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? "%n %i %l %t %s %b %f %a %c %d %C\n": - "%n %i %l %t %s %b %f %a %c %d\n") -- : (option_mask32 & OPT_SELINUX ? -+ : (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: \"%n\"\n" - " ID: %-8i Namelen: %-7l Type: %T\n" - "Block size: %-10s\n" -@@ -415,9 +439,9 @@ static bool do_statfs(const char *filena - "Blocks: Total: %-10b Free: %-10f Available: %a\n" - "Inodes: Total: %-10c Free: %d\n") - ); --# endif /* SELINUX */ -+# endif /* SELINUX or Smack */ - } -- print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext)); -+ print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext) IF_SMACK(, smack) ); - #else /* FEATURE_STAT_FORMAT */ - format = (option_mask32 & OPT_TERSE - ? "%s %llx %lu " -@@ -433,7 +457,7 @@ static bool do_statfs(const char *filena - else - printf("Type: %s\n", human_fstype(statfsbuf.f_type)); - --# if !ENABLE_SELINUX -+# if !ENABLE_SELINUX && !ENABLE_SMACK - format = (option_mask32 & OPT_TERSE - ? "%lu %llu %llu %llu %llu %llu\n" - : "Block size: %-10lu\n" -@@ -448,8 +472,8 @@ static bool do_statfs(const char *filena - (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 -+ ? (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? "%lu %llu %llu %llu %llu %llu %C\n" : "%lu %llu %llu %llu %llu %llu\n") -+ : (option_mask32 & (OPT_SELINUX | OPT_SMACK) - ? "Block size: %-10lu\n" - "Blocks: Total: %-10llu Free: %-10llu Available: %llu\n" - "Inodes: Total: %-10llu Free: %llu" -@@ -496,6 +520,18 @@ static bool do_stat(const char *filename - } - } - #endif -+#if ENABLE_SMACK -+ char smack[SMACKBUFFSIZE]; -+ -+ if (option_mask32 & OPT_SMACK) { -+ int i = option_mask32 & OPT_DEREFERENCE; -+ -+ if (smack_from_file(filename, smack, sizeof(smack), i) < 0) { -+ bb_perror_msg("%s", filename); -+ return 0; -+ } -+ } -+#endif - if ((option_mask32 & OPT_DEREFERENCE ? stat : lstat) (filename, &statbuf) != 0) { - bb_perror_msg("can't stat '%s'", filename); - return 0; -@@ -503,7 +539,7 @@ static bool do_stat(const char *filename - - #if ENABLE_FEATURE_STAT_FORMAT - if (format == NULL) { --# if !ENABLE_SELINUX -+#if !ENABLE_SELINUX && !ENABLE_SMACK - if (option_mask32 & OPT_TERSE) { - format = "%n %s %b %f %u %g %D %i %h %t %T %X %Y %Z %o"; - } else { -@@ -526,12 +562,12 @@ static bool do_stat(const char *filename - } - # else - if (option_mask32 & OPT_TERSE) { -- format = (option_mask32 & OPT_SELINUX ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - "%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 ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %-5h" -@@ -546,7 +582,7 @@ static bool do_stat(const char *filename - "Access: (%04a/%10.10A) Uid: (%5u/%8U) Gid: (%5g/%8G)\n" - "Access: %x\n" "Modify: %y\n" "Change: %z\n"); - } else { -- format = (option_mask32 & OPT_SELINUX ? -+ format = (option_mask32 & (OPT_SELINUX | OPT_SMACK) ? - " File: %N\n" - " Size: %-10s\tBlocks: %-10b IO Block: %-6o %F\n" - "Device: %Dh/%dd\tInode: %-10i Links: %h\n" -@@ -562,11 +598,14 @@ static bool do_stat(const char *filename - } - # endif - } -- print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext)); -+ print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext) IF_SMACK(, smack) ); - #else /* FEATURE_STAT_FORMAT */ - if (option_mask32 & OPT_TERSE) { -+#if !ENABLE_SELINUX && !ENABLE_SMACK -+ printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu\n" -+#else - printf("%s %llu %llu %lx %lu %lu %llx %llu %lu %lx %lx %lu %lu %lu %lu" -- IF_NOT_SELINUX("\n"), -+#endif - filename, - (unsigned long long) statbuf.st_size, - (unsigned long long) statbuf.st_blocks, -@@ -589,6 +628,12 @@ static bool do_stat(const char *filename - else - bb_putchar('\n'); - # endif -+#if ENABLE_SMACK -+ if (option_mask32 & OPT_SMACK) -+ printf(" %lc\n", smack); -+ else -+ bb_putchar('\n'); -+#endif - } else { - char *linkname = NULL; - -@@ -632,6 +677,9 @@ static bool do_stat(const char *filename - # if ENABLE_SELINUX - printf(" S_Context: %lc\n", *scontext); - # endif -+#if ENABLE_SMACK -+ printf(" Smack: %lc\n", smack); -+#endif - printf("Access: %s\n" "Modify: %s\n" "Change: %s\n", - human_time(statbuf.st_atime), - human_time(statbuf.st_mtime), -@@ -653,6 +701,7 @@ int stat_main(int argc UNUSED_PARAM, cha - opt_complementary = "-1"; /* min one arg */ - opts = getopt32(argv, "ftL" - IF_SELINUX("Z") -+ IF_SMACK("Z") - IF_FEATURE_STAT_FORMAT("c:", &format) - ); - if (opts & OPT_FILESYS) /* -f */ -diff -uprN busybox-1.17.1/findutils/find.c busybox-1.17.1-smack/findutils/find.c ---- busybox-1.17.1/findutils/find.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/findutils/find.c 2011-08-18 17:39:38.790218576 -0700 -@@ -223,6 +223,13 @@ - //config: help - //config: Support the 'find -context' option for matching security context. - //config: -+//config:config FEATURE_FIND_SMACK -+//config: bool "Enable -smack: Smack label matching" -+//config: default n -+//config: depends on FIND && SMACK -+//config: help -+//config: Support the 'find -smack' option for matching Smack label. -+//config: - //config:config FEATURE_FIND_LINKS - //config: bool "Enable -links: link count matching" - //config: default y -@@ -268,6 +275,7 @@ IF_FEATURE_FIND_INUM( ACTS(inum, ino_ - IF_FEATURE_FIND_USER( ACTS(user, uid_t uid;)) - IF_FEATURE_FIND_SIZE( ACTS(size, char size_char; off_t size;)) - IF_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;)) -+IF_FEATURE_FIND_SMACK( ACTS(smack, const char *smack;)) - IF_FEATURE_FIND_PAREN( ACTS(paren, action ***subexpr;)) - IF_FEATURE_FIND_PRUNE( ACTS(prune)) - IF_FEATURE_FIND_DELETE( ACTS(delete)) -@@ -573,6 +581,17 @@ ACTF(context) - return rc == 0; - } - #endif -+#if ENABLE_FEATURE_FIND_SMACK -+ACTF(smack) -+{ -+ char smack[SMACKBUFFSIZE]; -+ -+ if (smack_from_file(fileName, smack, SMACKBUFFSIZE, -+ (G.recurse_flags & ACTION_FOLLOWLINKS) ? 1 : 0) < 0) -+ return FALSE; -+ return strcmp(ap->smack, smack) == 0; -+} -+#endif - #if ENABLE_FEATURE_FIND_LINKS - ACTF(links) - { -@@ -704,6 +723,7 @@ static action*** parse_params(char **arg - IF_FEATURE_FIND_GROUP( PARM_group ,) - IF_FEATURE_FIND_SIZE( PARM_size ,) - IF_FEATURE_FIND_CONTEXT(PARM_context ,) -+ IF_FEATURE_FIND_SMACK( PARM_smack ,) - IF_FEATURE_FIND_LINKS( PARM_links ,) - }; - -@@ -738,6 +758,7 @@ static action*** parse_params(char **arg - IF_FEATURE_FIND_GROUP( "-group\0" ) - IF_FEATURE_FIND_SIZE( "-size\0" ) - IF_FEATURE_FIND_CONTEXT("-context\0") -+ IF_FEATURE_FIND_SMACK( "-smack\0" ) - IF_FEATURE_FIND_LINKS( "-links\0" ) - ; - -@@ -1028,6 +1049,13 @@ static action*** parse_params(char **arg - bb_simple_perror_msg(arg1); - } - #endif -+#if ENABLE_FEATURE_FIND_SMACK -+ else if (parm == PARM_smack) { -+ action_smack *ap; -+ ap = ALLOC_ACTION(smack); -+ ap->smack = arg1; -+ } -+#endif - #if ENABLE_FEATURE_FIND_LINKS - else if (parm == PARM_links) { - action_links *ap; -@@ -1115,6 +1143,9 @@ static action*** parse_params(char **arg - //usage: IF_FEATURE_FIND_CONTEXT( - //usage: "\n -context File has specified security context" - //usage: ) -+//usage: IF_FEATURE_FIND_CONTEXT( -+//usage: "\n -smack File has specified Smack label" -+//usage: ) - //usage: IF_FEATURE_FIND_EXEC( - //usage: "\n -exec CMD ARG ; Run CMD with all instances of {} replaced by the" - //usage: "\n matching files" -diff -uprN busybox-1.17.1/include/applets.src.h busybox-1.17.1-smack/include/applets.src.h ---- busybox-1.17.1/include/applets.src.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/applets.src.h 2011-08-18 11:40:15.809964682 -0700 -@@ -279,6 +279,7 @@ IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_D - IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_DROP)) - IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_DROP)) -+IF_NEWSMACK(APPLET(newsmack, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) - IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_DROP)) - IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -@@ -356,6 +357,9 @@ IF_SHA512SUM(APPLET_ODDNAME(sha512sum, m - IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_DROP)) - IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_DROP)) - IF_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_DROP, sleep)) -+IF_SMACKCIPSO(APPLET(smackcipso, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -+IF_SMACKENABLED(APPLET(smackenabled, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) -+IF_SMACKLOAD(APPLET(smackload, _BB_DIR_USR_SBIN, _BB_SUID_DROP)) - IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_DROP, softlimit)) - IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_DROP, sort)) - IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_DROP)) -diff -uprN busybox-1.17.1/include/libbb.h busybox-1.17.1-smack/include/libbb.h ---- busybox-1.17.1/include/libbb.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/libbb.h 2011-08-18 11:54:34.569974792 -0700 -@@ -52,6 +52,12 @@ - #include - #include - #endif -+#if ENABLE_SMACK -+#define SMACKBUFFSIZE 24 -+#define SMACKATTR "security.SMACK64" -+#define SMACKFLOOR "_" -+#define SMACKSTAR "*" -+#endif - #if ENABLE_LOCALE_SUPPORT - # include - #else -@@ -1183,6 +1189,16 @@ extern void selinux_preserve_fcontext(in - #endif - extern void selinux_or_die(void) FAST_FUNC; - -+#if ENABLE_SMACK -+extern int smack_from_file(const char *path, char *result, int len, int follow); -+extern int smack_from_proc(const int pid, char *result, int len); -+extern int smack_to_file(const char *path, const char *smack, int follow); -+extern int smack_to_proc(const int pid, const char *smack); -+extern int smack_user_default(const char *user, char *result, int len); -+extern int smack_user_allowed(const char *user, const char *smack); -+extern int smack_user_add(const char *user, const char *smack); -+#endif -+ - /* setup_environment: - * if chdir pw->pw_dir: ok: else if to_tmp == 1: goto /tmp else: goto / or die - * if clear_env = 1: cd(pw->pw_dir), clear environment, then set -@@ -1391,6 +1407,7 @@ typedef struct procps_status_t { - char *argv0; - char *exe; - IF_SELINUX(char *context;) -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - /* Everything below must contain no ptrs to malloc'ed data: - * it is memset(0) for each process in procps_scan() */ - unsigned long vsz, rss; /* we round it to kbytes */ -@@ -1453,6 +1470,7 @@ enum { - || ENABLE_SESTATUS - ), - PSSCAN_CONTEXT = (1 << 17) * ENABLE_SELINUX, -+ PSSCAN_SMACK = (1 << 17) * ENABLE_SMACK, - PSSCAN_START_TIME = 1 << 18, - PSSCAN_CPU = (1 << 19) * ENABLE_FEATURE_TOP_SMP_PROCESS, - PSSCAN_NICE = (1 << 20) * ENABLE_FEATURE_PS_ADDITIONAL_COLUMNS, -@@ -1574,6 +1592,9 @@ extern const char bb_path_group_file[]; - extern const char bb_path_motd_file[]; - extern const char bb_path_wtmp_file[]; - extern const char bb_dev_null[]; -+#if ENABLE_SMACK -+extern const char bb_path_smack_user[]; -+#endif - extern const char bb_busybox_exec_path[]; - extern const char *bb_busybox_exec_paths[]; - /* util-linux manpage says /sbin:/bin:/usr/sbin:/usr/bin, -diff -uprN busybox-1.17.1/include/usage.src.h busybox-1.17.1-smack/include/usage.src.h ---- busybox-1.17.1/include/usage.src.h 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/include/usage.src.h 2011-08-18 12:10:12.649985839 -0700 -@@ -1764,6 +1764,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Print the security context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Print the Smack label" \ -+ ) \ - "\n -u Print user ID" \ - "\n -g Print group ID" \ - "\n -G Print supplementary group IDs" \ -@@ -2982,6 +2985,11 @@ INSERT - "\n -p Display PID/Program name for sockets" \ - ) - -+#define newsmack_trivial_usage \ -+ "label [COMMAND [ARG] ...]" -+#define newsmack_full_usage \ -+ "Run a program or shell with the specified Smack label" \ -+ - #define nmeter_trivial_usage \ - "format_string" - #define nmeter_full_usage "\n\n" \ -@@ -3303,7 +3311,7 @@ INSERT - - #else /* !ENABLE_DESKTOP */ - --#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE -+#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE && !ENABLE_SMACK - #define USAGE_PS "\nThis version of ps accepts no options" - #else - #define USAGE_PS "\nOptions:" -@@ -3317,6 +3325,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Show selinux context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Show Smack label" \ -+ ) \ - IF_FEATURE_PS_WIDE( \ - "\n w Wide output" \ - ) -@@ -3845,6 +3856,17 @@ INSERT - "$ sleep 1d 3h 22m 8s\n" \ - "[98528 second delay results]\n") - -+#define smackcipso_trivial_usage -+#define smackcipso_full_usage \ -+ "Read and set Smack CIPSO mappings from the standard input" -+ -+#define smackenabled_trivial_usage -+#define smackenabled_full_usage -+ -+#define smackload_trivial_usage -+#define smackload_full_usage \ -+ "Read and set Smack access rules from the standard input" -+ - #define sort_trivial_usage \ - "[-nru" \ - IF_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") \ -@@ -3982,6 +4004,9 @@ INSERT - IF_SELINUX( \ - "\n -Z Print security context" \ - ) \ -+ IF_SMACK( \ -+ "\n -Z Print Smack label" \ -+ ) \ - IF_FEATURE_STAT_FORMAT( \ - "\n\nValid format sequences for files:\n" \ - " %a Access rights in octal\n" \ -@@ -4019,6 +4044,9 @@ INSERT - IF_SELINUX( \ - " %C Security context in selinux\n" \ - ) \ -+ IF_SMACK( \ -+ " %C Smack label\n" \ -+ ) \ - " %i File System ID in hex\n" \ - " %l Maximum length of filenames\n" \ - " %n File name\n" \ -diff -uprN busybox-1.17.1/libbb/Kbuild.src busybox-1.17.1-smack/libbb/Kbuild.src ---- busybox-1.17.1/libbb/Kbuild.src 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/Kbuild.src 2011-08-18 15:10:58.330113541 -0700 -@@ -126,6 +126,7 @@ lib-$(CONFIG_FEATURE_UTMP) += utmp.o - # A mix of optimizations (why build stuff we know won't be used) - # and objects which may fail to build (SELinux on selinux-less system) - lib-$(CONFIG_SELINUX) += selinux_common.o -+lib-$(CONFIG_SMACK) += smack_common.o - lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o - lib-$(CONFIG_UNICODE_SUPPORT) += unicode.o - lib-$(CONFIG_FEATURE_CHECK_NAMES) += die_if_bad_username.o -diff -uprN busybox-1.17.1/libbb/messages.c busybox-1.17.1-smack/libbb/messages.c ---- busybox-1.17.1/libbb/messages.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/messages.c 2011-08-17 15:27:12.889107702 -0700 -@@ -43,6 +43,9 @@ const char bb_path_shadow_file[] ALIGN1 - const char bb_path_group_file[] ALIGN1 = "/etc/group"; - const char bb_path_gshadow_file[] ALIGN1 = "/etc/gshadow"; - const char bb_path_motd_file[] ALIGN1 = "/etc/motd"; -+#if ENABLE_SMACK -+const char bb_path_smack_user[] ALIGN1 = "/etc/smack/user"; -+#endif - const char bb_dev_null[] ALIGN1 = "/dev/null"; - const char bb_busybox_exec_path[] ALIGN1 = CONFIG_BUSYBOX_EXEC_PATH; - const char *bb_busybox_exec_paths[] ALIGN1 = { -diff -uprN busybox-1.17.1/libbb/procps.c busybox-1.17.1-smack/libbb/procps.c ---- busybox-1.17.1/libbb/procps.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/libbb/procps.c 2011-08-17 15:27:12.909107701 -0700 -@@ -240,6 +240,12 @@ procps_status_t* FAST_FUNC procps_scan(p - sp->context = NULL; - } - #endif -+#if ENABLE_SMACK -+ if (flags & PSSCAN_SMACK) { -+ if (smack_from_proc(sp->pid, sp->smack, SMACKBUFFSIZE) < 0) -+ strcpy(sp->smack, "?"); -+ } -+#endif - - filename_tail = filename + sprintf(filename, "/proc/%u/", pid); - -diff -uprN busybox-1.17.1/libbb/smack_common.c busybox-1.17.1-smack/libbb/smack_common.c ---- busybox-1.17.1/libbb/smack_common.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/libbb/smack_common.c 2011-08-18 17:17:53.730203208 -0700 -@@ -0,0 +1,178 @@ -+/* -+ * libbb/smack_common.c -+ * -- common Smack utility functions -+ * -+ * Copyright 2007 Casey Schaufler -+ */ -+#include "libbb.h" -+#include -+ -+#define SMACKPROCPATH "/proc/%d/attr/current" -+#define SMACKUSERFILE "/etc/smack/user" -+#define SMACKFILELINE 256 -+ -+int smack_from_file(const char *path, char *result, int len, int follow) -+{ -+ char buffer[SMACKBUFFSIZE]; -+ int rc; -+ -+ if (follow) -+ rc = getxattr(path, SMACKATTR, buffer, SMACKBUFFSIZE - 1); -+ else -+ rc = lgetxattr(path, SMACKATTR, buffer, SMACKBUFFSIZE - 1); -+ -+ if (rc < 0) -+ return rc; -+ -+ buffer[rc] = '\0'; -+ if (strlen(buffer) > len) -+ return -EINVAL; -+ -+ strcpy(result, buffer); -+ return rc; -+} -+ -+int smack_from_proc(const int pid, char *result, int len) -+{ -+ char path[SMACKFILELINE]; -+ char buffer[SMACKFILELINE]; -+ int fd; -+ int i; -+ -+ sprintf(path, SMACKPROCPATH, (pid < 0) ? getpid() : pid); -+ -+ fd = open(path, O_RDONLY); -+ if (fd < 0) -+ return -EACCES; -+ -+ i = read(fd, buffer, SMACKFILELINE); -+ close(fd); -+ -+ if (i <= 0 || i >= len) -+ return -ERANGE; -+ buffer[i] = '\0'; -+ strcpy(result, buffer); -+ return 0; -+} -+ -+int smack_to_file(const char *path, const char *smack, int follow) -+{ -+ if (follow) -+ return setxattr(path, SMACKATTR, smack, strlen(smack)+1, 0); -+ return lsetxattr(path, SMACKATTR, smack, strlen(smack)+1, 0); -+} -+ -+int smack_to_proc(const int pid, const char *smack) -+{ -+ char path[SMACKFILELINE]; -+ int fd; -+ int i; -+ int slen; -+ -+ slen = strlen(smack) + 1; -+ if (slen >= SMACKBUFFSIZE) -+ return -ERANGE; -+ -+ sprintf(path, SMACKPROCPATH, (pid < 0) ? getpid() : pid); -+ -+ fd = open(path, O_RDWR); -+ if (fd < 0) -+ return -EACCES; -+ -+ i = write(fd, smack, slen); -+ close(fd); -+ -+ if (i != slen) -+ return -EINVAL; -+ return 0; -+} -+ -+int smack_user_default(const char *user, char *result, int len) -+{ -+ char line[SMACKFILELINE]; -+ char ruser[SMACKFILELINE]; -+ char rsmack[SMACKFILELINE]; -+ FILE *fp; -+ -+ fp = fopen(bb_path_smack_user, "r"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ if (sscanf(line, "%s %s", ruser, rsmack) != 2) -+ continue; -+ if (strcmp(ruser, user) != 0) -+ continue; -+ if (strlen(rsmack) >= len) -+ return -ERANGE; -+ strcpy(result, rsmack); -+ return 0; -+ } -+ return -ENOENT; -+} -+ -+int smack_user_allowed(const char *user, const char *smack) -+{ -+ char line[SMACKFILELINE]; -+ char *ruser; -+ char *rsmack; -+ FILE *fp; -+ int rc = 1; -+ -+ fp = fopen(SMACKUSERFILE, "r"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (rc == 1 && fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ -+ ruser = strtok(line, " \t\n"); -+ if (ruser == NULL) -+ continue; -+ -+ if (strcmp(ruser, user) != 0) -+ continue; -+ -+ while (rc == 1 && (rsmack = strtok(NULL, " \t\n")) != NULL) { -+ if (strcmp(rsmack, smack) == 0 || strcmp(rsmack, "+") == 0) -+ rc = 0; -+ } -+ } -+ fclose(fp); -+ return (rc == 1) ? -ENOENT : rc; -+} -+ -+int smack_user_add(const char *user, const char *smack) -+{ -+ char line[SMACKFILELINE]; -+ char *ruser; -+ FILE *fp; -+ int rc = 0; -+ -+ fp = fopen(SMACKUSERFILE, "a+"); -+ if (fp == NULL) -+ return -ENOENT; -+ -+ while (fgets(line, SMACKFILELINE, fp) != NULL) { -+ if (line[0] == '#' || line[0] == '\n') -+ continue; -+ -+ ruser = strtok(line, " \t\n"); -+ if (ruser == NULL) -+ continue; -+ -+ if (strcmp(ruser, user) == 0) { -+ rc = -EEXIST; -+ break; -+ } -+ } -+ -+ if (rc == 0) -+ fprintf(fp, "%s %s\n", user, smack); -+ -+ fclose(fp); -+ return rc; -+} -diff -uprN busybox-1.17.1/loginutils/adduser.c busybox-1.17.1-smack/loginutils/adduser.c ---- busybox-1.17.1/loginutils/adduser.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/adduser.c 2011-08-17 15:27:12.909107701 -0700 -@@ -112,6 +112,7 @@ int adduser_main(int argc UNUSED_PARAM, - const char *usegroup = NULL; - char *p; - unsigned opts; -+ IF_SMACK(const char *smack = SMACKSTAR;) - - #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS - applet_long_options = adduser_longopts; -@@ -130,10 +131,10 @@ int adduser_main(int argc UNUSED_PARAM, - /* disable interactive passwd for system accounts */ - opt_complementary = "=1:SD:u+"; - if (sizeof(pw.pw_uid) == sizeof(int)) { -- opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid); -+ opts = getopt32(argv, "h:g:s:G:DSHu:" IF_SMACK("L:"), &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &pw.pw_uid IF_SMACK(, &smack) ); - } else { - unsigned uid; -- opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid); -+ opts = getopt32(argv, "h:g:s:G:DSHu:" IF_SMACK("L:"), &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid IF_SMACK(, &smack) ); - if (opts & OPT_UID) { - pw.pw_uid = uid; - } -@@ -220,6 +221,14 @@ int adduser_main(int argc UNUSED_PARAM, - bb_simple_perror_msg(pw.pw_dir); - } - } -+#if ENABLE_SMACK -+ if (smack_user_add(pw.pw_name, smack) < 0) -+ bb_error_msg("cannot add user smack entry"); -+ if (strtok(smack, " \t") != NULL) -+ if (smack_to_file(pw.pw_dir, smack, 0) != 0) -+ bb_error_msg("cannot set smack on home directory"); -+#endif -+ - - if (!(opts & OPT_DONT_SET_PASS)) { - /* interactively set passwd */ -diff -uprN busybox-1.17.1/loginutils/login.c busybox-1.17.1-smack/loginutils/login.c ---- busybox-1.17.1/loginutils/login.c 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/login.c 2011-08-17 15:27:12.909107701 -0700 -@@ -218,6 +218,7 @@ int login_main(int argc UNUSED_PARAM, ch - struct passwd pwdstruct; - char pwdbuf[256]; - #endif -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - username[0] = '\0'; - signal(SIGALRM, alarm_handler); -@@ -376,6 +377,13 @@ int login_main(int argc UNUSED_PARAM, ch - die_if_nologin(); - - IF_SELINUX(initselinux(username, full_tty, &user_sid)); -+#if ENABLE_SMACK -+ if (smack_user_default(pw->pw_name, smack, SMACKBUFFSIZE) < 0) -+ strcpy(smack, SMACKFLOOR); -+ if (smack_to_proc(-1, smack) < 0) -+ bb_perror_msg_and_die("cannot set smack"); -+#endif -+ - - /* Try these, but don't complain if they fail. - * _f_chown is safe wrt race t=ttyname(0);...;chown(t); */ -diff -uprN busybox-1.17.1/loginutils/su.c busybox-1.17.1-smack/loginutils/su.c ---- busybox-1.17.1/loginutils/su.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/su.c 2011-08-18 15:13:07.830115065 -0700 -@@ -44,6 +44,7 @@ int su_main(int argc UNUSED_PARAM, char - const char *tty; - char user_buf[64]; - const char *old_user; -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - flags = getopt32(argv, "mplc:s:", &opt_command, &opt_shell); - //argc -= optind; -@@ -129,6 +130,13 @@ int su_main(int argc UNUSED_PARAM, char - + (!(flags & SU_OPT_mp) * SETUP_ENV_CHANGEENV), - pw); - IF_SELINUX(set_current_security_context(NULL);) -+#if ENABLE_SMACK -+ if (smack_from_proc(-1, smack, SMACKBUFFSIZE) < 0) -+ bb_error_msg_and_die("cannot identify process smack"); -+ if (smack_user_allowed(pw->pw_name, smack) < 0) -+ bb_error_msg_and_die("new usr not allowed current smack"); -+#endif -+ - - /* Never returns */ - run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv); -diff -uprN busybox-1.17.1/loginutils/sulogin.c busybox-1.17.1-smack/loginutils/sulogin.c ---- busybox-1.17.1/loginutils/sulogin.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/loginutils/sulogin.c 2011-08-17 15:27:12.909107701 -0700 -@@ -26,6 +26,7 @@ int sulogin_main(int argc UNUSED_PARAM, - char buffer[256]; - struct spwd spw; - #endif -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - logmode = LOGMODE_BOTH; - openlog(applet_name, 0, LOG_AUTH); -@@ -97,6 +98,11 @@ int sulogin_main(int argc UNUSED_PARAM, - bb_info_msg("System Maintenance Mode"); - - IF_SELINUX(renew_current_security_context()); -+#if ENABLE_SMACK -+ if (smack_to_proc(-1, SMACKFLOOR) < 0) -+ bb_error_msg("login incorrect"); -+#endif -+ - - shell = getenv("SUSHELL"); - if (!shell) -diff -uprN busybox-1.17.1/Makefile busybox-1.17.1-smack/Makefile ---- busybox-1.17.1/Makefile 2010-07-24 15:13:44.000000000 -0700 -+++ busybox-1.17.1-smack/Makefile 2011-08-17 15:27:12.909107701 -0700 -@@ -482,6 +482,7 @@ libs-y := \ - runit/ \ - selinux/ \ - shell/ \ -+ smack/ \ - sysklogd/ \ - util-linux/ \ - util-linux/volume_id/ \ -diff -uprN busybox-1.17.1/miscutils/crond.c busybox-1.17.1-smack/miscutils/crond.c ---- busybox-1.17.1/miscutils/crond.c 2010-07-24 15:12:43.000000000 -0700 -+++ busybox-1.17.1-smack/miscutils/crond.c 2011-08-17 15:27:12.909107701 -0700 -@@ -906,6 +906,7 @@ static void RunJob(const char *user, Cro - { - struct passwd *pas; - pid_t pid; -+ IF_SMACK(char smack[SMACKBUFFSIZE];) - - /* prepare things before vfork */ - pas = getpwnam(user); -@@ -919,6 +920,16 @@ static void RunJob(const char *user, Cro - pid = vfork(); - if (pid == 0) { - /* CHILD */ -+#if ENABLE_SMACK -+ if (smack_user_default(user, smack, SMACKBUFFSIZE) < 0) { -+ crondlog("\024user %s default smack unknown\n", user); -+ exit(0); -+ } -+ if (smack_to_proc(-1, smack) < 0) { -+ crondlog("\024user %s smack unsettable\n", user); -+ exit(0); -+ } -+#endif - /* change running state to the user in question */ - ChangeUser(pas); - if (DebugOpt) { -diff -uprN busybox-1.17.1/miscutils/crontab.c busybox-1.17.1-smack/miscutils/crontab.c ---- busybox-1.17.1/miscutils/crontab.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/miscutils/crontab.c 2011-08-17 15:27:12.909107701 -0700 -@@ -77,6 +77,10 @@ int crontab_main(int argc UNUSED_PARAM, - int fd; - int src_fd; - int opt_ler; -+#if ENABLE_SMACK -+ char psmack[SMACKBUFFSIZE]; -+ char dsmack[SMACKBUFFSIZE]; -+#endif - - /* file [opts] Replace crontab from file - * - [opts] Replace crontab from stdin -@@ -120,6 +124,15 @@ int crontab_main(int argc UNUSED_PARAM, - if ((opt_ler - 1) & opt_ler) /* more than one bit set? */ - bb_show_usage(); - -+#if ENABLE_SMACK -+ if (smack_user_default(pas->pw_name, dsmack, SMACKBUFFSIZE) < 0) -+ bb_perror_msg_and_die("user default smack unknown"); -+ if (smack_from_proc(-1, psmack, SMACKBUFFSIZE) < 0) -+ bb_perror_msg_and_die("user default smack unknown"); -+ if (strcmp(dsmack, psmack) != 0) -+ bb_perror_msg_and_die("current smack is not default smack"); -+#endif -+ - /* Read replacement file under user's UID/GID/group vector */ - src_fd = STDIN_FILENO; - if (!opt_ler) { /* Replace? */ -diff -uprN busybox-1.17.1/procps/ps.c busybox-1.17.1-smack/procps/ps.c ---- busybox-1.17.1/procps/ps.c 2010-07-05 19:25:54.000000000 -0700 -+++ busybox-1.17.1-smack/procps/ps.c 2011-08-18 17:28:10.070210464 -0700 -@@ -25,7 +25,12 @@ enum { MAX_WIDTH = 2*1024 }; - #if ENABLE_SELINUX - #define SELINUX_O_PREFIX "label," - #define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") --#else -+#endif -+#if ENABLE_SMACK -+#define SMACK_O_PREFIX "label," -+#define DEFAULT_O_STR (SMACK_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") -+#endif -+#if !ENABLE_SELINUX && !ENABLE_SMACK - #define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") - #endif - -@@ -288,6 +293,13 @@ static void func_label(char *buf, int si - } - #endif - -+#if ENABLE_SMACK -+static void func_label(char *buf, int size, const procps_status_t *ps) -+{ -+ safe_strncpy(buf, ps->smack[0] ? ps->smack : "?", size+1); -+} -+#endif -+ - /* - static void func_nice(char *buf, int size, const procps_status_t *ps) - { -@@ -327,6 +339,9 @@ static const ps_out_t out_spec[] = { - #if ENABLE_SELINUX - { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, - #endif -+#if ENABLE_SMACK -+ { 24 , "label" ,"LABEL" ,func_label ,PSSCAN_SMACK }, -+#endif - }; - - static ps_out_t* new_out_t(void) -@@ -516,6 +531,12 @@ int ps_main(int argc UNUSED_PARAM, char - strcpy(default_o, DEFAULT_O_STR + sizeof(SELINUX_O_PREFIX)-1); - } else - #endif -+#if ENABLE_SMACK -+ if (!(opt & 1)) { -+ /* no -Z : do not show LABEL */ -+ strcpy(default_o, DEFAULT_O_STR + sizeof(SMACK_O_PREFIX) -1); -+ } else -+#endif - { - strcpy(default_o, DEFAULT_O_STR); - } -@@ -557,17 +578,17 @@ int ps_main(int argc UNUSED_PARAM, char - | PSSCAN_STATE | PSSCAN_VSZ | PSSCAN_COMM; - unsigned terminal_width IF_NOT_FEATURE_PS_WIDE(= 79); - enum { -- OPT_Z = (1 << 0) * ENABLE_SELINUX, -- OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, -+ OPT_Z = (1 << 0) * (ENABLE_SELINUX | ENABLE_SMACK), -+ OPT_T = (1 << (ENABLE_SELINUX | ENABLE_SMACK)) * ENABLE_FEATURE_SHOW_THREADS, - }; - int opts = 0; - /* If we support any options, parse argv */ --#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE -+#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_SMACK - # if ENABLE_FEATURE_PS_WIDE - /* -w is a bit complicated */ - int w_count = 0; - opt_complementary = "-:ww"; -- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); -+ opts = getopt32(argv, IF_SELINUX("Z")IF_SMACK("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); - /* if w is given once, GNU ps sets the width to 132, - * if w is given more than once, it is "unlimited" - */ -@@ -582,7 +603,7 @@ int ps_main(int argc UNUSED_PARAM, char - # else - /* -w is not supported, only -Z and/or -T */ - opt_complementary = "-"; -- opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); -+ opts = getopt32(argv, IF_SELINUX("Z")IF_SMACK("Z")IF_FEATURE_SHOW_THREADS("T")); - # endif - #endif - -@@ -593,6 +614,13 @@ int ps_main(int argc UNUSED_PARAM, char - puts(" PID CONTEXT STAT COMMAND"); - } else - #endif -+#if ENABLE_SMACK -+ if (opts & OPT_Z) { -+ psscan_flags = PSSCAN_PID | PSSCAN_SMACK -+ | PSSCAN_STATE | PSSCAN_COMM; -+ puts(" PID CONTEXT STAT COMMAND"); -+ } else -+#endif - { - puts(" PID USER VSZ STAT COMMAND"); - } -@@ -611,6 +639,14 @@ int ps_main(int argc UNUSED_PARAM, char - p->state); - } else - #endif -+#if ENABLE_SMACK -+ if (psscan_flags & PSSCAN_SMACK) { -+ len = printf("%5u %-24.24s %s ", -+ p->pid, -+ p->smack ? p->smack : "unknown", -+ p->state); -+ } else -+#endif - { - const char *user = get_cached_username(p->uid); - //if (p->vsz == 0) -diff -uprN busybox-1.17.1/smack/Config.src busybox-1.17.1-smack/smack/Config.src ---- busybox-1.17.1/smack/Config.src 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/Config.src 2011-08-18 11:19:44.669950186 -0700 -@@ -0,0 +1,40 @@ -+# -+# For a description of the syntax of this configuration file, -+# see scripts/kbuild/config-language.txt. -+# -+ -+menu "Smack Utilities" -+ depends on SMACK -+ -+INSERT -+ -+config SMACKLOAD -+ bool "smackload" -+ default n -+ depends on SMACK -+ help -+ Enable support to load Smack access rules. -+ -+config SMACKCIPSO -+ bool "smackcipso" -+ default n -+ depends on SMACK -+ help -+ Enable support to specify Smack CIPSO mappings. -+ -+config NEWSMACK -+ bool "newsmack" -+ default n -+ depends on SMACK -+ help -+ Enable support to run command with specified Smack label. -+ -+config SMACKENABLED -+ bool "smackenabled" -+ default n -+ depends on SMACK -+ help -+ Enable support for this command to be used within shell scripts -+ to determine if smack is enabled. -+ -+endmenu -diff -uprN busybox-1.17.1/smack/Kbuild.src busybox-1.17.1-smack/smack/Kbuild.src ---- busybox-1.17.1/smack/Kbuild.src 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/Kbuild.src 2011-08-19 13:22:11.301054005 -0700 -@@ -0,0 +1,14 @@ -+# Makefile for busybox -+# -+# Copyright (C) 1999-2005 by Erik Andersen -+# Copyright (C) 2007 by KaiGai Kohei -+# -+# Licensed under the GPL v2, see the file LICENSE in this tarball. -+ -+INSERT -+ -+lib-y:= -+lib-$(CONFIG_NEWSMACK) += newsmack.o -+lib-$(CONFIG_SMACKLOAD) += smackload.o -+lib-$(CONFIG_SMACKCIPSO) += smackcipso.o -+lib-$(CONFIG_SMACKENABLED) += smackenabled.o -diff -uprN busybox-1.17.1/smack/newsmack.c busybox-1.17.1-smack/smack/newsmack.c ---- busybox-1.17.1/smack/newsmack.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/newsmack.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,61 @@ -+/* -+ * newsmack label [ command [ arg ] ... ] -+ * -+ * Port to busybox: Casey Schaufler -+ * -+ * Copyright (C) 2007 Casey Schaufler -+ * -+ */ -+ -+#include "libbb.h" -+ -+int newsmack_main(int argc, char **argv); -+int newsmack_main(int argc, char **argv) -+{ -+ struct passwd *pwd; -+ char *newargv[256]; /* yes, I know */ -+ char *smack; -+ int i; -+ int newargc; -+ -+ if (argc <= 1) -+ bb_error_msg_and_die("No smack value specified"); -+ -+ smack = argv[1]; -+ -+ /* -+ * Start a shell if no command is specified -+ */ -+ if (argc == 2) { -+ fprintf(stderr, "%s: start a shell at \"%s\"\n", -+ argv[0], smack); -+ newargv[0] = strdup("sh"); -+ newargv[1] = NULL; -+ } else { -+ for (newargc = 0, i = 2; i < argc; newargc++, i++) -+ newargv[newargc] = argv[i]; -+ newargv[newargc] = NULL; -+ } -+ -+ /* -+ * Verify the user is allowed the Smack label -+ */ -+ pwd = getpwuid(getuid()); -+ if (pwd == NULL) -+ bb_error_msg_and_die("User name not obtained"); -+ if (smack_user_allowed(pwd->pw_name, smack) != 0) -+ bb_error_msg_and_die("User not allowed this smack label"); -+ /* -+ * Set the process label. -+ */ -+ i = smack_to_proc(-1, smack); -+ if (i < 0) -+ bb_error_msg_and_die("Cannot set smack"); -+ -+ /* -+ * Do the exec -+ */ -+ execvp(newargv[0], newargv); -+ -+ bb_error_msg_and_die("%s: exec failure.", newargv[0]); -+} -diff -uprN busybox-1.17.1/smack/smackcipso.c busybox-1.17.1-smack/smack/smackcipso.c ---- busybox-1.17.1/smack/smackcipso.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/smackcipso.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,119 @@ -+/* -+ * smackcipso - properly format smack access cipsos for -+ * loading into the kernel by writing to /smack/cipso. -+ * -+ * Copyright (C) 2007 Casey Schaufler -+ * -+ * This program is free software; 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. -+ * -+ * Authors: -+ * Casey Schaufler -+ * Ahmed S. Darwish -+ * -+ */ -+/* -+#include -+#include -+#include -+#include -+#include -+#include -+#include -+*/ -+#include "libbb.h" -+ -+#define LSIZE 23 -+#define NSIZE 4 -+#define MAXCATNUM 239 -+#define MAXCATVAL 63 -+#define MAXLEVEL 255 -+ -+int smackcipso_main(int argc, char **argv); -+int smackcipso_main(int argc, char **argv) -+{ -+ int status = EXIT_SUCCESS; -+ int cipsofd; -+ char line[512]; -+ char cipso[LSIZE + NSIZE + NSIZE + (NSIZE * MAXCATNUM)]; -+ char cats[MAXCATNUM+1][NSIZE+1]; -+ char *cp; -+ int level; -+ int cat; -+ int catcount; -+ int i; -+ int err; -+ -+ cipsofd = open("/smack/cipso", O_RDWR); -+ if (cipsofd < 0) -+ bb_error_msg_and_die("failed opening /smack/cipso"); -+ -+ while (fgets(line, sizeof(line), stdin) != NULL) { -+ catcount = 0; -+ err = 0; -+ -+ if ((cp = strchr(line, '\n')) == NULL) { -+ fprintf(stderr, "missing newline \"%s\"\n", line); -+ continue; -+ } -+ *cp = '\0'; -+ cp = strtok(line, " \t"); -+ if (cp == NULL) { -+ fprintf(stderr, "Empty line: \"%s\"\n", line); -+ continue; -+ } -+ sprintf(cipso, "%-23s ", line); -+ if (strlen(cipso) != 24) { -+ fprintf(stderr, "Bad label starting: \"%s\"\n", line); -+ continue; -+ } -+ cp = strtok(NULL, " \t"); -+ if (cp == NULL) { -+ fprintf(stderr, "Missing level: \"%s\"\n", line); -+ continue; -+ } -+ if (!isdigit(*cp)) { -+ fprintf(stderr, "Bad level: \"%s\"\n", cp); -+ continue; -+ } -+ level = atoi(cp); -+ if (level > MAXLEVEL) { -+ fprintf(stderr, "Bad level: \"%s\"\n", cp); -+ continue; -+ } -+ sprintf(cipso+LSIZE+1, "%-4d", level); -+ -+ cp = strtok(NULL, " \t"); -+ for (i = 0; cp != NULL; cp = strtok(NULL, " \t"), i++) { -+ if (!isdigit(*cp)) { -+ fprintf(stderr, "Bad category \"%s\"\n", cp); -+ err = 1; -+ break; -+ } -+ cat = atoi(cp); -+ if (i >= MAXCATNUM) { -+ fprintf(stderr, "Maximum number of categories" -+ "exceeded \"%d\"\n", i); -+ err = 1; -+ break; -+ } -+ if (cat > MAXCATVAL) { -+ fprintf(stderr, "Bad category \"%s\"\n", cp); -+ err = 1; -+ break; -+ } -+ sprintf(cats[i], "%-4d", cat); -+ } -+ if (err) -+ continue; -+ -+ sprintf(cipso+LSIZE+1+NSIZE, "%-4d", i); -+ while (i > 0) -+ strcat(cipso, cats[--i]); -+ err = write(cipsofd, cipso, strlen(cipso)); -+ if (err < 0) -+ perror("writing /smack/cipso"); -+ } -+ return status; -+} -diff -uprN busybox-1.17.1/smack/smackenabled.c busybox-1.17.1-smack/smack/smackenabled.c ---- busybox-1.17.1/smack/smackenabled.c 1969-12-31 16:00:00.000000000 -0800 -+++ busybox-1.17.1-smack/smack/smackenabled.c 2011-08-17 15:27:12.909107701 -0700 -@@ -0,0 +1,17 @@ -+/* -+ * smackenabled -+ * -+ * Port to BusyBox Casey Schaufler -+ * -+ * This program is free software; 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. -+ * -+ * Author: -+ * Casey Schaufler -+ */ -+/* -+#include -+#include -+#include -+#include -+#include -+#include -+*/ -+#include "libbb.h" -+ -+#define LSIZE 23 -+#define ASIZE 4 -+ -+int smackload_main(int argc, char **argv); -+int smackload_main(int argc, char **argv) -+{ -+ int status = EXIT_SUCCESS; -+ int loadfd; -+ char line[80]; -+ char rule[LSIZE + LSIZE + ASIZE + 3]; -+ char subject[LSIZE+1]; -+ char object[LSIZE+1]; -+ char accesses[ASIZE+1]; -+ char real[ASIZE+1]; -+ char *cp; -+ int i; -+ int err; -+ -+ loadfd = open("/smack/load", O_RDWR); -+ if (loadfd < 0) -+ bb_error_msg_and_die("failed opening /smack/load"); -+ -+ while (fgets(line, 80, stdin) != NULL) { -+ err = 0; -+ if ((cp = strchr(line, '\n')) != NULL) -+ *cp = '\0'; -+ if (sscanf(line,"%23s %23s %4s",subject,object,accesses) != 3) -+ err = 1; -+ else { -+ strcpy(real, "----"); -+ for (i = 0; -+ i < ASIZE && accesses[i] != '\0' && err == 0; -+ i++) { -+ switch (accesses[i]) { -+ case 'r': -+ case 'R': -+ real[0] = 'r'; -+ break; -+ case 'w': -+ case 'W': -+ real[1] = 'w'; -+ break; -+ case 'x': -+ case 'X': -+ real[2] = 'x'; -+ break; -+ case 'a': -+ case 'A': -+ real[3] = 'a'; -+ break; -+ case '\0': -+ case '-': -+ break; -+ default: -+ err = 1; -+ break; -+ } -+ } -+ } -+ if (err == 0) { -+ sprintf(rule, "%-23s %-23s %4s", subject,object,real); -+ err = write(loadfd, rule, LSIZE + LSIZE + ASIZE + 2); -+ if (err < 0) -+ perror("writing /smack/load"); -+ } -+ else -+ fprintf(stderr, "Bad input line \"%s\"\n", line); -+ } -+ return status; -+} diff --git a/packaging/smack-conflict-with-selinux.patch b/packaging/smack-conflict-with-selinux.patch deleted file mode 100644 index 8e9d425..0000000 --- a/packaging/smack-conflict-with-selinux.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 0bfd7de40919494aa4a2cada5ca4c475d1a87b66 Mon Sep 17 00:00:00 2001 -From: Karol Lewandowski -Date: Wed, 11 Jan 2012 11:21:15 +0100 -Subject: [PATCH] Don't allow SELINUX and SMACK to be enabled at the same time - -Source code simply doesn't support it. ---- - Config.in | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) - -diff --git a/Config.in b/Config.in -index 76c2b68..cac552c 100644 ---- a/Config.in -+++ b/Config.in -@@ -385,6 +385,7 @@ config SELINUX - config SMACK - bool "Support Smack" - default n -+ depends on !SELINUX - help - Enable support for Smack in applets ls, ps, and id. Also provide - the option of compiling in Smack applets. --- -1.7.7.3 - diff --git a/packaging/strip.patch b/packaging/strip.patch deleted file mode 100644 index 1188e67..0000000 --- a/packaging/strip.patch +++ /dev/null @@ -1,24 +0,0 @@ ---- a/Makefile -+++ b/Makefile -@@ -690,20 +690,10 @@ - endif # ifdef CONFIG_KALLSYMS - - # busybox image - including updated kernel symbols --busybox_unstripped: $(busybox-all) FORCE -+busybox: $(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) ; diff --git a/packaging/stty-sort-out-preprocessor-conditionals.patch b/packaging/stty-sort-out-preprocessor-conditionals.patch deleted file mode 100644 index e078f3d..0000000 --- a/packaging/stty-sort-out-preprocessor-conditionals.patch +++ /dev/null @@ -1,705 +0,0 @@ -From 138ce54c9c1930348bc842be781accd7c50c2cef Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Fri, 30 Jul 2010 06:01:37 +0200 -Subject: [PATCH 2/2] stty: sort out preprocessor conditionals - -* Move the definitions of missing constants to the top of the file. -* Fix undefined IDX_xxx on missing termios constants. -* FreeBSD has TABDLY, TAB0 and TAB3, but no TAB1 or TAB2 -* Omit the definition of set_window_size() if TIOCGWINSZ is not available. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - coreutils/Config.src | 1 - - coreutils/stty.c | 339 +++++++++++++++++++++++++++++++------------------ - 2 files changed, 214 insertions(+), 126 deletions(-) - -diff --git a/coreutils/Config.src b/coreutils/Config.src -index 780b73f..0eb70af 100644 ---- a/coreutils/Config.src -+++ b/coreutils/Config.src -@@ -607,7 +607,6 @@ config FEATURE_STAT_FORMAT - config STTY - bool "stty" - default y -- depends on PLATFORM_LINUX - help - stty is used to change and print terminal line settings. - -diff --git a/coreutils/stty.c b/coreutils/stty.c -index c40d718..33f7b21 100644 ---- a/coreutils/stty.c -+++ b/coreutils/stty.c -@@ -115,6 +115,113 @@ - # 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 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 -+ - /* Which speeds to set */ - enum speed_setting { - input_speed, output_speed, both_speeds -@@ -167,13 +274,13 @@ enum { - IDX_cbreak, - IDX_crt, - IDX_dec, --#ifdef IXANY -+#if IXANY - IDX_decctlq, - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - IDX_tabs, - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - IDX_lcase, - IDX_LCASE, - #endif -@@ -196,13 +303,13 @@ static const char mode_name[] = - MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("crt", combination, OMIT, 0, 0 ) - MI_ENTRY("dec", combination, OMIT, 0, 0 ) --#ifdef IXANY -+#if IXANY - MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) - #endif -@@ -217,7 +324,7 @@ static const char mode_name[] = - MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) - MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) - MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) --#ifdef CRTSCTS -+#if CRTSCTS - MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) - #endif - MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) -@@ -232,74 +339,78 @@ static const char mode_name[] = - MI_ENTRY("ixon", input, REV, IXON, 0 ) - MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) --#ifdef IUCLC -+#if IUCLC - MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) - #endif --#ifdef IXANY -+#if IXANY - MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) - #endif --#ifdef IMAXBEL -+#if IMAXBEL - MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) - #endif - MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) --#ifdef OLCUC -+#if OLCUC - MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) - #endif --#ifdef OCRNL -+#if OCRNL - MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) - #endif --#ifdef ONLCR -+#if ONLCR - MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) - #endif --#ifdef ONOCR -+#if ONOCR - MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) - #endif --#ifdef ONLRET -+#if ONLRET - MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) - #endif --#ifdef OFILL -+#if OFILL - MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) - #endif --#ifdef OFDEL -+#if OFDEL - MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) - #endif --#ifdef NLDLY -+#if NLDLY - MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) - MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) - #endif --#ifdef CRDLY -+#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 - --#ifdef TABDLY -+#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 --# ifdef OXTABS -+# if OXTABS - MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) - # endif - #endif - --#ifdef BSDLY -+#if BSDLY - MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) - MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) - #endif --#ifdef VTDLY -+#if VTDLY - MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) - MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) - #endif --#ifdef FFDLY -+#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 ) --#ifdef IEXTEN -+#if IEXTEN - MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) - #endif - MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) -@@ -308,21 +419,21 @@ static const char mode_name[] = - MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) - MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) - MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) --#ifdef XCASE -+#if XCASE - MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) - #endif --#ifdef TOSTOP -+#if TOSTOP - MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) - #endif --#ifdef ECHOPRT -+#if ECHOPRT - MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) - #endif --#ifdef ECHOCTL -+#if ECHOCTL - MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) - #endif --#ifdef ECHOKE -+#if ECHOKE - MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) - #endif -@@ -346,13 +457,13 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("cbreak", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("crt", combination, OMIT, 0, 0 ) - MI_ENTRY("dec", combination, OMIT, 0, 0 ) --#ifdef IXANY -+#if IXANY - MI_ENTRY("decctlq", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(TABDLY) || defined(OXTABS) -+#if TABDLY || OXTABS - MI_ENTRY("tabs", combination, REV | OMIT, 0, 0 ) - #endif --#if defined(XCASE) && defined(IUCLC) && defined(OLCUC) -+#if XCASE && IUCLC && OLCUC - MI_ENTRY("lcase", combination, REV | OMIT, 0, 0 ) - MI_ENTRY("LCASE", combination, REV | OMIT, 0, 0 ) - #endif -@@ -367,7 +478,7 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("cstopb", control, REV, CSTOPB, 0 ) - MI_ENTRY("cread", control, SANE_SET | REV, CREAD, 0 ) - MI_ENTRY("clocal", control, REV, CLOCAL, 0 ) --#ifdef CRTSCTS -+#if CRTSCTS - MI_ENTRY("crtscts", control, REV, CRTSCTS, 0 ) - #endif - MI_ENTRY("ignbrk", input, SANE_UNSET | REV, IGNBRK, 0 ) -@@ -382,74 +493,78 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("ixon", input, REV, IXON, 0 ) - MI_ENTRY("ixoff", input, SANE_UNSET | REV, IXOFF, 0 ) - MI_ENTRY("tandem", input, REV | OMIT, IXOFF, 0 ) --#ifdef IUCLC -+#if IUCLC - MI_ENTRY("iuclc", input, SANE_UNSET | REV, IUCLC, 0 ) - #endif --#ifdef IXANY -+#if IXANY - MI_ENTRY("ixany", input, SANE_UNSET | REV, IXANY, 0 ) - #endif --#ifdef IMAXBEL -+#if IMAXBEL - MI_ENTRY("imaxbel", input, SANE_SET | REV, IMAXBEL, 0 ) - #endif - MI_ENTRY("opost", output, SANE_SET | REV, OPOST, 0 ) --#ifdef OLCUC -+#if OLCUC - MI_ENTRY("olcuc", output, SANE_UNSET | REV, OLCUC, 0 ) - #endif --#ifdef OCRNL -+#if OCRNL - MI_ENTRY("ocrnl", output, SANE_UNSET | REV, OCRNL, 0 ) - #endif --#ifdef ONLCR -+#if ONLCR - MI_ENTRY("onlcr", output, SANE_SET | REV, ONLCR, 0 ) - #endif --#ifdef ONOCR -+#if ONOCR - MI_ENTRY("onocr", output, SANE_UNSET | REV, ONOCR, 0 ) - #endif --#ifdef ONLRET -+#if ONLRET - MI_ENTRY("onlret", output, SANE_UNSET | REV, ONLRET, 0 ) - #endif --#ifdef OFILL -+#if OFILL - MI_ENTRY("ofill", output, SANE_UNSET | REV, OFILL, 0 ) - #endif --#ifdef OFDEL -+#if OFDEL - MI_ENTRY("ofdel", output, SANE_UNSET | REV, OFDEL, 0 ) - #endif --#ifdef NLDLY -+#if NLDLY - MI_ENTRY("nl1", output, SANE_UNSET, NL1, NLDLY) - MI_ENTRY("nl0", output, SANE_SET, NL0, NLDLY) - #endif --#ifdef CRDLY -+#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 - --#ifdef TABDLY -+#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 --# ifdef OXTABS -+# if OXTABS - MI_ENTRY("tab3", output, SANE_UNSET, OXTABS, 0 ) - # endif - #endif - --#ifdef BSDLY -+#if BSDLY - MI_ENTRY("bs1", output, SANE_UNSET, BS1, BSDLY) - MI_ENTRY("bs0", output, SANE_SET, BS0, BSDLY) - #endif --#ifdef VTDLY -+#if VTDLY - MI_ENTRY("vt1", output, SANE_UNSET, VT1, VTDLY) - MI_ENTRY("vt0", output, SANE_SET, VT0, VTDLY) - #endif --#ifdef FFDLY -+#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 ) --#ifdef IEXTEN -+#if IEXTEN - MI_ENTRY("iexten", local, SANE_SET | REV, IEXTEN, 0 ) - #endif - MI_ENTRY("echo", local, SANE_SET | REV, ECHO, 0 ) -@@ -458,21 +573,21 @@ static const struct mode_info mode_info[] = { - MI_ENTRY("echok", local, SANE_SET | REV, ECHOK, 0 ) - MI_ENTRY("echonl", local, SANE_UNSET | REV, ECHONL, 0 ) - MI_ENTRY("noflsh", local, SANE_UNSET | REV, NOFLSH, 0 ) --#ifdef XCASE -+#if XCASE - MI_ENTRY("xcase", local, SANE_UNSET | REV, XCASE, 0 ) - #endif --#ifdef TOSTOP -+#if TOSTOP - MI_ENTRY("tostop", local, SANE_UNSET | REV, TOSTOP, 0 ) - #endif --#ifdef ECHOPRT -+#if ECHOPRT - MI_ENTRY("echoprt", local, SANE_UNSET | REV, ECHOPRT, 0 ) - MI_ENTRY("prterase", local, REV | OMIT, ECHOPRT, 0 ) - #endif --#ifdef ECHOCTL -+#if ECHOCTL - MI_ENTRY("echoctl", local, SANE_SET | REV, ECHOCTL, 0 ) - MI_ENTRY("ctlecho", local, REV | OMIT, ECHOCTL, 0 ) - #endif --#ifdef ECHOKE -+#if ECHOKE - MI_ENTRY("echoke", local, SANE_SET | REV, ECHOKE, 0 ) - MI_ENTRY("crtkill", local, REV | OMIT, ECHOKE, 0 ) - #endif -@@ -497,31 +612,31 @@ enum { - CIDX_kill, - CIDX_eof, - CIDX_eol, --#ifdef VEOL2 -+#if VEOL2 - CIDX_eol2, - #endif --#ifdef VSWTCH -+#if VSWTCH - CIDX_swtch, - #endif - CIDX_start, - CIDX_stop, - CIDX_susp, --#ifdef VDSUSP -+#if VDSUSP - CIDX_dsusp, - #endif --#ifdef VREPRINT -+#if VREPRINT - CIDX_rprnt, - #endif --#ifdef VWERASE -+#if VWERASE - CIDX_werase, - #endif --#ifdef VLNEXT -+#if VLNEXT - CIDX_lnext, - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CIDX_flush, - #endif --#ifdef VSTATUS -+#if VSTATUS - CIDX_status, - #endif - CIDX_min, -@@ -538,31 +653,31 @@ static const char control_name[] = - CI_ENTRY("kill", CKILL, VKILL ) - CI_ENTRY("eof", CEOF, VEOF ) - CI_ENTRY("eol", CEOL, VEOL ) --#ifdef VEOL2 -+#if VEOL2 - CI_ENTRY("eol2", CEOL2, VEOL2 ) - #endif --#ifdef VSWTCH -+#if VSWTCH - CI_ENTRY("swtch", CSWTCH, VSWTCH ) - #endif - CI_ENTRY("start", CSTART, VSTART ) - CI_ENTRY("stop", CSTOP, VSTOP ) - CI_ENTRY("susp", CSUSP, VSUSP ) --#ifdef VDSUSP -+#if VDSUSP - CI_ENTRY("dsusp", CDSUSP, VDSUSP ) - #endif --#ifdef VREPRINT -+#if VREPRINT - CI_ENTRY("rprnt", CRPRNT, VREPRINT) - #endif --#ifdef VWERASE -+#if VWERASE - CI_ENTRY("werase", CWERASE, VWERASE ) - #endif --#ifdef VLNEXT -+#if VLNEXT - CI_ENTRY("lnext", CLNEXT, VLNEXT ) - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CI_ENTRY("flush", CFLUSHO, VFLUSHO ) - #endif --#ifdef VSTATUS -+#if VSTATUS - CI_ENTRY("status", CSTATUS, VSTATUS ) - #endif - /* These must be last because of the display routines */ -@@ -581,31 +696,31 @@ static const struct control_info control_info[] = { - CI_ENTRY("kill", CKILL, VKILL ) - CI_ENTRY("eof", CEOF, VEOF ) - CI_ENTRY("eol", CEOL, VEOL ) --#ifdef VEOL2 -+#if VEOL2 - CI_ENTRY("eol2", CEOL2, VEOL2 ) - #endif --#ifdef VSWTCH -+#if VSWTCH - CI_ENTRY("swtch", CSWTCH, VSWTCH ) - #endif - CI_ENTRY("start", CSTART, VSTART ) - CI_ENTRY("stop", CSTOP, VSTOP ) - CI_ENTRY("susp", CSUSP, VSUSP ) --#ifdef VDSUSP -+#if VDSUSP - CI_ENTRY("dsusp", CDSUSP, VDSUSP ) - #endif --#ifdef VREPRINT -+#if VREPRINT - CI_ENTRY("rprnt", CRPRNT, VREPRINT) - #endif --#ifdef VWERASE -+#if VWERASE - CI_ENTRY("werase", CWERASE, VWERASE ) - #endif --#ifdef VLNEXT -+#if VLNEXT - CI_ENTRY("lnext", CLNEXT, VLNEXT ) - #endif --#ifdef VFLUSHO -+#if VFLUSHO - CI_ENTRY("flush", CFLUSHO, VFLUSHO ) - #endif --#ifdef VSTATUS -+#if VSTATUS - CI_ENTRY("status", CSTATUS, VSTATUS ) - #endif - /* These must be last because of the display routines */ -@@ -740,6 +855,7 @@ static void newline(void) - wrapf("\n"); - } - -+#ifdef TIOCGWINSZ - static void set_window_size(int rows, int cols) - { - struct winsize win = { 0, 0, 0, 0 }; -@@ -760,6 +876,7 @@ static void set_window_size(int rows, int cols) - bail: - perror_on_device("%s"); - } -+#endif - - static void display_window_size(int fancy) - { -@@ -973,41 +1090,6 @@ static void sane_mode(struct termios *mode) - } - } - --/* Save set_mode from #ifdef forest plague */ --#ifndef ONLCR --#define ONLCR 0 --#endif --#ifndef OCRNL --#define OCRNL 0 --#endif --#ifndef ONLRET --#define ONLRET 0 --#endif --#ifndef XCASE --#define XCASE 0 --#endif --#ifndef IXANY --#define IXANY 0 --#endif --#ifndef TABDLY --#define TABDLY 0 --#endif --#ifndef OXTABS --#define OXTABS 0 --#endif --#ifndef IUCLC --#define IUCLC 0 --#endif --#ifndef OLCUC --#define OLCUC 0 --#endif --#ifndef ECHOCTL --#define ECHOCTL 0 --#endif --#ifndef ECHOKE --#define ECHOKE 0 --#endif -- - static void set_mode(const struct mode_info *info, int reversed, - struct termios *mode) - { -@@ -1093,27 +1175,32 @@ static void set_mode(const struct mode_info *info, int reversed, - mode->c_cc[VTIME] = 0; - } - } -- else if (IXANY && info == &mode_info[IDX_decctlq]) { -+#if IXANY -+ else if (info == &mode_info[IDX_decctlq]) { - if (reversed) - mode->c_iflag |= IXANY; - else - mode->c_iflag &= ~IXANY; - } -- else if (TABDLY && info == &mode_info[IDX_tabs]) { -+#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; - } -- else if (OXTABS && info == &mode_info[IDX_tabs]) { -+#endif -+#if OXTABS -+ else if (info == &mode_info[IDX_tabs]) { - if (reversed) - mode->c_oflag |= OXTABS; - else - mode->c_oflag &= ~OXTABS; -- } else -- if (XCASE && IUCLC && OLCUC -- && (info == &mode_info[IDX_lcase] || info == &mode_info[IDX_LCASE]) -- ) { -+ } -+#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; -@@ -1123,7 +1210,9 @@ static void set_mode(const struct mode_info *info, int reversed, - mode->c_iflag |= IUCLC; - mode->c_oflag |= OLCUC; - } -- } else if (info == &mode_info[IDX_crt]) { -+ } -+#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 */ -@@ -1419,7 +1508,7 @@ int stty_main(int argc UNUSED_PARAM, char **argv) - perror_on_device_and_die("%s"); - - if (memcmp(&mode, &new_mode, sizeof(mode)) != 0) { --#ifdef CIBAUD -+#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 --- -1.7.1 - diff --git a/packaging/swaponoff-FreeBSD-support.patch b/packaging/swaponoff-FreeBSD-support.patch deleted file mode 100644 index da273f5..0000000 --- a/packaging/swaponoff-FreeBSD-support.patch +++ /dev/null @@ -1,138 +0,0 @@ -From a5b837c34a96bdbb53151af455912b691c9aaa52 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 21:59:54 +0200 -Subject: [PATCH 19/19] swaponoff: FreeBSD support - - -Signed-off-by: Jeremie Koenig ---- - util-linux/Config.src | 3 +-- - util-linux/swaponoff.c | 6 +++--- - util-linux/xmount.c | 10 ++++++++++ - util-linux/xmount.h | 16 ++++++++++------ - 4 files changed, 24 insertions(+), 11 deletions(-) - -diff --git a/util-linux/Config.src b/util-linux/Config.src -index 99a6fbe..cb4de95 100644 ---- a/util-linux/Config.src -+++ b/util-linux/Config.src -@@ -639,7 +639,6 @@ config SETARCH - config SWAPONOFF - bool "swaponoff" - default y -- depends on PLATFORM_LINUX - help - This option enables both the 'swapon' and the 'swapoff' utilities. - Once you have created some swap space using 'mkswap', you also need -@@ -651,7 +650,7 @@ config SWAPONOFF - config FEATURE_SWAPON_PRI - bool "Support priority option -p" - default y -- depends on SWAPONOFF -+ depends on SWAPONOFF && PLATFORM_LINUX - help - Enable support for setting swap device priority in swapon. - -diff --git a/util-linux/swaponoff.c b/util-linux/swaponoff.c -index f2f52fb..d13c37e 100644 ---- a/util-linux/swaponoff.c -+++ b/util-linux/swaponoff.c -@@ -8,8 +8,8 @@ - */ - - #include "libbb.h" -+#include "xmount.h" - #include --#include - - #if ENABLE_FEATURE_MOUNT_LABEL - # include "volume_id.h" -@@ -43,9 +43,9 @@ static int swap_enable_disable(char *device) - #endif - - if (applet_name[5] == 'n') -- status = swapon(device, g_flags); -+ status = xswapon(device, g_flags); - else -- status = swapoff(device); -+ status = xswapoff(device); - - if (status != 0) { - bb_simple_perror_msg(device); -diff --git a/util-linux/xmount.c b/util-linux/xmount.c -index 3f322b8..16543f1 100644 ---- a/util-linux/xmount.c -+++ b/util-linux/xmount.c -@@ -63,4 +63,14 @@ int FAST_FUNC xumount(const char *target, int flags) - return unmount(target, flags); - } - -+int FAST_FUNC xswapon(const char *path, int swapflags UNUSED_PARAM) -+{ -+ return swapon(path); -+} -+ -+int FAST_FUNC xswapoff(const char *path) -+{ -+ return swapoff(path); -+} -+ - #endif -diff --git a/util-linux/xmount.h b/util-linux/xmount.h -index caef564..bcd6d18 100644 ---- a/util-linux/xmount.h -+++ b/util-linux/xmount.h -@@ -5,9 +5,9 @@ - * Copyright (C) 2010 by Jeremie Koenig - * Copyright (C) 2010 by Luca Favatella - * -- * The Linux prototypes for mount() and umount2() are used as a reference for -- * our xmount() and xumount(), which should be implemented as a compatibility -- * wrappers for non-Linux systems (see xmount.c). -+ * The Linux prototypes for mount(), umount2(), swapon() and swapoff() are -+ * used as a reference for our versions of them. On non-Linux system those -+ * should be implemented as compatibility wrappers (see xmount.c). - */ - - /* -@@ -17,6 +17,7 @@ - - #ifdef __linux__ - # include -+# include - /* Make sure we have all the new mount flags we actually try to use - * (grab more as needed from util-linux's mount/mount_constants.h). */ - # ifndef MS_DIRSYNC -@@ -56,6 +57,7 @@ - - #elif defined(__FreeBSD_kernel__) - # include -+# include - # define MS_NOSUID MNT_NOSUID - # define MS_NODEV MNT_NODEV - # define MS_NOEXEC MNT_NOEXEC -@@ -82,16 +84,18 @@ - #endif - - /* -- * Prototypes for xmount() and xumount(): on Linux we use the system calls -- * directly, otherwise xmount() and xumount() should be implemented as -- * compatibility wrappers (see xmount.c). -+ * Prototypes for the compatibility wrappers - */ - - #ifdef __linux__ - # define xmount mount - # define xumount umount2 -+# define xswapon swapon -+# define xswapoff swapoff - #else - int xmount(const char *source, const char *target, const char *filesystemtype, - unsigned long mountflags, const void *data) FAST_FUNC; - int xumount(const char *target, int flags) FAST_FUNC; -+int xswapon(const char *path, int swapflags) FAST_FUNC; -+int xswapoff(const char *path) FAST_FUNC; - #endif --- -1.7.1 - diff --git a/packaging/sysinfo-multiple-define-error-fix.patch b/packaging/sysinfo-multiple-define-error-fix.patch deleted file mode 100644 index 79edab1..0000000 --- a/packaging/sysinfo-multiple-define-error-fix.patch +++ /dev/null @@ -1,28 +0,0 @@ -diff --git a/include/libbb.h b/include/libbb.h -index e2a8322..18bed75 100644 ---- a/include/libbb.h -+++ b/include/libbb.h -@@ -104,6 +104,10 @@ char *dirname(char *path); - #endif - /* Include our own copy of struct sysinfo to avoid binary compatibility - * problems with Linux 2.4, which changed things. Grumble, grumble. */ -+/* kernel-header-3.x provide sysinfo struct. So then include header which kernel provide -+ * - walyong.cho */ -+#include -+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,0,0) - struct sysinfo { - long uptime; /* Seconds since boot */ - unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ -@@ -120,6 +124,9 @@ struct sysinfo { - unsigned int mem_unit; /* Memory unit size in bytes */ - char _f[20 - 2 * sizeof(long) - sizeof(int)]; /* Padding: libc5 uses this.. */ - }; -+#else -+#include -+#endif - int sysinfo(struct sysinfo* info); - #ifndef PATH_MAX - # define PATH_MAX 256 --- -1.7.9.5 - diff --git a/packaging/syslogd-disable-systemd-sa.patch b/packaging/syslogd-disable-systemd-sa.patch deleted file mode 100644 index 63c1c95..0000000 --- a/packaging/syslogd-disable-systemd-sa.patch +++ /dev/null @@ -1,36 +0,0 @@ -diff -Nru busybox-1.17.1.ORIG//Makefile.flags busybox-1.17.1/Makefile.flags ---- busybox-1.17.1.ORIG//Makefile.flags 2012-08-03 15:39:32.345043691 +0900 -+++ busybox-1.17.1/Makefile.flags 2012-08-03 15:44:37.017043654 +0900 -@@ -115,10 +115,6 @@ - LDLIBS += dmalloc - endif - --ifeq ($(CONFIG_SYSLOGD),y) --LDLIBS += systemd-daemon --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. -diff -Nru busybox-1.17.1.ORIG//sysklogd/syslogd.c busybox-1.17.1/sysklogd/syslogd.c ---- busybox-1.17.1.ORIG//sysklogd/syslogd.c 2012-08-03 15:39:32.349043691 +0900 -+++ busybox-1.17.1/sysklogd/syslogd.c 2012-08-03 15:40:05.013043687 +0900 -@@ -34,8 +34,6 @@ - #include - #endif - --#include "sd-daemon.h" -- - #define DEBUG 0 - - /* MARK code is not very useful, is bloat, and broken: -@@ -513,9 +511,6 @@ - int sock_fd; - char *dev_log_name; - -- if (sd_listen_fds(1) == 1 && sd_is_socket_unix(SD_LISTEN_FDS_START, SOCK_DGRAM, -1, "/dev/log", 0) > 0) -- return SD_LISTEN_FDS_START; -- - memset(&sunx, 0, sizeof(sunx)); - sunx.sun_family = AF_UNIX; - diff --git a/packaging/syslogd.manifest b/packaging/syslogd.manifest deleted file mode 100644 index 70bcf4e..0000000 --- a/packaging/syslogd.manifest +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/packaging/syslogd.service b/packaging/syslogd.service deleted file mode 100644 index 23cf06c..0000000 --- a/packaging/syslogd.service +++ /dev/null @@ -1,13 +0,0 @@ -[Unit] -Description=Run syslog -After=var.mount - -[Service] -Type=forking -ExecStart=/sbin/syslogd -b 5 -OOMScoreAdjust=-1000 -Restart=always -RestartSec=0 - -[Install] -WantedBy=basic.target diff --git a/packaging/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch b/packaging/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch deleted file mode 100644 index eb797bc..0000000 --- a/packaging/tcpsvd-udpsvd-conditionalize-usage-of-SO_ORIGINAL_DS.patch +++ /dev/null @@ -1,70 +0,0 @@ -From 2ea12d8b6d2a36c5d49df1ae97b86ba287835249 Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 27 May 2010 15:46:25 +0200 -Subject: [PATCH 9/9] tcpsvd,udpsvd: conditionalize usage of SO_ORIGINAL_DST - -On systems without this call, $TCPORIGDSTADDR is not set. - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - networking/Config.src | 2 -- - networking/tcpudp.c | 5 +++++ - 2 files changed, 5 insertions(+), 2 deletions(-) - -diff --git a/networking/Config.src b/networking/Config.src -index fc613e8..2d29c42 100644 ---- a/networking/Config.src -+++ b/networking/Config.src -@@ -733,7 +733,6 @@ config SLATTACH - config TCPSVD - bool "tcpsvd" - default y -- depends on PLATFORM_LINUX - help - tcpsvd listens on a TCP port and runs a program for each new - connection. -@@ -966,7 +965,6 @@ config IFUPDOWN_UDHCPC_CMD_OPTIONS - config UDPSVD - bool "udpsvd" - default y -- depends on PLATFORM_LINUX - help - udpsvd listens on an UDP port and runs a program for each new - connection. -diff --git a/networking/tcpudp.c b/networking/tcpudp.c -index 53e622b..40f6825 100644 ---- a/networking/tcpudp.c -+++ b/networking/tcpudp.c -@@ -30,9 +30,12 @@ - */ - - #include "libbb.h" -+ - /* Wants etc, thus included after libbb.h: */ -+#ifdef __linux__ - #include /* for __be32 etc */ - #include -+#endif - - // TODO: move into this file: - #include "tcpudp_perhost.h" -@@ -464,6 +467,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) - /* setup ucspi env */ - const char *proto = tcp ? "TCP" : "UDP"; - -+#ifdef SO_ORIGINAL_DST - /* Extract "original" destination addr:port - * from Linux firewall. Useful when you redirect - * an outbond connection to local handler, and it needs -@@ -473,6 +477,7 @@ int tcpudpsvd_main(int argc UNUSED_PARAM, char **argv) - xsetenv_plain("TCPORIGDSTADDR", addr); - free(addr); - } -+#endif - xsetenv_plain("PROTO", proto); - xsetenv_proto(proto, "LOCALADDR", local_addr); - xsetenv_proto(proto, "REMOTEADDR", remote_addr); --- -1.7.1 - diff --git a/packaging/tizen.config b/packaging/tizen.config deleted file mode 100644 index cede9d2..0000000 --- a/packaging/tizen.config +++ /dev/null @@ -1,946 +0,0 @@ -# -# Automatically generated make config: don't edit -# Busybox version: 1.17.1 -# Wed Feb 13 20:10:00 2013 -# -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_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=y -# CONFIG_FEATURE_WTMP is not set -# CONFIG_FEATURE_PIDFILE is not set -CONFIG_FEATURE_SUID=y -# 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 -CONFIG_FEATURE_HAVE_RPC=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_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_SIZE_VS_SPEED=2 -# 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_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 is not set -# CONFIG_FEATURE_SEAMLESS_LZMA is not set -# CONFIG_FEATURE_SEAMLESS_BZ2 is not set -# CONFIG_FEATURE_SEAMLESS_GZ is not set -# 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_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_FEATURE_DPKG_DEB_EXTRACT_ONLY 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_TO_COMMAND 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 is not set -# 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 is not set -# 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_LENGTH 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 is not set -# 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_AUTOWIDTH 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 is not set -# 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=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_VI_ASK_TERMINAL=y -CONFIG_FEATURE_VI_OPTIMIZE_CURSOR=y -CONFIG_FEATURE_ALLOW_EXEC=y - -# -# 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_BOOTCHARTD is not set -# CONFIG_FEATURE_BOOTCHARTD_BLOATED_HEADER is not set -# CONFIG_FEATURE_BOOTCHARTD_CONFIG_FILE is not set -# 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_EXTRA_QUIET is not set -# CONFIG_FEATURE_INIT_COREDUMPS is not set -# CONFIG_FEATURE_INITRD is not set -# CONFIG_HALT is not set -# CONFIG_FEATURE_CALL_TELINIT is not set -CONFIG_TELINIT_PATH="" -# CONFIG_MESG 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_REV is not set -# 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 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_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_FEATURE_USE_TERMIOS 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=y -CONFIG_FEATURE_MOUNT_CIFS=y -CONFIG_FEATURE_MOUNT_FLAGS=y -CONFIG_FEATURE_MOUNT_FSTAB=y -# 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=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_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_UBIATTACH is not set -# CONFIG_UBIDETACH is not set -# CONFIG_ADJTIMEX is not set -# CONFIG_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 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_NC is not set -# 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 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_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_SOURCE_ROUTE 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=y -# CONFIG_DHCPRELAY is not set -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="" -# 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_SMEMCAP is not set -# 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_BUILTIN_ECHO is not set -# CONFIG_ASH_BUILTIN_PRINTF is not set -# CONFIG_ASH_BUILTIN_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_LASH is not set -# CONFIG_MSH is not set -# 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=y -CONFIG_FEATURE_ROTATE_LOGFILE=y -CONFIG_FEATURE_REMOTE_LOG=y -CONFIG_FEATURE_SYSLOGD_DUP=y -CONFIG_FEATURE_SYSLOGD_READ_BUFFER_SIZE=300 -CONFIG_FEATURE_IPC_SYSLOG=y -CONFIG_FEATURE_IPC_SYSLOG_BUFFER_SIZE=16 -# CONFIG_LOGREAD is not set -# CONFIG_FEATURE_LOGREAD_REDUCED_LOCKING is not set -CONFIG_KLOGD=y -# CONFIG_LOGGER is not set diff --git a/packaging/top-display-rss.patch b/packaging/top-display-rss.patch deleted file mode 100644 index e7776f1..0000000 --- a/packaging/top-display-rss.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/procps/top.c b/procps/top.c -index ec84374..9049578 100644 ---- a/procps/top.c -+++ b/procps/top.c -@@ -35,7 +35,7 @@ - - - typedef struct top_status_t { -- unsigned long vsz; -+ unsigned long rss; - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - unsigned long ticks; - unsigned pcpu; /* delta of ticks */ -@@ -147,8 +147,8 @@ static int pid_sort(top_status_t *P, top_status_t *Q) - static int mem_sort(top_status_t *P, top_status_t *Q) - { - /* We want to avoid unsigned->signed and truncation errors */ -- if (Q->vsz < P->vsz) return -1; -- return Q->vsz != P->vsz; /* 0 if ==, 1 if > */ -+ if (Q->rss < P->rss) return -1; -+ return Q->rss != P->rss; /* 0 if ==, 1 if > */ - } - - -@@ -519,7 +519,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) - - /* what info of the processes is shown */ - printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width, -- " PID PPID USER STAT VSZ %MEM" -+ " PID PPID USER STAT RSS %MEM" - IF_FEATURE_TOP_SMP_PROCESS(" CPU") - IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") - " COMMAND"); -@@ -588,16 +588,16 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) - s = top; - while (--lines_rem >= 0) { - unsigned col; -- CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); -+ CALC_STAT(pmem, (s->rss*pmem_scale + pmem_half) >> pmem_shift); - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - CALC_STAT(pcpu, (s->pcpu*pcpu_scale + pcpu_half) >> pcpu_shift); - #endif - -- if (s->vsz >= 100000) -- sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); -+ if (s->rss >= 100000) -+ sprintf(vsz_str_buf, "%6ldm", s->rss/1024); - else -- sprintf(vsz_str_buf, "%7ld", s->vsz); -- /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */ -+ sprintf(vsz_str_buf, "%7ld", s->rss); -+ /* PID PPID USER STAT VSZ %RSS [%CPU] COMMAND */ - col = snprintf(line_buf, scr_width, - "\n" "%5u%6u %-8.8s %s%s" FMT - IF_FEATURE_TOP_SMP_PROCESS(" %3d") -@@ -929,7 +929,7 @@ int top_main(int argc UNUSED_PARAM, char **argv) - top = xrealloc_vector(top, 6, ntop++); - top[n].pid = p->pid; - top[n].ppid = p->ppid; -- top[n].vsz = p->vsz; -+ top[n].rss = p->rss; - #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - top[n].ticks = p->stime + p->utime; - #endif diff --git a/packaging/u-mount-FreeBSD-support.patch b/packaging/u-mount-FreeBSD-support.patch deleted file mode 100644 index 702c051..0000000 --- a/packaging/u-mount-FreeBSD-support.patch +++ /dev/null @@ -1,386 +0,0 @@ -From 5a075618b1deb735a6170e322052c7ba54b17d9e Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 21:16:09 +0200 -Subject: [PATCH 18/19] (u)mount: FreeBSD support - - -Signed-off-by: Jeremie Koenig ---- - util-linux/Config.src | 4 +-- - util-linux/Kbuild.src | 4 +- - util-linux/mount.c | 41 ++------------------- - util-linux/umount.c | 41 +++------------------ - util-linux/xmount.c | 66 +++++++++++++++++++++++++++++++++ - util-linux/xmount.h | 97 +++++++++++++++++++++++++++++++++++++++++++++++++ - 6 files changed, 174 insertions(+), 79 deletions(-) - create mode 100644 util-linux/xmount.c - create mode 100644 util-linux/xmount.h - -diff --git a/util-linux/Config.src b/util-linux/Config.src -index 98953c1..99a6fbe 100644 ---- a/util-linux/Config.src -+++ b/util-linux/Config.src -@@ -492,7 +492,6 @@ config FEATURE_USE_TERMIOS - config MOUNT - bool "mount" - default y -- depends on PLATFORM_LINUX - help - All files and filesystems in Unix are arranged into one big directory - tree. The 'mount' utility is used to graft a filesystem onto a -@@ -679,7 +678,6 @@ config SWITCH_ROOT - config UMOUNT - bool "umount" - default y -- depends on PLATFORM_LINUX - help - When you want to remove a mounted filesystem from its current mount - point, for example when you are shutting down the system, the -@@ -699,7 +697,7 @@ comment "Common options for mount/umount" - config FEATURE_MOUNT_LOOP - bool "Support loopback mounts" - default y -- depends on MOUNT || UMOUNT -+ depends on (MOUNT || UMOUNT) && PLATFORM_LINUX - help - Enabling this feature allows automatic mounting of files (containing - filesystem images) via the linux kernel's loopback devices. -diff --git a/util-linux/Kbuild.src b/util-linux/Kbuild.src -index afc0db5..312fc9e 100644 ---- a/util-linux/Kbuild.src -+++ b/util-linux/Kbuild.src -@@ -33,7 +33,7 @@ lib-$(CONFIG_MKFS_REISER) += mkfs_reiser.o - lib-$(CONFIG_MKFS_VFAT) += mkfs_vfat.o - lib-$(CONFIG_MKSWAP) += mkswap.o - lib-$(CONFIG_MORE) += more.o --lib-$(CONFIG_MOUNT) += mount.o -+lib-$(CONFIG_MOUNT) += mount.o xmount.o - lib-$(CONFIG_PIVOT_ROOT) += pivot_root.o - lib-$(CONFIG_RDATE) += rdate.o - lib-$(CONFIG_RDEV) += rdev.o -@@ -44,4 +44,4 @@ lib-$(CONFIG_SCRIPTREPLAY) += scriptreplay.o - lib-$(CONFIG_SETARCH) += setarch.o - lib-$(CONFIG_SWAPONOFF) += swaponoff.o - lib-$(CONFIG_SWITCH_ROOT) += switch_root.o --lib-$(CONFIG_UMOUNT) += umount.o -+lib-$(CONFIG_UMOUNT) += umount.o xmount.o -diff --git a/util-linux/mount.c b/util-linux/mount.c -index 9107e43..a62c4e8 100644 ---- a/util-linux/mount.c -+++ b/util-linux/mount.c -@@ -18,44 +18,9 @@ - // - #include - #include --#include --// Grab more as needed from util-linux's mount/mount_constants.h --#ifndef MS_DIRSYNC --# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous --#endif --#ifndef MS_UNION --# define MS_UNION (1 << 8) --#endif --#ifndef MS_BIND --# define MS_BIND (1 << 12) --#endif --#ifndef MS_MOVE --# define MS_MOVE (1 << 13) --#endif --#ifndef MS_RECURSIVE --# define MS_RECURSIVE (1 << 14) --#endif --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --// The shared subtree stuff, which went in around 2.6.15 --#ifndef MS_UNBINDABLE --# define MS_UNBINDABLE (1 << 17) --#endif --#ifndef MS_PRIVATE --# define MS_PRIVATE (1 << 18) --#endif --#ifndef MS_SLAVE --# define MS_SLAVE (1 << 19) --#endif --#ifndef MS_SHARED --# define MS_SHARED (1 << 20) --#endif --#ifndef MS_RELATIME --# define MS_RELATIME (1 << 21) --#endif - - #include "libbb.h" -+#include "xmount.h" - #if ENABLE_FEATURE_MOUNT_LABEL - # include "volume_id.h" - #else -@@ -288,7 +253,7 @@ static int verbose_mount(const char *source, const char *target, - int rc; - - errno = 0; -- rc = mount(source, target, filesystemtype, mountflags, data); -+ rc = xmount(source, target, filesystemtype, mountflags, data); - if (verbose >= 2) - bb_perror_msg("mount('%s','%s','%s',0x%08lx,'%s'):%d", - source, target, filesystemtype, -@@ -296,7 +261,7 @@ static int verbose_mount(const char *source, const char *target, - return rc; - } - #else --#define verbose_mount(...) mount(__VA_ARGS__) -+#define verbose_mount(...) xmount(__VA_ARGS__) - #endif - - // Append mount options to string -diff --git a/util-linux/umount.c b/util-linux/umount.c -index a19f86c..781e019 100644 ---- a/util-linux/umount.c -+++ b/util-linux/umount.c -@@ -8,40 +8,9 @@ - * Licensed under GPL version 2, see file LICENSE in this tarball for details. - */ - #include --#include --/* Make sure we have all the new mount flags we actually try to use. */ --#ifndef MS_BIND --# define MS_BIND (1 << 12) --#endif --#ifndef MS_MOVE --# define MS_MOVE (1 << 13) --#endif --#ifndef MS_RECURSIVE --# define MS_RECURSIVE (1 << 14) --#endif --#ifndef MS_SILENT --# define MS_SILENT (1 << 15) --#endif --/* The shared subtree stuff, which went in around 2.6.15. */ --#ifndef MS_UNBINDABLE --# define MS_UNBINDABLE (1 << 17) --#endif --#ifndef MS_PRIVATE --# define MS_PRIVATE (1 << 18) --#endif --#ifndef MS_SLAVE --# define MS_SLAVE (1 << 19) --#endif --#ifndef MS_SHARED --# define MS_SHARED (1 << 20) --#endif --#ifndef MS_RELATIME --# define MS_RELATIME (1 << 21) --#endif -+ - #include "libbb.h" --#ifndef PATH_MAX --# define PATH_MAX (4*1024) --#endif -+#include "xmount.h" - - - #if defined(__dietlibc__) -@@ -154,11 +123,11 @@ int umount_main(int argc UNUSED_PARAM, char **argv) - if (m) zapit = m->dir; - - // Let's ask the thing nicely to unmount. -- curstat = umount(zapit); -+ curstat = xumount(zapit, 0); - - // Force the unmount, if necessary. - if (curstat && doForce) -- curstat = umount2(zapit, doForce); -+ curstat = xumount(zapit, doForce); - - // If still can't umount, maybe remount read-only? - if (curstat) { -@@ -166,7 +135,7 @@ int umount_main(int argc UNUSED_PARAM, char **argv) - // Note! Even if we succeed here, later we should not - // free loop device or erase mtab entry! - const char *msg = "%s busy - remounted read-only"; -- curstat = mount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL); -+ curstat = xmount(m->device, zapit, NULL, MS_REMOUNT|MS_RDONLY, NULL); - if (curstat) { - msg = "can't remount %s read-only"; - status = EXIT_FAILURE; -diff --git a/util-linux/xmount.c b/util-linux/xmount.c -new file mode 100644 -index 0000000..3f322b8 ---- /dev/null -+++ b/util-linux/xmount.c -@@ -0,0 +1,70 @@ -+#include "libbb.h" -+#include "xmount.h" -+ -+#ifdef __linux__ -+ -+/* xmount and xumount short-circuited to mount and umount2 in xmount.h */ -+ -+#elif defined(__FreeBSD_kernel__) -+ -+static void build_iovec(struct iovec **iov, int *iovlen, const char *name, -+ void *val, size_t len) -+{ -+ int i; -+ -+ if (*iovlen < 0) -+ return; -+ i = *iovlen; -+ *iov = realloc(*iov, sizeof **iov * (i + 2)); -+ if (*iov == NULL) { -+ *iovlen = -1; -+ return; -+ } -+ (*iov)[i].iov_base = strdup(name); -+ (*iov)[i].iov_len = strlen(name) + 1; -+ i++; -+ (*iov)[i].iov_base = val; -+ if (len == (size_t)-1) { -+ if (val != NULL) -+ len = strlen(val) + 1; -+ else -+ len = 0; -+ } -+ (*iov)[i].iov_len = (int)len; -+ *iovlen = ++i; -+} -+ -+int FAST_FUNC xmount(const char *source, const char *target, -+ const char *filesystemtype, unsigned long mountflags, -+ const void *data UNUSED_PARAM) -+{ -+ struct iovec *iov = NULL; -+ int iovlen = 0; -+ char *fspath, *from; -+ int ret; -+ -+ fspath = realpath(target, NULL); -+ from = realpath(source, NULL); -+ -+ build_iovec(&iov, &iovlen, "fstype", (void*)filesystemtype, (size_t)-1); -+ build_iovec(&iov, &iovlen, "fspath", fspath, (size_t)-1); -+ if (!strcmp(filesystemtype, "nullfs")) -+ /* nullfs uses a "target" instead of "from" */ -+ build_iovec(&iov, &iovlen, "target", from, (size_t)-1); -+ else -+ build_iovec(&iov, &iovlen, "from", from, (size_t)-1); -+ -+ ret = nmount(iov, iovlen, mountflags); -+ -+ free(from); -+ free(fspath); -+ -+ return ret; -+} -+ -+int FAST_FUNC xumount(const char *target, int flags) -+{ -+ return unmount(target, flags); -+} -+ -+#endif -diff --git a/util-linux/xmount.h b/util-linux/xmount.h -new file mode 100644 -index 0000000..caef564 ---- /dev/null -+++ b/util-linux/xmount.h -@@ -0,0 +1,97 @@ -+/* vi: set sw=4 ts=4: */ -+/* -+ * System-specific definitions for mount. -+ * -+ * Copyright (C) 2010 by Jeremie Koenig -+ * Copyright (C) 2010 by Luca Favatella -+ * -+ * The Linux prototypes for mount() and umount2() are used as a reference for -+ * our xmount() and xumount(), which should be implemented as a compatibility -+ * wrappers for non-Linux systems (see xmount.c). -+ */ -+ -+/* -+ * Definitions for mount flags. Non-Linux systems are free to use whatever -+ * their version of xmount() will work with. -+ */ -+ -+#ifdef __linux__ -+# include -+/* Make sure we have all the new mount flags we actually try to use -+ * (grab more as needed from util-linux's mount/mount_constants.h). */ -+# ifndef MS_DIRSYNC -+# define MS_DIRSYNC (1 << 7) // Directory modifications are synchronous -+# endif -+# ifndef MS_UNION -+# define MS_UNION (1 << 8) -+# endif -+# ifndef MS_BIND -+# define MS_BIND (1 << 12) -+# endif -+# ifndef MS_MOVE -+# define MS_MOVE (1 << 13) -+# endif -+# ifndef MS_RECURSIVE -+# define MS_RECURSIVE (1 << 14) -+# endif -+# ifndef MS_SILENT -+# define MS_SILENT (1 << 15) -+# endif -+/* The shared subtree stuff, which went in around 2.6.15. */ -+# ifndef MS_UNBINDABLE -+# define MS_UNBINDABLE (1 << 17) -+# endif -+# ifndef MS_PRIVATE -+# define MS_PRIVATE (1 << 18) -+# endif -+# ifndef MS_SLAVE -+# define MS_SLAVE (1 << 19) -+# endif -+# ifndef MS_SHARED -+# define MS_SHARED (1 << 20) -+# endif -+# ifndef MS_RELATIME -+# define MS_RELATIME (1 << 21) -+# endif -+ -+#elif defined(__FreeBSD_kernel__) -+# include -+# define MS_NOSUID MNT_NOSUID -+# define MS_NODEV MNT_NODEV -+# define MS_NOEXEC MNT_NOEXEC -+# define MS_SYNCHRONOUS MNT_SYNCHRONOUS -+# define MS_DIRSYNC 0 -+# define MS_NOATIME MNT_NOATIME -+# define MS_NODIRATIME 0 -+# define MS_MANDLOCK 0 -+# define MS_RELATIME 0 -+# define MS_SILENT 0 -+# define MS_UNION MNT_UNION -+# define MS_BIND 0 -+# define MS_MOVE 0 -+# define MS_SHARED 0 -+# define MS_SLAVE 0 -+# define MS_PRIVATE 0 -+# define MS_UNBINDABLE 0 -+# define MS_RECURSIVE 0 -+# define MS_RDONLY MNT_RDONLY -+# define MS_REMOUNT MNT_UPDATE -+ -+#else -+# error There is no xmount() implementation for your system. -+#endif -+ -+/* -+ * Prototypes for xmount() and xumount(): on Linux we use the system calls -+ * directly, otherwise xmount() and xumount() should be implemented as -+ * compatibility wrappers (see xmount.c). -+ */ -+ -+#ifdef __linux__ -+# define xmount mount -+# define xumount umount2 -+#else -+int xmount(const char *source, const char *target, const char *filesystemtype, -+ unsigned long mountflags, const void *data) FAST_FUNC; -+int xumount(const char *target, int flags) FAST_FUNC; -+#endif --- -1.7.1 - diff --git a/packaging/udhcpc-fast-request.patch b/packaging/udhcpc-fast-request.patch deleted file mode 100644 index 47f5f3e..0000000 --- a/packaging/udhcpc-fast-request.patch +++ /dev/null @@ -1,129 +0,0 @@ -From: Hakgoo Lee -Date: Thu, 16 Sep 2010 14:51:22 +0900 -Subject: [PATCH] Add FEATURE_UDHCPC_FAST_REQUEST to udhcp. - -If selected, udhcpc will send Request if leased IP and DHCP server is specified. -So Discover/Offer routine can be skipped. It can reduce service recovery time in WiFi. ---- - include/usage.src.h | 4 ++++ - networking/udhcp/Config.src | 8 ++++++++ - networking/udhcp/dhcpc.c | 28 ++++++++++++++++++++++++++++ - 3 files changed, 40 insertions(+), 0 deletions(-) - -diff --git a/include/usage.src.h b/include/usage.src.h -index 94a3256..e3c987c 100644 ---- a/include/usage.src.h -+++ b/include/usage.src.h -@@ -4539,6 +4539,10 @@ INSERT - IF_FEATURE_UDHCPC_ARPING( \ - "\n -a,--arping Use arping to validate offered address" \ - ) \ -+ IF_FEATURE_UDHCPC_FAST_REQUEST( \ -+ "\n -d,--request-direct=IP IP address to request without discover, must be used with -D" \ -+ "\n -D,--dhcp-server=IP DHCP server IP address to get leased IP address" \ -+ ) \ - "\n -O,--request-option OPT Request DHCP option OPT (cumulative)" \ - "\n -o,--no-default-options Don't request any options (unless -O is given)" \ - "\n -x OPT:VAL Include option OPT in sent packets (cumulative)" \ -diff --git a/networking/udhcp/Config.src b/networking/udhcp/Config.src -index 331dffc..c4ec82f 100644 ---- a/networking/udhcp/Config.src -+++ b/networking/udhcp/Config.src -@@ -130,3 +130,11 @@ config UDHCPC_SLACK_FOR_BUGGY_SERVERS - maximum size of entire IP packet, and sends packets which are - 28 bytes too large. - Seednet (ISP) VDSL: sends packets 2 bytes too large. -+ -+config FEATURE_UDHCPC_FAST_REQUEST -+ bool "Send Fast Request without Discover/Offer (e.g. When same subnet is connected again like WiFi AP)." -+ default y -+ depends on UDHCPC -+ help -+ If selected, udhcpc will send Request if leased IP and DHCP server is specified. -+ So Discover/Offer routine can be skipped. It can reduce service recovery time in WiFi. -diff --git a/networking/udhcp/dhcpc.c b/networking/udhcp/dhcpc.c -index de1b798..e740871 100644 ---- a/networking/udhcp/dhcpc.c -+++ b/networking/udhcp/dhcpc.c -@@ -767,6 +767,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - { - uint8_t *temp, *message; - const char *str_c, *str_V, *str_h, *str_F, *str_r; -+ IF_FEATURE_UDHCPC_FAST_REQUEST(char *str_d, *str_D;) - IF_FEATURE_UDHCP_PORT(char *str_P;) - llist_t *list_O = NULL; - llist_t *list_x = NULL; -@@ -812,6 +813,8 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - "background\0" No_argument "b" - IF_FEATURE_UDHCPC_ARPING("arping\0" No_argument "a") - IF_FEATURE_UDHCP_PORT("client-port\0" Required_argument "P") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("request-direct\0" Required_argument "d") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("dhcp-server\0" Required_argument "D") - ; - #endif - enum { -@@ -841,9 +844,13 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - USE_FOR_MMU( OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPTBIT_P,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPTBIT_d,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPTBIT_D,) - USE_FOR_MMU( OPT_b = 1 << OPTBIT_b,) - IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,) - IF_FEATURE_UDHCP_PORT( OPT_P = 1 << OPTBIT_P,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPT_d = 1 << OPTBIT_d,) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(OPT_D = 1 << OPTBIT_D,) - }; - - /* Default options. */ -@@ -865,6 +872,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - USE_FOR_MMU("b") - IF_FEATURE_UDHCPC_ARPING("a") - IF_FEATURE_UDHCP_PORT("P:") -+ IF_FEATURE_UDHCPC_FAST_REQUEST("d:D:") - "v" - , &str_c, &str_V, &str_h, &str_h, &str_F - , &client_config.interface, &client_config.pidfile, &str_r /* i,p */ -@@ -873,6 +881,7 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - , &list_O - , &list_x - IF_FEATURE_UDHCP_PORT(, &str_P) -+ IF_FEATURE_UDHCPC_FAST_REQUEST(, &str_d, &str_D) - #if defined CONFIG_UDHCP_DEBUG && CONFIG_UDHCP_DEBUG >= 1 - , &dhcp_verbose - #endif -@@ -950,6 +959,18 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - logmode |= LOGMODE_SYSLOG; - } - -+#if ENABLE_FEATURE_UDHCPC_FAST_REQUEST -+ if (opt & OPT_d) { -+ log1("Parsing request-direct option"); -+ requested_ip = inet_addr(str_d); -+ state = REQUESTING; -+ } -+ if (opt & OPT_D) { -+ log1("Parsing dhcp-server option"); -+ server_addr = inet_addr(str_D); -+ } -+#endif -+ - /* Make sure fd 0,1,2 are open */ - bb_sanitize_stdio(); - /* Equivalent of doing a fflush after every \n */ -@@ -963,7 +984,14 @@ int udhcpc_main(int argc UNUSED_PARAM, char **argv) - /* We want random_xid to be random... */ - srand(monotonic_us()); - -+#if ENABLE_FEATURE_UDHCPC_FAST_REQUEST -+ if (state != REQUESTING) -+ state = INIT_SELECTING; -+ log1("Initial state is %d", state); -+#else - state = INIT_SELECTING; -+#endif -+ - udhcp_run_script(NULL, "deconfig"); - change_listen_mode(LISTEN_RAW); - packet_num = 0; --- diff --git a/packaging/update-scripts-kconfig-_shipped.patch b/packaging/update-scripts-kconfig-_shipped.patch deleted file mode 100644 index 52cc64e..0000000 --- a/packaging/update-scripts-kconfig-_shipped.patch +++ /dev/null @@ -1,28 +0,0 @@ -commit 6e06da5efd5d6e341ae2f5116c449994740f5613 -Author: Denys Vlasenko -Date: Mon Aug 2 02:17:25 2010 +0200 - - update _shipped file with hurd fix - - Signed-off-by: Denys Vlasenko - -diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped -index 4837bbf..51f15e1 100644 ---- a/scripts/kconfig/lex.zconf.c_shipped -+++ b/scripts/kconfig/lex.zconf.c_shipped -@@ -2235,13 +2235,14 @@ static void zconf_endhelp(void) - */ - FILE *zconf_fopen(const char *name) - { -- char *env, fullname[PATH_MAX+1]; -+ char *env; - FILE *f; - - f = fopen(name, "r"); - if (!f && name[0] != '/') { - env = getenv(SRCTREE); - if (env) { -+ char *fullname = alloca(strlen(env) + strlen(name) + 2); - sprintf(fullname, "%s/%s", env, name); - f = fopen(fullname, "r"); - } diff --git a/packaging/usrbin.links b/packaging/usrbin.links deleted file mode 100644 index 4c4c18c..0000000 --- a/packaging/usrbin.links +++ /dev/null @@ -1,144 +0,0 @@ -[ -[[ -adjtimex -ar -arping -basename -brctl -cal -catv -chpst -chrt -chvt -cksum -cmp -comm -crontab -cut -dc -deallocvt -diff -dirname -dos2unix -du -dumpleases -eject -env -envdir -envuidgid -ether-wake -expand -expr -fdformat -find -flock -fold -free -freeramdisk -ftpget -ftpput -getopt -hd -head -hexdump -hostid -id -install -ionice -ipcalc -ipcrm -ipcs -kbd_mode -killall -length -less -linux32 -linux64 -loadfont -logger -logname -lzcat -lzma -lzop -lzopcat -md5sum -microcom -mkfifo -nice -nmeter -nohup -nslookup -od -openvt -passwd -patch -pgrep -pkill -printenv -printf -pscan -readahead -realpath -renice -resize -rev -rtcwake -runsv -runsvdir -rx -script -scriptreplay -seq -setarch -setkeycodes -setlogcons -setsid -setuidgid -sha1sum -sha256sum -sha512sum -showkey -softlimit -sort -split -stat -strings -sum -sv -svlogd -tac -tail -taskset -tcpsvd -tee -test -tftp -time -timeout -top -tr -tty -ttysize -udhcpc -udpsvd -unexpand -uniq -unix2dos -unlzma -unlzop -unzip -uptime -uudecode -uuencode -vlock -volname -wall -watch -wc -wget -who -whoami -xargs -yes -zcip -vi diff --git a/packaging/usrsbin.links b/packaging/usrsbin.links deleted file mode 100644 index 27966d1..0000000 --- a/packaging/usrsbin.links +++ /dev/null @@ -1,28 +0,0 @@ -addgroup -adduser -arp -chat -chpasswd -chroot -crond -delgroup -deluser -dhcprelay -dnsd -fakeidentd -flashcp -flash_eraseall -flash_lock -flash_unlock -httpd -inetd -rdate -rdev -readprofile -sendmail -telnetd -tftpd -ubiattach -ubidetach -udhcpd -watchdog diff --git a/packaging/version.patch b/packaging/version.patch deleted file mode 100644 index a09b782..0000000 --- a/packaging/version.patch +++ /dev/null @@ -1,23 +0,0 @@ ---- a/Makefile.flags -+++ b/Makefile.flags -@@ -4,6 +4,11 @@ - - BB_VER = $(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) - export BB_VER -+ifndef BB_EXTRA_VERSION -+BB_BT = AUTOCONF_TIMESTAMP -+else -+BB_BT = KBUILD_STR($(BB_EXTRA_VERSION)) -+endif - SKIP_STRIP = n - - # -std=gnu99 needed for [U]LLONG_MAX on some systems -@@ -15,7 +20,7 @@ - -include include/autoconf.h \ - -D_GNU_SOURCE -DNDEBUG \ - $(if $(CONFIG_LFS),-D_LARGEFILE_SOURCE -D_LARGEFILE64_SOURCE -D_FILE_OFFSET_BITS=64) \ -- -D"BB_VER=KBUILD_STR($(BB_VER))" -DBB_BT=AUTOCONF_TIMESTAMP -+ -D"BB_VER=KBUILD_STR($(BB_VER))" -D"BB_BT=$(BB_BT)" - - CFLAGS += $(call cc-option,-Wall,) - CFLAGS += $(call cc-option,-Wshadow,) diff --git a/packaging/vlock-disable-linux-console-calls-on-other-systems.patch b/packaging/vlock-disable-linux-console-calls-on-other-systems.patch deleted file mode 100644 index f717473..0000000 --- a/packaging/vlock-disable-linux-console-calls-on-other-systems.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 68fca4cd55e7bf6075eb1ccd303ae57a7ec1b8da Mon Sep 17 00:00:00 2001 -From: Jeremie Koenig -Date: Thu, 29 Jul 2010 04:29:52 +0200 -Subject: [PATCH 12/12] vlock: disable linux console calls on other systems - -Signed-off-by: Jeremie Koenig -Signed-off-by: Denys Vlasenko ---- - loginutils/Config.src | 1 - - loginutils/vlock.c | 15 +++++++++++++-- - 2 files changed, 13 insertions(+), 3 deletions(-) - -diff --git a/loginutils/Config.src b/loginutils/Config.src -index 6ec2893..5d497c4 100644 ---- a/loginutils/Config.src -+++ b/loginutils/Config.src -@@ -295,7 +295,6 @@ config SULOGIN - config VLOCK - bool "vlock" - default y -- depends on PLATFORM_LINUX - select FEATURE_SUID - help - Build the "vlock" applet which allows you to lock (virtual) terminals. -diff --git a/loginutils/vlock.c b/loginutils/vlock.c -index 85f489c..59aeb54 100644 ---- a/loginutils/vlock.c -+++ b/loginutils/vlock.c -@@ -15,9 +15,11 @@ - /* Fixed by Erik Andersen to do passwords the tinylogin way... - * It now works with md5, sha1, etc passwords. */ - --#include - #include "libbb.h" - -+#ifdef __linux__ -+#include -+ - static void release_vt(int signo UNUSED_PARAM) - { - /* If -a, param is 0, which means: -@@ -30,14 +32,17 @@ static void acquire_vt(int signo UNUSED_PARAM) - /* ACK to kernel that switch to console is successful */ - ioctl(STDIN_FILENO, VT_RELDISP, VT_ACKACQ); - } -+#endif - - int vlock_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; - int vlock_main(int argc UNUSED_PARAM, char **argv) - { -+#ifdef __linux__ - struct vt_mode vtm; -+ struct vt_mode ovtm; -+#endif - struct termios term; - struct termios oterm; -- struct vt_mode ovtm; - struct passwd *pw; - - pw = xgetpwuid(getuid()); -@@ -55,6 +60,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - + (1 << SIGINT ) - , SIG_IGN); - -+#ifdef __linux__ - /* We will use SIGUSRx for console switch control: */ - /* 1: set handlers */ - signal_SA_RESTART_empty_mask(SIGUSR1, release_vt); -@@ -62,12 +68,14 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - /* 2: unmask them */ - sig_unblock(SIGUSR1); - sig_unblock(SIGUSR2); -+#endif - - /* Revert stdin/out to our controlling tty - * (or die if we have none) */ - xmove_fd(xopen(CURRENT_TTY, O_RDWR), STDIN_FILENO); - xdup2(STDIN_FILENO, STDOUT_FILENO); - -+#ifdef __linux__ - xioctl(STDIN_FILENO, VT_GETMODE, &vtm); - ovtm = vtm; - /* "console switches are controlled by us, not kernel!" */ -@@ -75,6 +83,7 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - vtm.relsig = SIGUSR1; - vtm.acqsig = SIGUSR2; - ioctl(STDIN_FILENO, VT_SETMODE, &vtm); -+#endif - - tcgetattr(STDIN_FILENO, &oterm); - term = oterm; -@@ -95,7 +104,9 @@ int vlock_main(int argc UNUSED_PARAM, char **argv) - puts("Password incorrect"); - } while (1); - -+#ifdef __linux__ - ioctl(STDIN_FILENO, VT_SETMODE, &ovtm); -+#endif - tcsetattr_stdin_TCSANOW(&oterm); - fflush_stdout_and_exit(EXIT_SUCCESS); - } --- -1.7.1 - diff --git a/printutils/Kbuild.src b/printutils/Kbuild.src index 008290e..194fe01 100644 --- a/printutils/Kbuild.src +++ b/printutils/Kbuild.src @@ -1,6 +1,6 @@ # Makefile for busybox # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y := diff --git a/printutils/lpd.c b/printutils/lpd.c index d91491f..642e8a8 100644 --- a/printutils/lpd.c +++ b/printutils/lpd.c @@ -4,7 +4,7 @@ * * Copyright (C) 2008 by Vladimir Dronnikov * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* @@ -70,6 +70,17 @@ * mv -f ./"$DATAFILE" save/ */ +//usage:#define lpd_trivial_usage +//usage: "SPOOLDIR [HELPER [ARGS]]" +//usage:#define lpd_full_usage "\n\n" +//usage: "SPOOLDIR must contain (symlinks to) device nodes or directories" +//usage: "\nwith names matching print queue names. In the first case, jobs are" +//usage: "\nsent directly to the device. Otherwise each job is stored in queue" +//usage: "\ndirectory and HELPER program is called. Name of file to print" +//usage: "\nis passed in $DATAFILE variable." +//usage: "\nExample:" +//usage: "\n tcpsvd -E 0 515 softlimit -m 999999 lpd /var/spool ./print" + #include "libbb.h" // strip argument of bad chars @@ -91,7 +102,7 @@ static char *xmalloc_read_stdin(void) { // SECURITY: size_t max = 4 * 1024; // more than enough for commands! - return xmalloc_reads(STDIN_FILENO, NULL, &max); + return xmalloc_reads(STDIN_FILENO, &max); } int lpd_main(int argc, char *argv[]) MAIN_EXTERNALLY_VISIBLE; @@ -135,7 +146,7 @@ int lpd_main(int argc UNUSED_PARAM, char *argv[]) while (1) { char *fname; int fd; - // int is easier than ssize_t: can use xatoi_u, + // int is easier than ssize_t: can use xatoi_positive, // and can correctly display error returns (-1) int expected_len, real_len; diff --git a/printutils/lpr.c b/printutils/lpr.c index f21cffd..70cda77 100644 --- a/printutils/lpr.c +++ b/printutils/lpr.c @@ -7,10 +7,29 @@ * Original idea and code: * Walter Harms * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. * * See RFC 1179 for protocol description. */ + +//usage:#define lpr_trivial_usage +//usage: "-P queue[@host[:port]] -U USERNAME -J TITLE -Vmh [FILE]..." +/* -C CLASS exists too, not shown. + * CLASS is supposed to be printed on banner page, if one is requested */ +//usage:#define lpr_full_usage "\n\n" +//usage: " -P lp service to connect to (else uses $PRINTER)" +//usage: "\n -m Send mail on completion" +//usage: "\n -h Print banner page too" +//usage: "\n -V Verbose" +//usage: +//usage:#define lpq_trivial_usage +//usage: "[-P queue[@host[:port]]] [-U USERNAME] [-d JOBID]... [-fs]" +//usage:#define lpq_full_usage "\n\n" +//usage: " -P lp service to connect to (else uses $PRINTER)" +//usage: "\n -d Delete jobs" +//usage: "\n -f Force any waiting job to be printed" +//usage: "\n -s Short display" + #include "libbb.h" /* @@ -70,6 +89,10 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) unsigned opts; int fd; + queue = getenv("PRINTER"); + if (!queue) + queue = "lp"; + // parse options // TODO: set opt_complementary: s,d,f are mutually exclusive opts = getopt32(argv, @@ -79,16 +102,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) ); argv += optind; - // if queue is not specified -> use $PRINTER - if (!(opts & OPT_P)) - queue = getenv("PRINTER"); - // if queue is still not specified -> - if (!queue) { - // ... queue defaults to "lp" - // server defaults to "localhost" - queue = "lp"; - // if queue is specified -> - } else { + { // queue name is to the left of '@' char *s = strchr(queue, '@'); if (s) { @@ -159,9 +173,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) // if data file is stdin, we need to dump it first if (LONE_DASH(*argv)) { strcpy(tempfile, "/tmp/lprXXXXXX"); - dfd = mkstemp(tempfile); - if (dfd < 0) - bb_perror_msg_and_die("mkstemp"); + dfd = xmkstemp(tempfile); bb_copyfd_eof(STDIN_FILENO, dfd); xlseek(dfd, 0, SEEK_SET); *argv = (char*)bb_msg_standard_input; @@ -169,6 +181,17 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) dfd = xopen(*argv, O_RDONLY); } + st.st_size = 0; /* paranoia: fstat may theoretically fail */ + fstat(dfd, &st); + + /* Apparently, some servers are buggy and won't accept 0-sized jobs. + * Standard lpr works around it by refusing to send such jobs: + */ + if (st.st_size == 0) { + bb_error_msg("nothing to print"); + continue; + } + /* "The name ... should start with ASCII "cfA", * followed by a three digit job number, followed * by the host name which has constructed the file." @@ -193,14 +216,11 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) , (opts & LPR_m) ? user : "" , remote_filename ); - // delete possible "\nX\n" patterns + // delete possible "\nX\n" (that is, one-char) patterns c = controlfile; - cflen = (unsigned)strlen(controlfile); while ((c = strchr(c, '\n')) != NULL) { if (c[1] && c[2] == '\n') { - /* can't use strcpy, results are undefined */ - memmove(c, c+2, cflen - (c-controlfile) - 1); - cflen -= 2; + overlapping_strcpy(c, c+2); } else { c++; } @@ -211,6 +231,7 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) bb_error_msg("sending control file"); /* "Acknowledgement processing must occur as usual * after the command is sent." */ + cflen = (unsigned)strlen(controlfile); fdprintf(fd, "\x2" "%u c%s\n", cflen, remote_filename); get_response_or_say_and_die(fd, "sending control file"); /* "Once all of the contents have @@ -224,8 +245,6 @@ int lpqr_main(int argc UNUSED_PARAM, char *argv[]) // send data file, with name "dfaXXX" if (opts & LPR_V) bb_error_msg("sending data file"); - st.st_size = 0; /* paranoia: fstat may theoretically fail */ - fstat(dfd, &st); fdprintf(fd, "\x3" "%"OFF_FMT"u d%s\n", st.st_size, remote_filename); get_response_or_say_and_die(fd, "sending data file"); if (bb_copyfd_size(dfd, fd, st.st_size) != st.st_size) { diff --git a/procps/Config.src b/procps/Config.src index e61de56..527d9ee 100644 --- a/procps/Config.src +++ b/procps/Config.src @@ -10,6 +10,7 @@ INSERT config FREE bool "free" default y + select PLATFORM_LINUX #sysinfo() help free displays the total amount of free and used physical and swap memory in the system, as well as the buffers used by the kernel. @@ -45,12 +46,6 @@ config KILLALL5 default y depends on KILL -config NMETER - bool "nmeter" - default y - help - Prints selected system stats continuously, one line per update. - config PGREP bool "pgrep" default y @@ -95,16 +90,25 @@ config PS config FEATURE_PS_WIDE bool "Enable wide output option (-w)" default y - depends on PS + depends on PS && !DESKTOP help Support argument 'w' for wide output. If given once, 132 chars are printed, and if given more than once, the length is unlimited. +config FEATURE_PS_LONG + bool "Enable long output option (-l)" + default y + depends on PS && !DESKTOP + help + Support argument 'l' for long output. + Adds fields PPID, RSS, START, TIME & TTY + config FEATURE_PS_TIME bool "Enable time and elapsed time output" default y depends on PS && DESKTOP + select PLATFORM_LINUX help Support -o time and -o etime output specifiers. @@ -136,74 +140,13 @@ config BB_SYSCTL help Configure kernel parameters at runtime. -config TOP - bool "top" - default y - help - The top program provides a dynamic real-time view of a running - system. - -config FEATURE_TOP_CPU_USAGE_PERCENTAGE - bool "Show CPU per-process usage percentage" - default y - depends on TOP - help - Make top display CPU usage for each process. - This adds about 2k. - -config FEATURE_TOP_CPU_GLOBAL_PERCENTS - bool "Show CPU global usage percentage" - default y - depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE - help - Makes top display "CPU: NN% usr NN% sys..." line. - This adds about 0.5k. - -config FEATURE_TOP_SMP_CPU - bool "SMP CPU usage display ('c' key)" - default y - depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS - help - Allow 'c' key to switch between individual/cumulative CPU stats - This adds about 0.5k. - -config FEATURE_TOP_DECIMALS - bool "Show 1/10th of a percent in CPU/mem statistics" - default y - depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE - help - Show 1/10th of a percent in CPU/mem statistics. - This adds about 0.3k. - -config FEATURE_TOP_SMP_PROCESS - bool "Show CPU process runs on ('j' field)" - default y - depends on TOP - help - Show CPU where process was last found running on. - This is the 'j' field. - -config FEATURE_TOPMEM - bool "Topmem command ('s' key)" - default y - depends on TOP - help - Enable 's' in top (gives lots of memory info). - config FEATURE_SHOW_THREADS - bool "Support for showing threads in ps/top" - default y - depends on PS || TOP - help - Enables ps -T option and 'h' command in top - -config UPTIME - bool "uptime" + bool "Support for showing threads in ps/pstree/top" default y + depends on PS || TOP || PSTREE help - uptime gives a one line display of the current time, how long - the system has been running, how many users are currently logged - on, and the system load averages for the past 1, 5, and 15 minutes. + Enables the ps -T option, showing of threads in pstree, + and 'h' command in top. config WATCH bool "watch" diff --git a/procps/Kbuild.src b/procps/Kbuild.src index c41f12b..89b1cc0 100644 --- a/procps/Kbuild.src +++ b/procps/Kbuild.src @@ -2,7 +2,7 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= @@ -11,7 +11,6 @@ lib-$(CONFIG_FREE) += free.o lib-$(CONFIG_FUSER) += fuser.o lib-$(CONFIG_KILL) += kill.o lib-$(CONFIG_ASH) += kill.o # used for built-in kill by ash -lib-$(CONFIG_NMETER) += nmeter.o lib-$(CONFIG_PGREP) += pgrep.o lib-$(CONFIG_PKILL) += pgrep.o lib-$(CONFIG_PIDOF) += pidof.o diff --git a/procps/free.c b/procps/free.c index 473d70b..47f2fc3 100644 --- a/procps/free.c +++ b/procps/free.c @@ -4,77 +4,118 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ /* getopt not needed */ +//usage:#define free_trivial_usage +//usage: "" IF_DESKTOP("[-b/k/m/g]") +//usage:#define free_full_usage "\n\n" +//usage: "Display the amount of free and used system memory" +//usage: +//usage:#define free_example_usage +//usage: "$ free\n" +//usage: " total used free shared buffers\n" +//usage: " Mem: 257628 248724 8904 59644 93124\n" +//usage: " Swap: 128516 8404 120112\n" +//usage: "Total: 386144 257128 129016\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif + +struct globals { + unsigned mem_unit; +#if ENABLE_DESKTOP + unsigned unit_steps; +# define G_unit_steps G.unit_steps +#else +# define G_unit_steps 10 +#endif +} FIX_ALIASING; +#define G (*(struct globals*)&bb_common_bufsiz1) +#define INIT_G() do { } while (0) + + +static unsigned long long scale(unsigned long d) +{ + return ((unsigned long long)d * G.mem_unit) >> G_unit_steps; +} + int free_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int free_main(int argc UNUSED_PARAM, char **argv IF_NOT_DESKTOP(UNUSED_PARAM)) { struct sysinfo info; - unsigned mem_unit; + + INIT_G(); #if ENABLE_DESKTOP - if (argv[1] && argv[1][0] == '-') - bb_show_usage(); + G.unit_steps = 10; + if (argv[1] && argv[1][0] == '-') { + switch (argv[1][1]) { + case 'b': + G.unit_steps = 0; + break; + case 'k': /* 2^10 */ + /* G.unit_steps = 10; - already is */ + break; + case 'm': /* 2^(2*10) */ + G.unit_steps = 20; + break; + case 'g': /* 2^(3*10) */ + G.unit_steps = 30; + break; + default: + bb_show_usage(); + } + } #endif sysinfo(&info); /* Kernels prior to 2.4.x will return info.mem_unit==0, so cope... */ - mem_unit = 1; - if (info.mem_unit != 0) { - mem_unit = info.mem_unit; - } - - /* Convert values to kbytes */ - if (mem_unit == 1) { - info.totalram >>= 10; - info.freeram >>= 10; -#if BB_MMU - info.totalswap >>= 10; - info.freeswap >>= 10; -#endif - info.sharedram >>= 10; - info.bufferram >>= 10; - } else { - mem_unit >>= 10; - /* TODO: Make all this stuff not overflow when mem >= 4 Tb */ - info.totalram *= mem_unit; - info.freeram *= mem_unit; -#if BB_MMU - info.totalswap *= mem_unit; - info.freeswap *= mem_unit; -#endif - info.sharedram *= mem_unit; - info.bufferram *= mem_unit; - } + G.mem_unit = (info.mem_unit ? info.mem_unit : 1); - printf(" %13s%13s%13s%13s%13s\n", + printf(" %13s%13s%13s%13s%13s\n", "total", "used", "free", "shared", "buffers" /* swap and total don't have these columns */ + /* procps version 3.2.8 also shows "cached" column, but + * sysinfo() does not provide this value, need to parse + * /proc/meminfo instead and get "Cached: NNN kB" from there. + */ + ); + +#define FIELDS_5 "%13llu%13llu%13llu%13llu%13llu\n" +#define FIELDS_3 (FIELDS_5 + 2*6) +#define FIELDS_2 (FIELDS_5 + 3*6) + + printf("Mem: "); + printf(FIELDS_5, + scale(info.totalram), + scale(info.totalram - info.freeram), + scale(info.freeram), + scale(info.sharedram), + scale(info.bufferram) ); - printf("%6s%13lu%13lu%13lu%13lu%13lu\n", "Mem:", - info.totalram, - info.totalram - info.freeram, - info.freeram, - info.sharedram, info.bufferram + /* Show alternate, more meaningful busy/free numbers by counting + * buffer cache as free memory (make it "-/+ buffers/cache" + * if/when we add support for "cached" column): */ + printf("-/+ buffers: "); + printf(FIELDS_2, + scale(info.totalram - info.freeram - info.bufferram), + scale(info.freeram + info.bufferram) ); #if BB_MMU - printf("%6s%13lu%13lu%13lu\n", "Swap:", - info.totalswap, - info.totalswap - info.freeswap, - info.freeswap - ); - printf("%6s%13lu%13lu%13lu\n", "Total:", - info.totalram + info.totalswap, - (info.totalram - info.freeram) + (info.totalswap - info.freeswap), - info.freeram + info.freeswap + printf("Swap:"); + printf(FIELDS_3, + scale(info.totalswap), + scale(info.totalswap - info.freeswap), + scale(info.freeswap) ); #endif return EXIT_SUCCESS; diff --git a/procps/fuser.c b/procps/fuser.c index 85523c3..05b52ab 100644 --- a/procps/fuser.c +++ b/procps/fuser.c @@ -4,9 +4,19 @@ * * Copyright 2004 Tony J. White * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define fuser_trivial_usage +//usage: "[OPTIONS] FILE or PORT/PROTO" +//usage:#define fuser_full_usage "\n\n" +//usage: "Find processes which use FILEs or PORTs\n" +//usage: "\n -m Find processes which use same fs as FILEs" +//usage: "\n -4,-6 Search only IPv4/IPv6 space" +//usage: "\n -s Don't display PIDs" +//usage: "\n -k Kill found processes" +//usage: "\n -SIGNAL Signal to send (default: KILL)" + #include "libbb.h" #define MAX_LINE 255 @@ -26,33 +36,18 @@ typedef struct inode_list { dev_t dev; } inode_list; -typedef struct pid_list { - struct pid_list *next; - pid_t pid; -} pid_list; - - struct globals { - pid_list *pid_list_head; + int recursion_depth; + pid_t mypid; inode_list *inode_list_head; -}; + smallint kill_failed; + int killsig; +} FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) -#define INIT_G() do { } while (0) - - -static void add_pid(const pid_t pid) -{ - pid_list **curr = &G.pid_list_head; - - while (*curr) { - if ((*curr)->pid == pid) - return; - curr = &(*curr)->next; - } - - *curr = xzalloc(sizeof(pid_list)); - (*curr)->pid = pid; -} +#define INIT_G() do { \ + G.mypid = getpid(); \ + G.killsig = SIGKILL; \ +} while (0) static void add_inode(const struct stat *st) { @@ -72,48 +67,7 @@ static void add_inode(const struct stat *st) (*curr)->inode = st->st_ino; } -static void scan_proc_net(const char *path, unsigned port) -{ - char line[MAX_LINE + 1]; - long long uint64_inode; - unsigned tmp_port; - FILE *f; - struct stat st; - int fd; - - /* find socket dev */ - st.st_dev = 0; - fd = socket(AF_INET, SOCK_DGRAM, 0); - if (fd >= 0) { - fstat(fd, &st); - close(fd); - } - - f = fopen_for_read(path); - if (!f) - return; - - while (fgets(line, MAX_LINE, f)) { - char addr[68]; - if (sscanf(line, "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x %*x:%*x " - "%*x:%*x %*x %*d %*d %llu", - addr, &tmp_port, &uint64_inode) == 3 - ) { - int len = strlen(addr); - if (len == 8 && (option_mask32 & OPT_IP6)) - continue; - if (len > 8 && (option_mask32 & OPT_IP4)) - continue; - if (tmp_port == port) { - st.st_ino = uint64_inode; - add_inode(&st); - } - } - } - fclose(f); -} - -static int search_dev_inode(const struct stat *st) +static smallint search_dev_inode(const struct stat *st) { inode_list *ilist = G.inode_list_head; @@ -129,130 +83,202 @@ static int search_dev_inode(const struct stat *st) return 0; } -static void scan_pid_maps(const char *fname, pid_t pid) +enum { + PROC_NET = 0, + PROC_DIR, + PROC_DIR_LINKS, + PROC_SUBDIR_LINKS, +}; + +static smallint scan_proc_net_or_maps(const char *path, unsigned port) { - FILE *file; - char line[MAX_LINE + 1]; - int major, minor; + FILE *f; + char line[MAX_LINE + 1], addr[68]; + int major, minor, r; long long uint64_inode; - struct stat st; + unsigned tmp_port; + smallint retval; + struct stat statbuf; + const char *fmt; + void *fag, *sag; - file = fopen_for_read(fname); - if (!file) - return; + f = fopen_for_read(path); + if (!f) + return 0; - while (fgets(line, MAX_LINE, file)) { - if (sscanf(line, "%*s %*s %*s %x:%x %llu", &major, &minor, &uint64_inode) != 3) - continue; - st.st_ino = uint64_inode; - if (major == 0 && minor == 0 && st.st_ino == 0) - continue; - st.st_dev = makedev(major, minor); - if (search_dev_inode(&st)) - add_pid(pid); - } - fclose(file); -} + if (G.recursion_depth == PROC_NET) { + int fd; -static void scan_link(const char *lname, pid_t pid) -{ - struct stat st; + /* find socket dev */ + statbuf.st_dev = 0; + fd = socket(AF_INET, SOCK_DGRAM, 0); + if (fd >= 0) { + fstat(fd, &statbuf); + close(fd); + } - if (stat(lname, &st) >= 0) { - if (search_dev_inode(&st)) - add_pid(pid); + fmt = "%*d: %64[0-9A-Fa-f]:%x %*x:%*x %*x " + "%*x:%*x %*x:%*x %*x %*d %*d %llu"; + fag = addr; + sag = &tmp_port; + } else { + fmt = "%*s %*s %*s %x:%x %llu"; + fag = &major; + sag = &minor; } -} - -static void scan_dir_links(const char *dname, pid_t pid) -{ - DIR *d; - struct dirent *de; - char *lname; - d = opendir(dname); - if (!d) - return; - - while ((de = readdir(d)) != NULL) { - lname = concat_subpath_file(dname, de->d_name); - if (lname == NULL) + retval = 0; + while (fgets(line, MAX_LINE, f)) { + r = sscanf(line, fmt, fag, sag, &uint64_inode); + if (r != 3) continue; - scan_link(lname, pid); - free(lname); + + statbuf.st_ino = uint64_inode; + if (G.recursion_depth == PROC_NET) { + r = strlen(addr); + if (r == 8 && (option_mask32 & OPT_IP6)) + continue; + if (r > 8 && (option_mask32 & OPT_IP4)) + continue; + if (tmp_port == port) + add_inode(&statbuf); + } else { + if (major != 0 && minor != 0 && statbuf.st_ino != 0) { + statbuf.st_dev = makedev(major, minor); + retval = search_dev_inode(&statbuf); + if (retval) + break; + } + } } - closedir(d); + fclose(f); + + return retval; } -/* NB: does chdir internally */ -static void scan_proc_pids(void) +static smallint scan_recursive(const char *path) { DIR *d; - struct dirent *de; - pid_t pid; - - xchdir("/proc"); - d = opendir("/proc"); - if (!d) - return; - - while ((de = readdir(d)) != NULL) { - pid = (pid_t)bb_strtou(de->d_name, NULL, 10); - if (errno) - continue; - if (chdir(de->d_name) < 0) - continue; - scan_link("cwd", pid); - scan_link("exe", pid); - scan_link("root", pid); - - scan_dir_links("fd", pid); - scan_dir_links("lib", pid); - scan_dir_links("mmap", pid); + struct dirent *d_ent; + smallint stop_scan; + smallint retval; + + d = opendir(path); + if (d == NULL) + return 0; + + G.recursion_depth++; + retval = 0; + stop_scan = 0; + while (!stop_scan && (d_ent = readdir(d)) != NULL) { + struct stat statbuf; + pid_t pid; + char *subpath; + + subpath = concat_subpath_file(path, d_ent->d_name); + if (subpath == NULL) + continue; /* . or .. */ + + switch (G.recursion_depth) { + case PROC_DIR: + pid = (pid_t)bb_strtou(d_ent->d_name, NULL, 10); + if (errno != 0 + || pid == G.mypid + /* "this PID doesn't use specified FILEs or PORT/PROTO": */ + || scan_recursive(subpath) == 0 + ) { + break; + } + if (option_mask32 & OPT_KILL) { + if (kill(pid, G.killsig) != 0) { + bb_perror_msg("kill pid %s", d_ent->d_name); + G.kill_failed = 1; + } + } + if (!(option_mask32 & OPT_SILENT)) + printf("%s ", d_ent->d_name); + retval = 1; + break; - scan_pid_maps("maps", pid); - xchdir("/proc"); + case PROC_DIR_LINKS: + switch ( + index_in_substrings( + "cwd" "\0" "exe" "\0" + "root" "\0" "fd" "\0" + "lib" "\0" "mmap" "\0" + "maps" "\0", + d_ent->d_name + ) + ) { + enum { + CWD_LINK, + EXE_LINK, + ROOT_LINK, + FD_DIR_LINKS, + LIB_DIR_LINKS, + MMAP_DIR_LINKS, + MAPS, + }; + case CWD_LINK: + case EXE_LINK: + case ROOT_LINK: + goto scan_link; + case FD_DIR_LINKS: + case LIB_DIR_LINKS: + case MMAP_DIR_LINKS: + stop_scan = scan_recursive(subpath); + if (stop_scan) + retval = stop_scan; + break; + case MAPS: + stop_scan = scan_proc_net_or_maps(subpath, 0); + if (stop_scan) + retval = stop_scan; + default: + break; + } + break; + case PROC_SUBDIR_LINKS: + scan_link: + if (stat(subpath, &statbuf) < 0) + break; + stop_scan = search_dev_inode(&statbuf); + if (stop_scan) + retval = stop_scan; + default: + break; + } + free(subpath); } closedir(d); + G.recursion_depth--; + return retval; } int fuser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int fuser_main(int argc UNUSED_PARAM, char **argv) { - pid_list *plist; - pid_t mypid; char **pp; - struct stat st; - unsigned port; - int opt; - int exitcode; - int killsig; -/* -fuser [OPTIONS] FILE or PORT/PROTO -Find processes which use FILEs or PORTs - -m Find processes which use same fs as FILEs - -4 Search only IPv4 space - -6 Search only IPv6 space - -s Don't display PIDs - -k Kill found processes - -SIGNAL Signal to send (default: KILL) -*/ + + INIT_G(); + /* Handle -SIGNAL. Oh my... */ - killsig = SIGKILL; /* yes, the default is not SIGTERM */ pp = argv; while (*++pp) { + int sig; char *arg = *pp; + if (arg[0] != '-') continue; if (arg[1] == '-' && arg[2] == '\0') /* "--" */ break; if ((arg[1] == '4' || arg[1] == '6') && arg[2] == '\0') continue; /* it's "-4" or "-6" */ - opt = get_signum(&arg[1]); - if (opt < 0) + sig = get_signum(&arg[1]); + if (sig < 0) continue; /* "-SIGNAL" option found. Remove it and bail out */ - killsig = opt; + G.killsig = sig; do { pp[0] = arg = pp[1]; pp++; @@ -261,57 +287,35 @@ Find processes which use FILEs or PORTs } opt_complementary = "-1"; /* at least one param */ - opt = getopt32(argv, OPTION_STRING); + getopt32(argv, OPTION_STRING); argv += optind; pp = argv; while (*pp) { /* parse net arg */ - char path[20], tproto[5]; - if (sscanf(*pp, "%u/%4s", &port, tproto) != 2) - goto file; - sprintf(path, "/proc/net/%s", tproto); - if (access(path, R_OK) != 0) { /* PORT/PROTO */ - scan_proc_net(path, port); - } else { /* FILE */ - file: - xstat(*pp, &st); - add_inode(&st); + unsigned port; + char path[sizeof("/proc/net/TCP6")]; + + strcpy(path, "/proc/net/"); + if (sscanf(*pp, "%u/%4s", &port, path + sizeof("/proc/net/")-1) == 2 + && access(path, R_OK) == 0 + ) { + /* PORT/PROTO */ + scan_proc_net_or_maps(path, port); + } else { + /* FILE */ + struct stat statbuf; + xstat(*pp, &statbuf); + add_inode(&statbuf); } pp++; } - scan_proc_pids(); /* changes dir to "/proc" */ - - mypid = getpid(); - plist = G.pid_list_head; - while (1) { - if (!plist) - return EXIT_FAILURE; - if (plist->pid != mypid) - break; - plist = plist->next; - } - - exitcode = EXIT_SUCCESS; - do { - if (plist->pid != mypid) { - if (opt & OPT_KILL) { - if (kill(plist->pid, killsig) != 0) { - bb_perror_msg("kill pid %u", (unsigned)plist->pid); - exitcode = EXIT_FAILURE; - } - } - if (!(opt & OPT_SILENT)) { - printf("%u ", (unsigned)plist->pid); - } - } - plist = plist->next; - } while (plist); - - if (!(opt & (OPT_SILENT))) { - bb_putchar('\n'); + if (scan_recursive("/proc")) { + if (!(option_mask32 & OPT_SILENT)) + bb_putchar('\n'); + return G.kill_failed; } - return exitcode; + return EXIT_FAILURE; } diff --git a/procps/iostat.c b/procps/iostat.c new file mode 100644 index 0000000..978d234 --- /dev/null +++ b/procps/iostat.c @@ -0,0 +1,535 @@ +/* vi: set sw=4 ts=4: */ +/* + * Report CPU and I/O stats, based on sysstat version 9.1.2 by Sebastien Godard + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config IOSTAT +//config: bool "iostat" +//config: default y +//config: help +//config: Report CPU and I/O statistics + +//applet:IF_IOSTAT(APPLET(iostat, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_IOSTAT) += iostat.o + +#include "libbb.h" +#include /* struct utsname */ + +//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#define debug(fmt, ...) ((void)0) + +#define MAX_DEVICE_NAME 12 +#define MAX_DEVICE_NAME_STR "12" + +#if 1 +typedef unsigned long long cputime_t; +typedef long long icputime_t; +# define FMT_DATA "ll" +# define CPUTIME_MAX (~0ULL) +#else +typedef unsigned long cputime_t; +typedef long icputime_t; +# define FMT_DATA "l" +# define CPUTIME_MAX (~0UL) +#endif + +enum { + STATS_CPU_USER, + STATS_CPU_NICE, + STATS_CPU_SYSTEM, + STATS_CPU_IDLE, + STATS_CPU_IOWAIT, + STATS_CPU_IRQ, + STATS_CPU_SOFTIRQ, + STATS_CPU_STEAL, + STATS_CPU_GUEST, + + GLOBAL_UPTIME, + SMP_UPTIME, + + N_STATS_CPU, +}; + +typedef struct { + cputime_t vector[N_STATS_CPU]; +} stats_cpu_t; + +typedef struct { + stats_cpu_t *prev; + stats_cpu_t *curr; + cputime_t itv; +} stats_cpu_pair_t; + +typedef struct { + unsigned long long rd_sectors; + unsigned long long wr_sectors; + unsigned long rd_ops; + unsigned long wr_ops; +} stats_dev_data_t; + +typedef struct stats_dev { + struct stats_dev *next; + char dname[MAX_DEVICE_NAME + 1]; + stats_dev_data_t prev_data; + stats_dev_data_t curr_data; +} stats_dev_t; + +/* Globals. Sort by size and access frequency. */ +struct globals { + smallint show_all; + unsigned total_cpus; /* Number of CPUs */ + unsigned clk_tck; /* Number of clock ticks per second */ + llist_t *dev_name_list; /* List of devices entered on the command line */ + stats_dev_t *stats_dev_list; + struct tm tmtime; + struct { + const char *str; + unsigned div; + } unit; +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + G.unit.str = "Blk"; \ + G.unit.div = 1; \ +} while (0) + +/* Must match option string! */ +enum { + OPT_c = 1 << 0, + OPT_d = 1 << 1, + OPT_t = 1 << 2, + OPT_z = 1 << 3, + OPT_k = 1 << 4, + OPT_m = 1 << 5, +}; + +static ALWAYS_INLINE unsigned get_user_hz(void) +{ + return sysconf(_SC_CLK_TCK); +} + +static ALWAYS_INLINE int this_is_smp(void) +{ + return (G.total_cpus > 1); +} + +static void print_header(void) +{ + char buf[32]; + struct utsname uts; + + uname(&uts); /* never fails */ + + /* Date representation for the current locale */ + strftime(buf, sizeof(buf), "%x", &G.tmtime); + + printf("%s %s (%s) \t%s \t_%s_\t(%u CPU)\n\n", + uts.sysname, uts.release, uts.nodename, + buf, uts.machine, G.total_cpus); +} + +static void get_localtime(struct tm *ptm) +{ + time_t timer; + time(&timer); + localtime_r(&timer, ptm); +} + +static void print_timestamp(void) +{ + char buf[64]; + /* %x: date representation for the current locale */ + /* %X: time representation for the current locale */ + strftime(buf, sizeof(buf), "%x %X", &G.tmtime); + printf("%s\n", buf); +} + +static cputime_t get_smp_uptime(void) +{ + FILE *fp; + unsigned long sec, dec; + + fp = xfopen_for_read("/proc/uptime"); + + if (fscanf(fp, "%lu.%lu", &sec, &dec) != 2) + bb_error_msg_and_die("can't read '%s'", "/proc/uptime"); + + fclose(fp); + + return (cputime_t)sec * G.clk_tck + dec * G.clk_tck / 100; +} + +/* Fetch CPU statistics from /proc/stat */ +static void get_cpu_statistics(stats_cpu_t *sc) +{ + FILE *fp; + char buf[1024]; + + fp = xfopen_for_read("/proc/stat"); + + memset(sc, 0, sizeof(*sc)); + + while (fgets(buf, sizeof(buf), fp)) { + int i; + char *ibuf; + + /* Does the line start with "cpu "? */ + if (!starts_with_cpu(buf) || buf[3] != ' ') { + continue; + } + ibuf = buf + 4; + for (i = STATS_CPU_USER; i <= STATS_CPU_GUEST; i++) { + ibuf = skip_whitespace(ibuf); + sscanf(ibuf, "%"FMT_DATA"u", &sc->vector[i]); + if (i != STATS_CPU_GUEST) { + sc->vector[GLOBAL_UPTIME] += sc->vector[i]; + } + ibuf = skip_non_whitespace(ibuf); + } + break; + } + + if (this_is_smp()) { + sc->vector[SMP_UPTIME] = get_smp_uptime(); + } + + fclose(fp); +} + +static ALWAYS_INLINE cputime_t get_interval(cputime_t old, cputime_t new) +{ + cputime_t itv = new - old; + + return (itv == 0) ? 1 : itv; +} + +#if CPUTIME_MAX > 0xffffffff +/* + * Handle overflow conditions properly for counters which can have + * less bits than cputime_t, depending on the kernel version. + */ +/* Surprisingly, on 32bit inlining is a size win */ +static ALWAYS_INLINE cputime_t overflow_safe_sub(cputime_t prev, cputime_t curr) +{ + cputime_t v = curr - prev; + + if ((icputime_t)v < 0 /* curr < prev - counter overflow? */ + && prev <= 0xffffffff /* kernel uses 32bit value for the counter? */ + ) { + /* Add 33th bit set to 1 to curr, compensating for the overflow */ + /* double shift defeats "warning: left shift count >= width of type" */ + v += ((cputime_t)1 << 16) << 16; + } + return v; +} +#else +static ALWAYS_INLINE cputime_t overflow_safe_sub(cputime_t prev, cputime_t curr) +{ + return curr - prev; +} +#endif + +static double percent_value(cputime_t prev, cputime_t curr, cputime_t itv) +{ + return ((double)overflow_safe_sub(prev, curr)) / itv * 100; +} + +static void print_stats_cpu_struct(stats_cpu_pair_t *stats) +{ + cputime_t *p = stats->prev->vector; + cputime_t *c = stats->curr->vector; + printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", + percent_value(p[STATS_CPU_USER] , c[STATS_CPU_USER] , stats->itv), + percent_value(p[STATS_CPU_NICE] , c[STATS_CPU_NICE] , stats->itv), + percent_value(p[STATS_CPU_SYSTEM] + p[STATS_CPU_SOFTIRQ] + p[STATS_CPU_IRQ], + c[STATS_CPU_SYSTEM] + c[STATS_CPU_SOFTIRQ] + c[STATS_CPU_IRQ], stats->itv), + percent_value(p[STATS_CPU_IOWAIT], c[STATS_CPU_IOWAIT], stats->itv), + percent_value(p[STATS_CPU_STEAL] , c[STATS_CPU_STEAL] , stats->itv), + percent_value(p[STATS_CPU_IDLE] , c[STATS_CPU_IDLE] , stats->itv) + ); +} + +static void cpu_report(stats_cpu_pair_t *stats) +{ + /* Always print a header */ + puts("avg-cpu: %user %nice %system %iowait %steal %idle"); + + /* Print current statistics */ + print_stats_cpu_struct(stats); +} + +static void print_stats_dev_struct(stats_dev_t *stats_dev, cputime_t itv) +{ + stats_dev_data_t *p = &stats_dev->prev_data; + stats_dev_data_t *c = &stats_dev->curr_data; + if (option_mask32 & OPT_z) + if (p->rd_ops == c->rd_ops && p->wr_ops == c->wr_ops) + return; + + printf("%-13s %8.2f %12.2f %12.2f %10llu %10llu\n", + stats_dev->dname, + percent_value(p->rd_ops + p->wr_ops, c->rd_ops + c->wr_ops, itv), + percent_value(p->rd_sectors, c->rd_sectors, itv) / G.unit.div, + percent_value(p->wr_sectors, c->wr_sectors, itv) / G.unit.div, + (c->rd_sectors - p->rd_sectors) / G.unit.div, + (c->wr_sectors - p->wr_sectors) / G.unit.div + ); +} + +static void print_devstat_header(void) +{ + printf("Device:%15s%6s%s/s%6s%s/s%6s%s%6s%s\n", + "tps", + G.unit.str, "_read", G.unit.str, "_wrtn", + G.unit.str, "_read", G.unit.str, "_wrtn" + ); +} + +/* + * Is input partition of format [sdaN]? + */ +static int is_partition(const char *dev) +{ + /* Ok, this is naive... */ + return ((dev[0] - 's') | (dev[1] - 'd') | (dev[2] - 'a')) == 0 && isdigit(dev[3]); +} + +static stats_dev_t *stats_dev_find_or_new(const char *dev_name) +{ + stats_dev_t **curr = &G.stats_dev_list; + + while (*curr != NULL) { + if (strcmp((*curr)->dname, dev_name) == 0) + return *curr; + curr = &(*curr)->next; + } + + *curr = xzalloc(sizeof(stats_dev_t)); + strncpy((*curr)->dname, dev_name, MAX_DEVICE_NAME); + return *curr; +} + +static void stats_dev_free(stats_dev_t *stats_dev) +{ + if (stats_dev) { + stats_dev_free(stats_dev->next); + free(stats_dev); + } +} + +static void do_disk_statistics(cputime_t itv) +{ + char buf[128]; + char dev_name[MAX_DEVICE_NAME + 1]; + unsigned long long rd_sec_or_dummy; + unsigned long long wr_sec_or_dummy; + stats_dev_data_t *curr_data; + stats_dev_t *stats_dev; + FILE *fp; + int rc; + + fp = xfopen_for_read("/proc/diskstats"); + /* Read and possibly print stats from /proc/diskstats */ + while (fgets(buf, sizeof(buf), fp)) { + sscanf(buf, "%*s %*s %"MAX_DEVICE_NAME_STR"s", dev_name); + if (G.dev_name_list) { + /* Is device name in list? */ + if (!llist_find_str(G.dev_name_list, dev_name)) + continue; + } else if (is_partition(dev_name)) { + continue; + } + + stats_dev = stats_dev_find_or_new(dev_name); + curr_data = &stats_dev->curr_data; + + rc = sscanf(buf, "%*s %*s %*s %lu %llu %llu %llu %lu %*s %llu", + &curr_data->rd_ops, + &rd_sec_or_dummy, + &curr_data->rd_sectors, + &wr_sec_or_dummy, + &curr_data->wr_ops, + &curr_data->wr_sectors); + if (rc != 6) { + curr_data->rd_sectors = rd_sec_or_dummy; + curr_data->wr_sectors = wr_sec_or_dummy; + //curr_data->rd_ops = ; + curr_data->wr_ops = (unsigned long)curr_data->rd_sectors; + } + + if (!G.dev_name_list /* User didn't specify device */ + && !G.show_all + && curr_data->rd_ops == 0 + && curr_data->wr_ops == 0 + ) { + /* Don't print unused device */ + continue; + } + + /* Print current statistics */ + print_stats_dev_struct(stats_dev, itv); + stats_dev->prev_data = *curr_data; + } + + fclose(fp); +} + +static void dev_report(cputime_t itv) +{ + /* Always print a header */ + print_devstat_header(); + + /* Fetch current disk statistics */ + do_disk_statistics(itv); +} + +//usage:#define iostat_trivial_usage +//usage: "[-c] [-d] [-t] [-z] [-k|-m] [ALL|BLOCKDEV...] [INTERVAL [COUNT]]" +//usage:#define iostat_full_usage "\n\n" +//usage: "Report CPU and I/O statistics\n" +//usage: "\n -c Show CPU utilization" +//usage: "\n -d Show device utilization" +//usage: "\n -t Print current time" +//usage: "\n -z Omit devices with no activity" +//usage: "\n -k Use kb/s" +//usage: "\n -m Use Mb/s" + +int iostat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int iostat_main(int argc UNUSED_PARAM, char **argv) +{ + int opt; + unsigned interval; + int count; + stats_cpu_t stats_data[2]; + smallint current_stats; + + INIT_G(); + + memset(&stats_data, 0, sizeof(stats_data)); + + /* Get number of clock ticks per sec */ + G.clk_tck = get_user_hz(); + + /* Determine number of CPUs */ + G.total_cpus = get_cpu_count(); + if (G.total_cpus == 0) + G.total_cpus = 1; + + /* Parse and process arguments */ + /* -k and -m are mutually exclusive */ + opt_complementary = "k--m:m--k"; + opt = getopt32(argv, "cdtzkm"); + if (!(opt & (OPT_c + OPT_d))) + /* Default is -cd */ + opt |= OPT_c + OPT_d; + + argv += optind; + + /* Store device names into device list */ + while (*argv && !isdigit(*argv[0])) { + if (strcmp(*argv, "ALL") != 0) { + /* If not ALL, save device name */ + char *dev_name = skip_dev_pfx(*argv); + if (!llist_find_str(G.dev_name_list, dev_name)) { + llist_add_to(&G.dev_name_list, dev_name); + } + } else { + G.show_all = 1; + } + argv++; + } + + interval = 0; + count = 1; + if (*argv) { + /* Get interval */ + interval = xatoi_positive(*argv); + count = (interval != 0 ? -1 : 1); + argv++; + if (*argv) + /* Get count value */ + count = xatoi_positive(*argv); + } + + if (opt & OPT_m) { + G.unit.str = " MB"; + G.unit.div = 2048; + } + + if (opt & OPT_k) { + G.unit.str = " kB"; + G.unit.div = 2; + } + + get_localtime(&G.tmtime); + + /* Display header */ + print_header(); + + current_stats = 0; + /* Main loop */ + for (;;) { + stats_cpu_pair_t stats; + + stats.prev = &stats_data[current_stats ^ 1]; + stats.curr = &stats_data[current_stats]; + + /* Fill the time structure */ + get_localtime(&G.tmtime); + + /* Fetch current CPU statistics */ + get_cpu_statistics(stats.curr); + + /* Get interval */ + stats.itv = get_interval( + stats.prev->vector[GLOBAL_UPTIME], + stats.curr->vector[GLOBAL_UPTIME] + ); + + if (opt & OPT_t) + print_timestamp(); + + if (opt & OPT_c) { + cpu_report(&stats); + if (opt & OPT_d) + /* Separate outputs by a newline */ + bb_putchar('\n'); + } + + if (opt & OPT_d) { + if (this_is_smp()) { + stats.itv = get_interval( + stats.prev->vector[SMP_UPTIME], + stats.curr->vector[SMP_UPTIME] + ); + } + dev_report(stats.itv); + } + + bb_putchar('\n'); + + if (count > 0) { + if (--count == 0) + break; + } + + /* Swap stats */ + current_stats ^= 1; + + sleep(interval); + } + + if (ENABLE_FEATURE_CLEAN_UP) { + llist_free(G.dev_name_list, NULL); + stats_dev_free(G.stats_dev_list); + free(&G); + } + + return EXIT_SUCCESS; +} diff --git a/procps/kill.c b/procps/kill.c index 1d343ed..c5c7a8d 100644 --- a/procps/kill.c +++ b/procps/kill.c @@ -5,9 +5,45 @@ * Copyright (C) 1995, 1996 by Bruce Perens . * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ +//usage:#define kill_trivial_usage +//usage: "[-l] [-SIG] PID..." +//usage:#define kill_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to given PIDs\n" +//usage: "\n -l List all signal names and numbers" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ +//usage: +//usage:#define kill_example_usage +//usage: "$ ps | grep apache\n" +//usage: "252 root root S [apache]\n" +//usage: "263 www-data www-data S [apache]\n" +//usage: "264 www-data www-data S [apache]\n" +//usage: "265 www-data www-data S [apache]\n" +//usage: "266 www-data www-data S [apache]\n" +//usage: "267 www-data www-data S [apache]\n" +//usage: "$ kill 252\n" +//usage: +//usage:#define killall_trivial_usage +//usage: "[-l] [-q] [-SIG] PROCESS_NAME..." +//usage:#define killall_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to given processes\n" +//usage: "\n -l List all signal names and numbers" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ +//usage: "\n -q Don't complain if no processes were killed" +//usage: +//usage:#define killall_example_usage +//usage: "$ killall apache\n" +//usage: +//usage:#define killall5_trivial_usage +//usage: "[-l] [-SIG] [-o PID]..." +//usage:#define killall5_full_usage "\n\n" +//usage: "Send a signal (default: TERM) to all processes outside current session\n" +//usage: "\n -l List all signal names and numbers" +//usage: "\n -o PID Don't signal this PID" +/* //usage: "\n -s SIG Yet another way of specifying SIG" */ + #include "libbb.h" /* Note: kill_main is directly called from shell in order to implement @@ -24,7 +60,7 @@ * This is needed to avoid collision with kill -9 ... syntax */ -int kill_main(int argc, char **argv) +int kill_main(int argc UNUSED_PARAM, char **argv) { char *arg; pid_t pid; @@ -43,10 +79,9 @@ int kill_main(int argc, char **argv) #endif /* Parse any options */ - argc--; arg = *++argv; - if (argc < 1 || arg[0] != '-') { + if (!arg || arg[0] != '-') { goto do_it_now; } @@ -55,13 +90,14 @@ int kill_main(int argc, char **argv) * echo "Died of SIG`kill -l $?`" * We try to mimic what kill from coreutils-6.8 does */ if (arg[1] == 'l' && arg[2] == '\0') { - if (argc == 1) { + arg = *++argv; + if (!arg) { /* Print the whole signal list */ print_signames(); return 0; } /* -l */ - while ((arg = *++argv)) { + do { if (isdigit(arg[0])) { signo = bb_strtou(arg, NULL, 10); if (errno) { @@ -82,8 +118,8 @@ int kill_main(int argc, char **argv) } printf("%d\n", signo); } - } - /* If they specified -l, we are all done */ + arg = *++argv; + } while (arg); return EXIT_SUCCESS; } @@ -91,8 +127,7 @@ int kill_main(int argc, char **argv) if (killall && arg[1] == 'q' && arg[2] == '\0') { quiet = 1; arg = *++argv; - argc--; - if (argc < 1) + if (!arg) bb_show_usage(); if (arg[0] != '-') goto do_it_now; @@ -104,8 +139,7 @@ int kill_main(int argc, char **argv) if (killall5 && arg[0] == 'o') goto do_it_now; - if (argc > 1 && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */ - argc--; + if (argv[1] && arg[0] == 's' && arg[1] == '\0') { /* -s SIG? */ arg = *++argv; } /* else it must be -SIG */ signo = get_signum(arg); @@ -114,7 +148,6 @@ int kill_main(int argc, char **argv) return EXIT_FAILURE; } arg = *++argv; - argc--; do_it_now: pid = getpid(); @@ -122,38 +155,44 @@ int kill_main(int argc, char **argv) if (killall5) { pid_t sid; procps_status_t* p = NULL; - int ret = 0; + /* compat: exitcode 2 is "no one was signaled" */ + int ret = 2; /* Find out our session id */ sid = getsid(pid); /* Stop all processes */ - kill(-1, SIGSTOP); + if (signo != SIGSTOP && signo != SIGCONT) + kill(-1, SIGSTOP); /* Signal all processes except those in our session */ - while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID))) { - int i; + while ((p = procps_scan(p, PSSCAN_PID|PSSCAN_SID)) != NULL) { + char **args; if (p->sid == (unsigned)sid + || p->sid == 0 /* compat: kernel thread, don't signal it */ || p->pid == (unsigned)pid - || p->pid == 1) + || p->pid == 1 + ) { continue; + } /* All remaining args must be -o PID options. * Check p->pid against them. */ - for (i = 0; i < argc; i++) { + args = argv; + while (*args) { pid_t omit; - arg = argv[i]; + arg = *args++; if (arg[0] != '-' || arg[1] != 'o') { bb_error_msg("bad option '%s'", arg); ret = 1; goto resume; } arg += 2; - if (!arg[0] && argv[++i]) - arg = argv[i]; + if (!arg[0] && *args) + arg = *args++; omit = bb_strtoi(arg, NULL, 10); if (errno) { - bb_error_msg("bad pid '%s'", arg); + bb_error_msg("invalid number '%s'", arg); ret = 1; goto resume; } @@ -161,23 +200,25 @@ int kill_main(int argc, char **argv) goto dont_kill; } kill(p->pid, signo); + ret = 0; dont_kill: ; } resume: /* And let them continue */ - kill(-1, SIGCONT); + if (signo != SIGSTOP && signo != SIGCONT) + kill(-1, SIGCONT); return ret; } /* Pid or name is required for kill/killall */ - if (argc < 1) { + if (!arg) { bb_error_msg("you need to specify whom to kill"); return EXIT_FAILURE; } if (killall) { /* Looks like they want to do a killall. Do that */ - while (arg) { + do { pid_t* pidList; pidList = find_pid_by_name(arg); @@ -200,23 +241,44 @@ int kill_main(int argc, char **argv) } free(pidList); arg = *++argv; - } + } while (arg); return errors; } /* Looks like they want to do a kill. Do that */ while (arg) { - /* Support shell 'space' trick */ - if (arg[0] == ' ') - arg++; +#if ENABLE_ASH || ENABLE_HUSH + /* + * We need to support shell's "hack formats" of + * " -PRGP_ID" (yes, with a leading space) + * and " PID1 PID2 PID3" (with degenerate case "") + */ + while (*arg != '\0') { + char *end; + if (*arg == ' ') + arg++; + pid = bb_strtoi(arg, &end, 10); + if (errno && (errno != EINVAL || *end != ' ')) { + bb_error_msg("invalid number '%s'", arg); + errors++; + break; + } + if (kill(pid, signo) != 0) { + bb_perror_msg("can't kill pid %d", (int)pid); + errors++; + } + arg = end; /* can only point to ' ' or '\0' now */ + } +#else pid = bb_strtoi(arg, NULL, 10); if (errno) { - bb_error_msg("bad pid '%s'", arg); + bb_error_msg("invalid number '%s'", arg); errors++; } else if (kill(pid, signo) != 0) { bb_perror_msg("can't kill pid %d", (int)pid); errors++; } +#endif arg = *++argv; } return errors; diff --git a/procps/lsof.c b/procps/lsof.c new file mode 100644 index 0000000..b0156a5 --- /dev/null +++ b/procps/lsof.c @@ -0,0 +1,79 @@ +/* vi: set sw=4 ts=4: */ +/* + * Mini lsof implementation for busybox + * + * Copyright (C) 2012 by Sven Oliver 'SvOlli' Moll + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config LSOF +//config: bool "lsof" +//config: default y +//config: help +//config: Show open files in the format of: +//config: PID /path/to/executable /path/to/opened/file + +//applet:IF_LSOF(APPLET(lsof, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_LSOF) += lsof.o + +//usage:#define lsof_trivial_usage +//usage: "" +//usage:#define lsof_full_usage "\n\n" +//usage: "Show all open files" + +#include "libbb.h" + +/* + * Examples of "standard" lsof output: + * + * COMMAND PID USER FD TYPE DEVICE SIZE NODE NAME + * init 1 root cwd DIR 8,5 4096 2 / + * init 1 root rtd DIR 8,5 4096 2 / + * init 1 root txt REG 8,5 872400 63408 /app/busybox-1.19.2/busybox + * rpc.portm 1064 root mem REG 8,5 43494 47451 /app/glibc-2.11/lib/libnss_files-2.11.so + * rpc.portm 1064 root 3u IPv4 2178 UDP *:111 + * rpc.portm 1064 root 4u IPv4 1244 TCP *:111 (LISTEN) + * runsvdir 1116 root 0r CHR 1,3 1214 /dev/null + * runsvdir 1116 root 1w CHR 1,3 1214 /dev/null + * runsvdir 1116 root 2w CHR 1,3 1214 /dev/null + * runsvdir 1116 root 3r DIR 8,6 1560 58359 /.local/var/service + * gpm 1128 root 4u unix 0xffff88007c09ccc0 1302 /dev/gpmctl + */ + +int lsof_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int lsof_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + procps_status_t *proc = NULL; + + while ((proc = procps_scan(proc, PSSCAN_PID|PSSCAN_EXE)) != NULL) { + char name[sizeof("/proc/%u/fd/0123456789") + sizeof(int)*3]; + unsigned baseofs; + DIR *d_fd; + char *fdlink; + struct dirent *entry; + + if (getpid() == proc->pid) + continue; + + baseofs = sprintf(name, "/proc/%u/fd/", proc->pid); + d_fd = opendir(name); + if (d_fd) { + while ((entry = readdir(d_fd)) != NULL) { + /* Skip entries '.' and '..' (and any hidden file) */ + if (entry->d_name[0] == '.') + continue; + + safe_strncpy(name + baseofs, entry->d_name, 10); + if ((fdlink = xmalloc_readlink(name)) != NULL) { + printf("%d\t%s\t%s\n", proc->pid, proc->exe, fdlink); + free(fdlink); + } + } + closedir(d_fd); + } + } + + return EXIT_SUCCESS; +} diff --git a/procps/mpstat.c b/procps/mpstat.c new file mode 100644 index 0000000..aa5a5c7 --- /dev/null +++ b/procps/mpstat.c @@ -0,0 +1,977 @@ +/* vi: set sw=4 ts=4: */ +/* + * Per-processor statistics, based on sysstat version 9.1.2 by Sebastien Godard + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//applet:IF_MPSTAT(APPLET(mpstat, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_MPSTAT) += mpstat.o + +//config:config MPSTAT +//config: bool "mpstat" +//config: default y +//config: help +//config: Per-processor statistics + +#include "libbb.h" +#include /* struct utsname */ + +//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#define debug(fmt, ...) ((void)0) + +/* Size of /proc/interrupts line, CPU data excluded */ +#define INTERRUPTS_LINE 64 +/* Maximum number of interrupts */ +#define NR_IRQS 256 +#define NR_IRQCPU_PREALLOC 3 +#define MAX_IRQNAME_LEN 16 +#define MAX_PF_NAME 512 +/* sysstat 9.0.6 uses width 8, but newer code which also prints /proc/softirqs + * data needs more: "interrupts" in /proc/softirqs have longer names, + * most are up to 8 chars, one (BLOCK_IOPOLL) is even longer. + * We are printing headers in the " IRQNAME/s" form, experimentally + * anything smaller than 10 chars looks ugly for /proc/softirqs stats. + */ +#define INTRATE_SCRWIDTH 10 +#define INTRATE_SCRWIDTH_STR "10" + +/* System files */ +#define PROCFS_STAT "/proc/stat" +#define PROCFS_INTERRUPTS "/proc/interrupts" +#define PROCFS_SOFTIRQS "/proc/softirqs" +#define PROCFS_UPTIME "/proc/uptime" + + +#if 1 +typedef unsigned long long data_t; +typedef long long idata_t; +#define FMT_DATA "ll" +#define DATA_MAX ULLONG_MAX +#else +typedef unsigned long data_t; +typedef long idata_t; +#define FMT_DATA "l" +#define DATA_MAX ULONG_MAX +#endif + + +struct stats_irqcpu { + unsigned interrupts; + char irq_name[MAX_IRQNAME_LEN]; +}; + +struct stats_cpu { + data_t cpu_user; + data_t cpu_nice; + data_t cpu_system; + data_t cpu_idle; + data_t cpu_iowait; + data_t cpu_steal; + data_t cpu_irq; + data_t cpu_softirq; + data_t cpu_guest; +}; + +struct stats_irq { + data_t irq_nr; +}; + + +/* Globals. Sort by size and access frequency. */ +struct globals { + int interval; + int count; + unsigned cpu_nr; /* Number of CPUs */ + unsigned irqcpu_nr; /* Number of interrupts per CPU */ + unsigned softirqcpu_nr; /* Number of soft interrupts per CPU */ + unsigned options; + unsigned hz; + unsigned cpu_bitmap_len; + smallint p_option; + // 9.0.6 does not do it. Try "mpstat -A 1 2" - headers are repeated! + //smallint header_done; + //smallint avg_header_done; + unsigned char *cpu_bitmap; /* Bit 0: global, bit 1: 1st proc... */ + data_t global_uptime[3]; + data_t per_cpu_uptime[3]; + struct stats_cpu *st_cpu[3]; + struct stats_irq *st_irq[3]; + struct stats_irqcpu *st_irqcpu[3]; + struct stats_irqcpu *st_softirqcpu[3]; + struct tm timestamp[3]; +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +/* The selected interrupts statistics (bits in G.options) */ +enum { + D_CPU = 1 << 0, + D_IRQ_SUM = 1 << 1, + D_IRQ_CPU = 1 << 2, + D_SOFTIRQS = 1 << 3, +}; + + +/* Is option on? */ +static ALWAYS_INLINE int display_opt(int opt) +{ + return (opt & G.options); +} + +#if DATA_MAX > 0xffffffff +/* + * Handle overflow conditions properly for counters which can have + * less bits than data_t, depending on the kernel version. + */ +/* Surprisingly, on 32bit inlining is a size win */ +static ALWAYS_INLINE data_t overflow_safe_sub(data_t prev, data_t curr) +{ + data_t v = curr - prev; + + if ((idata_t)v < 0 /* curr < prev - counter overflow? */ + && prev <= 0xffffffff /* kernel uses 32bit value for the counter? */ + ) { + /* Add 33th bit set to 1 to curr, compensating for the overflow */ + /* double shift defeats "warning: left shift count >= width of type" */ + v += ((data_t)1 << 16) << 16; + } + return v; +} +#else +static ALWAYS_INLINE data_t overflow_safe_sub(data_t prev, data_t curr) +{ + return curr - prev; +} +#endif + +static double percent_value(data_t prev, data_t curr, data_t itv) +{ + return ((double)overflow_safe_sub(prev, curr)) / itv * 100; +} + +static double hz_value(data_t prev, data_t curr, data_t itv) +{ + //bb_error_msg("curr:%lld prev:%lld G.hz:%u", curr, prev, G.hz); + return ((double)overflow_safe_sub(prev, curr)) / itv * G.hz; +} + +static ALWAYS_INLINE data_t jiffies_diff(data_t old, data_t new) +{ + data_t diff = new - old; + return (diff == 0) ? 1 : diff; +} + +static int is_cpu_in_bitmap(unsigned cpu) +{ + return G.cpu_bitmap[cpu >> 3] & (1 << (cpu & 7)); +} + +static void write_irqcpu_stats(struct stats_irqcpu *per_cpu_stats[], + int total_irqs, + data_t itv, + int prev, int current, + const char *prev_str, const char *current_str) +{ + int j; + int offset, cpu; + struct stats_irqcpu *p0, *q0; + + /* Check if number of IRQs has changed */ + if (G.interval != 0) { + for (j = 0; j <= total_irqs; j++) { + p0 = &per_cpu_stats[current][j]; + if (p0->irq_name[0] != '\0') { + q0 = &per_cpu_stats[prev][j]; + if (strcmp(p0->irq_name, q0->irq_name) != 0) { + /* Strings are different */ + break; + } + } + } + } + + /* Print header */ + printf("\n%-11s CPU", prev_str); + { + /* A bit complex code to "buy back" space if one header is too wide. + * Here's how it looks like. BLOCK_IOPOLL eats too much space, + * and latter headers use smaller width to compensate: + * ...BLOCK/s BLOCK_IOPOLL/s TASKLET/s SCHED/s HRTIMER/s RCU/s + * ... 2.32 0.00 0.01 17.58 0.14 141.96 + */ + int expected_len = 0; + int printed_len = 0; + for (j = 0; j < total_irqs; j++) { + p0 = &per_cpu_stats[current][j]; + if (p0->irq_name[0] != '\0') { + int n = (INTRATE_SCRWIDTH-3) - (printed_len - expected_len); + printed_len += printf(" %*s/s", n > 0 ? n : 0, skip_whitespace(p0->irq_name)); + expected_len += INTRATE_SCRWIDTH; + } + } + } + bb_putchar('\n'); + + for (cpu = 1; cpu <= G.cpu_nr; cpu++) { + /* Check if we want stats about this CPU */ + if (!is_cpu_in_bitmap(cpu) && G.p_option) { + continue; + } + + printf("%-11s %4u", current_str, cpu - 1); + + for (j = 0; j < total_irqs; j++) { + /* IRQ field set only for proc 0 */ + p0 = &per_cpu_stats[current][j]; + + /* + * An empty string for irq name means that + * interrupt is no longer used. + */ + if (p0->irq_name[0] != '\0') { + offset = j; + q0 = &per_cpu_stats[prev][offset]; + + /* + * If we want stats for the time since boot + * we have p0->irq != q0->irq. + */ + if (strcmp(p0->irq_name, q0->irq_name) != 0 + && G.interval != 0 + ) { + if (j) { + offset = j - 1; + q0 = &per_cpu_stats[prev][offset]; + } + if (strcmp(p0->irq_name, q0->irq_name) != 0 + && (j + 1 < total_irqs) + ) { + offset = j + 1; + q0 = &per_cpu_stats[prev][offset]; + } + } + + if (strcmp(p0->irq_name, q0->irq_name) == 0 + || G.interval == 0 + ) { + struct stats_irqcpu *p, *q; + p = &per_cpu_stats[current][(cpu - 1) * total_irqs + j]; + q = &per_cpu_stats[prev][(cpu - 1) * total_irqs + offset]; + printf("%"INTRATE_SCRWIDTH_STR".2f", + (double)(p->interrupts - q->interrupts) / itv * G.hz); + } else { + printf(" N/A"); + } + } + } + bb_putchar('\n'); + } +} + +static data_t get_per_cpu_interval(const struct stats_cpu *scc, + const struct stats_cpu *scp) +{ + return ((scc->cpu_user + scc->cpu_nice + + scc->cpu_system + scc->cpu_iowait + + scc->cpu_idle + scc->cpu_steal + + scc->cpu_irq + scc->cpu_softirq) - + (scp->cpu_user + scp->cpu_nice + + scp->cpu_system + scp->cpu_iowait + + scp->cpu_idle + scp->cpu_steal + + scp->cpu_irq + scp->cpu_softirq)); +} + +static void print_stats_cpu_struct(const struct stats_cpu *p, + const struct stats_cpu *c, + data_t itv) +{ + printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", + percent_value(p->cpu_user - p->cpu_guest, + /**/ c->cpu_user - c->cpu_guest, itv), + percent_value(p->cpu_nice , c->cpu_nice , itv), + percent_value(p->cpu_system , c->cpu_system , itv), + percent_value(p->cpu_iowait , c->cpu_iowait , itv), + percent_value(p->cpu_irq , c->cpu_irq , itv), + percent_value(p->cpu_softirq, c->cpu_softirq, itv), + percent_value(p->cpu_steal , c->cpu_steal , itv), + percent_value(p->cpu_guest , c->cpu_guest , itv), + percent_value(p->cpu_idle , c->cpu_idle , itv) + ); +} + +static void write_stats_core(int prev, int current, + const char *prev_str, const char *current_str) +{ + struct stats_cpu *scc, *scp; + data_t itv, global_itv; + int cpu; + + /* Compute time interval */ + itv = global_itv = jiffies_diff(G.global_uptime[prev], G.global_uptime[current]); + + /* Reduce interval to one CPU */ + if (G.cpu_nr > 1) + itv = jiffies_diff(G.per_cpu_uptime[prev], G.per_cpu_uptime[current]); + + /* Print CPU stats */ + if (display_opt(D_CPU)) { + + ///* This is done exactly once */ + //if (!G.header_done) { + printf("\n%-11s CPU %%usr %%nice %%sys %%iowait %%irq %%soft %%steal %%guest %%idle\n", + prev_str + ); + // G.header_done = 1; + //} + + for (cpu = 0; cpu <= G.cpu_nr; cpu++) { + data_t per_cpu_itv; + + /* Print stats about this particular CPU? */ + if (!is_cpu_in_bitmap(cpu)) + continue; + + scc = &G.st_cpu[current][cpu]; + scp = &G.st_cpu[prev][cpu]; + per_cpu_itv = global_itv; + + printf((cpu ? "%-11s %4u" : "%-11s all"), current_str, cpu - 1); + if (cpu) { + double idle; + /* + * If the CPU is offline, then it isn't in /proc/stat, + * so all values are 0. + * NB: Guest time is already included in user time. + */ + if ((scc->cpu_user | scc->cpu_nice | scc->cpu_system | + scc->cpu_iowait | scc->cpu_idle | scc->cpu_steal | + scc->cpu_irq | scc->cpu_softirq) == 0 + ) { + /* + * Set current struct fields to values from prev. + * iteration. Then their values won't jump from + * zero, when the CPU comes back online. + */ + *scc = *scp; + idle = 0.0; + goto print_zeros; + } + /* Compute interval again for current proc */ + per_cpu_itv = get_per_cpu_interval(scc, scp); + if (per_cpu_itv == 0) { + /* + * If the CPU is tickless then there is no change in CPU values + * but the sum of values is not zero. + */ + idle = 100.0; + print_zeros: + printf(" %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f %7.2f\n", + 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, idle); + continue; + } + } + print_stats_cpu_struct(scp, scc, per_cpu_itv); + } + } + + /* Print total number of IRQs per CPU */ + if (display_opt(D_IRQ_SUM)) { + + ///* Print average header, this is done exactly once */ + //if (!G.avg_header_done) { + printf("\n%-11s CPU intr/s\n", prev_str); + // G.avg_header_done = 1; + //} + + for (cpu = 0; cpu <= G.cpu_nr; cpu++) { + data_t per_cpu_itv; + + /* Print stats about this CPU? */ + if (!is_cpu_in_bitmap(cpu)) + continue; + + per_cpu_itv = itv; + printf((cpu ? "%-11s %4u" : "%-11s all"), current_str, cpu - 1); + if (cpu) { + scc = &G.st_cpu[current][cpu]; + scp = &G.st_cpu[prev][cpu]; + /* Compute interval again for current proc */ + per_cpu_itv = get_per_cpu_interval(scc, scp); + if (per_cpu_itv == 0) { + printf(" %9.2f\n", 0.0); + continue; + } + } + //bb_error_msg("G.st_irq[%u][%u].irq_nr:%lld - G.st_irq[%u][%u].irq_nr:%lld", + // current, cpu, G.st_irq[prev][cpu].irq_nr, prev, cpu, G.st_irq[current][cpu].irq_nr); + printf(" %9.2f\n", hz_value(G.st_irq[prev][cpu].irq_nr, G.st_irq[current][cpu].irq_nr, per_cpu_itv)); + } + } + + if (display_opt(D_IRQ_CPU)) { + write_irqcpu_stats(G.st_irqcpu, G.irqcpu_nr, + itv, + prev, current, + prev_str, current_str + ); + } + + if (display_opt(D_SOFTIRQS)) { + write_irqcpu_stats(G.st_softirqcpu, G.softirqcpu_nr, + itv, + prev, current, + prev_str, current_str + ); + } +} + +/* + * Print the statistics + */ +static void write_stats(int current) +{ + char prev_time[16]; + char curr_time[16]; + + strftime(prev_time, sizeof(prev_time), "%X", &G.timestamp[!current]); + strftime(curr_time, sizeof(curr_time), "%X", &G.timestamp[current]); + + write_stats_core(!current, current, prev_time, curr_time); +} + +static void write_stats_avg(int current) +{ + write_stats_core(2, current, "Average:", "Average:"); +} + +/* + * Read CPU statistics + */ +static void get_cpu_statistics(struct stats_cpu *cpu, data_t *up, data_t *up0) +{ + FILE *fp; + char buf[1024]; + + fp = xfopen_for_read(PROCFS_STAT); + + while (fgets(buf, sizeof(buf), fp)) { + data_t sum; + unsigned cpu_number; + struct stats_cpu *cp; + + if (!starts_with_cpu(buf)) + continue; /* not "cpu" */ + + cp = cpu; /* for "cpu " case */ + if (buf[3] != ' ') { + /* "cpuN " */ + if (G.cpu_nr == 0 + || sscanf(buf + 3, "%u ", &cpu_number) != 1 + || cpu_number >= G.cpu_nr + ) { + continue; + } + cp = &cpu[cpu_number + 1]; + } + + /* Read the counters, save them */ + /* Not all fields have to be present */ + memset(cp, 0, sizeof(*cp)); + sscanf(buf, "%*s" + " %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u" + " %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u" + " %"FMT_DATA"u %"FMT_DATA"u %"FMT_DATA"u", + &cp->cpu_user, &cp->cpu_nice, &cp->cpu_system, + &cp->cpu_idle, &cp->cpu_iowait, &cp->cpu_irq, + &cp->cpu_softirq, &cp->cpu_steal, &cp->cpu_guest + ); + /* + * Compute uptime in jiffies (1/HZ), it'll be the sum of + * individual CPU's uptimes. + * NB: We have to omit cpu_guest, because cpu_user includes it. + */ + sum = cp->cpu_user + cp->cpu_nice + cp->cpu_system + + cp->cpu_idle + cp->cpu_iowait + cp->cpu_irq + + cp->cpu_softirq + cp->cpu_steal; + + if (buf[3] == ' ') { + /* "cpu " */ + *up = sum; + } else { + /* "cpuN " */ + if (cpu_number == 0 && *up0 != 0) { + /* Compute uptime of single CPU */ + *up0 = sum; + } + } + } + fclose(fp); +} + +/* + * Read IRQs from /proc/stat + */ +static void get_irqs_from_stat(struct stats_irq *irq) +{ + FILE *fp; + char buf[1024]; + + fp = fopen_for_read(PROCFS_STAT); + if (!fp) + return; + + while (fgets(buf, sizeof(buf), fp)) { + //bb_error_msg("/proc/stat:'%s'", buf); + if (strncmp(buf, "intr ", 5) == 0) { + /* Read total number of IRQs since system boot */ + sscanf(buf + 5, "%"FMT_DATA"u", &irq->irq_nr); + } + } + + fclose(fp); +} + +/* + * Read stats from /proc/interrupts or /proc/softirqs + */ +static void get_irqs_from_interrupts(const char *fname, + struct stats_irqcpu *per_cpu_stats[], + int irqs_per_cpu, int current) +{ + FILE *fp; + struct stats_irq *irq_i; + struct stats_irqcpu *ic; + char *buf; + unsigned buflen; + unsigned cpu; + unsigned irq; + int cpu_index[G.cpu_nr]; + int iindex; + +// Moved to caller. +// Otherwise reading of /proc/softirqs +// was resetting counts to 0 after we painstakingly collected them from +// /proc/interrupts. Which resulted in: +// 01:32:47 PM CPU intr/s +// 01:32:47 PM all 591.47 +// 01:32:47 PM 0 0.00 <= ??? +// 01:32:47 PM 1 0.00 <= ??? +// for (cpu = 1; cpu <= G.cpu_nr; cpu++) { +// G.st_irq[current][cpu].irq_nr = 0; +// //bb_error_msg("G.st_irq[%u][%u].irq_nr=0", current, cpu); +// } + + fp = fopen_for_read(fname); + if (!fp) + return; + + buflen = INTERRUPTS_LINE + 16 * G.cpu_nr; + buf = xmalloc(buflen); + + /* Parse header and determine, which CPUs are online */ + iindex = 0; + while (fgets(buf, buflen, fp)) { + char *cp, *next; + next = buf; + while ((cp = strstr(next, "CPU")) != NULL + && iindex < G.cpu_nr + ) { + cpu = strtoul(cp + 3, &next, 10); + cpu_index[iindex++] = cpu; + } + if (iindex) /* We found header */ + break; + } + + irq = 0; + while (fgets(buf, buflen, fp) + && irq < irqs_per_cpu + ) { + int len; + char last_char; + char *cp; + + /* Skip over "IRQNAME:" */ + cp = strchr(buf, ':'); + if (!cp) + continue; + last_char = cp[-1]; + + ic = &per_cpu_stats[current][irq]; + len = cp - buf; + if (len >= sizeof(ic->irq_name)) { + len = sizeof(ic->irq_name) - 1; + } + safe_strncpy(ic->irq_name, buf, len + 1); + //bb_error_msg("%s: irq%d:'%s' buf:'%s'", fname, irq, ic->irq_name, buf); + cp++; + + for (cpu = 0; cpu < iindex; cpu++) { + char *next; + ic = &per_cpu_stats[current][cpu_index[cpu] * irqs_per_cpu + irq]; + irq_i = &G.st_irq[current][cpu_index[cpu] + 1]; + ic->interrupts = strtoul(cp, &next, 10); + /* Count only numerical IRQs */ + if (isdigit(last_char)) { + irq_i->irq_nr += ic->interrupts; + //bb_error_msg("G.st_irq[%u][%u].irq_nr + %u = %lld", + // current, cpu_index[cpu] + 1, ic->interrupts, irq_i->irq_nr); + } + cp = next; + } + irq++; + } + fclose(fp); + free(buf); + + while (irq < irqs_per_cpu) { + /* Number of interrupts per CPU has changed */ + ic = &per_cpu_stats[current][irq]; + ic->irq_name[0] = '\0'; /* False interrupt */ + irq++; + } +} + +static void get_uptime(data_t *uptime) +{ + FILE *fp; + char buf[sizeof(long)*3 * 2 + 4]; /* enough for long.long */ + unsigned long uptime_sec, decimal; + + fp = fopen_for_read(PROCFS_UPTIME); + if (!fp) + return; + if (fgets(buf, sizeof(buf), fp)) { + if (sscanf(buf, "%lu.%lu", &uptime_sec, &decimal) == 2) { + *uptime = (data_t)uptime_sec * G.hz + decimal * G.hz / 100; + } + } + + fclose(fp); +} + +static void get_localtime(struct tm *tm) +{ + time_t timer; + time(&timer); + localtime_r(&timer, tm); +} + +static void alarm_handler(int sig UNUSED_PARAM) +{ + signal(SIGALRM, alarm_handler); + alarm(G.interval); +} + +static void main_loop(void) +{ + unsigned current; + unsigned cpus; + + /* Read the stats */ + if (G.cpu_nr > 1) { + G.per_cpu_uptime[0] = 0; + get_uptime(&G.per_cpu_uptime[0]); + } + + get_cpu_statistics(G.st_cpu[0], &G.global_uptime[0], &G.per_cpu_uptime[0]); + + if (display_opt(D_IRQ_SUM)) + get_irqs_from_stat(G.st_irq[0]); + + if (display_opt(D_IRQ_SUM | D_IRQ_CPU)) + get_irqs_from_interrupts(PROCFS_INTERRUPTS, G.st_irqcpu, + G.irqcpu_nr, 0); + + if (display_opt(D_SOFTIRQS)) + get_irqs_from_interrupts(PROCFS_SOFTIRQS, G.st_softirqcpu, + G.softirqcpu_nr, 0); + + if (G.interval == 0) { + /* Display since boot time */ + cpus = G.cpu_nr + 1; + G.timestamp[1] = G.timestamp[0]; + memset(G.st_cpu[1], 0, sizeof(G.st_cpu[1][0]) * cpus); + memset(G.st_irq[1], 0, sizeof(G.st_irq[1][0]) * cpus); + memset(G.st_irqcpu[1], 0, sizeof(G.st_irqcpu[1][0]) * cpus * G.irqcpu_nr); + memset(G.st_softirqcpu[1], 0, sizeof(G.st_softirqcpu[1][0]) * cpus * G.softirqcpu_nr); + + write_stats(0); + + /* And we're done */ + return; + } + + /* Set a handler for SIGALRM */ + alarm_handler(0); + + /* Save the stats we already have. We need them to compute the average */ + G.timestamp[2] = G.timestamp[0]; + G.global_uptime[2] = G.global_uptime[0]; + G.per_cpu_uptime[2] = G.per_cpu_uptime[0]; + cpus = G.cpu_nr + 1; + memcpy(G.st_cpu[2], G.st_cpu[0], sizeof(G.st_cpu[0][0]) * cpus); + memcpy(G.st_irq[2], G.st_irq[0], sizeof(G.st_irq[0][0]) * cpus); + memcpy(G.st_irqcpu[2], G.st_irqcpu[0], sizeof(G.st_irqcpu[0][0]) * cpus * G.irqcpu_nr); + if (display_opt(D_SOFTIRQS)) { + memcpy(G.st_softirqcpu[2], G.st_softirqcpu[0], + sizeof(G.st_softirqcpu[0][0]) * cpus * G.softirqcpu_nr); + } + + current = 1; + while (1) { + /* Suspend until a signal is received */ + pause(); + + /* Set structures to 0 to distinguish off/online CPUs */ + memset(&G.st_cpu[current][/*cpu:*/ 1], 0, sizeof(G.st_cpu[0][0]) * G.cpu_nr); + + get_localtime(&G.timestamp[current]); + + /* Read stats */ + if (G.cpu_nr > 1) { + G.per_cpu_uptime[current] = 0; + get_uptime(&G.per_cpu_uptime[current]); + } + get_cpu_statistics(G.st_cpu[current], &G.global_uptime[current], &G.per_cpu_uptime[current]); + + if (display_opt(D_IRQ_SUM)) + get_irqs_from_stat(G.st_irq[current]); + + if (display_opt(D_IRQ_SUM | D_IRQ_CPU)) { + int cpu; + for (cpu = 1; cpu <= G.cpu_nr; cpu++) { + G.st_irq[current][cpu].irq_nr = 0; + } + /* accumulates .irq_nr */ + get_irqs_from_interrupts(PROCFS_INTERRUPTS, G.st_irqcpu, + G.irqcpu_nr, current); + } + + if (display_opt(D_SOFTIRQS)) + get_irqs_from_interrupts(PROCFS_SOFTIRQS, + G.st_softirqcpu, + G.softirqcpu_nr, current); + + write_stats(current); + + if (G.count > 0) { + if (--G.count == 0) + break; + } + + current ^= 1; + } + + /* Print average statistics */ + write_stats_avg(current); +} + +/* Initialization */ + +/* Get number of clock ticks per sec */ +static ALWAYS_INLINE unsigned get_hz(void) +{ + return sysconf(_SC_CLK_TCK); +} + +static void alloc_struct(int cpus) +{ + int i; + for (i = 0; i < 3; i++) { + G.st_cpu[i] = xzalloc(sizeof(G.st_cpu[i][0]) * cpus); + G.st_irq[i] = xzalloc(sizeof(G.st_irq[i][0]) * cpus); + G.st_irqcpu[i] = xzalloc(sizeof(G.st_irqcpu[i][0]) * cpus * G.irqcpu_nr); + G.st_softirqcpu[i] = xzalloc(sizeof(G.st_softirqcpu[i][0]) * cpus * G.softirqcpu_nr); + } + G.cpu_bitmap_len = (cpus >> 3) + 1; + G.cpu_bitmap = xzalloc(G.cpu_bitmap_len); +} + +static void print_header(struct tm *t) +{ + char cur_date[16]; + struct utsname uts; + + /* Get system name, release number and hostname */ + uname(&uts); + + strftime(cur_date, sizeof(cur_date), "%x", t); + + printf("%s %s (%s)\t%s\t_%s_\t(%u CPU)\n", + uts.sysname, uts.release, uts.nodename, cur_date, uts.machine, G.cpu_nr); +} + +/* + * Get number of interrupts available per processor + */ +static int get_irqcpu_nr(const char *f, int max_irqs) +{ + FILE *fp; + char *line; + unsigned linelen; + unsigned irq; + + fp = fopen_for_read(f); + if (!fp) /* No interrupts file */ + return 0; + + linelen = INTERRUPTS_LINE + 16 * G.cpu_nr; + line = xmalloc(linelen); + + irq = 0; + while (fgets(line, linelen, fp) + && irq < max_irqs + ) { + int p = strcspn(line, ":"); + if ((p > 0) && (p < 16)) + irq++; + } + + fclose(fp); + free(line); + + return irq; +} + +//usage:#define mpstat_trivial_usage +//usage: "[-A] [-I SUM|CPU|ALL|SCPU] [-u] [-P num|ALL] [INTERVAL [COUNT]]" +//usage:#define mpstat_full_usage "\n\n" +//usage: "Per-processor statistics\n" +//usage: "\n -A Same as -I ALL -u -P ALL" +//usage: "\n -I SUM|CPU|ALL|SCPU Report interrupt statistics" +//usage: "\n -P num|ALL Processor to monitor" +//usage: "\n -u Report CPU utilization" + +int mpstat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int mpstat_main(int UNUSED_PARAM argc, char **argv) +{ + char *opt_irq_fmt; + char *opt_set_cpu; + int i, opt; + enum { + OPT_ALL = 1 << 0, /* -A */ + OPT_INTS = 1 << 1, /* -I */ + OPT_SETCPU = 1 << 2, /* -P */ + OPT_UTIL = 1 << 3, /* -u */ + }; + + /* Dont buffer data if redirected to a pipe */ + setbuf(stdout, NULL); + + INIT_G(); + + G.interval = -1; + + /* Get number of processors */ + G.cpu_nr = get_cpu_count(); + + /* Get number of clock ticks per sec */ + G.hz = get_hz(); + + /* Calculate number of interrupts per processor */ + G.irqcpu_nr = get_irqcpu_nr(PROCFS_INTERRUPTS, NR_IRQS) + NR_IRQCPU_PREALLOC; + + /* Calculate number of soft interrupts per processor */ + G.softirqcpu_nr = get_irqcpu_nr(PROCFS_SOFTIRQS, NR_IRQS) + NR_IRQCPU_PREALLOC; + + /* Allocate space for structures. + 1 for global structure. */ + alloc_struct(G.cpu_nr + 1); + + /* Parse and process arguments */ + opt = getopt32(argv, "AI:P:u", &opt_irq_fmt, &opt_set_cpu); + argv += optind; + + if (*argv) { + /* Get interval */ + G.interval = xatoi_positive(*argv); + G.count = -1; + argv++; + if (*argv) { + /* Get count value */ + if (G.interval == 0) + bb_show_usage(); + G.count = xatoi_positive(*argv); + //if (*++argv) + // bb_show_usage(); + } + } + if (G.interval < 0) + G.interval = 0; + + if (opt & OPT_ALL) { + G.p_option = 1; + G.options |= D_CPU + D_IRQ_SUM + D_IRQ_CPU + D_SOFTIRQS; + /* Select every CPU */ + memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len); + } + + if (opt & OPT_INTS) { + static const char v[] = { + D_IRQ_CPU, D_IRQ_SUM, D_SOFTIRQS, + D_IRQ_SUM + D_IRQ_CPU + D_SOFTIRQS + }; + i = index_in_strings("CPU\0SUM\0SCPU\0ALL\0", opt_irq_fmt); + if (i == -1) + bb_show_usage(); + G.options |= v[i]; + } + + if ((opt & OPT_UTIL) /* -u? */ + || G.options == 0 /* nothing? (use default then) */ + ) { + G.options |= D_CPU; + } + + if (opt & OPT_SETCPU) { + char *t; + G.p_option = 1; + + for (t = strtok(opt_set_cpu, ","); t; t = strtok(NULL, ",")) { + if (strcmp(t, "ALL") == 0) { + /* Select every CPU */ + memset(G.cpu_bitmap, 0xff, G.cpu_bitmap_len); + } else { + /* Get CPU number */ + unsigned n = xatoi_positive(t); + if (n >= G.cpu_nr) + bb_error_msg_and_die("not that many processors"); + n++; + G.cpu_bitmap[n >> 3] |= 1 << (n & 7); + } + } + } + + if (!G.p_option) + /* Display global stats */ + G.cpu_bitmap[0] = 1; + + /* Get time */ + get_localtime(&G.timestamp[0]); + + /* Display header */ + print_header(&G.timestamp[0]); + + /* The main loop */ + main_loop(); + + if (ENABLE_FEATURE_CLEAN_UP) { + /* Clean up */ + for (i = 0; i < 3; i++) { + free(G.st_cpu[i]); + free(G.st_irq[i]); + free(G.st_irqcpu[i]); + free(G.st_softirqcpu[i]); + } + free(G.cpu_bitmap); + free(&G); + } + + return EXIT_SUCCESS; +} diff --git a/procps/nmeter.c b/procps/nmeter.c index bb1e819..5d5b83b 100644 --- a/procps/nmeter.c +++ b/procps/nmeter.c @@ -1,9 +1,44 @@ /* -** Licensed under the GPL v2, see the file LICENSE in this tarball -** -** Based on nanotop.c from floppyfw project -** -** Contact me: vda.linux@googlemail.com */ + * Licensed under GPLv2, see file LICENSE in this source tree. + * + * Based on nanotop.c from floppyfw project + * + * Contact me: vda.linux@googlemail.com + */ + +//config:config NMETER +//config: bool "nmeter" +//config: default y +//config: help +//config: Prints selected system stats continuously, one line per update. + +//applet:IF_NMETER(APPLET(nmeter, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_NMETER) += nmeter.o + +//usage:#define nmeter_trivial_usage +//usage: "[-d MSEC] FORMAT_STRING" +//usage:#define nmeter_full_usage "\n\n" +//usage: "Monitor system in real time" +//usage: "\n" +//usage: "\n -d MSEC Milliseconds between updates (default:1000)" +//usage: "\n" +//usage: "\nFormat specifiers:" +//usage: "\n %Nc or %[cN] CPU. N - bar size (default:10)" +//usage: "\n (displays: S:system U:user N:niced D:iowait I:irq i:softirq)" +//usage: "\n %[nINTERFACE] Network INTERFACE" +//usage: "\n %m Allocated memory" +//usage: "\n %[mf] Free memory" +//usage: "\n %[mt] Total memory" +//usage: "\n %s Allocated swap" +//usage: "\n %f Number of used file descriptors" +//usage: "\n %Ni Total/specific IRQ rate" +//usage: "\n %x Context switch rate" +//usage: "\n %p Forks" +//usage: "\n %[pn] # of processes" +//usage: "\n %b Block io" +//usage: "\n %Nt Time (with N decimal points)" +//usage: "\n %r Print instead of at EOL" //TODO: // simplify code @@ -236,33 +271,59 @@ static int rdval_loadavg(const char* p, ullong *vec, ...) } // Parses /proc/diskstats -// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 +// 1 2 3 4 5 6(rd) 7 8 9 10(wr) 11 12 13 14 // 3 0 hda 51292 14441 841783 926052 25717 79650 843256 3029804 0 148459 3956933 // 3 1 hda1 0 0 0 0 <- ignore if only 4 fields +// Linux 3.0 (maybe earlier) started printing full stats for hda1 too. +// Had to add code which skips such devices. static int rdval_diskstats(const char* p, ullong *vec) { - ullong rd = rd; // for compiler - int indexline = 0; + char devname[32]; + unsigned devname_len = 0; + int value_idx = 0; + vec[0] = 0; vec[1] = 0; while (1) { - indexline++; - while (*p == ' ' || *p == '\t') p++; - if (*p == '\0') break; + value_idx++; + while (*p == ' ' || *p == '\t') + p++; + if (*p == '\0') + break; if (*p == '\n') { - indexline = 0; + value_idx = 0; p++; continue; } - if (indexline == 6) { - rd = strtoull(p, NULL, 10); - } else if (indexline == 10) { - vec[0] += rd; // TODO: *sectorsize (don't know how to find out sectorsize) + if (value_idx == 3) { + char *end = strchrnul(p, ' '); + /* If this a hda1-like device (same prefix as last one + digit)? */ + if (devname_len && strncmp(devname, p, devname_len) == 0 && isdigit(p[devname_len])) { + p = end; + goto skip_line; /* skip entire line */ + } + /* It is not. Remember the name for future checks */ + devname_len = end - p; + if (devname_len > sizeof(devname)-1) + devname_len = sizeof(devname)-1; + strncpy(devname, p, devname_len); + /* devname[devname_len] = '\0'; - not really needed */ + p = end; + } else + if (value_idx == 6) { + // TODO: *sectorsize (don't know how to find out sectorsize) + vec[0] += strtoull(p, NULL, 10); + } else + if (value_idx == 10) { + // TODO: *sectorsize (don't know how to find out sectorsize) vec[1] += strtoull(p, NULL, 10); - while (*p != '\n' && *p != '\0') p++; + skip_line: + while (*p != '\n' && *p != '\0') + p++; continue; } - while (*p > ' ') p++; // skip over value + while ((unsigned char)(*p) > ' ') // skip over value + p++; } return 0; } @@ -272,8 +333,7 @@ static void scale(ullong ul) char buf[5]; /* see http://en.wikipedia.org/wiki/Tera */ - smart_ulltoa4(ul, buf, " kmgtpezy"); - buf[4] = '\0'; + smart_ulltoa4(ul, buf, " kmgtpezy")[0] = '\0'; put(buf); } @@ -422,7 +482,7 @@ static s_stat* init_int(const char *param) if (param[0] == '\0') { s->no = 1; } else { - int n = xatoi_u(param); + int n = xatoi_positive(param); s->no = n + 2; } return (s_stat*)s; @@ -768,6 +828,7 @@ static void FAST_FUNC collect_info(s_stat *s) typedef s_stat* init_func(const char *param); +// Deprecated %NNNd is to be removed, -d MSEC supersedes it static const char options[] ALIGN1 = "ncmsfixptbdr"; static init_func *const init_functions[] = { init_if, @@ -791,23 +852,28 @@ int nmeter_main(int argc UNUSED_PARAM, char **argv) s_stat *first = NULL; s_stat *last = NULL; s_stat *s; + char *opt_d; char *cur, *prev; INIT_G(); xchdir("/proc"); - if (!argv[1]) - bb_show_usage(); - if (open_read_close("version", buf, sizeof(buf)-1) > 0) { buf[sizeof(buf)-1] = '\0'; is26 = (strstr(buf, " 2.4.") == NULL); } - // Can use argv[1] directly, but this will mess up + if (getopt32(argv, "d:", &opt_d)) + init_delay(opt_d); + argv += optind; + + if (!argv[0]) + bb_show_usage(); + + // Can use argv[0] directly, but this will mess up // parameters as seen by e.g. ps. Making a copy... - cur = xstrdup(argv[1]); + cur = xstrdup(argv[0]); while (1) { char *param, *p; prev = cur; diff --git a/procps/pgrep.c b/procps/pgrep.c index 45de8bc..1c7c7c4 100644 --- a/procps/pgrep.c +++ b/procps/pgrep.c @@ -4,8 +4,35 @@ * * Copyright (C) 2007 Loic Grenie * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ + +//usage:#define pgrep_trivial_usage +//usage: "[-flnovx] [-s SID|-P PPID|PATTERN]" +//usage:#define pgrep_full_usage "\n\n" +//usage: "Display process(es) selected by regex PATTERN\n" +//usage: "\n -l Show command name too" +//usage: "\n -f Match against entire command line" +//usage: "\n -n Show the newest process only" +//usage: "\n -o Show the oldest process only" +//usage: "\n -v Negate the match" +//usage: "\n -x Match whole name (not substring)" +//usage: "\n -s Match session ID (0 for current)" +//usage: "\n -P Match parent process ID" +//usage: +//usage:#define pkill_trivial_usage +//usage: "[-l|-SIGNAL] [-fnovx] [-s SID|-P PPID|PATTERN]" +//usage:#define pkill_full_usage "\n\n" +//usage: "Send a signal to process(es) selected by regex PATTERN\n" +//usage: "\n -l List all signals" +//usage: "\n -f Match against entire command line" +//usage: "\n -n Signal the newest process only" +//usage: "\n -o Signal the oldest process only" +//usage: "\n -v Negate the match" +//usage: "\n -x Match whole name (not substring)" +//usage: "\n -s Match session ID (0 for current)" +//usage: "\n -P Match parent process ID" + #include "libbb.h" #include "xregex.h" @@ -38,9 +65,9 @@ static void act(unsigned pid, char *cmd, int signo) { if (pgrep) { if (option_mask32 & (1 << OPTBIT_L)) /* OPT_LIST */ - printf("%d %s\n", pid, cmd); + printf("%u %s\n", pid, cmd); else - printf("%d\n", pid); + printf("%u\n", pid); } else kill(pid, signo); } @@ -101,7 +128,7 @@ int pgrep_main(int argc UNUSED_PARAM, char **argv) bb_show_usage(); if (argv[0]) - xregcomp(&re_buffer, argv[0], 0); + xregcomp(&re_buffer, argv[0], OPT_ANCHOR ? REG_EXTENDED : (REG_EXTENDED|REG_NOSUB)); matched_pid = 0; cmd_last = NULL; diff --git a/procps/pidof.c b/procps/pidof.c index bf5e784..6d7b591 100644 --- a/procps/pidof.c +++ b/procps/pidof.c @@ -4,9 +4,37 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#if (ENABLE_FEATURE_PIDOF_SINGLE || ENABLE_FEATURE_PIDOF_OMIT) +//usage:#define pidof_trivial_usage +//usage: "[OPTIONS] [NAME]..." +//usage:#define USAGE_PIDOF "\n" +//usage:#else +//usage:#define pidof_trivial_usage +//usage: "[NAME]..." +//usage:#define USAGE_PIDOF /* none */ +//usage:#endif +//usage:#define pidof_full_usage "\n\n" +//usage: "List PIDs of all processes with names that match NAMEs" +//usage: USAGE_PIDOF +//usage: IF_FEATURE_PIDOF_SINGLE( +//usage: "\n -s Show only one PID" +//usage: ) +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "\n -o PID Omit given pid" +//usage: "\n Use %PPID to omit pid of pidof's parent" +//usage: ) +//usage: +//usage:#define pidof_example_usage +//usage: "$ pidof init\n" +//usage: "1\n" +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "$ pidof /bin/sh\n20351 5973 5950\n") +//usage: IF_FEATURE_PIDOF_OMIT( +//usage: "$ pidof /bin/sh -o %PPID\n20351 5950") + #include "libbb.h" enum { diff --git a/procps/pmap.c b/procps/pmap.c new file mode 100644 index 0000000..fd995a5 --- /dev/null +++ b/procps/pmap.c @@ -0,0 +1,111 @@ +/* + * pmap implementation for busybox + * + * Copyright (C) 2010 Nokia Corporation. All rights reserved. + * Written by Alexander Shishkin + * + * Licensed under GPLv2 or later, see the LICENSE file in this source tree + * for details. + */ + +//config:config PMAP +//config: bool "pmap" +//config: default y +//config: help +//config: Display processes' memory mappings. + +//applet:IF_PMAP(APPLET(pmap, BB_DIR_USR_BIN, BB_SUID_DROP)) +//kbuild:lib-$(CONFIG_PMAP) += pmap.o + +//usage:#define pmap_trivial_usage +//usage: "[-xq] PID" +//usage:#define pmap_full_usage "\n\n" +//usage: "Display detailed process memory usage" +//usage: "\n" +//usage: "\n -x Show details" +//usage: "\n -q Quiet" + +#include "libbb.h" + +#if ULONG_MAX == 0xffffffff +# define TABS "\t" +# define AFMT "8" +# define DASHES "" +#else +# define TABS "\t\t" +# define AFMT "16" +# define DASHES "--------" +#endif + +enum { + OPT_x = 1 << 0, + OPT_q = 1 << 1, +}; + +static void print_smaprec(struct smaprec *currec, void *data) +{ + unsigned opt = (uintptr_t)data; + + printf("%0" AFMT "lx ", currec->smap_start); + + if (opt & OPT_x) + printf("%7lu %7lu %7lu %7lu ", + currec->smap_size, + currec->smap_pss, + currec->private_dirty, + currec->smap_swap); + else + printf("%7luK", currec->smap_size); + + printf(" %.4s %s\n", currec->smap_mode, currec->smap_name); +} + +static int procps_get_maps(pid_t pid, unsigned opt) +{ + struct smaprec total; + int ret; + char buf[256]; + + read_cmdline(buf, sizeof(buf), pid, "no such process"); + printf("%u: %s\n", (int)pid, buf); + + if (!(opt & OPT_q) && (opt & OPT_x)) + puts("Address" TABS " Kbytes PSS Dirty Swap Mode Mapping"); + + memset(&total, 0, sizeof(total)); + + ret = procps_read_smaps(pid, &total, print_smaprec, (void*)(uintptr_t)opt); + if (ret) + return ret; + + if (!(opt & OPT_q)) { + if (opt & OPT_x) + printf("--------" DASHES " ------ ------ ------ ------\n" + "total" TABS " %7lu %7lu %7lu %7lu\n", + total.smap_size, total.smap_pss, total.private_dirty, total.smap_swap); + else + printf("mapped: %luK\n", total.smap_size); + } + + return 0; +} + +int pmap_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pmap_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + int ret; + + opts = getopt32(argv, "xq"); + argv += optind; + + ret = 0; + while (*argv) { + pid_t pid = xatoi_positive(*argv++); + /* GNU pmap returns 42 if any of the pids failed */ + if (procps_get_maps(pid, opts) != 0) + ret = 42; + } + + return ret; +} diff --git a/procps/powertop.c b/procps/powertop.c new file mode 100644 index 0000000..e3c29d1 --- /dev/null +++ b/procps/powertop.c @@ -0,0 +1,856 @@ +/* vi: set sw=4 ts=4: */ +/* + * A mini 'powertop' utility: + * Analyze power consumption on Intel-based laptops. + * Based on powertop 1.11. + * + * Copyright (C) 2010 Marek Polacek + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//applet:IF_POWERTOP(APPLET(powertop, BB_DIR_USR_SBIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_POWERTOP) += powertop.o + +//config:config POWERTOP +//config: bool "powertop" +//config: default y +//config: help +//config: Analyze power consumption on Intel-based laptops + +// XXX This should be configurable +#define ENABLE_FEATURE_POWERTOP_PROCIRQ 1 + +#include "libbb.h" + + +//#define debug(fmt, ...) fprintf(stderr, fmt, ## __VA_ARGS__) +#define debug(fmt, ...) ((void)0) + + +#define BLOATY_HPET_IRQ_NUM_DETECTION 0 +#define MAX_CSTATE_COUNT 8 +#define IRQCOUNT 40 + + +#define DEFAULT_SLEEP 10 +#define DEFAULT_SLEEP_STR "10" + +/* Frequency of the ACPI timer */ +#define FREQ_ACPI 3579.545 +#define FREQ_ACPI_1000 3579545 + +/* Max filename length of entry in /sys/devices subsystem */ +#define BIG_SYSNAME_LEN 16 + +typedef unsigned long long ullong; + +struct line { + char *string; + int count; + /*int disk_count;*/ +}; + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +struct irqdata { + smallint active; + int number; + ullong count; + char irq_desc[32]; +}; +#endif + +struct globals { + struct line *lines; /* the most often used member */ + int lines_cnt; + int lines_cumulative_count; + int maxcstate; + unsigned total_cpus; + smallint cant_enable_timer_stats; +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +# if BLOATY_HPET_IRQ_NUM_DETECTION + smallint scanned_timer_list; + int percpu_hpet_start; + int percpu_hpet_end; +# endif + int interrupt_0; + int total_interrupt; + struct irqdata interrupts[IRQCOUNT]; +#endif + ullong start_usage[MAX_CSTATE_COUNT]; + ullong last_usage[MAX_CSTATE_COUNT]; + ullong start_duration[MAX_CSTATE_COUNT]; + ullong last_duration[MAX_CSTATE_COUNT]; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios init_settings; +#endif +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + +#if ENABLE_FEATURE_USE_TERMIOS +static void reset_term(void) +{ + tcsetattr_stdin_TCSANOW(&G.init_settings); +} + +static void sig_handler(int signo UNUSED_PARAM) +{ + reset_term(); + _exit(EXIT_FAILURE); +} +#endif + +static int write_str_to_file(const char *fname, const char *str) +{ + FILE *fp = fopen_for_write(fname); + if (!fp) + return 1; + fputs(str, fp); + fclose(fp); + return 0; +} + +/* Make it more readable */ +#define start_timer() write_str_to_file("/proc/timer_stats", "1\n") +#define stop_timer() write_str_to_file("/proc/timer_stats", "0\n") + +static NOINLINE void clear_lines(void) +{ + int i; + if (G.lines) { + for (i = 0; i < G.lines_cnt; i++) + free(G.lines[i].string); + free(G.lines); + G.lines_cnt = 0; + G.lines = NULL; + } +} + +static void update_lines_cumulative_count(void) +{ + int i; + for (i = 0; i < G.lines_cnt; i++) + G.lines_cumulative_count += G.lines[i].count; +} + +static int line_compare(const void *p1, const void *p2) +{ + const struct line *a = p1; + const struct line *b = p2; + return (b->count /*+ 50 * b->disk_count*/) - (a->count /*+ 50 * a->disk_count*/); +} + +static void sort_lines(void) +{ + qsort(G.lines, G.lines_cnt, sizeof(G.lines[0]), line_compare); +} + +/* Save C-state usage and duration. Also update maxcstate. */ +static void read_cstate_counts(ullong *usage, ullong *duration) +{ + DIR *dir; + struct dirent *d; + + dir = opendir("/proc/acpi/processor"); + if (!dir) + return; + + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[192]; + int level; + int len; + + len = strlen(d->d_name); /* "CPUnn" */ + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + sprintf(buf, "%s/%s/power", "/proc/acpi/processor", d->d_name); + fp = fopen_for_read(buf); + if (!fp) + continue; + +// Example file contents: +// active state: C0 +// max_cstate: C8 +// maximum allowed latency: 2000000000 usec +// states: +// C1: type[C1] promotion[--] demotion[--] latency[001] usage[00006173] duration[00000000000000000000] +// C2: type[C2] promotion[--] demotion[--] latency[001] usage[00085191] duration[00000000000083024907] +// C3: type[C3] promotion[--] demotion[--] latency[017] usage[01017622] duration[00000000017921327182] + level = 0; + while (fgets(buf, sizeof(buf), fp)) { + char *p = strstr(buf, "age["); + if (!p) + continue; + p += 4; + usage[level] += bb_strtoull(p, NULL, 10) + 1; + p = strstr(buf, "ation["); + if (!p) + continue; + p += 6; + duration[level] += bb_strtoull(p, NULL, 10); + + if (level >= MAX_CSTATE_COUNT-1) + break; + level++; + if (level > G.maxcstate) /* update maxcstate */ + G.maxcstate = level; + } + fclose(fp); + } + closedir(dir); +} + +/* Add line and/or update count */ +static void save_line(const char *string, int count) +{ + int i; + for (i = 0; i < G.lines_cnt; i++) { + if (strcmp(string, G.lines[i].string) == 0) { + /* It's already there, only update count */ + G.lines[i].count += count; + return; + } + } + + /* Add new line */ + G.lines = xrealloc_vector(G.lines, 4, G.lines_cnt); + G.lines[G.lines_cnt].string = xstrdup(string); + G.lines[G.lines_cnt].count = count; + /*G.lines[G.lines_cnt].disk_count = 0;*/ + G.lines_cnt++; +} + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ +static int is_hpet_irq(const char *name) +{ + char *p; +# if BLOATY_HPET_IRQ_NUM_DETECTION + long hpet_chan; + + /* Learn the range of existing hpet timers. This is done once */ + if (!G.scanned_timer_list) { + FILE *fp; + char buf[80]; + + G.scanned_timer_list = true; + fp = fopen_for_read("/proc/timer_list"); + if (!fp) + return 0; + + while (fgets(buf, sizeof(buf), fp)) { + p = strstr(buf, "Clock Event Device: hpet"); + if (!p) + continue; + p += sizeof("Clock Event Device: hpet")-1; + if (!isdigit(*p)) + continue; + hpet_chan = xatoi_positive(p); + if (hpet_chan < G.percpu_hpet_start) + G.percpu_hpet_start = hpet_chan; + if (hpet_chan > G.percpu_hpet_end) + G.percpu_hpet_end = hpet_chan; + } + fclose(fp); + } +# endif +//TODO: optimize + p = strstr(name, "hpet"); + if (!p) + return 0; + p += 4; + if (!isdigit(*p)) + return 0; +# if BLOATY_HPET_IRQ_NUM_DETECTION + hpet_chan = xatoi_positive(p); + if (hpet_chan < G.percpu_hpet_start || hpet_chan > G.percpu_hpet_end) + return 0; +# endif + return 1; +} + +/* Save new IRQ count, return delta from old one */ +static int save_irq_count(int irq, ullong count) +{ + int unused = IRQCOUNT; + int i; + for (i = 0; i < IRQCOUNT; i++) { + if (G.interrupts[i].active && G.interrupts[i].number == irq) { + ullong old = G.interrupts[i].count; + G.interrupts[i].count = count; + return count - old; + } + if (!G.interrupts[i].active && unused > i) + unused = i; + } + if (unused < IRQCOUNT) { + G.interrupts[unused].active = 1; + G.interrupts[unused].count = count; + G.interrupts[unused].number = irq; + } + return count; +} + +/* Read /proc/interrupts, save IRQ counts and IRQ description */ +static void process_irq_counts(void) +{ + FILE *fp; + char buf[128]; + + /* Reset values */ + G.interrupt_0 = 0; + G.total_interrupt = 0; + + fp = xfopen_for_read("/proc/interrupts"); + while (fgets(buf, sizeof(buf), fp)) { + char irq_desc[sizeof(" : ") + sizeof(buf)]; + char *p; + const char *name; + int nr; + ullong count; + ullong delta; + + p = strchr(buf, ':'); + if (!p) + continue; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + *p = '\0'; + /* Deal with non-maskable interrupts -- make up fake numbers */ + nr = index_in_strings("NMI\0RES\0CAL\0TLB\0TRM\0THR\0SPU\0", buf); + if (nr >= 0) { + nr += 20000; + } else { + /* bb_strtou doesn't eat leading spaces, using strtoul */ + errno = 0; + nr = strtoul(buf, NULL, 10); + if (errno) + continue; + } + p++; + /* 0: 143646045 153901007 IO-APIC-edge timer + * ^ + */ + /* Sum counts for this IRQ */ + count = 0; + while (1) { + char *tmp; + p = skip_whitespace(p); + if (!isdigit(*p)) + break; + count += bb_strtoull(p, &tmp, 10); + p = tmp; + } + /* 0: 143646045 153901007 IO-APIC-edge timer + * NMI: 1 2 Non-maskable interrupts + * ^ + */ + if (nr < 20000) { + /* Skip to the interrupt name, e.g. 'timer' */ + p = strchr(p, ' '); + if (!p) + continue; + p = skip_whitespace(p); + } + + name = p; + strchrnul(name, '\n')[0] = '\0'; + /* Save description of the interrupt */ + if (nr >= 20000) + sprintf(irq_desc, " : %s", name); + else + sprintf(irq_desc, " : %s", name); + + delta = save_irq_count(nr, count); + + /* Skip per CPU timer interrupts */ + if (is_hpet_irq(name)) + continue; + + if (nr != 0 && delta != 0) + save_line(irq_desc, delta); + + if (nr == 0) + G.interrupt_0 = delta; + else + G.total_interrupt += delta; + } + + fclose(fp); +} +#else /* !ENABLE_FEATURE_POWERTOP_PROCIRQ */ +# define process_irq_counts() ((void)0) +#endif + +static NOINLINE int process_timer_stats(void) +{ + char buf[128]; + char line[15 + 3 + 128]; + int n; + FILE *fp; + + buf[0] = '\0'; + + n = 0; + fp = NULL; + if (!G.cant_enable_timer_stats) + fp = fopen_for_read("/proc/timer_stats"); + if (fp) { +// Example file contents: +// Timer Stats Version: v0.2 +// Sample period: 1.329 s +// 76, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 88, 0 swapper hrtimer_start_range_ns (tick_sched_timer) +// 24, 3787 firefox hrtimer_start_range_ns (hrtimer_wakeup) +// 46D, 1136 kondemand/1 do_dbs_timer (delayed_work_timer_fn) +// ... +// 1, 1656 Xorg hrtimer_start_range_ns (hrtimer_wakeup) +// 1, 2159 udisks-daemon hrtimer_start_range_ns (hrtimer_wakeup) +// 331 total events, 249.059 events/sec + while (fgets(buf, sizeof(buf), fp)) { + const char *count, *process, *func; + char *p; + int idx; + unsigned cnt; + + count = skip_whitespace(buf); + p = strchr(count, ','); + if (!p) + continue; + *p++ = '\0'; + cnt = bb_strtou(count, NULL, 10); + if (strcmp(skip_non_whitespace(count), " total events") == 0) { +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + n = cnt / G.total_cpus; + if (n > 0 && n < G.interrupt_0) { + sprintf(line, " : %s", "extra timer interrupt"); + save_line(line, G.interrupt_0 - n); + } +#endif + break; + } + if (strchr(count, 'D')) + continue; /* deferred */ + p = skip_whitespace(p); /* points to pid now */ + process = NULL; + get_func_name: + p = strchr(p, ' '); + if (!p) + continue; + *p++ = '\0'; + p = skip_whitespace(p); + if (process == NULL) { + process = p; + goto get_func_name; + } + func = p; + + //if (strcmp(process, "swapper") == 0 + // && strcmp(func, "hrtimer_start_range_ns (tick_sched_timer)\n") == 0 + //) { + // process = "[kernel scheduler]"; + // func = "Load balancing tick"; + //} + + if (strncmp(func, "tick_nohz_", 10) == 0) + continue; + if (strncmp(func, "tick_setup_sched_timer", 20) == 0) + continue; + //if (strcmp(process, "powertop") == 0) + // continue; + + idx = index_in_strings("insmod\0modprobe\0swapper\0", process); + if (idx != -1) { + process = idx < 2 ? "[kernel module]" : ""; + } + + strchrnul(p, '\n')[0] = '\0'; + + // 46D\01136\0kondemand/1\0do_dbs_timer (delayed_work_timer_fn) + // ^ ^ ^ + // count process func + + //if (strchr(process, '[')) + sprintf(line, "%15.15s : %s", process, func); + //else + // sprintf(line, "%s", process); + save_line(line, cnt); + } + fclose(fp); + } + + return n; +} + +#ifdef __i386__ +/* + * Get information about CPU using CPUID opcode. + */ +static void cpuid(unsigned int *eax, unsigned int *ebx, unsigned int *ecx, + unsigned int *edx) +{ + /* EAX value specifies what information to return */ + __asm__( + " pushl %%ebx\n" /* Save EBX */ + " cpuid\n" + " movl %%ebx, %1\n" /* Save content of EBX */ + " popl %%ebx\n" /* Restore EBX */ + : "=a"(*eax), /* Output */ + "=r"(*ebx), + "=c"(*ecx), + "=d"(*edx) + : "0"(*eax), /* Input */ + "1"(*ebx), + "2"(*ecx), + "3"(*edx) + /* No clobbered registers */ + ); +} +#endif + +#ifdef __i386__ +static NOINLINE void print_intel_cstates(void) +{ + int bios_table[8] = { 0 }; + int nbios = 0; + DIR *cpudir; + struct dirent *d; + int i; + unsigned eax, ebx, ecx, edx; + + cpudir = opendir("/sys/devices/system/cpu"); + if (!cpudir) + return; + + /* Loop over cpuN entries */ + while ((d = readdir(cpudir)) != NULL) { + DIR *dir; + int len; + char fname[sizeof("/sys/devices/system/cpu//cpuidle//desc") + 2*BIG_SYSNAME_LEN]; + + len = strlen(d->d_name); + if (len < 3 || len > BIG_SYSNAME_LEN) + continue; + + if (!isdigit(d->d_name[3])) + continue; + + len = sprintf(fname, "%s/%s/cpuidle", "/sys/devices/system/cpu", d->d_name); + dir = opendir(fname); + if (!dir) + continue; + + /* + * Every C-state has its own stateN directory, that + * contains a 'time' and a 'usage' file. + */ + while ((d = readdir(dir)) != NULL) { + FILE *fp; + char buf[64]; + int n; + + n = strlen(d->d_name); + if (n < 3 || n > BIG_SYSNAME_LEN) + continue; + + sprintf(fname + len, "/%s/desc", d->d_name); + fp = fopen_for_read(fname); + if (fp) { + char *p = fgets(buf, sizeof(buf), fp); + fclose(fp); + if (!p) + break; + p = strstr(p, "MWAIT "); + if (p) { + int pos; + p += sizeof("MWAIT ") - 1; + pos = (bb_strtoull(p, NULL, 16) >> 4) + 1; + if (pos >= ARRAY_SIZE(bios_table)) + continue; + bios_table[pos]++; + nbios++; + } + } + } + closedir(dir); + } + closedir(cpudir); + + if (!nbios) + return; + + eax = 5; + ebx = ecx = edx = 0; + cpuid(&eax, &ebx, &ecx, &edx); + if (!edx || !(ecx & 1)) + return; + + printf("Your CPU supports the following C-states: "); + i = 0; + while (edx) { + if (edx & 7) + printf("C%u ", i); + edx >>= 4; + i++; + } + bb_putchar('\n'); + + /* Print BIOS C-States */ + printf("Your BIOS reports the following C-states: "); + for (i = 0; i < ARRAY_SIZE(bios_table); i++) + if (bios_table[i]) + printf("C%u ", i); + + bb_putchar('\n'); +} +#else +# define print_intel_cstates() ((void)0) +#endif + +static void show_timerstats(void) +{ + unsigned lines; + + /* Get terminal height */ + get_terminal_width_height(STDOUT_FILENO, NULL, &lines); + + /* We don't have whole terminal just for timerstats */ + lines -= 12; + + if (!G.cant_enable_timer_stats) { + int i, n = 0; + char strbuf6[6]; + + puts("\nTop causes for wakeups:"); + for (i = 0; i < G.lines_cnt; i++) { + if ((G.lines[i].count > 0 /*|| G.lines[i].disk_count > 0*/) + && n++ < lines + ) { + /* NB: upstream powertop prints "(wakeups/sec)", + * we print just "(wakeup counts)". + */ + /*char c = ' '; + if (G.lines[i].disk_count) + c = 'D';*/ + smart_ulltoa5(G.lines[i].count, strbuf6, " KMGTPEZY")[0] = '\0'; + printf(/*" %5.1f%% (%s)%c %s\n"*/ + " %5.1f%% (%s) %s\n", + G.lines[i].count * 100.0 / G.lines_cumulative_count, + strbuf6, /*c,*/ + G.lines[i].string); + } + } + } else { + bb_putchar('\n'); + bb_error_msg("no stats available; run as root or" + " enable the timer_stats module"); + } +} + +// Example display from powertop version 1.11 +// Cn Avg residency P-states (frequencies) +// C0 (cpu running) ( 0.5%) 2.00 Ghz 0.0% +// polling 0.0ms ( 0.0%) 1.67 Ghz 0.0% +// C1 mwait 0.0ms ( 0.0%) 1333 Mhz 0.1% +// C2 mwait 0.1ms ( 0.1%) 1000 Mhz 99.9% +// C3 mwait 12.1ms (99.4%) +// +// Wakeups-from-idle per second : 93.6 interval: 15.0s +// no ACPI power usage estimate available +// +// Top causes for wakeups: +// 32.4% ( 26.7) : extra timer interrupt +// 29.0% ( 23.9) : hrtimer_start_range_ns (tick_sched_timer) +// 9.0% ( 7.5) : hrtimer_start (tick_sched_timer) +// 6.5% ( 5.3) : ata_piix +// 5.0% ( 4.1) inetd : hrtimer_start_range_ns (hrtimer_wakeup) + +//usage:#define powertop_trivial_usage +//usage: "" +//usage:#define powertop_full_usage "\n\n" +//usage: "Analyze power consumption on Intel-based laptops\n" + +int powertop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int powertop_main(int UNUSED_PARAM argc, char UNUSED_PARAM **argv) +{ + ullong cur_usage[MAX_CSTATE_COUNT]; + ullong cur_duration[MAX_CSTATE_COUNT]; + char cstate_lines[MAX_CSTATE_COUNT + 2][64]; +#if ENABLE_FEATURE_USE_TERMIOS + struct termios new_settings; + struct pollfd pfd[1]; + + pfd[0].fd = 0; + pfd[0].events = POLLIN; +#endif + + INIT_G(); + +#if ENABLE_FEATURE_POWERTOP_PROCIRQ && BLOATY_HPET_IRQ_NUM_DETECTION + G.percpu_hpet_start = INT_MAX; + G.percpu_hpet_end = INT_MIN; +#endif + + /* Print warning when we don't have superuser privileges */ + if (geteuid() != 0) + bb_error_msg("run as root to collect enough information"); + + /* Get number of CPUs */ + G.total_cpus = get_cpu_count(); + + printf("Collecting data for "DEFAULT_SLEEP_STR" seconds\n"); + +#if ENABLE_FEATURE_USE_TERMIOS + tcgetattr(0, (void *)&G.init_settings); + memcpy(&new_settings, &G.init_settings, sizeof(new_settings)); + /* Turn on unbuffered input, turn off echoing */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + /* So we don't forget to reset term settings */ + atexit(reset_term); + bb_signals(BB_FATAL_SIGS, sig_handler); + tcsetattr_stdin_TCSANOW(&new_settings); +#endif + + /* Collect initial data */ + process_irq_counts(); + + /* Read initial usage and duration */ + read_cstate_counts(G.start_usage, G.start_duration); + + /* Copy them to "last" */ + memcpy(G.last_usage, G.start_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, G.start_duration, sizeof(G.last_duration)); + + /* Display C-states */ + print_intel_cstates(); + + G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ + + /* The main loop */ + for (;;) { + //double maxsleep = 0.0; + ullong totalticks, totalevents; + int i; + + G.cant_enable_timer_stats |= start_timer(); /* 1 on error */ +#if !ENABLE_FEATURE_USE_TERMIOS + sleep(DEFAULT_SLEEP); +#else + if (safe_poll(pfd, 1, DEFAULT_SLEEP * 1000) > 0) { + unsigned char c; + if (safe_read(STDIN_FILENO, &c, 1) != 1) + break; /* EOF/error */ + if (c == G.init_settings.c_cc[VINTR]) + break; /* ^C */ + if ((c | 0x20) == 'q') + break; + } +#endif + G.cant_enable_timer_stats |= stop_timer(); /* 1 on error */ + + clear_lines(); + process_irq_counts(); + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Read them */ + read_cstate_counts(cur_usage, cur_duration); + + /* Count totalticks and totalevents */ + totalticks = totalevents = 0; + for (i = 0; i < MAX_CSTATE_COUNT; i++) { + if (cur_usage[i] != 0) { + totalticks += cur_duration[i] - G.last_duration[i]; + totalevents += cur_usage[i] - G.last_usage[i]; + } + } + + /* Clear the screen */ + printf("\033[H\033[J"); + + /* Clear C-state lines */ + memset(&cstate_lines, 0, sizeof(cstate_lines)); + + if (totalevents == 0 && G.maxcstate <= 1) { + /* This should not happen */ + strcpy(cstate_lines[0], "C-state information is not available\n"); + } else { + double percentage; + unsigned newticks; + + newticks = G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000 - totalticks; + /* Handle rounding errors: do not display negative values */ + if ((int)newticks < 0) + newticks = 0; + + sprintf(cstate_lines[0], "Cn\t\t Avg residency\n"); + percentage = newticks * 100.0 / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + sprintf(cstate_lines[1], "C0 (cpu running) (%4.1f%%)\n", percentage); + + /* Compute values for individual C-states */ + for (i = 0; i < MAX_CSTATE_COUNT; i++) { + if (cur_usage[i] != 0) { + double slept; + slept = (cur_duration[i] - G.last_duration[i]) + / (cur_usage[i] - G.last_usage[i] + 0.1) / FREQ_ACPI; + percentage = (cur_duration[i] - G.last_duration[i]) * 100 + / (G.total_cpus * DEFAULT_SLEEP * FREQ_ACPI_1000); + sprintf(cstate_lines[i + 2], "C%u\t\t%5.1fms (%4.1f%%)\n", + i + 1, slept, percentage); + //if (maxsleep < slept) + // maxsleep = slept; + } + } + } + + for (i = 0; i < MAX_CSTATE_COUNT + 2; i++) + if (cstate_lines[i][0]) + fputs(cstate_lines[i], stdout); + + i = process_timer_stats(); +#if ENABLE_FEATURE_POWERTOP_PROCIRQ + if (totalevents == 0) { + /* No C-state info available, use timerstats */ + totalevents = i * G.total_cpus + G.total_interrupt; + if (i < 0) + totalevents += G.interrupt_0 - i; + } +#endif + /* Upstream powertop prints wakeups per sec per CPU, + * we print just raw wakeup counts. + */ +//TODO: show real seconds (think about manual refresh) + printf("\nWakeups-from-idle in %u seconds: %llu\n", + DEFAULT_SLEEP, + totalevents + ); + + update_lines_cumulative_count(); + sort_lines(); + show_timerstats(); + fflush(stdout); + + /* Clear the stats */ + memset(cur_duration, 0, sizeof(cur_duration)); + memset(cur_usage, 0, sizeof(cur_usage)); + + /* Get new values */ + read_cstate_counts(cur_usage, cur_duration); + + /* Save them */ + memcpy(G.last_usage, cur_usage, sizeof(G.last_usage)); + memcpy(G.last_duration, cur_duration, sizeof(G.last_duration)); + } /* for (;;) */ + + bb_putchar('\n'); + + return EXIT_SUCCESS; +} diff --git a/procps/ps.c b/procps/ps.c index a3220a9..c65fa01 100644 --- a/procps/ps.c +++ b/procps/ps.c @@ -6,29 +6,124 @@ * Fix for SELinux Support:(c)2007 Hiroshi Shinji * (c)2007 Yuichi Nakamura * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#if ENABLE_DESKTOP +//usage: +//usage:#define ps_trivial_usage +//usage: "[-o COL1,COL2=HEADER]" IF_FEATURE_SHOW_THREADS(" [-T]") +//usage:#define ps_full_usage "\n\n" +//usage: "Show list of processes\n" +//usage: "\n -o COL1,COL2=HEADER Select columns for display" +//usage: IF_FEATURE_SHOW_THREADS( +//usage: "\n -T Show threads" +//usage: ) +//usage: +//usage:#else /* !ENABLE_DESKTOP */ +//usage: +//usage:#if !ENABLE_SELINUX && !ENABLE_FEATURE_PS_WIDE +//usage:#define USAGE_PS "\nThis version of ps accepts no options" +//usage:#else +//usage:#define USAGE_PS "" +//usage:#endif +//usage: +//usage:#define ps_trivial_usage +//usage: "" +//usage:#define ps_full_usage "\n\n" +//usage: "Show list of processes\n" +//usage: USAGE_PS +//usage: IF_SELINUX( +//usage: "\n -Z Show selinux context" +//usage: ) +//usage: IF_FEATURE_PS_WIDE( +//usage: "\n w Wide output" +//usage: ) +//usage: IF_FEATURE_PS_LONG( +//usage: "\n l Long output" +//usage: ) +//usage: IF_FEATURE_SHOW_THREADS( +//usage: "\n T Show threads" +//usage: ) +//usage: +//usage:#endif /* ENABLE_DESKTOP */ +//usage: +//usage:#define ps_example_usage +//usage: "$ ps\n" +//usage: " PID Uid Gid State Command\n" +//usage: " 1 root root S init\n" +//usage: " 2 root root S [kflushd]\n" +//usage: " 3 root root S [kupdate]\n" +//usage: " 4 root root S [kpiod]\n" +//usage: " 5 root root S [kswapd]\n" +//usage: " 742 andersen andersen S [bash]\n" +//usage: " 743 andersen andersen S -bash\n" +//usage: " 745 root root S [getty]\n" +//usage: " 2990 andersen andersen R ps\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif /* Absolute maximum on output line length */ enum { MAX_WIDTH = 2*1024 }; +#if ENABLE_FEATURE_PS_TIME || ENABLE_FEATURE_PS_LONG +static unsigned long get_uptime(void) +{ +#ifdef __linux__ + struct sysinfo info; + if (sysinfo(&info) < 0) + return 0; + return info.uptime; +#elif 1 + unsigned long uptime; + char buf[sizeof(uptime)*3 + 2]; + /* /proc/uptime is "UPTIME_SEC.NN IDLE_SEC.NN\n" + * (where IDLE is cumulative over all CPUs) + */ + if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) + bb_perror_msg_and_die("can't read '%s'", "/proc/uptime"); + buf[sizeof(buf)-1] = '\0'; + sscanf(buf, "%lu", &uptime); + return uptime; +#else + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) < 0) + return 0; + return ts.tv_sec; +#endif +} +#endif + #if ENABLE_DESKTOP #include /* for times() */ #ifndef AT_CLKTCK -#define AT_CLKTCK 17 -#endif - - -#if ENABLE_SELINUX -#define SELINUX_O_PREFIX "label," -#define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") -#else -#define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") +# define AT_CLKTCK 17 #endif +/* TODO: + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html + * specifies (for XSI-conformant systems) following default columns + * (l and f mark columns shown with -l and -f respectively): + * F l Flags (octal and additive) associated with the process (??) + * S l The state of the process + * UID f,l The user ID; the login name is printed with -f + * PID The process ID + * PPID f,l The parent process + * C f,l Processor utilization + * PRI l The priority of the process; higher numbers mean lower priority + * NI l Nice value + * ADDR l The address of the process + * SZ l The size in blocks of the core image of the process + * WCHAN l The event for which the process is waiting or sleeping + * STIME f Starting time of the process + * TTY The controlling terminal for the process + * TIME The cumulative execution time for the process + * CMD The command name; the full command line is shown with -f + */ typedef struct { uint16_t width; char name6[6]; @@ -46,9 +141,8 @@ struct globals { unsigned terminal_width; #if ENABLE_FEATURE_PS_TIME unsigned kernel_HZ; - unsigned long long seconds_since_boot; + unsigned long seconds_since_boot; #endif - char default_o[sizeof(DEFAULT_O_STR)]; } FIX_ALIASING; #define G (*(struct globals*)&bb_common_bufsiz1) #define out (G.out ) @@ -58,17 +152,16 @@ struct globals { #define buffer (G.buffer ) #define terminal_width (G.terminal_width ) #define kernel_HZ (G.kernel_HZ ) -#define seconds_since_boot (G.seconds_since_boot) -#define default_o (G.default_o ) #define INIT_G() do { } while (0) #if ENABLE_FEATURE_PS_TIME /* for ELF executables, notes are pushed before environment and args */ -static ptrdiff_t find_elf_note(ptrdiff_t findme) +static uintptr_t find_elf_note(uintptr_t findme) { - ptrdiff_t *ep = (ptrdiff_t *) environ; + uintptr_t *ep = (uintptr_t *) environ; - while (*ep++); + while (*ep++) + continue; while (*ep) { if (ep[0] == findme) { return ep[1]; @@ -131,9 +224,6 @@ static inline unsigned get_HZ_by_waiting(void) static unsigned get_kernel_HZ(void) { - //char buf[64]; - struct sysinfo info; - if (kernel_HZ) return kernel_HZ; @@ -142,12 +232,7 @@ static unsigned get_kernel_HZ(void) if (kernel_HZ == (unsigned)-1) kernel_HZ = get_HZ_by_waiting(); - //if (open_read_close("/proc/uptime", buf, sizeof(buf)) <= 0) - // bb_perror_msg_and_die("can't read %s", "/proc/uptime"); - //buf[sizeof(buf)-1] = '\0'; - ///sscanf(buf, "%llu", &seconds_since_boot); - sysinfo(&info); - seconds_since_boot = info.uptime; + G.seconds_since_boot = get_uptime(); return kernel_HZ; } @@ -184,6 +269,11 @@ static void func_comm(char *buf, int size, const procps_status_t *ps) safe_strncpy(buf, ps->comm, size+1); } +static void func_state(char *buf, int size, const procps_status_t *ps) +{ + safe_strncpy(buf, ps->state, size+1); +} + static void func_args(char *buf, int size, const procps_status_t *ps) { read_cmdline(buf, size+1, ps->pid, ps->comm); @@ -209,8 +299,7 @@ static void put_lu(char *buf, int size, unsigned long u) char buf4[5]; /* see http://en.wikipedia.org/wiki/Tera */ - smart_ulltoa4(u, buf4, " mgtpezy"); - buf4[4] = '\0'; + smart_ulltoa4(u, buf4, " mgtpezy")[0] = '\0'; sprintf(buf, "%.*s", size, buf4); } @@ -261,7 +350,7 @@ static void func_etime(char *buf, int size, const procps_status_t *ps) mm = ps->start_time / get_kernel_HZ(); /* must be after get_kernel_HZ()! */ - mm = seconds_since_boot - mm; + mm = G.seconds_since_boot - mm; ss = mm % 60; mm /= 60; snprintf(buf, size+1, "%3lu:%02u", mm, ss); @@ -300,7 +389,7 @@ static void func_pcpu(char *buf, int size, const procps_status_t *ps) */ static const ps_out_t out_spec[] = { -// Mandated by POSIX: +/* Mandated by http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html: */ { 8 , "user" ,"USER" ,func_user ,PSSCAN_UIDGID }, { 8 , "group" ,"GROUP" ,func_group ,PSSCAN_UIDGID }, { 16 , "comm" ,"COMMAND",func_comm ,PSSCAN_COMM }, @@ -322,7 +411,8 @@ static const ps_out_t out_spec[] = { #endif { 6 , "tty" ,"TT" ,func_tty ,PSSCAN_TTY }, { 4 , "vsz" ,"VSZ" ,func_vsz ,PSSCAN_VSZ }, -// Not mandated by POSIX, but useful: +/* Not mandated, but useful: */ + { 4 , "stat" ,"STAT" ,func_state ,PSSCAN_STATE }, { 4 , "rss" ,"RSS" ,func_rss ,PSSCAN_RSS }, #if ENABLE_SELINUX { 35 , "label" ,"LABEL" ,func_label ,PSSCAN_CONTEXT }, @@ -338,24 +428,16 @@ static ps_out_t* new_out_t(void) static const ps_out_t* find_out_spec(const char *name) { unsigned i; -#if ENABLE_DESKTOP char buf[ARRAY_SIZE(out_spec)*7 + 1]; char *p = buf; -#endif for (i = 0; i < ARRAY_SIZE(out_spec); i++) { if (strncmp(name, out_spec[i].name6, 6) == 0) return &out_spec[i]; -#if ENABLE_DESKTOP p += sprintf(p, "%.6s,", out_spec[i].name6); -#endif } -#if ENABLE_DESKTOP p[-1] = '\0'; bb_error_msg_and_die("bad -o argument '%s', supported arguments: %s", name, buf); -#else - bb_error_msg_and_die("bad -o argument '%s'"); -#endif } static void parse_o(char* opt) @@ -467,11 +549,19 @@ static void format_process(const procps_status_t *ps) printf("%.*s\n", terminal_width, buffer); } +#if ENABLE_SELINUX +# define SELINUX_O_PREFIX "label," +# define DEFAULT_O_STR (SELINUX_O_PREFIX "pid,user" IF_FEATURE_PS_TIME(",time") ",args") +#else +# define DEFAULT_O_STR ("pid,user" IF_FEATURE_PS_TIME(",time") ",args") +#endif + int ps_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int ps_main(int argc UNUSED_PARAM, char **argv) { procps_status_t *p; llist_t* opt_o = NULL; + char default_o[sizeof(DEFAULT_O_STR)]; int opt; enum { OPT_Z = (1 << 0), @@ -498,7 +588,7 @@ int ps_main(int argc UNUSED_PARAM, char **argv) // -o col1,col2,col3=header // Select which columns to display /* We allow (and ignore) most of the above. FIXME. - * -T is picked for threads (POSIX hasn't it standardized). + * -T is picked for threads (POSIX hasn't standardized it). * procps v3.2.7 supports -T and shows tids as SPID column, * it also supports -L where it shows tids as LWP column. */ @@ -509,7 +599,9 @@ int ps_main(int argc UNUSED_PARAM, char **argv) parse_o(llist_pop(&opt_o)); } while (opt_o); } else { - /* Below: parse_o() needs char*, NOT const char*... */ + /* Below: parse_o() needs char*, NOT const char*, + * can't pass it constant string. Need to make a copy first. + */ #if ENABLE_SELINUX if (!(opt & OPT_Z) || !is_selinux_enabled()) { /* no -Z or no SELinux: do not show LABEL */ @@ -559,15 +651,21 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) enum { OPT_Z = (1 << 0) * ENABLE_SELINUX, OPT_T = (1 << ENABLE_SELINUX) * ENABLE_FEATURE_SHOW_THREADS, + OPT_l = (1 << ENABLE_SELINUX) * (1 << ENABLE_FEATURE_SHOW_THREADS) * ENABLE_FEATURE_PS_LONG, }; - int opts = 0; +#if ENABLE_FEATURE_PS_LONG + time_t now = now; + unsigned long uptime; +#endif /* If we support any options, parse argv */ -#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE +#if ENABLE_SELINUX || ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_PS_WIDE || ENABLE_FEATURE_PS_LONG + int opts = 0; # if ENABLE_FEATURE_PS_WIDE /* -w is a bit complicated */ int w_count = 0; opt_complementary = "-:ww"; - opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")"w", &w_count); + opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l") + "w", &w_count); /* if w is given once, GNU ps sets the width to 132, * if w is given more than once, it is "unlimited" */ @@ -582,23 +680,51 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) # else /* -w is not supported, only -Z and/or -T */ opt_complementary = "-"; - opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")); + opts = getopt32(argv, IF_SELINUX("Z")IF_FEATURE_SHOW_THREADS("T")IF_FEATURE_PS_LONG("l")); # endif -#endif -#if ENABLE_SELINUX +# if ENABLE_SELINUX if ((opts & OPT_Z) && is_selinux_enabled()) { psscan_flags = PSSCAN_PID | PSSCAN_CONTEXT | PSSCAN_STATE | PSSCAN_COMM; puts(" PID CONTEXT STAT COMMAND"); } else -#endif - { +# endif + if (opts & OPT_l) { + psscan_flags = PSSCAN_STATE | PSSCAN_UIDGID | PSSCAN_PID | PSSCAN_PPID + | PSSCAN_TTY | PSSCAN_STIME | PSSCAN_UTIME | PSSCAN_COMM + | PSSCAN_VSZ | PSSCAN_RSS; +/* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/ps.html + * mandates for -l: + * -F Flags (?) + * S State + * UID,PID,PPID + * -C CPU usage + * -PRI The priority of the process; higher numbers mean lower priority + * -NI Nice value + * -ADDR The address of the process (?) + * SZ The size in blocks of the core image + * -WCHAN The event for which the process is waiting or sleeping + * TTY + * TIME The cumulative execution time + * CMD + * We don't show fields marked with '-'. + * We show VSZ and RSS instead of SZ. + * We also show STIME (standard says that -f shows it, -l doesn't). + */ + puts("S UID PID PPID VSZ RSS TTY STIME TIME CMD"); +# if ENABLE_FEATURE_PS_LONG + now = time(NULL); + uptime = get_uptime(); +# endif + } + else { puts(" PID USER VSZ STAT COMMAND"); } if (opts & OPT_T) { psscan_flags |= PSSCAN_TASKS; } +#endif p = NULL; while ((p = procps_scan(p, psscan_flags)) != NULL) { @@ -612,15 +738,47 @@ int ps_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } else #endif { - const char *user = get_cached_username(p->uid); - //if (p->vsz == 0) - // len = printf("%5u %-8.8s %s ", - // p->pid, user, p->state); - //else + char buf6[6]; + smart_ulltoa5(p->vsz, buf6, " mgtpezy")[0] = '\0'; +#if ENABLE_FEATURE_PS_LONG + if (opts & OPT_l) { + char bufr[6], stime_str[6]; + char tty[2 * sizeof(int)*3 + 2]; + char *endp; + unsigned sut = (p->stime + p->utime) / 100; + unsigned elapsed = uptime - (p->start_time / 100); + time_t start = now - elapsed; + struct tm *tm = localtime(&start); + + smart_ulltoa5(p->rss, bufr, " mgtpezy")[0] = '\0'; + + if (p->tty_major == 136) + /* It should be pts/N, not ptsN, but N > 9 + * will overflow field width... + */ + endp = stpcpy(tty, "pts"); + else + if (p->tty_major == 4) { + endp = stpcpy(tty, "tty"); + if (p->tty_minor >= 64) { + p->tty_minor -= 64; + *endp++ = 'S'; + } + } + else + endp = tty + sprintf(tty, "%d:", p->tty_major); + strcpy(endp, utoa(p->tty_minor)); + + strftime(stime_str, 6, (elapsed >= (24 * 60 * 60)) ? "%b%d" : "%H:%M", tm); + stime_str[5] = '\0'; + // S UID PID PPID VSZ RSS TTY STIME TIME CMD + len = printf("%c %5u %5u %5u %5s %5s %-5s %s %02u:%02u:%02u ", + p->state[0], p->uid, p->pid, p->ppid, buf6, bufr, tty, + stime_str, sut / 3600, (sut % 3600) / 60, sut % 60); + } else +#endif { - char buf6[6]; - smart_ulltoa5(p->vsz, buf6, " mgtpezy"); - buf6[5] = '\0'; + const char *user = get_cached_username(p->uid); len = printf("%5u %-8.8s %s %s ", p->pid, user, buf6, p->state); } diff --git a/procps/pstree.c b/procps/pstree.c new file mode 100644 index 0000000..ed1a412 --- /dev/null +++ b/procps/pstree.c @@ -0,0 +1,414 @@ +/* + * pstree.c - display process tree + * + * Copyright (C) 1993-2002 Werner Almesberger + * Copyright (C) 2002-2009 Craig Small + * Copyright (C) 2010 Lauri Kasanen + * + * Based on pstree (PSmisc) 22.13. + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config PSTREE +//config: bool "pstree" +//config: default y +//config: help +//config: Display a tree of processes. + +//applet:IF_PSTREE(APPLET(pstree, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PSTREE) += pstree.o + +//usage:#define pstree_trivial_usage +//usage: "[-p] [PID|USER]" +//usage:#define pstree_full_usage "\n\n" +//usage: "Display process tree, optionally start from USER or PID\n" +//usage: "\n -p Show pids" + +#include "libbb.h" + +#define PROC_BASE "/proc" + +#define OPT_PID (1 << 0) + +struct child; + +#ifdef ENABLE_FEATURE_SHOW_THREADS +/* For threads, we add {...} around the comm, so we need two extra bytes */ +# define COMM_DISP_LEN (COMM_LEN + 2) +#else +# define COMM_DISP_LEN COMM_LEN +#endif + +typedef struct proc { + char comm[COMM_DISP_LEN + 1]; +// char flags; - unused, delete? + pid_t pid; + uid_t uid; + struct child *children; + struct proc *parent; + struct proc *next; +} PROC; + +/* For flags above */ +//#define PFLAG_THREAD 0x01 + +typedef struct child { + PROC *child; + struct child *next; +} CHILD; + +#define empty_2 " " +#define branch_2 "|-" +#define vert_2 "| " +#define last_2 "`-" +#define single_3 "---" +#define first_3 "-+-" + +struct globals { + /* 0-based. IOW: the number of chars we printed on current line */ + unsigned cur_x; + unsigned output_width; + + /* The buffers will be dynamically increased in size as needed */ + unsigned capacity; + unsigned *width; + uint8_t *more; + + PROC *list; + + smallint dumped; /* used by dump_by_user */ +}; +#define G (*ptr_to_globals) +#define INIT_G() do { \ + SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ +} while (0) + + +/* + * Allocates additional buffer space for width and more as needed. + * The first call will allocate the first buffer. + * + * bufindex the index that will be used after the call to this function. + */ +static void ensure_buffer_capacity(int bufindex) +{ + if (bufindex >= G.capacity) { + G.capacity += 0x100; + G.width = xrealloc(G.width, G.capacity * sizeof(G.width[0])); + G.more = xrealloc(G.more, G.capacity * sizeof(G.more[0])); + } +} + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_char(char c) +{ + G.cur_x++; + if (G.cur_x > G.output_width) + return; + if (G.cur_x == G.output_width) + c = '+'; + putchar(c); +} + +/* NB: this function is never called with "bad" chars + * (control chars or chars >= 0x7f) + */ +static void out_string(const char *str) +{ + while (*str) + out_char(*str++); +} + +static void out_newline(void) +{ + putchar('\n'); + G.cur_x = 0; +} + +static PROC *find_proc(pid_t pid) +{ + PROC *walk; + + for (walk = G.list; walk; walk = walk->next) + if (walk->pid == pid) + break; + + return walk; +} + +static PROC *new_proc(const char *comm, pid_t pid, uid_t uid) +{ + PROC *new = xzalloc(sizeof(*new)); + + strcpy(new->comm, comm); + new->pid = pid; + new->uid = uid; + new->next = G.list; + + G.list = new; + return G.list; +} + +static void add_child(PROC *parent, PROC *child) +{ + CHILD *new, **walk; + int cmp; + + new = xmalloc(sizeof(*new)); + + new->child = child; + for (walk = &parent->children; *walk; walk = &(*walk)->next) { + cmp = strcmp((*walk)->child->comm, child->comm); + if (cmp > 0) + break; + if (cmp == 0 && (*walk)->child->uid > child->uid) + break; + } + new->next = *walk; + *walk = new; +} + +static void add_proc(const char *comm, pid_t pid, pid_t ppid, + uid_t uid /*, char isthread*/) +{ + PROC *this, *parent; + + this = find_proc(pid); + if (!this) + this = new_proc(comm, pid, uid); + else { + strcpy(this->comm, comm); + this->uid = uid; + } + + if (pid == ppid) + ppid = 0; +// if (isthread) +// this->flags |= PFLAG_THREAD; + + parent = find_proc(ppid); + if (!parent) + parent = new_proc("?", ppid, 0); + + add_child(parent, this); + this->parent = parent; +} + +static int tree_equal(const PROC *a, const PROC *b) +{ + const CHILD *walk_a, *walk_b; + + if (strcmp(a->comm, b->comm) != 0) + return 0; + if ((option_mask32 /*& OPT_PID*/) && a->pid != b->pid) + return 0; + + for (walk_a = a->children, walk_b = b->children; + walk_a && walk_b; + walk_a = walk_a->next, walk_b = walk_b->next + ) { + if (!tree_equal(walk_a->child, walk_b->child)) + return 0; + } + + return !(walk_a || walk_b); +} + +static int out_args(const char *mystr) +{ + const char *here; + int strcount = 0; + char tmpstr[5]; + + for (here = mystr; *here; here++) { + if (*here == '\\') { + out_string("\\\\"); + strcount += 2; + } else if (*here >= ' ' && *here < 0x7f) { + out_char(*here); + strcount++; + } else { + sprintf(tmpstr, "\\%03o", (unsigned char) *here); + out_string(tmpstr); + strcount += 4; + } + } + + return strcount; +} + +static void +dump_tree(PROC *current, int level, int rep, int leaf, int last, int closing) +{ + CHILD *walk, *next, **scan; + int lvl, i, add, offset, count, comm_len, first; + char tmp[sizeof(int)*3 + 4]; + + if (!current) + return; + + if (!leaf) { + for (lvl = 0; lvl < level; lvl++) { + i = G.width[lvl] + 1; + while (--i >= 0) + out_char(' '); + + if (lvl == level - 1) { + if (last) { + out_string(last_2); + } else { + out_string(branch_2); + } + } else { + if (G.more[lvl + 1]) { + out_string(vert_2); + } else { + out_string(empty_2); + } + } + } + } + + add = 0; + if (rep > 1) { + add += sprintf(tmp, "%d*[", rep); + out_string(tmp); + } + comm_len = out_args(current->comm); + if (option_mask32 /*& OPT_PID*/) { + comm_len += sprintf(tmp, "(%d)", (int)current->pid); + out_string(tmp); + } + offset = G.cur_x; + + if (!current->children) { + while (closing--) + out_char(']'); + out_newline(); + } + ensure_buffer_capacity(level); + G.more[level] = !last; + + G.width[level] = comm_len + G.cur_x - offset + add; + if (G.cur_x >= G.output_width) { + //out_string(first_3); - why? it won't print anything + //out_char('+'); + out_newline(); + return; + } + + first = 1; + for (walk = current->children; walk; walk = next) { + count = 0; + next = walk->next; + scan = &walk->next; + while (*scan) { + if (!tree_equal(walk->child, (*scan)->child)) + scan = &(*scan)->next; + else { + if (next == *scan) + next = (*scan)->next; + count++; + *scan = (*scan)->next; + } + } + if (first) { + out_string(next ? first_3 : single_3); + first = 0; + } + + dump_tree(walk->child, level + 1, count + 1, + walk == current->children, !next, + closing + (count ? 1 : 0)); + } +} + +static void dump_by_user(PROC *current, uid_t uid) +{ + const CHILD *walk; + + if (!current) + return; + + if (current->uid == uid) { + if (G.dumped) + putchar('\n'); + dump_tree(current, 0, 1, 1, 1, 0); + G.dumped = 1; + return; + } + for (walk = current->children; walk; walk = walk->next) + dump_by_user(walk->child, uid); +} + +#if ENABLE_FEATURE_SHOW_THREADS +static void handle_thread(const char *comm, pid_t pid, pid_t ppid, uid_t uid) +{ + char threadname[COMM_DISP_LEN + 1]; + sprintf(threadname, "{%.*s}", (int)sizeof(threadname) - 3, comm); + add_proc(threadname, pid, ppid, uid/*, 1*/); +} +#endif + +static void mread_proc(void) +{ + procps_status_t *p = NULL; + pid_t parent = 0; + int flags = PSSCAN_COMM | PSSCAN_PID | PSSCAN_PPID | PSSCAN_UIDGID | PSSCAN_TASKS; + + while ((p = procps_scan(p, flags)) != NULL) { +#if ENABLE_FEATURE_SHOW_THREADS + if (p->pid != p->main_thread_pid) + handle_thread(p->comm, p->pid, parent, p->uid); + else +#endif + { + add_proc(p->comm, p->pid, p->ppid, p->uid/*, 0*/); + parent = p->pid; + } + } +} + +int pstree_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pstree_main(int argc UNUSED_PARAM, char **argv) +{ + pid_t pid = 1; + long uid = 0; + + INIT_G(); + + get_terminal_width_height(0, &G.output_width, NULL); + + opt_complementary = "?1"; + getopt32(argv, "p"); + argv += optind; + + if (argv[0]) { + if (argv[0][0] >= '0' && argv[0][0] <= '9') { + pid = xatoi(argv[0]); + } else { + uid = xuname2uid(argv[0]); + } + } + + mread_proc(); + + if (!uid) + dump_tree(find_proc(pid), 0, 1, 1, 1, 0); + else { + dump_by_user(find_proc(1), uid); + if (!G.dumped) { + bb_error_msg_and_die("no processes found"); + } + } + + if (ENABLE_FEATURE_CLEAN_UP) { + free(G.width); + free(G.more); + } + return 0; +} diff --git a/procps/pwdx.c b/procps/pwdx.c new file mode 100644 index 0000000..7818104 --- /dev/null +++ b/procps/pwdx.c @@ -0,0 +1,60 @@ +/* vi: set sw=4 ts=4: */ +/* + * pwdx implementation for busybox + * + * Copyright (c) 2004 Nicholas Miell + * ported from procps by Pere Orga 2011 + * + * Licensed under GPLv2, see file LICENSE in this source tree. + */ + +//config:config PWDX +//config: bool "pwdx" +//config: default y +//config: help +//config: Report current working directory of a process + +//applet:IF_PWDX(APPLET(pwdx, BB_DIR_USR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_PWDX) += pwdx.o + +//usage:#define pwdx_trivial_usage +//usage: "PID..." +//usage:#define pwdx_full_usage "\n\n" +//usage: "Show current directory for PIDs\n" + +#include "libbb.h" + +int pwdx_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int pwdx_main(int argc UNUSED_PARAM, char **argv) +{ + opt_complementary = "-1"; + getopt32(argv, ""); + argv += optind; + + do { + char buf[sizeof("/proc/%u/cwd") + sizeof(int)*3]; + unsigned pid; + char *s; + char *arg = *argv; + + // Allowed on the command line: + // /proc/NUM + // NUM + if (strncmp(arg, "/proc/", 6) == 0) + arg += 6; + + pid = bb_strtou(arg, NULL, 10); + if (errno) + bb_error_msg_and_die("invalid process id: '%s'", arg); + + sprintf(buf, "/proc/%u/cwd", pid); + + s = xmalloc_readlink(buf); + // "pwdx /proc/1" says "/proc/1: DIR", not "1: DIR" + printf("%s: %s\n", *argv, s ? s : strerror(errno == ENOENT ? ESRCH : errno)); + free(s); + } while (*++argv); + + return EXIT_SUCCESS; +} diff --git a/procps/renice.c b/procps/renice.c index ea5fc70..77f400a 100644 --- a/procps/renice.c +++ b/procps/renice.c @@ -4,7 +4,7 @@ * * Copyright (C) 2005 Manuel Novoa III * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* Notes: @@ -19,6 +19,15 @@ * following IDs (if any). Multiple switches are allowed. */ +//usage:#define renice_trivial_usage +//usage: "{{-n INCREMENT} | PRIORITY} [[-p | -g | -u] ID...]" +//usage:#define renice_full_usage "\n\n" +//usage: "Change scheduling priority for a running process\n" +//usage: "\n -n Adjust current nice value (smaller is faster)" +//usage: "\n -p Process id(s) (default)" +//usage: "\n -g Process group id(s)" +//usage: "\n -u Process user name(s) and/or id(s)" + #include "libbb.h" #include @@ -32,7 +41,7 @@ int renice_main(int argc UNUSED_PARAM, char **argv) static const char Xetpriority_msg[] ALIGN1 = "%cetpriority"; int retval = EXIT_SUCCESS; - int which = PRIO_PROCESS; /* Default 'which' value. */ + int which = PRIO_PROCESS; /* Default 'which' value. */ int use_relative = 0; int adjustment, new_priority; unsigned who; @@ -57,7 +66,7 @@ int renice_main(int argc UNUSED_PARAM, char **argv) arg += 2; } - if (!arg) { /* No args? Then show usage. */ + if (!arg) { /* No args? Then show usage. */ bb_show_usage(); } @@ -91,7 +100,7 @@ int renice_main(int argc UNUSED_PARAM, char **argv) } else { who = bb_strtou(arg, NULL, 10); if (errno) { - bb_error_msg("bad value: %s", arg); + bb_error_msg("invalid number '%s'", arg); goto HAD_ERROR; } } @@ -100,7 +109,7 @@ int renice_main(int argc UNUSED_PARAM, char **argv) if (use_relative) { int old_priority; - errno = 0; /* Needed for getpriority error detection. */ + errno = 0; /* Needed for getpriority error detection. */ old_priority = getpriority(which, who); if (errno) { bb_perror_msg(Xetpriority_msg, 'g'); diff --git a/procps/smemcap.c b/procps/smemcap.c index 06cf93c..9d1126a 100644 --- a/procps/smemcap.c +++ b/procps/smemcap.c @@ -8,7 +8,7 @@ herein by reference. */ -//applet:IF_SMEMCAP(APPLET(smemcap, _BB_DIR_USR_BIN, _BB_SUID_DROP)) +//applet:IF_SMEMCAP(APPLET(smemcap, BB_DIR_USR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_SMEMCAP) += smemcap.o @@ -20,7 +20,7 @@ //config: a memory usage statistic tool. #include "libbb.h" -#include "unarchive.h" +#include "bb_archive.h" struct fileblock { struct fileblock *next; @@ -41,7 +41,7 @@ static void writeheader(const char *path, struct stat *sb, int type) sprintf(header.size, "%o", (unsigned)sb->st_size); sprintf(header.mtime, "%llo", sb->st_mtime & 077777777777LL); header.typeflag = type; - //strcpy(header.magic, "ustar "); - do we want to be standard-compliant? + strcpy(header.magic, "ustar "); /* like GNU tar */ /* 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 @@ -125,5 +125,8 @@ int smemcap_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } } + if (ENABLE_FEATURE_CLEAN_UP) + closedir(d); + return EXIT_SUCCESS; } diff --git a/procps/sysctl.c b/procps/sysctl.c index fc601d6..c6a1de2 100644 --- a/procps/sysctl.c +++ b/procps/sysctl.c @@ -4,13 +4,33 @@ * * Copyright 1999 George Staikos * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Changelog: * v1.01 - added -p to preload values from a file * v1.01.1 - busybox applet aware by */ +//usage:#define sysctl_trivial_usage +//usage: "[OPTIONS] [KEY[=VALUE]]..." +//usage:#define sysctl_full_usage "\n\n" +//usage: "Show/set kernel parameters\n" +//usage: "\n -e Don't warn about unknown keys" +//usage: "\n -n Don't show key names" +//usage: "\n -a Show all values" +/* Same as -a, no need to show it */ +/* //usage: "\n -A Show all values in table form" */ +//usage: "\n -w Set values" +//usage: "\n -p FILE Set values from FILE (default /etc/sysctl.conf)" +//usage: "\n -q Set values silently" +//usage: +//usage:#define sysctl_example_usage +//usage: "sysctl [-n] [-e] variable...\n" +//usage: "sysctl [-n] [-e] [-q] -w variable=value...\n" +//usage: "sysctl [-n] [-e] -a\n" +//usage: "sysctl [-n] [-e] [-q] -p file (default /etc/sysctl.conf)\n" +//usage: "sysctl [-n] [-e] -A\n" + #include "libbb.h" enum { @@ -19,9 +39,11 @@ enum { FLAG_TABLE_FORMAT = 1 << 2, /* not implemented */ FLAG_SHOW_ALL = 1 << 3, FLAG_PRELOAD_FILE = 1 << 4, +/* TODO: procps 3.2.8 seems to not require -w for KEY=VAL to work: */ FLAG_WRITE = 1 << 5, + FLAG_QUIET = 1 << 6, }; -#define OPTION_STR "neAapw" +#define OPTION_STR "neAapwq" static void sysctl_dots_to_slashes(char *name) { @@ -91,7 +113,7 @@ static int sysctl_act_on_setting(char *setting) retval = EXIT_FAILURE; goto end; } - value = cptr + 1; /* point to the value in name=value */ + value = cptr + 1; /* point to the value in name=value */ if (setting == cptr || !*value) { bb_error_msg("error: malformed setting '%s'", outname); retval = EXIT_FAILURE; @@ -126,9 +148,11 @@ static int sysctl_act_on_setting(char *setting) //TODO: procps 3.2.7 writes "value\n", note trailing "\n" xwrite_str(fd, value); close(fd); - if (option_mask32 & FLAG_SHOW_KEYS) - printf("%s = ", outname); - puts(value); + if (!(option_mask32 & FLAG_QUIET)) { + if (option_mask32 & FLAG_SHOW_KEYS) + printf("%s = ", outname); + puts(value); + } } else { char c; @@ -181,7 +205,7 @@ static int sysctl_act_recursive(const char *path) continue; /* d_name is "." or ".." */ /* if path was ".", drop "./" prefix: */ retval |= sysctl_act_recursive((next[0] == '.' && next[1] == '/') ? - next + 2 : next); + next + 2 : next); free(next); } closedir(dirp); @@ -206,7 +230,7 @@ static int sysctl_handle_preload_file(const char *filename) parser = config_open(filename); /* Must do it _after_ config_open(): */ xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ //TODO: ';' is comment char too //TODO: comment may be only at line start. "var=1 #abc" - "1 #abc" is the value @@ -242,7 +266,7 @@ int sysctl_main(int argc UNUSED_PARAM, char **argv) return sysctl_handle_preload_file(*argv ? *argv : "/etc/sysctl.conf"); } xchdir("/proc/sys"); - /* xchroot(".") - if you are paranoid */ + /* xchroot("/proc/sys") - if you are paranoid */ if (opt & (FLAG_TABLE_FORMAT | FLAG_SHOW_ALL)) { return sysctl_act_recursive("."); } diff --git a/procps/top.c b/procps/top.c index ec84374..51f1c1a 100644 --- a/procps/top.c +++ b/procps/top.c @@ -19,18 +19,91 @@ * * Sept 2008: Vineet Gupta * Added Support for reporting SMP Information - * - CPU where Process was last seen running + * - CPU where process was last seen running * (to see effect of sched_setaffinity() etc) - * - CPU Time Split (idle/IO/wait etc) PER CPU + * - CPU time split (idle/IO/wait etc) per CPU * * Copyright (c) 1992 Branko Lankester * Copyright (c) 1992 Roger Binns * Copyright (C) 1994-1996 Charles L. Blake. * Copyright (C) 1992-1998 Michael K. Johnson * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. + */ +/* How to snapshot /proc for debugging top problems: + * for f in /proc/[0-9]*""/stat; do + * n=${f#/proc/} + * n=${n%/stat}_stat + * cp $f $n + * done + * cp /proc/stat /proc/meminfo /proc/loadavg . + * top -bn1 >top.out + * + * ...and how to run top on it on another machine: + * rm -rf proc; mkdir proc + * for f in [0-9]*_stat; do + * p=${f%_stat} + * mkdir -p proc/$p + * cp $f proc/$p/stat + * done + * cp stat meminfo loadavg proc + * chroot . ./top -bn1 >top1.out */ +//config:config TOP +//config: bool "top" +//config: default y +//config: help +//config: The top program provides a dynamic real-time view of a running +//config: system. +//config: +//config:config FEATURE_TOP_CPU_USAGE_PERCENTAGE +//config: bool "Show CPU per-process usage percentage" +//config: default y +//config: depends on TOP +//config: help +//config: Make top display CPU usage for each process. +//config: This adds about 2k. +//config: +//config:config FEATURE_TOP_CPU_GLOBAL_PERCENTS +//config: bool "Show CPU global usage percentage" +//config: default y +//config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE +//config: help +//config: Makes top display "CPU: NN% usr NN% sys..." line. +//config: This adds about 0.5k. +//config: +//config:config FEATURE_TOP_SMP_CPU +//config: bool "SMP CPU usage display ('c' key)" +//config: default y +//config: depends on FEATURE_TOP_CPU_GLOBAL_PERCENTS +//config: help +//config: Allow 'c' key to switch between individual/cumulative CPU stats +//config: This adds about 0.5k. +//config: +//config:config FEATURE_TOP_DECIMALS +//config: bool "Show 1/10th of a percent in CPU/mem statistics" +//config: default y +//config: depends on FEATURE_TOP_CPU_USAGE_PERCENTAGE +//config: help +//config: Show 1/10th of a percent in CPU/mem statistics. +//config: This adds about 0.3k. +//config: +//config:config FEATURE_TOP_SMP_PROCESS +//config: bool "Show CPU process runs on ('j' field)" +//config: default y +//config: depends on TOP +//config: help +//config: Show CPU where process was last found running on. +//config: This is the 'j' field. +//config: +//config:config FEATURE_TOPMEM +//config: bool "Topmem command ('s' key)" +//config: default y +//config: depends on TOP +//config: help +//config: Enable 's' in top (gives lots of memory info). + #include "libbb.h" @@ -73,15 +146,20 @@ enum { SORT_DEPTH = 3 }; struct globals { top_status_t *top; int ntop; + smallint inverted; #if ENABLE_FEATURE_TOPMEM smallint sort_field; - smallint inverted; #endif #if ENABLE_FEATURE_TOP_SMP_CPU smallint smp_cpu_info; /* one/many cpu info lines? */ #endif + unsigned lines; /* screen height */ #if ENABLE_FEATURE_USE_TERMIOS struct termios initial_settings; + int scroll_ofs; +#define G_scroll_ofs G.scroll_ofs +#else +#define G_scroll_ofs 0 #endif #if !ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE cmp_funcp sort_function[1]; @@ -99,6 +177,9 @@ struct globals { jiffy_counts_t *cpu_jif, *cpu_prev_jif; int num_cpus; #endif +#if ENABLE_FEATURE_USE_TERMIOS + char kbd_input[KEYCODE_BUFFER_SIZE]; +#endif char line_buf[80]; }; //FIX_ALIASING; - large code growth enum { LINE_BUF_SIZE = COMMON_BUFSIZE - offsetof(struct globals, line_buf) }; @@ -107,7 +188,6 @@ struct BUG_bad_size { char BUG_G_too_big[sizeof(G) <= COMMON_BUFSIZE ? 1 : -1]; char BUG_line_buf_too_small[LINE_BUF_SIZE > 80 ? 1 : -1]; }; -#define INIT_G() do { } while (0) #define top (G.top ) #define ntop (G.ntop ) #define sort_field (G.sort_field ) @@ -124,6 +204,7 @@ struct BUG_bad_size { #define num_cpus (G.num_cpus ) #define total_pcpu (G.total_pcpu ) #define line_buf (G.line_buf ) +#define INIT_G() do { } while (0) enum { OPT_d = (1 << 0), @@ -175,9 +256,9 @@ static int mult_lvl_cmp(void* a, void* b) for (i = 0; i < SORT_DEPTH; i++) { cmp_val = (*sort_function[i])(a, b); if (cmp_val != 0) - return cmp_val; + break; } - return 0; + return inverted ? -cmp_val : cmp_val; } static NOINLINE int read_cpu_jiffy(FILE *fp, jiffy_counts_t *p_jif) @@ -213,7 +294,7 @@ static void get_jiffy_counts(void) * they are used to calculate per process CPU% */ prev_jif = cur_jif; if (read_cpu_jiffy(fp, &cur_jif) < 4) - bb_error_msg_and_die("can't read /proc/stat"); + bb_error_msg_and_die("can't read '%s'", "/proc/stat"); #if !ENABLE_FEATURE_TOP_SMP_CPU fclose(fp); @@ -519,7 +600,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) /* what info of the processes is shown */ printf(OPT_BATCH_MODE ? "%.*s" : "\033[7m%.*s\033[0m", scr_width, - " PID PPID USER STAT VSZ %MEM" + " PID PPID USER STAT VSZ %VSZ" IF_FEATURE_TOP_SMP_PROCESS(" CPU") IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE(" %CPU") " COMMAND"); @@ -537,7 +618,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) # define FMT "%4u%%" #endif /* - * MEM% = s->vsz/MemTotal + * %VSZ = s->vsz/MemTotal */ pmem_shift = BITS_PER_INT-11; pmem_scale = UPSCALE*(1U<<(BITS_PER_INT-11)) / total_memory; @@ -546,7 +627,7 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) pmem_scale /= 4; pmem_shift -= 2; } - pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); + pmem_half = (1U << pmem_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE busy_jifs = cur_jif.busy - prev_jif.busy; /* This happens if there were lots of short-lived processes @@ -577,15 +658,15 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) pcpu_scale /= 4; pcpu_shift -= 2; } - pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS? 20 : 2); + pcpu_half = (1U << pcpu_shift) / (ENABLE_FEATURE_TOP_DECIMALS ? 20 : 2); /* printf(" pmem_scale=%u pcpu_scale=%u ", pmem_scale, pcpu_scale); */ #endif /* Ok, all preliminary data is ready, go through the list */ scr_width += 2; /* account for leading '\n' and trailing NUL */ - if (lines_rem > ntop) - lines_rem = ntop; - s = top; + if (lines_rem > ntop - G_scroll_ofs) + lines_rem = ntop - G_scroll_ofs; + s = top + G_scroll_ofs; while (--lines_rem >= 0) { unsigned col; CALC_STAT(pmem, (s->vsz*pmem_scale + pmem_half) >> pmem_shift); @@ -596,8 +677,8 @@ static NOINLINE void display_process_list(int lines_rem, int scr_width) if (s->vsz >= 100000) sprintf(vsz_str_buf, "%6ldm", s->vsz/1024); else - sprintf(vsz_str_buf, "%7ld", s->vsz); - /* PID PPID USER STAT VSZ %MEM [%CPU] COMMAND */ + sprintf(vsz_str_buf, "%7lu", s->vsz); + /* PID PPID USER STAT VSZ %VSZ [%CPU] COMMAND */ col = snprintf(line_buf, scr_width, "\n" "%5u%6u %-8.8s %s%s" FMT IF_FEATURE_TOP_SMP_PROCESS(" %3d") @@ -630,14 +711,14 @@ static void clearmems(void) clear_username_cache(); free(top); top = NULL; - ntop = 0; } #if ENABLE_FEATURE_USE_TERMIOS static void reset_term(void) { - tcsetattr_stdin_TCSANOW(&initial_settings); + if (!OPT_BATCH_MODE) + tcsetattr_stdin_TCSANOW(&initial_settings); if (ENABLE_FEATURE_CLEAN_UP) { clearmems(); # if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE @@ -646,11 +727,12 @@ static void reset_term(void) } } -static void sig_catcher(int sig UNUSED_PARAM) +static void sig_catcher(int sig) { reset_term(); - exit(EXIT_FAILURE); + kill_myself_with_sig(sig); } + #endif /* FEATURE_USE_TERMIOS */ /* @@ -765,24 +847,23 @@ static void display_topmem_header(int scr_width, int *lines_rem_p) static void ulltoa6_and_space(unsigned long long ul, char buf[6]) { /* see http://en.wikipedia.org/wiki/Tera */ - smart_ulltoa5(ul, buf, " mgtpezy"); - buf[5] = ' '; + smart_ulltoa5(ul, buf, " mgtpezy")[0] = ' '; } static NOINLINE void display_topmem_process_list(int lines_rem, int scr_width) { #define HDR_STR " PID VSZ VSZRW RSS (SHR) DIRTY (SHR) STACK" #define MIN_WIDTH sizeof(HDR_STR) - const topmem_status_t *s = topmem; + const topmem_status_t *s = topmem + G_scroll_ofs; display_topmem_header(scr_width, &lines_rem); strcpy(line_buf, HDR_STR " COMMAND"); - line_buf[5 + sort_field * 6] = '*'; + line_buf[11 + sort_field * 6] = "^_"[inverted]; printf(OPT_BATCH_MODE ? "%.*s" : "\e[7m%.*s\e[0m", scr_width, line_buf); lines_rem--; - if (lines_rem > ntop) - lines_rem = ntop; + if (lines_rem > ntop - G_scroll_ofs) + lines_rem = ntop - G_scroll_ofs; while (--lines_rem >= 0) { /* PID VSZ VSZRW RSS (SHR) DIRTY (SHR) COMMAND */ ulltoa6_and_space(s->pid , &line_buf[0*6]); @@ -830,24 +911,210 @@ enum { | PSSCAN_PID | PSSCAN_SMAPS | PSSCAN_COMM, + EXIT_MASK = (unsigned)-1, }; +#if ENABLE_FEATURE_USE_TERMIOS +static unsigned handle_input(unsigned scan_mask, unsigned interval) +{ + struct pollfd pfd[1]; + + if (option_mask32 & OPT_EOF) { + /* EOF on stdin ("top = ntop) + G_scroll_ofs = ntop - 1; + if (G_scroll_ofs < 0) + G_scroll_ofs = 0; + break; + } + + c |= 0x20; /* lowercase */ + if (c == 'q') + return EXIT_MASK; + + if (c == 'n') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = pid_sort; + continue; + } + if (c == 'm') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = mem_sort; +# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + sort_function[1] = pcpu_sort; + sort_function[2] = time_sort; +# endif + continue; + } +# if ENABLE_FEATURE_SHOW_THREADS + if (c == 'h' + IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) + ) { + scan_mask ^= PSSCAN_TASKS; + continue; + } +# endif +# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE + if (c == 'p') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = pcpu_sort; + sort_function[1] = mem_sort; + sort_function[2] = time_sort; + continue; + } + if (c == 't') { + IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) + sort_function[0] = time_sort; + sort_function[1] = mem_sort; + sort_function[2] = pcpu_sort; + continue; + } +# if ENABLE_FEATURE_TOPMEM + if (c == 's') { + scan_mask = TOPMEM_MASK; + free(prev_hist); + prev_hist = NULL; + prev_hist_count = 0; + sort_field = (sort_field + 1) % NUM_SORT_FIELD; + continue; + } +# endif + if (c == 'r') { + inverted ^= 1; + continue; + } +# if ENABLE_FEATURE_TOP_SMP_CPU + /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ + if (c == 'c' || c == '1') { + /* User wants to toggle per cpu <> aggregate */ + if (smp_cpu_info) { + free(cpu_prev_jif); + free(cpu_jif); + cpu_jif = &cur_jif; + cpu_prev_jif = &prev_jif; + } else { + /* Prepare for xrealloc() */ + cpu_jif = cpu_prev_jif = NULL; + } + num_cpus = 0; + smp_cpu_info = !smp_cpu_info; + get_jiffy_counts(); + continue; + } +# endif +# endif + break; /* unknown key -> force refresh */ + } + + return scan_mask; +} +#endif + +//usage:#if ENABLE_FEATURE_SHOW_THREADS || ENABLE_FEATURE_TOP_SMP_CPU +//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) __VA_ARGS__ +//usage:#else +//usage:# define IF_SHOW_THREADS_OR_TOP_SMP(...) +//usage:#endif +//usage:#define top_trivial_usage +//usage: "[-b] [-nCOUNT] [-dSECONDS]" IF_FEATURE_TOPMEM(" [-m]") +//usage:#define top_full_usage "\n\n" +//usage: "Provide a view of process activity in real time." +//usage: "\n""Read the status of all processes from /proc each SECONDS" +//usage: "\n""and display a screenful of them." +//usage: "\n""Keys:" +//usage: "\n"" N/M" +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/P") +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/T") +//usage: ": " IF_FEATURE_TOPMEM("show CPU usage, ") "sort by pid/mem" +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/cpu") +//usage: IF_FEATURE_TOP_CPU_USAGE_PERCENTAGE("/time") +//usage: IF_FEATURE_TOPMEM( +//usage: "\n"" S: show memory" +//usage: ) +//usage: "\n"" R: reverse sort" +//usage: IF_SHOW_THREADS_OR_TOP_SMP( +//usage: "\n"" " +//usage: IF_FEATURE_SHOW_THREADS("H: toggle threads") +//usage: IF_FEATURE_SHOW_THREADS(IF_FEATURE_TOP_SMP_CPU(", ")) +//usage: IF_FEATURE_TOP_SMP_CPU("1: toggle SMP") +//usage: ) +//usage: "\n"" Q,^C: exit" +//usage: "\n" +//usage: "\n""Options:" +//usage: "\n"" -b Batch mode" +//usage: "\n"" -n N Exit after N iterations" +//usage: "\n"" -d N Delay between updates" +//usage: IF_FEATURE_TOPMEM( +//usage: "\n"" -m Same as 's' key" +//usage: ) + +/* Interactive testing: + * echo sss | ./busybox top + * - shows memory screen + * echo sss | ./busybox top -bn1 >mem + * - saves memory screen - the *whole* list, not first NROWS processes! + * echo .m.s.s.s.s.s.s.q | ./busybox top -b >z + * - saves several different screens, and exits + * + * TODO: -i STRING param as a better alternative? + */ + int top_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int top_main(int argc UNUSED_PARAM, char **argv) { int iterations; - unsigned lines, col; - int lines_rem; + unsigned col; unsigned interval; char *str_interval, *str_iterations; unsigned scan_mask = TOP_MASK; #if ENABLE_FEATURE_USE_TERMIOS struct termios new_settings; - struct pollfd pfd[1]; - unsigned char c; - - pfd[0].fd = 0; - pfd[0].events = POLLIN; #endif INIT_G(); @@ -884,15 +1151,6 @@ int top_main(int argc UNUSED_PARAM, char **argv) /* change to /proc */ xchdir("/proc"); -#if ENABLE_FEATURE_USE_TERMIOS - tcgetattr(0, (void *) &initial_settings); - memcpy(&new_settings, &initial_settings, sizeof(new_settings)); - /* unbuffered input, turn off echo */ - new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); - - bb_signals(BB_FATAL_SIGS, sig_catcher); - tcsetattr_stdin_TCSANOW(&new_settings); -#endif #if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE sort_function[0] = pcpu_sort; @@ -902,23 +1160,47 @@ int top_main(int argc UNUSED_PARAM, char **argv) sort_function[0] = mem_sort; #endif - while (1) { + if (OPT_BATCH_MODE) { + option_mask32 |= OPT_EOF; + } +#if ENABLE_FEATURE_USE_TERMIOS + else { + tcgetattr(0, (void *) &initial_settings); + memcpy(&new_settings, &initial_settings, sizeof(new_settings)); + /* unbuffered input, turn off echo */ + new_settings.c_lflag &= ~(ISIG | ICANON | ECHO | ECHONL); + tcsetattr_stdin_TCSANOW(&new_settings); + } + + bb_signals(BB_FATAL_SIGS, sig_catcher); + + /* Eat initial input, if any */ + scan_mask = handle_input(scan_mask, 0); +#endif + + while (scan_mask != EXIT_MASK) { procps_status_t *p = NULL; - lines = 24; /* default */ - col = 79; + if (OPT_BATCH_MODE) { + G.lines = INT_MAX; + col = LINE_BUF_SIZE - 2; /* +2 bytes for '\n', NUL */ + } else { + G.lines = 24; /* default */ + col = 79; #if ENABLE_FEATURE_USE_TERMIOS - /* We output to stdout, we need size of stdout (not stdin)! */ - get_terminal_width_height(STDOUT_FILENO, &col, &lines); - if (lines < 5 || col < 10) { - sleep(interval); - continue; - } + /* We output to stdout, we need size of stdout (not stdin)! */ + get_terminal_width_height(STDOUT_FILENO, &col, &G.lines); + if (G.lines < 5 || col < 10) { + sleep(interval); + continue; + } #endif - if (col > LINE_BUF_SIZE-2) /* +2 bytes for '\n', NUL, */ - col = LINE_BUF_SIZE-2; + if (col > LINE_BUF_SIZE - 2) + col = LINE_BUF_SIZE - 2; + } /* read process IDs & status for all the processes */ + ntop = 0; while ((p = procps_scan(p, scan_mask)) != NULL) { int n; #if ENABLE_FEATURE_TOPMEM @@ -942,20 +1224,20 @@ int top_main(int argc UNUSED_PARAM, char **argv) } #if ENABLE_FEATURE_TOPMEM else { /* TOPMEM */ - if (!(p->mapped_ro | p->mapped_rw)) + if (!(p->smaps.mapped_ro | p->smaps.mapped_rw)) continue; /* kernel threads are ignored */ n = ntop; /* No bug here - top and topmem are the same */ top = xrealloc_vector(topmem, 6, ntop++); strcpy(topmem[n].comm, p->comm); topmem[n].pid = p->pid; - topmem[n].vsz = p->mapped_rw + p->mapped_ro; - topmem[n].vszrw = p->mapped_rw; - topmem[n].rss_sh = p->shared_clean + p->shared_dirty; - topmem[n].rss = p->private_clean + p->private_dirty + topmem[n].rss_sh; - topmem[n].dirty = p->private_dirty + p->shared_dirty; - topmem[n].dirty_sh = p->shared_dirty; - topmem[n].stack = p->stack; + topmem[n].vsz = p->smaps.mapped_rw + p->smaps.mapped_ro; + topmem[n].vszrw = p->smaps.mapped_rw; + topmem[n].rss_sh = p->smaps.shared_clean + p->smaps.shared_dirty; + topmem[n].rss = p->smaps.private_clean + p->smaps.private_dirty + topmem[n].rss_sh; + topmem[n].dirty = p->smaps.private_dirty + p->smaps.shared_dirty; + topmem[n].dirty_sh = p->smaps.shared_dirty; + topmem[n].stack = p->smaps.stack; } #endif } /* end of "while we read /proc" */ @@ -984,15 +1266,11 @@ int top_main(int argc UNUSED_PARAM, char **argv) qsort(topmem, ntop, sizeof(topmem_status_t), (void*)topmem_sort); } #endif - lines_rem = lines; - if (OPT_BATCH_MODE) { - lines_rem = INT_MAX; - } if (scan_mask != TOPMEM_MASK) - display_process_list(lines_rem, col); + display_process_list(G.lines, col); #if ENABLE_FEATURE_TOPMEM else - display_topmem_process_list(lines_rem, col); + display_topmem_process_list(G.lines, col); #endif clearmems(); if (iterations >= 0 && !--iterations) @@ -1000,84 +1278,9 @@ int top_main(int argc UNUSED_PARAM, char **argv) #if !ENABLE_FEATURE_USE_TERMIOS sleep(interval); #else - if (option_mask32 & (OPT_b|OPT_EOF)) - /* batch mode, or EOF on stdin ("top 0) { - if (safe_read(STDIN_FILENO, &c, 1) != 1) { /* error/EOF? */ - option_mask32 |= OPT_EOF; - continue; - } - if (c == initial_settings.c_cc[VINTR]) - break; - c |= 0x20; /* lowercase */ - if (c == 'q') - break; - if (c == 'n') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = pid_sort; - } - if (c == 'm') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = mem_sort; -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - sort_function[1] = pcpu_sort; - sort_function[2] = time_sort; -# endif - } -# if ENABLE_FEATURE_SHOW_THREADS - if (c == 'h' - IF_FEATURE_TOPMEM(&& scan_mask != TOPMEM_MASK) - ) { - scan_mask ^= PSSCAN_TASKS; - } -# endif -# if ENABLE_FEATURE_TOP_CPU_USAGE_PERCENTAGE - if (c == 'p') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = pcpu_sort; - sort_function[1] = mem_sort; - sort_function[2] = time_sort; - } - if (c == 't') { - IF_FEATURE_TOPMEM(scan_mask = TOP_MASK;) - sort_function[0] = time_sort; - sort_function[1] = mem_sort; - sort_function[2] = pcpu_sort; - } -# if ENABLE_FEATURE_TOPMEM - if (c == 's') { - scan_mask = TOPMEM_MASK; - free(prev_hist); - prev_hist = NULL; - prev_hist_count = 0; - sort_field = (sort_field + 1) % NUM_SORT_FIELD; - } - if (c == 'r') - inverted ^= 1; -# endif -# if ENABLE_FEATURE_TOP_SMP_CPU - /* procps-2.0.18 uses 'C', 3.2.7 uses '1' */ - if (c == 'c' || c == '1') { - /* User wants to toggle per cpu <> aggregate */ - if (smp_cpu_info) { - free(cpu_prev_jif); - free(cpu_jif); - cpu_jif = &cur_jif; - cpu_prev_jif = &prev_jif; - } else { - /* Prepare for xrealloc() */ - cpu_jif = cpu_prev_jif = NULL; - } - num_cpus = 0; - smp_cpu_info = !smp_cpu_info; - get_jiffy_counts(); - } -# endif -# endif - } + scan_mask = handle_input(scan_mask, interval); #endif /* FEATURE_USE_TERMIOS */ - } /* end of "while (1)" */ + } /* end of "while (not Q)" */ bb_putchar('\n'); #if ENABLE_FEATURE_USE_TERMIOS diff --git a/procps/uptime.c b/procps/uptime.c index d9aa1d0..778812a 100644 --- a/procps/uptime.c +++ b/procps/uptime.c @@ -4,31 +4,59 @@ * * Copyright (C) 1999-2004 by Erik Andersen * - * Licensed under the GPL version 2, see the file LICENSE in this tarball. + * Licensed under GPLv2, see file LICENSE in this source tree. */ -/* This version of uptime doesn't display the number of users on the system, - * since busybox init doesn't mess with utmp. For folks using utmp that are - * just dying to have # of users reported, feel free to write it as some type - * of CONFIG_FEATURE_UTMP_SUPPORT #define +/* 2011 Pere Orga + * + * Added FEATURE_UPTIME_UTMP_SUPPORT flag. */ /* getopt not needed */ +//config:config UPTIME +//config: bool "uptime" +//config: default y +//config: select PLATFORM_LINUX #sysinfo() +//config: help +//config: uptime gives a one line display of the current time, how long +//config: the system has been running, how many users are currently logged +//config: on, and the system load averages for the past 1, 5, and 15 minutes. +//config: +//config:config FEATURE_UPTIME_UTMP_SUPPORT +//config: bool "Support for showing the number of users" +//config: default y +//config: depends on UPTIME && FEATURE_UTMP +//config: help +//config: Makes uptime display the number of users currently logged on. + +//usage:#define uptime_trivial_usage +//usage: "" +//usage:#define uptime_full_usage "\n\n" +//usage: "Display the time since the last boot" +//usage: +//usage:#define uptime_example_usage +//usage: "$ uptime\n" +//usage: " 1:55pm up 2:30, load average: 0.09, 0.04, 0.00\n" + #include "libbb.h" +#ifdef __linux__ +# include +#endif + #ifndef FSHIFT # define FSHIFT 16 /* nr of bits of precision */ #endif -#define FIXED_1 (1<> FSHIFT) -#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) +#define FIXED_1 (1 << FSHIFT) /* 1.0 as fixed-point */ +#define LOAD_INT(x) (unsigned)((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1 - 1)) * 100) int uptime_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int uptime_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) { - int updays, uphours, upminutes; + unsigned updays, uphours, upminutes; struct sysinfo info; struct tm *current_time; time_t current_secs; @@ -38,20 +66,32 @@ int uptime_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) sysinfo(&info); - printf(" %02d:%02d:%02d up ", + printf(" %02u:%02u:%02u up ", current_time->tm_hour, current_time->tm_min, current_time->tm_sec); - updays = (int) info.uptime / (60*60*24); + updays = (unsigned) info.uptime / (unsigned)(60*60*24); if (updays) - printf("%d day%s, ", updays, (updays != 1) ? "s" : ""); - upminutes = (int) info.uptime / 60; - uphours = (upminutes / 60) % 24; + printf("%u day%s, ", updays, (updays != 1) ? "s" : ""); + upminutes = (unsigned) info.uptime / (unsigned)60; + uphours = (upminutes / (unsigned)60) % (unsigned)24; upminutes %= 60; if (uphours) - printf("%2d:%02d, ", uphours, upminutes); + printf("%2u:%02u", uphours, upminutes); else - printf("%d min, ", upminutes); + printf("%u min", upminutes); + +#if ENABLE_FEATURE_UPTIME_UTMP_SUPPORT + { + struct utmp *ut; + unsigned users = 0; + while ((ut = getutent()) != NULL) { + if ((ut->ut_type == USER_PROCESS) && (ut->ut_name[0] != '\0')) + users++; + } + printf(", %u users", users); + } +#endif - printf("load average: %ld.%02ld, %ld.%02ld, %ld.%02ld\n", + printf(", load average: %u.%02u, %u.%02u, %u.%02u\n", LOAD_INT(info.loads[0]), LOAD_FRAC(info.loads[0]), LOAD_INT(info.loads[1]), LOAD_FRAC(info.loads[1]), LOAD_INT(info.loads[2]), LOAD_FRAC(info.loads[2])); diff --git a/procps/watch.c b/procps/watch.c index a1cde9e..0397f21 100644 --- a/procps/watch.c +++ b/procps/watch.c @@ -5,12 +5,25 @@ * Copyright (C) 2001 by Michael Habermann * Copyrigjt (C) Mar 16, 2003 Manuel Novoa III (mjn3@codepoet.org) * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* BB_AUDIT SUSv3 N/A */ /* BB_AUDIT GNU defects -- only option -n is supported. */ +//usage:#define watch_trivial_usage +//usage: "[-n SEC] [-t] PROG ARGS" +//usage:#define watch_full_usage "\n\n" +//usage: "Run PROG periodically\n" +//usage: "\n -n Loop period in seconds (default 2)" +//usage: "\n -t Don't print header" +//usage: +//usage:#define watch_example_usage +//usage: "$ watch date\n" +//usage: "Mon Dec 17 10:31:40 GMT 2000\n" +//usage: "Mon Dec 17 10:31:42 GMT 2000\n" +//usage: "Mon Dec 17 10:31:44 GMT 2000" + #include "libbb.h" // procps 2.0.18: @@ -56,7 +69,6 @@ int watch_main(int argc UNUSED_PARAM, char **argv) printf("\033[H""\033[J"); if (!(opt & 0x2)) { // no -t const unsigned time_len = sizeof("1234-67-90 23:56:89"); - time_t t; // STDERR_FILENO is procps3 compat: // "watch ls 2>/dev/null" does not detect tty size @@ -66,10 +78,13 @@ int watch_main(int argc UNUSED_PARAM, char **argv) free(header); header = xasprintf("Every %us: %-*s", period, (int)width, cmd); } - time(&t); - if (time_len < width) - strftime(header + width - time_len, time_len, - "%Y-%m-%d %H:%M:%S", localtime(&t)); + if (time_len < width) { + strftime_YYYYMMDDHHMMSS( + header + width - time_len, + time_len, + /*time_t*:*/ NULL + ); + } // compat: empty line between header and cmd output printf("%s\n\n", header); diff --git a/runit/Kbuild.src b/runit/Kbuild.src index 4d85372..0fce955 100644 --- a/runit/Kbuild.src +++ b/runit/Kbuild.src @@ -2,16 +2,16 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= INSERT -lib-$(CONFIG_RUNSV) += runsv.o runit_lib.o -lib-$(CONFIG_RUNSVDIR) += runsvdir.o runit_lib.o -lib-$(CONFIG_SV) += sv.o runit_lib.o -lib-$(CONFIG_SVLOGD) += svlogd.o runit_lib.o +lib-$(CONFIG_RUNSV) += runsv.o +lib-$(CONFIG_RUNSVDIR) += runsvdir.o +lib-$(CONFIG_SV) += sv.o +lib-$(CONFIG_SVLOGD) += svlogd.o lib-$(CONFIG_CHPST) += chpst.o lib-$(CONFIG_ENVDIR) += chpst.o diff --git a/runit/chpst.c b/runit/chpst.c index ad08112..71af29f 100644 --- a/runit/chpst.c +++ b/runit/chpst.c @@ -28,8 +28,70 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* Dependencies on runit_lib.c removed */ +//usage:#define chpst_trivial_usage +//usage: "[-vP012] [-u USER[:GRP]] [-U USER[:GRP]] [-e DIR]\n" +//usage: " [-/ DIR] [-n NICE] [-m BYTES] [-d BYTES] [-o N]\n" +//usage: " [-p N] [-f BYTES] [-c BYTES] PROG ARGS" +//usage:#define chpst_full_usage "\n\n" +//usage: "Change the process state, run PROG\n" +//usage: "\n -u USER[:GRP] Set uid and gid" +//usage: "\n -U USER[:GRP] Set $UID and $GID in environment" +//usage: "\n -e DIR Set environment variables as specified by files" +//usage: "\n in DIR: file=1st_line_of_file" +//usage: "\n -/ DIR Chroot to DIR" +//usage: "\n -n NICE Add NICE to nice value" +//usage: "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES" +//usage: "\n -d BYTES Limit data segment" +//usage: "\n -o N Limit number of open files per process" +//usage: "\n -p N Limit number of processes per uid" +//usage: "\n -f BYTES Limit output file sizes" +//usage: "\n -c BYTES Limit core file size" +//usage: "\n -v Verbose" +//usage: "\n -P Create new process group" +//usage: "\n -0 Close stdin" +//usage: "\n -1 Close stdout" +//usage: "\n -2 Close stderr" +//usage: +//usage:#define envdir_trivial_usage +//usage: "DIR PROG ARGS" +//usage:#define envdir_full_usage "\n\n" +//usage: "Set various environment variables as specified by files\n" +//usage: "in the directory DIR, run PROG" +//usage: +//usage:#define envuidgid_trivial_usage +//usage: "USER PROG ARGS" +//usage:#define envuidgid_full_usage "\n\n" +//usage: "Set $UID to USER's uid and $GID to USER's gid, run PROG" +//usage: +//usage:#define setuidgid_trivial_usage +//usage: "USER PROG ARGS" +//usage:#define setuidgid_full_usage "\n\n" +//usage: "Set uid and gid to USER's uid and gid, drop supplementary group ids,\n" +//usage: "run PROG" +//usage: +//usage:#define softlimit_trivial_usage +//usage: "[-a BYTES] [-m BYTES] [-d BYTES] [-s BYTES] [-l BYTES]\n" +//usage: " [-f BYTES] [-c BYTES] [-r BYTES] [-o N] [-p N] [-t N]\n" +//usage: " PROG ARGS" +//usage:#define softlimit_full_usage "\n\n" +//usage: "Set soft resource limits, then run PROG\n" +//usage: "\n -a BYTES Limit total size of all segments" +//usage: "\n -m BYTES Same as -d BYTES -s BYTES -l BYTES -a BYTES" +//usage: "\n -d BYTES Limit data segment" +//usage: "\n -s BYTES Limit stack segment" +//usage: "\n -l BYTES Limit locked memory size" +//usage: "\n -o N Limit number of open files per process" +//usage: "\n -p N Limit number of processes per uid" +//usage: "\nOptions controlling file sizes:" +//usage: "\n -f BYTES Limit output file sizes" +//usage: "\n -c BYTES Limit core file size" +//usage: "\nEfficiency opts:" +//usage: "\n -r BYTES Limit resident set size" +//usage: "\n -t N Limit CPU time, process receives" +//usage: "\n a SIGXCPU after N seconds" + #include "libbb.h" -#include +#include /* getrlimit */ /* Five applets here: chpst, envdir, envuidgid, setuidgid, softlimit. @@ -123,10 +185,10 @@ static NOINLINE void edir(const char *directory_name) if ((errno == EISDIR) && directory_name) { if (option_mask32 & OPT_v) bb_perror_msg("warning: %s/%s is a directory", - directory_name, d->d_name); + directory_name, d->d_name); continue; - } else - bb_perror_msg_and_die("open %s/%s", + } + bb_perror_msg_and_die("open %s/%s", directory_name, d->d_name); } size = full_read(fd, buf, sizeof(buf)-1); @@ -174,7 +236,6 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) { struct bb_uidgid_t ugid; char *set_user = set_user; /* for compiler */ - char *env_user = env_user; char *env_dir = env_dir; char *root; char *nicestr; @@ -202,7 +263,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) IF_CHPST("/:n:vP012"), &limita, &limitc, &limitd, &limitf, &limitl, &limitm, &limito, &limitp, &limitr, &limits, &limitt, - &set_user, &env_user, &env_dir + &set_user, &set_user, &env_dir IF_CHPST(, &root, &nicestr)); argv += optind; if (opt & OPT_m) { // -m means -asld @@ -230,7 +291,7 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) // envuidgid? if (ENABLE_ENVUIDGID && applet_name[0] == 'e' && applet_name[3] == 'u') { - env_user = *argv++; + set_user = *argv++; opt |= OPT_U; } @@ -344,22 +405,19 @@ int chpst_main(int argc UNUSED_PARAM, char **argv) if (opt & OPT_e) edir(env_dir); - // FIXME: chrooted jail must have /etc/passwd if we move this after chroot! - // OTOH chroot fails for non-roots! - // SOLUTION: cache uid/gid before chroot, apply uid/gid after + if (opt & (OPT_u|OPT_U)) + xget_uidgid(&ugid, set_user); + + // chrooted jail must have /etc/passwd if we move this after chroot. + // OTOH chroot fails for non-roots. + // Solution: cache uid/gid before chroot, apply uid/gid after. if (opt & OPT_U) { - xget_uidgid(&ugid, env_user); xsetenv("GID", utoa(ugid.gid)); xsetenv("UID", utoa(ugid.uid)); } - if (opt & OPT_u) { - xget_uidgid(&ugid, set_user); - } - if (opt & OPT_root) { - xchdir(root); - xchroot("."); + xchroot(root); } if (opt & OPT_u) { diff --git a/runit/runit_lib.c b/runit/runit_lib.c deleted file mode 100644 index ec18b5e..0000000 --- a/runit/runit_lib.c +++ /dev/null @@ -1,273 +0,0 @@ -/* -Copyright (c) 2001-2006, Gerrit Pape -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. 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. -*/ - -/* Busyboxed by Denys Vlasenko */ -/* Collected into one file from runit's many tiny files */ -/* TODO: review, eliminate unneeded stuff, move good stuff to libbb */ - -#include -#include -#include "libbb.h" -#include "runit_lib.h" - -#ifdef UNUSED -unsigned byte_chr(char *s,unsigned n,int c) -{ - char ch; - char *t; - - ch = c; - t = s; - for (;;) { - if (!n) break; - if (*t == ch) break; - ++t; - --n; - } - return t - s; -} - -static /* as it isn't used anywhere else */ -void tai_pack(char *s, const struct tai *t) -{ - uint64_t x; - - x = t->x; - s[7] = x & 255; x >>= 8; - s[6] = x & 255; x >>= 8; - s[5] = x & 255; x >>= 8; - s[4] = x & 255; x >>= 8; - s[3] = x & 255; x >>= 8; - s[2] = x & 255; x >>= 8; - s[1] = x & 255; x >>= 8; - s[0] = x; -} - -void tai_unpack(const char *s,struct tai *t) -{ - uint64_t x; - - x = (unsigned char) s[0]; - x <<= 8; x += (unsigned char) s[1]; - x <<= 8; x += (unsigned char) s[2]; - x <<= 8; x += (unsigned char) s[3]; - x <<= 8; x += (unsigned char) s[4]; - x <<= 8; x += (unsigned char) s[5]; - x <<= 8; x += (unsigned char) s[6]; - x <<= 8; x += (unsigned char) s[7]; - t->x = x; -} - - -void taia_add(struct taia *t,const struct taia *u,const struct taia *v) -{ - t->sec.x = u->sec.x + v->sec.x; - t->nano = u->nano + v->nano; - t->atto = u->atto + v->atto; - if (t->atto > 999999999UL) { - t->atto -= 1000000000UL; - ++t->nano; - } - if (t->nano > 999999999UL) { - t->nano -= 1000000000UL; - ++t->sec.x; - } -} - -int taia_less(const struct taia *t, const struct taia *u) -{ - if (t->sec.x < u->sec.x) return 1; - if (t->sec.x > u->sec.x) return 0; - if (t->nano < u->nano) return 1; - if (t->nano > u->nano) return 0; - return t->atto < u->atto; -} - -void taia_now(struct taia *t) -{ - struct timeval now; - gettimeofday(&now, NULL); - tai_unix(&t->sec, now.tv_sec); - t->nano = 1000 * now.tv_usec + 500; - t->atto = 0; -} - -/* UNUSED -void taia_pack(char *s, const struct taia *t) -{ - unsigned long x; - - tai_pack(s, &t->sec); - s += 8; - - x = t->atto; - s[7] = x & 255; x >>= 8; - s[6] = x & 255; x >>= 8; - s[5] = x & 255; x >>= 8; - s[4] = x; - x = t->nano; - s[3] = x & 255; x >>= 8; - s[2] = x & 255; x >>= 8; - s[1] = x & 255; x >>= 8; - s[0] = x; -} -*/ - -void taia_sub(struct taia *t, const struct taia *u, const struct taia *v) -{ - unsigned long unano = u->nano; - unsigned long uatto = u->atto; - - t->sec.x = u->sec.x - v->sec.x; - t->nano = unano - v->nano; - t->atto = uatto - v->atto; - if (t->atto > uatto) { - t->atto += 1000000000UL; - --t->nano; - } - if (t->nano > unano) { - t->nano += 1000000000UL; - --t->sec.x; - } -} - -/* XXX: breaks tai encapsulation */ -void taia_uint(struct taia *t, unsigned s) -{ - t->sec.x = s; - t->nano = 0; - t->atto = 0; -} - -static -uint64_t taia2millisec(const struct taia *t) -{ - return (t->sec.x * 1000) + (t->nano / 1000000); -} - -void iopause(iopause_fd *x, unsigned len, struct taia *deadline, struct taia *stamp) -{ - int millisecs; - int i; - - if (taia_less(deadline, stamp)) - millisecs = 0; - else { - uint64_t m; - struct taia t; - t = *stamp; - taia_sub(&t, deadline, &t); - millisecs = m = taia2millisec(&t); - if (m > 1000) millisecs = 1000; - millisecs += 20; - } - - for (i = 0; i < len; ++i) - x[i].revents = 0; - - poll(x, len, millisecs); - /* XXX: some kernels apparently need x[0] even if len is 0 */ - /* XXX: how to handle EAGAIN? are kernels really this dumb? */ - /* XXX: how to handle EINVAL? when exactly can this happen? */ -} -#endif - -int lock_ex(int fd) -{ - return flock(fd,LOCK_EX); -} - -int lock_exnb(int fd) -{ - return flock(fd,LOCK_EX | LOCK_NB); -} - -int open_append(const char *fn) -{ - return open(fn, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); -} - -int open_read(const char *fn) -{ - return open(fn, O_RDONLY|O_NDELAY); -} - -int open_trunc(const char *fn) -{ - return open(fn,O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT,0644); -} - -int open_write(const char *fn) -{ - return open(fn, O_WRONLY|O_NDELAY); -} - -unsigned pmatch(const char *p, const char *s, unsigned len) -{ - for (;;) { - char c = *p++; - if (!c) return !len; - switch (c) { - case '*': - c = *p; - if (!c) return 1; - for (;;) { - if (!len) return 0; - if (*s == c) break; - ++s; - --len; - } - continue; - case '+': - c = *p++; - if (c != *s) return 0; - for (;;) { - if (!len) return 1; - if (*s != c) break; - ++s; - --len; - } - continue; - /* - case '?': - if (*p == '?') { - if (*s != '?') return 0; - ++p; - } - ++s; --len; - continue; - */ - default: - if (!len) return 0; - if (*s != c) return 0; - ++s; - --len; - continue; - } - } - return 0; -} diff --git a/runit/runit_lib.h b/runit/runit_lib.h index 88d1c9f..c36ea4c 100644 --- a/runit/runit_lib.h +++ b/runit/runit_lib.h @@ -27,59 +27,6 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN -//extern unsigned byte_chr(char *s,unsigned n,int c); -// -//struct tai { -// uint64_t x; -//}; -// -//#define tai_unix(t,u) ((void) ((t)->x = 0x400000000000000aULL + (uint64_t) (u))) -// -//#define TAI_PACK 8 -//extern void tai_unpack(const char *,struct tai *); -// -//extern void tai_uint(struct tai *,unsigned); -// -//struct taia { -// struct tai sec; -// unsigned long nano; /* 0...999999999 */ -// unsigned long atto; /* 0...999999999 */ -//}; -// -//extern void taia_now(struct taia *); -// -//extern void taia_add(struct taia *,const struct taia *,const struct taia *); -//extern void taia_addsec(struct taia *,const struct taia *,int); -//extern void taia_sub(struct taia *,const struct taia *,const struct taia *); -//extern void taia_half(struct taia *,const struct taia *); -//extern int taia_less(const struct taia *,const struct taia *); -// -//#define TAIA_PACK 16 -//extern void taia_pack(char *,const struct taia *); -// -//extern void taia_uint(struct taia *,unsigned); -// -//typedef struct pollfd iopause_fd; -//#define IOPAUSE_READ POLLIN -//#define IOPAUSE_WRITE POLLOUT -// -//extern void iopause(iopause_fd *,unsigned,struct taia *,struct taia *); - -extern int lock_ex(int); -extern int lock_un(int); -extern int lock_exnb(int); - -extern int open_read(const char *); -extern int open_excl(const char *); -extern int open_append(const char *); -extern int open_trunc(const char *); -extern int open_write(const char *); - -extern unsigned pmatch(const char *, const char *, unsigned); - -#define str_diff(s,t) strcmp((s), (t)) -#define str_equal(s,t) (!strcmp((s), (t))) - /* * runsv / supervise / sv stuff */ diff --git a/runit/runsv.c b/runit/runsv.c index 5b221e9..d941e89 100644 --- a/runit/runsv.c +++ b/runit/runsv.c @@ -28,7 +28,11 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ -#include +//usage:#define runsv_trivial_usage +//usage: "DIR" +//usage:#define runsv_full_usage "\n\n" +//usage: "Start and monitor a service and optionally an appendant log service" + #include #include "libbb.h" #include "runit_lib.h" @@ -139,19 +143,10 @@ static void s_term(int sig_no UNUSED_PARAM) write(selfpipe.wr, "", 1); /* XXX */ } -/* libbb candidate */ -static char *bb_stpcpy(char *p, const char *to_add) -{ - while ((*p = *to_add) != '\0') { - p++; - to_add++; - } - return p; -} - static int open_trunc_or_warn(const char *name) { - int fd = open_trunc(name); + /* Why O_NDELAY? */ + int fd = open(name, O_WRONLY | O_NDELAY | O_TRUNC | O_CREAT, 0644); if (fd < 0) bb_perror_msg("%s: warning: cannot open %s", dir, name); @@ -176,7 +171,7 @@ static void update_status(struct svdir *s) } close(fd); if (rename_or_warn("supervise/pid.new", - s->islog ? "log/supervise/pid" : "log/supervise/pid"+4)) + s->islog ? "log/supervise/pid" : "log/supervise/pid"+4)) return; pidchanged = 0; } @@ -191,26 +186,26 @@ static void update_status(struct svdir *s) char *p = stat_buf; switch (s->state) { case S_DOWN: - p = bb_stpcpy(p, "down"); + p = stpcpy(p, "down"); break; case S_RUN: - p = bb_stpcpy(p, "run"); + p = stpcpy(p, "run"); break; case S_FINISH: - p = bb_stpcpy(p, "finish"); + p = stpcpy(p, "finish"); break; } if (s->ctrl & C_PAUSE) - p = bb_stpcpy(p, ", paused"); + p = stpcpy(p, ", paused"); if (s->ctrl & C_TERM) - p = bb_stpcpy(p, ", got TERM"); + p = stpcpy(p, ", got TERM"); if (s->state != S_DOWN) switch (s->sd_want) { case W_DOWN: - p = bb_stpcpy(p, ", want down"); + p = stpcpy(p, ", want down"); break; case W_EXIT: - p = bb_stpcpy(p, ", want exit"); + p = stpcpy(p, ", want exit"); break; } *p++ = '\n'; @@ -523,7 +518,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv) } svd[0].fdlock = xopen3("log/supervise/lock"+4, O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); - if (lock_exnb(svd[0].fdlock) == -1) + if (flock(svd[0].fdlock, LOCK_EX | LOCK_NB) == -1) fatal_cannot("lock supervise/lock"); close_on_exec_on(svd[0].fdlock); if (haslog) { @@ -547,7 +542,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv) } svd[1].fdlock = xopen3("log/supervise/lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); - if (lock_ex(svd[1].fdlock) == -1) + if (flock(svd[1].fdlock, LOCK_EX) == -1) fatal_cannot("lock log/supervise/lock"); close_on_exec_on(svd[1].fdlock); } @@ -617,7 +612,7 @@ int runsv_main(int argc UNUSED_PARAM, char **argv) pidchanged = 1; svd[0].ctrl &= ~C_TERM; if (svd[0].state != S_FINISH) { - fd = open_read("finish"); + fd = open("finish", O_RDONLY|O_NDELAY); if (fd != -1) { close(fd); svd[0].state = S_FINISH; diff --git a/runit/runsvdir.c b/runit/runsvdir.c index 71fde75..af7e75b 100644 --- a/runit/runsvdir.c +++ b/runit/runsvdir.c @@ -28,7 +28,13 @@ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ -#include +//usage:#define runsvdir_trivial_usage +//usage: "[-P] [-s SCRIPT] DIR" +//usage:#define runsvdir_full_usage "\n\n" +//usage: "Start a runsv process for each subdirectory. If it exits, restart it.\n" +//usage: "\n -P Put each runsv in a new session" +//usage: "\n -s SCRIPT Run SCRIPT after signal is processed" + #include #include "libbb.h" #include "runit_lib.h" @@ -68,8 +74,7 @@ struct globals { #define logpipe (G.logpipe ) #define pfd (G.pfd ) #define stamplog (G.stamplog ) -#define INIT_G() do { \ -} while (0) +#define INIT_G() do { } while (0) static void fatal2_cannot(const char *m1, const char *m2) { @@ -276,7 +281,7 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) } run: #endif - curdir = open_read("."); + curdir = open(".", O_RDONLY|O_NDELAY); if (curdir == -1) fatal2_cannot("open current directory", ""); close_on_exec_on(curdir); @@ -312,8 +317,11 @@ int runsvdir_main(int argc UNUSED_PARAM, char **argv) last_mtime = s.st_mtime; last_dev = s.st_dev; last_ino = s.st_ino; - //if (now <= mtime) - // sleep(1); + /* if the svdir changed this very second, wait until the + * next second, because we won't be able to detect more + * changes within this second */ + while (time(NULL) == last_mtime) + usleep(100000); need_rescan = do_rescan(); while (fchdir(curdir) == -1) { warn2_cannot("change directory, pausing", ""); diff --git a/runit/sv.c b/runit/sv.c index 3f76a2d..825e9d4 100644 --- a/runit/sv.c +++ b/runit/sv.c @@ -153,7 +153,22 @@ Exit Codes /* Busyboxed by Denys Vlasenko */ /* TODO: depends on runit_lib.c - review and reduce/eliminate */ -#include +//usage:#define sv_trivial_usage +//usage: "[-v] [-w SEC] CMD SERVICE_DIR..." +//usage:#define sv_full_usage "\n\n" +//usage: "Control services monitored by runsv supervisor.\n" +//usage: "Commands (only first character is enough):\n" +//usage: "\n" +//usage: "status: query service status\n" +//usage: "up: if service isn't running, start it. If service stops, restart it\n" +//usage: "once: like 'up', but if service stops, don't restart it\n" +//usage: "down: send TERM and CONT signals. If ./run exits, start ./finish\n" +//usage: " if it exists. After it stops, don't restart service\n" +//usage: "exit: send TERM and CONT signals to service and log service. If they exit,\n" +//usage: " runsv exits too\n" +//usage: "pause, cont, hup, alarm, interrupt, quit, 1, 2, term, kill: send\n" +//usage: "STOP, CONT, HUP, ALRM, INT, QUIT, USR1, USR2, TERM, KILL signal to service" + #include #include "libbb.h" #include "runit_lib.h" @@ -176,6 +191,9 @@ struct globals { #define INIT_G() do { } while (0) +#define str_equal(s,t) (!strcmp((s), (t))) + + static void fatal_cannot(const char *m1) NORETURN; static void fatal_cannot(const char *m1) { @@ -221,7 +239,7 @@ static int svstatus_get(void) { int fd, r; - fd = open_write("supervise/ok"); + fd = open("supervise/ok", O_WRONLY|O_NDELAY); if (fd == -1) { if (errno == ENODEV) { *acts == 'x' ? ok("runsv not running") @@ -232,7 +250,7 @@ static int svstatus_get(void) return -1; } close(fd); - fd = open_read("supervise/status"); + fd = open("supervise/status", O_RDONLY|O_NDELAY); if (fd == -1) { warn("can't open supervise/status"); return -1; @@ -397,7 +415,7 @@ static int control(const char *a) if (svstatus.want == *a) return 0; */ - fd = open_write("supervise/control"); + fd = open("supervise/control", O_WRONLY|O_NDELAY); if (fd == -1) { if (errno != ENODEV) warn("can't open supervise/control"); @@ -418,7 +436,6 @@ static int control(const char *a) int sv_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int sv_main(int argc UNUSED_PARAM, char **argv) { - unsigned opt; char *x; char *action; const char *varservice = CONFIG_SV_DEFAULT_SERVICE_DIR; @@ -439,14 +456,14 @@ int sv_main(int argc UNUSED_PARAM, char **argv) if (x) waitsec = xatou(x); opt_complementary = "w+:vv"; /* -w N, -v is a counter */ - opt = getopt32(argv, "w:v", &waitsec, &verbose); + getopt32(argv, "w:v", &waitsec, &verbose); argv += optind; action = *argv++; if (!action || !*argv) bb_show_usage(); tnow = time(NULL) + 0x400000000000000aULL; tstart = tnow; - curdir = open_read("."); + curdir = open(".", O_RDONLY|O_NDELAY); if (curdir == -1) fatal_cannot("open current directory"); diff --git a/runit/svlogd.c b/runit/svlogd.c index 9fe81b9..c080b9a 100644 --- a/runit/svlogd.c +++ b/runit/svlogd.c @@ -125,7 +125,23 @@ log message, you can use a pattern like this instead -*: *: pid * */ -#include +//usage:#define svlogd_trivial_usage +//usage: "[-ttv] [-r C] [-R CHARS] [-l MATCHLEN] [-b BUFLEN] DIR..." +//usage:#define svlogd_full_usage "\n\n" +//usage: "Continuously read log data from stdin and write to rotated log files in DIRs" +//usage: "\n" +//usage: "\n""DIR/config file modifies behavior:" +//usage: "\n""sSIZE - when to rotate logs" +//usage: "\n""nNUM - number of files to retain" +/*usage: "\n""NNUM - min number files to retain" - confusing */ +/*usage: "\n""tSEC - rotate file if it get SEC seconds old" - confusing */ +//usage: "\n""!PROG - process rotated log with PROG" +/*usage: "\n""uIPADDR - send log over UDP" - unsupported */ +/*usage: "\n""UIPADDR - send log over UDP and DONT log" - unsupported */ +/*usage: "\n""pPFX - prefix each line with PFX" - unsupported */ +//usage: "\n""+,-PATTERN - (de)select line for logging" +//usage: "\n""E,ePATTERN - (de)select line for stderr" + #include #include "libbb.h" #include "runit_lib.h" @@ -170,6 +186,7 @@ struct globals { unsigned nearest_rotate; void* (*memRchr)(const void *, int, size_t); + char *shell; smallint exitasap; smallint rotateasap; @@ -261,6 +278,52 @@ static char* wstrdup(const char *str) return s; } +static unsigned pmatch(const char *p, const char *s, unsigned len) +{ + for (;;) { + char c = *p++; + if (!c) return !len; + switch (c) { + case '*': + c = *p; + if (!c) return 1; + for (;;) { + if (!len) return 0; + if (*s == c) break; + ++s; + --len; + } + continue; + case '+': + c = *p++; + if (c != *s) return 0; + for (;;) { + if (!len) return 1; + if (*s != c) break; + ++s; + --len; + } + continue; + /* + case '?': + if (*p == '?') { + if (*s != '?') return 0; + ++p; + } + ++s; --len; + continue; + */ + default: + if (!len) return 0; + if (*s != c) return 0; + ++s; + --len; + continue; + } + } + return 0; +} + /*** ex fmt_ptime.[ch] ***/ /* NUL terminated */ @@ -319,6 +382,9 @@ static void processorstart(struct logdir *ld) /* vfork'ed child trashes this byte, save... */ sv_ch = ld->fnsave[26]; + if (!G.shell) + G.shell = xstrdup(get_shell_name()); + while ((pid = vfork()) == -1) pause2cannot("vfork for processor", ld->name); if (!pid) { @@ -342,7 +408,7 @@ static void processorstart(struct logdir *ld) ld->fnsave[26] = 't'; /* <- that's why we need sv_ch! */ fd = xopen(ld->fnsave, O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); xmove_fd(fd, 1); - fd = open_read("state"); + fd = open("state", O_RDONLY|O_NDELAY); if (fd == -1) { if (errno != ENOENT) bb_perror_msg_and_die(FATAL"can't %s processor %s", "open state for", ld->name); @@ -353,8 +419,7 @@ static void processorstart(struct logdir *ld) fd = xopen("newstate", O_WRONLY|O_NDELAY|O_TRUNC|O_CREAT); xmove_fd(fd, 5); -// getenv("SHELL")? - execl(DEFAULT_SHELL, DEFAULT_SHELL_SHORT_NAME, "-c", ld->processor, (char*) NULL); + execl(G.shell, G.shell, "-c", ld->processor, (char*) NULL); bb_perror_msg_and_die(FATAL"can't %s processor %s", "run", ld->name); } ld->fnsave[26] = sv_ch; /* ...restore */ @@ -535,12 +600,12 @@ static int buffer_pwrite(int n, char *s, unsigned len) while (fchdir(ld->fddir) == -1) pause2cannot("change directory, want remove old logfile", - ld->name); + ld->name); oldest[0] = 'A'; oldest[1] = oldest[27] = '\0'; while (!(d = opendir("."))) pause2cannot("open directory, want remove old logfile", - ld->name); + ld->name); errno = 0; while ((f = readdir(d))) if ((f->d_name[0] == '@') && (strlen(f->d_name) == 27)) { @@ -626,7 +691,7 @@ static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn) } ld->fdlock = open("lock", O_WRONLY|O_NDELAY|O_APPEND|O_CREAT, 0600); if ((ld->fdlock == -1) - || (lock_exnb(ld->fdlock) == -1) + || (flock(ld->fdlock, LOCK_EX | LOCK_NB) == -1) ) { logdir_close(ld); warn2("can't lock directory", (char*)fn); @@ -679,19 +744,14 @@ static NOINLINE unsigned logdir_open(struct logdir *ld, const char *fn) ld->inst = new; break; case 's': { - static const struct suffix_mult km_suffixes[] = { - { "k", 1024 }, - { "m", 1024*1024 }, - { "", 0 } - }; ld->sizemax = xatou_sfx(&s[1], km_suffixes); break; } case 'n': - ld->nmax = xatoi_u(&s[1]); + ld->nmax = xatoi_positive(&s[1]); break; case 'N': - ld->nmin = xatoi_u(&s[1]); + ld->nmin = xatoi_positive(&s[1]); break; case 't': { static const struct suffix_mult mh_suffixes[] = { @@ -981,7 +1041,7 @@ int svlogd_main(int argc, char **argv) linemax = 256; } ////if (opt & 8) { // -b - //// buflen = xatoi_u(b); + //// buflen = xatoi_positive(b); //// if (buflen == 0) buflen = 1024; ////} //if (opt & 0x10) timestamp++; // -t @@ -1068,7 +1128,8 @@ int svlogd_main(int argc, char **argv) /* Search for '\n' (in fact, np already holds the result) */ linelen = stdin_cnt; if (np) { - print_to_nl: /* NB: starting from here lineptr may point + print_to_nl: + /* NB: starting from here lineptr may point * farther out into line[] */ linelen = np - lineptr + 1; } diff --git a/scripts/Makefile.IMA b/scripts/Makefile.IMA index 11ae39e..0eced29 100644 --- a/scripts/Makefile.IMA +++ b/scripts/Makefile.IMA @@ -9,7 +9,10 @@ objtree := $(CURDIR) src := $(srctree) obj := $(objtree) -# Look for make include files relative to root of kernel src +# Make generated files +DUMMY := $(shell $(Q)$(srctree)/scripts/gen_build_files.sh $(srctree) $(objtree) >&2) + +# Look for make include files relative to root of src MAKEFLAGS += --include-dir=$(srctree) default: busybox @@ -85,8 +88,8 @@ lib-y:= include archival/Kbuild lib-all-y += $(patsubst %,archival/%,$(sort $(lib-y))) lib-y:= -include archival/libunarchive/Kbuild -lib-all-y += $(patsubst %,archival/libunarchive/%,$(sort $(lib-y))) +include archival/libarchive/Kbuild +lib-all-y += $(patsubst %,archival/libarchive/%,$(sort $(lib-y))) lib-y:= include applets/Kbuild lib-all-y += $(patsubst %,applets/%,$(sort $(lib-y))) @@ -121,6 +124,9 @@ lib-y:= include miscutils/Kbuild lib-all-y += $(patsubst %,miscutils/%,$(sort $(lib-y))) lib-y:= +include mailutils/Kbuild +lib-all-y += $(patsubst %,mailutils/%,$(sort $(lib-y))) +lib-y:= include coreutils/libcoreutils/Kbuild lib-all-y += $(patsubst %,coreutils/libcoreutils/%,$(sort $(lib-y))) lib-y:= @@ -168,7 +174,7 @@ lib-all-y += $(patsubst %,libbb/%,$(sort $(lib-y))) lib-y:= comma:=, -busybox_unstripped.o: $(usage_stuff) include/applet_tables.h include/autoconf.h +busybox_unstripped.o: $(usage_stuff) include/applet_tables.h include/NUM_APPLETS.h include/autoconf.h $(CC) $(CPPFLAGS) $(CFLAGS) $(EXTRA_CFLAGS) \ $(patsubst %,-Wl$(comma)%,$(LDFLAGS) $(EXTRA_LDFLAGS)) \ -DGCC_COMBINE=1 \ @@ -194,14 +200,9 @@ busybox: busybox_unstripped.o include/autoconf.h: .config $(MAKE) -f $(srctree)/Makefile silentoldconfig +# Override rules for host compile applets/usage: include/autoconf.h - $(HOSTCC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I$(srctree)/include -o applets/usage applets/usage.c + $(HOSTCC) -Wall -O2 -I$(srctree)/include -o applets/usage applets/usage.c applets/applet_tables: include/autoconf.h - $(HOSTCC) -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -I$(srctree)/include -o applets/applet_tables applets/applet_tables.c - -include/usage_compressed.h: include/usage.h applets/usage - $(srctree)/applets/usage_compressed include/usage_compressed.h applets - -include/applet_tables.h: include/applets.h - applets/applet_tables include/applet_tables.h + $(HOSTCC) -Wall -O2 -I$(srctree)/include -o applets/applet_tables applets/applet_tables.c diff --git a/scripts/Makefile.host b/scripts/Makefile.host index 23bd9ff..2e62850 100644 --- a/scripts/Makefile.host +++ b/scripts/Makefile.host @@ -153,4 +153,3 @@ $(host-cshlib): %: $(host-cshobjs) FORCE targets += $(host-csingle) $(host-cmulti) $(host-cobjs)\ $(host-cxxmulti) $(host-cxxobjs) $(host-cshlib) $(host-cshobjs) - diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index be679b6..3e54ea7 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -168,5 +168,3 @@ cmd_objcopy = $(OBJCOPY) $(OBJCOPYFLAGS) $(OBJCOPYFLAGS_$(@F)) $< $@ quiet_cmd_gzip = GZIP $@ cmd_gzip = gzip -f -9 < $< > $@ - - diff --git a/scripts/basic/docproc.c b/scripts/basic/docproc.c index 50ef371..b125698 100644 --- a/scripts/basic/docproc.c +++ b/scripts/basic/docproc.c @@ -39,6 +39,7 @@ #include #include #include +#include /* exitstatus is used to keep track of any failing calls to kernel-doc, * but execution continues. */ @@ -212,7 +213,7 @@ void find_export_symbols(char * filename) * Document all external or internal functions in a file. * Call kernel-doc with following parameters: * kernel-doc -docbook -nofunction function_name1 filename - * function names are obtained from all the the src files + * function names are obtained from all the src files * by find_export_symbols. * intfunc uses -nofunction * extfunc uses -function @@ -397,4 +398,3 @@ int main(int argc, char **argv) fflush(stdout); return exitstatus; } - diff --git a/scripts/basic/fixdep.c b/scripts/basic/fixdep.c index 1a5b10f..165a8c3 100644 --- a/scripts/basic/fixdep.c +++ b/scripts/basic/fixdep.c @@ -113,6 +113,7 @@ #include #include #include +#include /* bbox: not needed #define INT_CONF ntohl(0x434f4e46) @@ -329,7 +330,7 @@ void parse_dep_file(void *map, size_t len) clear_config(); while (m < end) { - while (m < end && (*m == ' ' || *m == '\\' || *m == '\n')) + while (m < end && (*m == ' ' || *m == '\\' || *m == '\n' || *m == '\r')) m++; p = m; while (p < end && *p != ' ') p++; diff --git a/scripts/bloat-o-meter b/scripts/bloat-o-meter index 95cbbe6..cb861b8 100755 --- a/scripts/bloat-o-meter +++ b/scripts/bloat-o-meter @@ -1,17 +1,20 @@ -#!/usr/bin/python +#!/usr/bin/env python # # Copyright 2004 Matt Mackall # -# inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen +# Inspired by perl Bloat-O-Meter (c) 1997 by Andi Kleen # # This software may be used and distributed according to the terms # of the GNU General Public License, incorporated herein by reference. -import sys, os#, re +import sys, os def usage(): - sys.stderr.write("usage: %s [-t] file1 file2\n" % sys.argv[0]) - sys.exit(-1) + sys.stderr.write("usage: %s [-t] file1 file2 [-- ]\n" + % sys.argv[0]) + sys.stderr.write("\t-t\tShow time spent on parsing/processing\n") + sys.stderr.write("\t--\tPass additional parameters to readelf\n") + sys.exit(1) f1, f2 = (None, None) flag_timing, dashes = (False, False) @@ -31,6 +34,8 @@ for f in sys.argv[1:]: f1 = f elif f2 is None: f2 = f + else: + usage() if flag_timing: import time if f1 is None or f2 is None: @@ -39,31 +44,22 @@ if f1 is None or f2 is None: sym_args = " ".join(sys.argv[3 + flag_timing + dashes:]) def getsizes(file): sym, alias, lut = {}, {}, {} - #dynsym_filter = re.compile("^\d+:\s+[\dA-Fa-f]+\s+\d+\s+\w+\s+\w+\s+\w+\s+\w+\s+\w+$") for l in os.popen("readelf -W -s %s %s" % (sym_args, file)).readlines(): - if True: - l = l.strip() - if not (len(l) and l[0].isdigit() and len(l.split()) == 8): - continue - num, value, size, typ, bind, vis, ndx, name = l.split() - if ndx == "UND": continue # skip undefined - if typ in ["SECTION", "FILES"]: continue # skip sections and files - #else: - # l = l.strip() - # match = dynsym_filter.match(l) - # if not match: continue - # x, value, size, typ, bind, x, ndx, name = l.split() - # if ndx == "UND": continue # skip undefined - # if typ in ["SECTION", "FILES"]: continue # skip sections and files + l = l.strip() + if not (len(l) and l[0].isdigit() and len(l.split()) == 8): + continue + num, value, size, typ, bind, vis, ndx, name = l.split() + if ndx == "UND": continue # skip undefined + if typ in ["SECTION", "FILES"]: continue # skip sections and files if "." in name: name = "static." + name.split(".")[0] value = int(value, 16) - size = int(size) + size = int(size, 16) if size.startswith('0x') else int(size) if vis != "DEFAULT" and bind != "GLOBAL": # see if it is an alias alias[(value, size)] = {"name" : name} else: sym[name] = {"addr" : value, "size": size} lut[(value, size)] = 0 - for addr, sz in alias.iterkeys(): + for addr, sz in iter(alias.keys()): # If the non-GLOBAL sym has an implementation elsewhere then # it's an alias, disregard it. if not (addr, sz) in lut: @@ -92,7 +88,7 @@ if flag_timing: grow, shrink, add, remove, up, down = 0, 0, 0, 0, 0, 0 delta, common = [], {} -for name in old.iterkeys(): +for name in iter(old.keys()): if name in new: common[name] = 1 diff --git a/scripts/cleanup_printf2puts b/scripts/cleanup_printf2puts index 446152e..00193a8 100755 --- a/scripts/cleanup_printf2puts +++ b/scripts/cleanup_printf2puts @@ -3,7 +3,7 @@ # Processes current directory recursively: # printf("abc\n") -> puts("abc"). Beware of fprintf etc... -# BTW, gcc 4.1.2 already does tha same! Can't believe it... +# BTW, gcc 4.1.2 already does the same! Can't believe it... grep -lr 'printf\([^%%]*\\n"\)' . | grep '.[ch]$' | xargs -n1 \ sed -e 's/\([^A-Za-z0-9_]\)printf(\( *"[^%]*\)\\n")/\1puts(\2")/' -i diff --git a/scripts/echo.c b/scripts/echo.c index 3c45e33..cb207ae 100644 --- a/scripts/echo.c +++ b/scripts/echo.c @@ -6,7 +6,7 @@ * Copyright (c) 1991, 1993 * The Regents of the University of California. All rights reserved. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * Original copyright notice is retained at the end of this file. */ diff --git a/scripts/find_stray_empty_lines b/scripts/find_stray_empty_lines new file mode 100755 index 0000000..aae18f9 --- /dev/null +++ b/scripts/find_stray_empty_lines @@ -0,0 +1,19 @@ +#!/bin/sh + +grep -n -B1 -r $'^\t*}$' . | grep -A1 '.[ch]-[0-9]*-$' +grep -n -A1 -r $'^\t*{$' . | grep -B1 '.[ch]-[0-9]*-$' +# or (less surefire ones): +grep -n -B1 -r $'^\t*}' . | grep -A1 '.[ch]-[0-9]*-$' +grep -n -A1 -r $'^\t*{' . | grep -B1 '.[ch]-[0-9]*-$' + +# find trailing empty lines +find -type f | while read file; do + test x"$file" = x"" && continue + tail -n1 $file | while read lastline + do + #echo "|$file|$lastline" + if test x"$lastline" = x""; then + echo "$file" + fi + done +done diff --git a/scripts/gen_build_files.sh b/scripts/gen_build_files.sh index 18c172d..0989b2f 100755 --- a/scripts/gen_build_files.sh +++ b/scripts/gen_build_files.sh @@ -1,5 +1,9 @@ #!/bin/sh +# Note: was using sed OPTS CMD -- FILES +# but users complain that many sed implementations +# are misinterpreting --. + test $# -ge 2 || { echo "Syntax: $0 SRCTREE OBJTREE"; exit 1; } # cd to objtree @@ -9,86 +13,78 @@ mkdir include 2>/dev/null srctree="$1" +status() { printf ' %-8s%s\n' "$1" "$2"; } +gen() { status "GEN" "$@"; } +chk() { status "CHK" "$@"; } + +generate() +{ + # NB: data to be inserted at INSERT line is coming on stdin + local src="$1" dst="$2" header="$3" + #chk "${dst}" + { + # Need to use printf: different shells have inconsistent + # rules re handling of "\n" in echo params. + printf "%s\n" "${header}" + # print everything up to INSERT line + sed -n '/^INSERT$/ q; p' "${src}" + # copy stdin to stdout + cat + # print everything after INSERT line + sed -n '/^INSERT$/ { :l; n; p; bl }' "${src}" + } >"${dst}.tmp" + if ! cmp -s "${dst}" "${dst}.tmp"; then + gen "${dst}" + mv "${dst}.tmp" "${dst}" + else + rm -f "${dst}.tmp" + fi +} + # (Re)generate include/applets.h -src="$srctree/include/applets.src.h" -dst="include/applets.h" -s=`sed -n 's@^//applet:@@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -old=`cat "$dst" 2>/dev/null` -# Why "IFS='' read -r REPLY"?? -# This atrocity is needed to read lines without mangling. -# IFS='' prevents whitespace trimming, -# -r suppresses backslash handling. -new=`echo "/* DO NOT EDIT. This file is generated from applets.src.h */" -while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" -done <"$src"` -if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" -fi +sed -n 's@^//applet:@@p' "$srctree"/*/*.c "$srctree"/*/*/*.c \ +| generate \ + "$srctree/include/applets.src.h" \ + "include/applets.h" \ + "/* DO NOT EDIT. This file is generated from applets.src.h */" # (Re)generate include/usage.h -src="$srctree/include/usage.src.h" -dst="include/usage.h" # We add line continuation backslash after each line, # and insert empty line before each line which doesn't start # with space or tab -# (note: we need to use \\\\ because of ``) -s=`sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\\\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\\\@p' -- "$srctree"/*/*.c "$srctree"/*/*/*.c` -old=`cat "$dst" 2>/dev/null` -new=`echo "/* DO NOT EDIT. This file is generated from usage.src.h */" -while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" -done <"$src"` -if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" -fi +sed -n -e 's@^//usage:\([ \t].*\)$@\1 \\@p' -e 's@^//usage:\([^ \t].*\)$@\n\1 \\@p' \ + "$srctree"/*/*.c "$srctree"/*/*/*.c \ +| generate \ + "$srctree/include/usage.src.h" \ + "include/usage.h" \ + "/* DO NOT EDIT. This file is generated from usage.src.h */" # (Re)generate */Kbuild and */Config.in -{ cd -- "$srctree" && find -type d; } | while read -r d; do +# We skip .dotdirs - makes git/svn/etc users happier +{ cd -- "$srctree" && find . -type d -not '(' -name '.?*' -prune ')'; } \ +| while read -r d; do d="${d#./}" src="$srctree/$d/Kbuild.src" dst="$d/Kbuild" if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - #echo " CHK $dst" - - s=`sed -n 's@^//kbuild:@@p' -- "$srctree/$d"/*.c` - old=`cat "$dst" 2>/dev/null` - new=`echo "# DO NOT EDIT. This file is generated from Kbuild.src" - while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" - done <"$src"` - if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" - fi + sed -n 's@^//kbuild:@@p' "$srctree/$d"/*.c \ + | generate \ + "${src}" "${dst}" \ + "# DO NOT EDIT. This file is generated from Kbuild.src" fi src="$srctree/$d/Config.src" dst="$d/Config.in" if test -f "$src"; then mkdir -p -- "$d" 2>/dev/null - #echo " CHK $dst" - - s=`sed -n 's@^//config:@@p' -- "$srctree/$d"/*.c` - old=`cat "$dst" 2>/dev/null` - new=`echo "# DO NOT EDIT. This file is generated from Config.src" - while IFS='' read -r REPLY; do - test x"$REPLY" = x"INSERT" && REPLY="$s" - printf "%s\n" "$REPLY" - done <"$src"` - if test x"$new" != x"$old"; then - echo " GEN $dst" - printf "%s\n" "$new" >"$dst" - fi + sed -n 's@^//config:@@p' "$srctree/$d"/*.c \ + | generate \ + "${src}" "${dst}" \ + "# DO NOT EDIT. This file is generated from Config.src" fi done diff --git a/scripts/individual b/scripts/individual deleted file mode 100755 index e93ca55..0000000 --- a/scripts/individual +++ /dev/null @@ -1,129 +0,0 @@ -#!/bin/sh - -# Compile individual versions of each busybox applet. - -if [ $# -eq 0 ] -then - -# Clear out the build directory. (Make clean should do this instead of here.) - -rm -rf build -mkdir build - -# Make our prerequisites. - -make busybox.links include/bb_config.h $(pwd)/{libbb/libbb.a,archival/libunarchive/libunarchive.a,coreutils/libcoreutils/libcoreutils.a,networking/libiproute/libiproute.a} - -else -# Could very well be that we want to build an individual applet but have no -# 'build' dir yet.. - -test -d ./build || mkdir build - -fi - -# About 3/5 of the applets build from one .c file (with the same name as the -# corresponding applet), and all it needs to link against. However, to build -# them all we need more than that. - -# Figure out which applets need extra libraries added to their command line. - -function substithing() -{ - if [ "${1/ $3 //}" != "$1" ] - then - echo $2 - fi -} - -function extra_libraries() -{ - # gzip needs gunzip.c (when gunzip is enabled, anyway). - substithing " gzip " "archival/gunzip.c archival/uncompress.c" "$1" - - # init needs init_shared.c - substithing " init " "init/init_shared.c" "$1" - - # ifconfig needs interface.c - substithing " ifconfig " "networking/interface.c" "$1" - - # Applets that need libunarchive.a - substithing " ar bunzip2 unlzma cpio dpkg gunzip rpm2cpio rpm tar uncompress unzip dpkg_deb gzip " "archival/libunarchive/libunarchive.a" "$1" - - # Applets that need libcoreutils.a - substithing " cp mv " "coreutils/libcoreutils/libcoreutils.a" "$1" - - # Applets that need libiproute.a - substithing " ip " "networking/libiproute/libiproute.a" "$1" - - # What needs -libm? - substithing " awk dc " "-lm" "$1" - - # What needs -lcrypt? - substithing " httpd vlock " "-lcrypt" "$1" -} - -# Query applets.h to figure out which applets need special treatment - -strange_names=`sed -rn -e 's/\#.*//' -e 's/.*APPLET_NOUSAGE\(([^,]*),([^,]*),.*/\1 \2/p' -e 's/.*APPLET_ODDNAME\(([^,]*),([^,]*),.*, *([^)]*).*/\1 \2@\3/p' include/applets.h` - -function bonkname() -{ - while [ $# -gt 0 ] - do - if [ "$APPLET" == "$1" ] - then - APPFILT="${2/@*/}" - if [ "${APPFILT}" == "$2" ] - then - HELPNAME='"nousage\n"' # These should be _fixed_. - else - HELPNAME="${2/*@/}"_full_usage - fi - break - fi - shift 2 - done -#echo APPLET=${APPLET} APPFILT=${APPFILT} HELPNAME=${HELPNAME} 2=${2} -} - -# Iterate through every name in busybox.links - -function buildit () -{ - export APPLET="$1" - export APPFILT=${APPLET} - export HELPNAME=${APPLET}_full_usage - - bonkname $strange_names - - j=`find archival console-tools coreutils debianutils editors findutils init loginutils miscutils modutils networking procps shell sysklogd util-linux -name "${APPFILT}.c"` - if [ -z "$j" ] - then - echo no file for $APPLET - else - echo "Building $APPLET" - gcc -Os -o build/$APPLET applets/individual.c $j \ - `extra_libraries $APPFILT` libbb/libbb.a -Iinclude \ - -DBUILD_INDIVIDUAL \ - '-Drun_applet_and_exit(...)' '-Dfind_applet_by_name(...)=0' \ - -DAPPLET_main=${APPFILT}_main -DAPPLET_full_usage=${HELPNAME} - if [ $? -ne 0 ]; - then - echo "Failed $APPLET" - fi - fi -} - -if [ $# -eq 0 ] -then - for APPLET in `sed 's .*/ ' busybox.links` - do - buildit "$APPLET" - done -else - buildit "$1" -fi - - -strip build/* diff --git a/scripts/kconfig/Makefile b/scripts/kconfig/Makefile index b5708e2..38bae80 100644 --- a/scripts/kconfig/Makefile +++ b/scripts/kconfig/Makefile @@ -87,7 +87,7 @@ endif $(MTIME_IS_COARSE) && sleep 1 %_defconfig: $(obj)/conf - $(Q)$< -D $@ Config.in + $(Q)$< -D configs/$@ Config.in $(MTIME_IS_COARSE) && sleep 1 # Help text used by make help @@ -150,7 +150,7 @@ HOSTCFLAGS_zconf.tab.o := -I$(src) HOSTLOADLIBES_qconf = $(KC_QT_LIBS) -ldl HOSTCXXFLAGS_qconf.o = $(KC_QT_CFLAGS) -D LKC_DIRECT_LINK -HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` +HOSTLOADLIBES_gconf = `pkg-config --libs gtk+-2.0 gmodule-2.0 libglade-2.0` -ldl HOSTCFLAGS_gconf.o = `pkg-config --cflags gtk+-2.0 gmodule-2.0 libglade-2.0` \ -D LKC_DIRECT_LINK diff --git a/scripts/kconfig/check.sh b/scripts/kconfig/check.sh index fa59cbf..15fc294 100755 --- a/scripts/kconfig/check.sh +++ b/scripts/kconfig/check.sh @@ -11,4 +11,3 @@ EOF if [ ! "$?" -eq "0" ]; then echo -DKBUILD_NO_NLS; fi - diff --git a/scripts/kconfig/conf.c b/scripts/kconfig/conf.c index 9befa2b..ea2446a 100644 --- a/scripts/kconfig/conf.c +++ b/scripts/kconfig/conf.c @@ -3,6 +3,8 @@ * Released under the terms of the GNU GPL v2.0. */ +#define _XOPEN_SOURCE 700 + #include #include #include @@ -171,7 +173,7 @@ static void conf_askvalue(struct symbol *sym, const char *def) int conf_string(struct menu *menu) { struct symbol *sym = menu->sym; - const char *def, *help; + const char *def; while (1) { printf("%*s%s ", indent - 1, "", menu->prompt->text); @@ -186,10 +188,7 @@ int conf_string(struct menu *menu) case '?': /* print help */ if (line[1] == '\n') { - help = nohelp_text; - if (menu->sym->help) - help = menu->sym->help; - printf("\n%s\n", menu->sym->help); + printf("\n%s\n", menu->sym->help ? menu->sym->help : nohelp_text); def = NULL; break; } @@ -205,7 +204,6 @@ int conf_string(struct menu *menu) static int conf_sym(struct menu *menu) { struct symbol *sym = menu->sym; - int type; tristate oldval, newval; const char *help; @@ -213,7 +211,6 @@ static int conf_sym(struct menu *menu) printf("%*s%s ", indent - 1, "", menu->prompt->text); if (sym->name) printf("(%s) ", sym->name); - type = sym_get_type(sym); putchar('['); oldval = sym_get_tristate_value(sym); switch (oldval) { @@ -280,11 +277,9 @@ static int conf_choice(struct menu *menu) { struct symbol *sym, *def_sym; struct menu *child; - int type; bool is_new; sym = menu->sym; - type = sym_get_type(sym); is_new = !sym_has_value(sym); if (sym_is_changable(sym)) { conf_sym(menu); diff --git a/scripts/kconfig/confdata.c b/scripts/kconfig/confdata.c index bd2d70e..303df0b 100644 --- a/scripts/kconfig/confdata.c +++ b/scripts/kconfig/confdata.c @@ -474,7 +474,11 @@ int conf_write(const char *name) fprintf(out_h, "#define CONFIG_%s 1\n", sym->name); /* bbox */ fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#ifdef MAKE_SUID\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name); + fprintf(out_h, "#else\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#endif\n"); fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); } break; @@ -506,7 +510,11 @@ int conf_write(const char *name) fputs("\"\n", out_h); /* bbox */ fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#ifdef MAKE_SUID\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name); + fprintf(out_h, "#else\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#endif\n"); fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); } break; @@ -518,7 +526,11 @@ int conf_write(const char *name) fprintf(out_h, "#define CONFIG_%s 0x%s\n", sym->name, str); /* bbox */ fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#ifdef MAKE_SUID\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name); + fprintf(out_h, "#else\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#endif\n"); fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); } break; @@ -532,7 +544,11 @@ int conf_write(const char *name) fprintf(out_h, "#define CONFIG_%s %s\n", sym->name, str); /* bbox */ fprintf(out_h, "#define ENABLE_%s 1\n", sym->name); - fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#ifdef MAKE_SUID\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__ \"CONFIG_%s\"\n", sym->name, sym->name); + fprintf(out_h, "#else\n"); + fprintf(out_h, "# define IF_%s(...) __VA_ARGS__\n", sym->name); + fprintf(out_h, "#endif\n"); fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name); } break; diff --git a/scripts/kconfig/lex.zconf.c_shipped b/scripts/kconfig/lex.zconf.c_shipped index 5fc323d..51f15e1 100644 --- a/scripts/kconfig/lex.zconf.c_shipped +++ b/scripts/kconfig/lex.zconf.c_shipped @@ -2235,13 +2235,14 @@ static void zconf_endhelp(void) */ FILE *zconf_fopen(const char *name) { - char *env, fullname[PATH_MAX+1]; + char *env; FILE *f; f = fopen(name, "r"); if (!f && name[0] != '/') { env = getenv(SRCTREE); if (env) { + char *fullname = alloca(strlen(env) + strlen(name) + 2); sprintf(fullname, "%s/%s", env, name); f = fopen(fullname, "r"); } @@ -2322,4 +2323,3 @@ char *zconf_curname(void) { return current_pos.file ? current_pos.file->name : ""; } - diff --git a/scripts/kconfig/lxdialog/textbox.c b/scripts/kconfig/lxdialog/textbox.c index 77848bb..de4ae41 100644 --- a/scripts/kconfig/lxdialog/textbox.c +++ b/scripts/kconfig/lxdialog/textbox.c @@ -38,11 +38,8 @@ int dialog_textbox(const char *title, const char *file, int height, int width) { int i, x, y, cur_x, cur_y, fpos, key = 0; int passed_end; - char search_term[MAX_LEN + 1]; WINDOW *dialog, *text; - search_term[0] = '\0'; /* no search term entered yet */ - /* Open input file for reading */ if ((fd = open(file, O_RDONLY)) == -1) { endwin(); @@ -437,7 +434,6 @@ static void print_page(WINDOW * win, int height, int width) */ static void print_line(WINDOW * win, int row, int width) { - int y, x; char *line; line = get_line(); @@ -446,11 +442,13 @@ static void print_line(WINDOW * win, int row, int width) waddch(win, ' '); waddnstr(win, line, MIN(strlen(line), width - 2)); - getyx(win, y, x); /* Clear 'residue' of previous line */ #if OLD_NCURSES { int i; + int y, x; + + getyx(win, y, x); for (i = 0; i < width - x; i++) waddch(win, ' '); } diff --git a/scripts/kconfig/mconf.c b/scripts/kconfig/mconf.c index 0c548bf..006d037 100644 --- a/scripts/kconfig/mconf.c +++ b/scripts/kconfig/mconf.c @@ -8,6 +8,10 @@ * i18n, 2005, Arnaldo Carvalho de Melo */ +#define _XOPEN_SOURCE 700 +/* On Darwin, this may be needed to get SIGWINCH: */ +#define _DARWIN_C_SOURCE 1 + #include #include #include @@ -18,6 +22,7 @@ #include #include #include +#include /* for strcasecmp */ #include #include #include @@ -256,7 +261,7 @@ search_help[] = N_( " USB$ => find all CONFIG_ symbols ending with USB\n" "\n"); -static char buf[4096], *bufptr = buf; +static char buf[4096*10], *bufptr = buf; static char input_buf[4096]; static const char filename[] = ".config"; static char *args[1024], **argptr = args; @@ -440,6 +445,7 @@ static struct gstr get_relations_str(struct symbol **sym_arr) pid_t pid; +#ifdef SIGWINCH static void winch_handler(int sig) { if (!do_resize) { @@ -447,11 +453,11 @@ static void winch_handler(int sig) do_resize = 1; } } +#endif static int exec_conf(void) { int pipefd[2], stat, size; - struct sigaction sa; sigset_t sset, osset; sigemptyset(&sset); @@ -460,10 +466,15 @@ static int exec_conf(void) signal(SIGINT, SIG_DFL); - sa.sa_handler = winch_handler; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART; - sigaction(SIGWINCH, &sa, NULL); +#ifdef SIGWINCH + { + struct sigaction sa; + sa.sa_handler = winch_handler; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGWINCH, &sa, NULL); + } +#endif *argptr++ = NULL; diff --git a/scripts/kconfig/menu.c b/scripts/kconfig/menu.c index 0fce20c..14cf2ea 100644 --- a/scripts/kconfig/menu.c +++ b/scripts/kconfig/menu.c @@ -394,4 +394,3 @@ struct menu *menu_get_parent_menu(struct menu *menu) } return menu; } - diff --git a/scripts/kconfig/util.c b/scripts/kconfig/util.c index ef4c832..2630919 100644 --- a/scripts/kconfig/util.c +++ b/scripts/kconfig/util.c @@ -112,4 +112,3 @@ const char *str_get(struct gstr *gs) { return gs->s; } - diff --git a/scripts/kconfig/zconf.hash.c_shipped b/scripts/kconfig/zconf.hash.c_shipped index 345f0fc..d39cf18 100644 --- a/scripts/kconfig/zconf.hash.c_shipped +++ b/scripts/kconfig/zconf.hash.c_shipped @@ -228,4 +228,3 @@ kconf_id_lookup (register const char *str, register unsigned int len) } return 0; } - diff --git a/scripts/kconfig/zconf.tab.c_shipped b/scripts/kconfig/zconf.tab.c_shipped index b62724d..a27d256 100644 --- a/scripts/kconfig/zconf.tab.c_shipped +++ b/scripts/kconfig/zconf.tab.c_shipped @@ -2169,5 +2169,3 @@ void zconfdump(FILE *out) #include "expr.c" #include "symbol.c" #include "menu.c" - - diff --git a/scripts/kconfig/zconf.y b/scripts/kconfig/zconf.y index 2007a4e..bef5e92 100644 --- a/scripts/kconfig/zconf.y +++ b/scripts/kconfig/zconf.y @@ -473,7 +473,7 @@ void conf_parse(const char *name) menu_finalize(&rootmenu); for_all_symbols(i, sym) { sym_check_deps(sym); - } + } sym_change_count = 1; } diff --git a/scripts/mkconfigs b/scripts/mkconfigs index ef6ae8a..6a26fe1 100755 --- a/scripts/mkconfigs +++ b/scripts/mkconfigs @@ -26,26 +26,51 @@ # - Retain lines that begin with "# CONFIG_" # - lines that use double-quotes must \\-escape-quote them -config="$1" -if [ $# -lt 1 ] -then - config=.config -fi +config=.config +{ echo "\ #ifndef _BBCONFIGOPTS_H #define _BBCONFIGOPTS_H /* * busybox configuration settings. * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. * * This file is generated automatically by scripts/mkconfigs. * Do not edit. */ -static const char bbconfig_config[] =" +static const char bbconfig_config[] ALIGN1 =" -sed 's/\"/\\\"/g' $config | grep "^#\? \?CONFIG_" | awk '{print "\"" $0 "\\n\"";}' +grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ +| sed -e 's/\"/\\\"/g' -e 's/^/"/' -e 's/$/\\n"/' echo ";" -echo "#endif /* _BBCONFIGOPTS_H */" +echo "#endif" +} >"$1" + +{ +echo "\ +#ifndef _BBCONFIGOPTS_BZ2_H +#define _BBCONFIGOPTS_BZ2_H +/* + * busybox configuration settings. + * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * + * This file is generated automatically by scripts/mkconfigs. + * Do not edit. + */ +static const char bbconfig_config_bz2[] ALIGN1 = {" + +grep -e '^# CONFIG_' -e '^CONFIG_' "$config" \ +| bzip2 -1 | dd bs=2 skip=1 2>/dev/null \ +| od -v -b \ +| sed -e 's/^[^ ]*//' \ + -e 's/ //g' \ + -e '/^$/d' \ + -e 's/\(...\)/0\1,/g' + +echo "};" +echo "#endif" +} >"$2" diff --git a/scripts/mkdiff_obj b/scripts/mkdiff_obj index a6ec5e6..3074748 100755 --- a/scripts/mkdiff_obj +++ b/scripts/mkdiff_obj @@ -1,28 +1,35 @@ #!/bin/sh +usage() { + echo "Usage: ${0##*/} DIR1 DIR2" + echo + echo "Compares all object files recursivelty found in DIR1 and DIR2." + echo "Prints diff of their disassembly." + echo + exit $1 +} + filter() { # sed removes " address: " prefixes which mess up diff sed $'s/^\\(\t*\\)[ ]*[0-9a-f][0-9a-f]*:[ \t]*/\\1/' \ | sed 's/__GI_//g' } -test -d "$1" || exit 1 -test -d "$2" || exit 1 +test -d "$1" || usage 1 +test -d "$2" || usage 1 { ( cd "$1" || exit 1 - find -name '*.o' -o -name '*.os' # -o -name '*.so' + find -name '*.o' # -o -name '*.os' # -o -name '*.so' ) ( cd "$2" || exit 1 - find -name '*.o' -o -name '*.os' # -o -name '*.so' + find -name '*.o' # -o -name '*.os' # -o -name '*.so' ) } | sed 's:^\./::' | sort | uniq | \ -tee LST | \ ( -IFS='' -while read -r oname; do +while IFS='' read -r oname; do if ! test -f "$1/$oname"; then echo "Only $2/$oname" continue @@ -32,8 +39,8 @@ while read -r oname; do continue fi diff -q -- "$1/$oname" "$2/$oname" >/dev/null && continue - (cd "$1"; objdump -dr "$oname" | filter >"$oname.disasm") - (cd "$2"; objdump -dr "$oname" | filter >"$oname.disasm") - diff -u "$1/$oname.disasm" "$2/$oname.disasm" + (cd "$1" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm") + (cd "$2" && { size "$oname"; objdump -dr "$oname" | filter; } >"$oname.disasm") + diff -u -- "$1/$oname.disasm" "$2/$oname.disasm" done ) diff --git a/scripts/mkmakefile b/scripts/mkmakefile index 7f9d544..9fc51a7 100755 --- a/scripts/mkmakefile +++ b/scripts/mkmakefile @@ -31,6 +31,9 @@ all: Makefile:; -\$(filter-out all Makefile,\$(MAKECMDGOALS)) %/: +\$(filter-out all Makefile,\$(MAKECMDGOALS)): + \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT) \$@ + +%/: \$(MAKE) -C \$(KERNELSRC) O=\$(KERNELOUTPUT) \$@ EOF diff --git a/scripts/randomtest b/scripts/randomtest index a102593..d2b26bc 100755 --- a/scripts/randomtest +++ b/scripts/randomtest @@ -65,6 +65,7 @@ if test x"$LIBC" = x"uclibc"; then | grep -v CONFIG_BUILD_LIBBUSYBOX \ | grep -v CONFIG_PIE \ \ + | grep -v CONFIG_FEATURE_TOUCH_NODEREF \ | grep -v CONFIG_FEATURE_2_4_MODULES \ >.config.new mv .config.new .config @@ -72,6 +73,7 @@ if test x"$LIBC" = x"uclibc"; then echo '# CONFIG_BUILD_LIBBUSYBOX is not set' >>.config echo '# CONFIG_PIE is not set' >>.config echo '# CONFIG_FEATURE_2_4_MODULES is not set' >>.config + echo '# CONFIG_FEATURE_TOUCH_NODEREF is not set' >>.config fi # If STATIC, remove some things. diff --git a/scripts/randomtest.loop b/scripts/randomtest.loop index 311536d..758a8e8 100755 --- a/scripts/randomtest.loop +++ b/scripts/randomtest.loop @@ -1,10 +1,12 @@ #!/bin/sh +run_testsuite=true + test -d "$1" || { echo "'$1' is not a directory"; exit 1; } test -x "$1/scripts/randomtest" || { echo "No scripts/randomtest in '$1'"; exit 1; } export LIBC="uclibc" -export CROSS_COMPILER_PREFIX="i486-linux-uclibc-" +export CROSS_COMPILER_PREFIX="i686-" export MAKEOPTS="-j9" cnt=0 @@ -21,7 +23,9 @@ while sleep 1; do echo "Failed build in: failed.$dir" exit 1 # you may comment this out... let fail++ - else + continue + fi + if $run_testsuite; then ( cd -- "$dir/testsuite" || exit 1 echo "Running testsuite in $dir..." @@ -29,10 +33,12 @@ while sleep 1; do ) if test $? != 0; then echo "Failed runtest in $dir" - exit 1 + exit 1 # you may comment this out... + let fail++ + continue fi tail -n10 -- "$dir/testsuite/runtest.log" - rm -rf -- "$dir" fi + rm -rf -- "$dir" let cnt++ done diff --git a/scripts/showasm b/scripts/showasm index 0464426..b61ab98 100755 --- a/scripts/showasm +++ b/scripts/showasm @@ -1,7 +1,7 @@ #!/bin/sh # Copyright 2006 Rob Landley -# Licensed under GPLv2 or later, see file LICENSE in this tarball for details. +# Licensed under GPLv2 or later, see file LICENSE in this source tree. # Dumb little utility function to print out the assembly dump of a single # function, or list the functions so dumpable in an executable. You'd think @@ -18,4 +18,3 @@ then fi objdump -d $1 | sed -n -e '/./{H;$!d}' -e "x;/^.[0-9a-fA-F]* <$2>:/p" - diff --git a/scripts/trylink b/scripts/trylink index 5994a75..e471699 100755 --- a/scripts/trylink +++ b/scripts/trylink @@ -117,7 +117,7 @@ LDLIBS=`echo "$LDLIBS" | xargs -n1 | sort | uniq | xargs` # First link with all libs. If it fails, bail out echo "Trying libraries: $LDLIBS" # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" -l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` +l_list=`echo " $LDLIBS " | sed -e 's: \([^- ][^ ]*\): -l\1:g'` test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" try $CC $CFLAGS $LDFLAGS \ -o $EXE \ @@ -141,7 +141,7 @@ while test "$LDLIBS"; do for one in $LDLIBS; do without_one=`echo " $LDLIBS " | sed "s/ $one / /g" | xargs` # "lib1 lib2 lib3" -> "-llib1 -llib2 -llib3" - l_list=`echo "$without_one" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` + l_list=`echo " $without_one " | sed -e 's: \([^- ][^ ]*\): -l\1:g'` test x"$l_list" != x"" && l_list="$START_GROUP $l_list $END_GROUP" $debug && echo "Trying -l options: '$l_list'" try $CC $CFLAGS $LDFLAGS \ @@ -172,7 +172,7 @@ done # Make the binary with final, minimal list of libs echo "Final link with: ${LDLIBS:-}" -l_list=`echo "$LDLIBS" | sed -e 's/ / -l/g' -e 's/^/-l/' -e 's/^-l$//'` +l_list=`echo " $LDLIBS " | sed -e 's: \([^- ][^ ]*\): -l\1:g'` test "x$l_list" != "x" && l_list="$START_GROUP $l_list $END_GROUP" # --verbose gives us gobs of info to stdout (e.g. linker script used) if ! test -f busybox_ldscript; then @@ -255,6 +255,7 @@ if test "$CONFIG_FEATURE_SHARED_BUSYBOX" = y; then $GC_SECTIONS \ $START_GROUP $O_FILES $END_GROUP \ -L"$sharedlib_dir" -lbusybox \ + $l_list \ $INFO_OPTS \ || { echo "Linking $EXE failed" diff --git a/selinux/Config.src b/selinux/Config.src index 64a9920..47d15b6 100644 --- a/selinux/Config.src +++ b/selinux/Config.src @@ -122,4 +122,3 @@ config SESTATUS Displays the status of SELinux. endmenu - diff --git a/selinux/Kbuild.src b/selinux/Kbuild.src index 6567e3c..cdd5f2a 100644 --- a/selinux/Kbuild.src +++ b/selinux/Kbuild.src @@ -3,7 +3,7 @@ # Copyright (C) 1999-2005 by Erik Andersen # Copyright (C) 2007 by KaiGai Kohei # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= diff --git a/selinux/chcon.c b/selinux/chcon.c index c6be37f..f947c2c 100644 --- a/selinux/chcon.c +++ b/selinux/chcon.c @@ -5,9 +5,41 @@ * * Copyright (C) 2006 - 2007 KaiGai Kohei * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include + +//usage:#define chcon_trivial_usage +//usage: "[OPTIONS] CONTEXT FILE..." +//usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." +//usage: IF_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." +//usage: ) +//usage:#define chcon_full_usage "\n\n" +//usage: "Change the security context of each FILE to CONTEXT\n" +//usage: IF_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n -v,--verbose Verbose" +//usage: "\n -c,--changes Report changes made" +//usage: "\n -h,--no-dereference Affect symlinks instead of their targets" +//usage: "\n -f,--silent,--quiet Suppress most error messages" +//usage: "\n --reference=RFILE Use RFILE's group instead of using a CONTEXT value" +//usage: "\n -u,--user=USER Set user/role/type/range in the target" +//usage: "\n -r,--role=ROLE security context" +//usage: "\n -t,--type=TYPE" +//usage: "\n -l,--range=RANGE" +//usage: "\n -R,--recursive Recurse" +//usage: ) +//usage: IF_NOT_FEATURE_CHCON_LONG_OPTIONS( +//usage: "\n -v Verbose" +//usage: "\n -c Report changes made" +//usage: "\n -h Affect symlinks instead of their targets" +//usage: "\n -f Suppress most error messages" +//usage: "\n -u USER Set user/role/type/range in the target security context" +//usage: "\n -r ROLE" +//usage: "\n -t TYPE" +//usage: "\n -l RNG" +//usage: "\n -R Recurse" +//usage: ) + #include #include "libbb.h" @@ -60,7 +92,7 @@ static int FAST_FUNC change_filedir_context( if (specified_context == NULL) { context = set_security_context_component(file_context, - user, role, type, range); + user, role, type, range); if (!context) { bb_error_msg("can't compute security context from %s", file_context); goto skip; @@ -89,15 +121,15 @@ static int FAST_FUNC change_filedir_context( } if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) { printf(!fail - ? "context of %s changed to %s\n" - : "can't change context of %s to %s\n", - fname, context_string); + ? "context of %s changed to %s\n" + : "can't change context of %s to %s\n", + fname, context_string); } if (!fail) { rc = TRUE; } else if ((option_mask32 & OPT_QUIET) == 0) { bb_error_msg("can't change context of %s to %s", - fname, context_string); + fname, context_string); } } else if (option_mask32 & OPT_VERBOSE) { printf("context of %s retained as %s\n", fname, context_string); @@ -149,7 +181,7 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_FEATURE_CHCON_LONG_OPTIONS if (option_mask32 & OPT_REFERENCE) { /* FIXME: lgetfilecon() should be used when '-h' is specified. - But current implementation follows the original one. */ + * But current implementation follows the original one. */ if (getfilecon(reference_file, &specified_context) < 0) bb_perror_msg_and_die("getfilecon('%s') failed", reference_file); } else @@ -169,10 +201,10 @@ int chcon_main(int argc UNUSED_PARAM, char **argv) fname[fname_len] = '\0'; if (recursive_action(fname, - 1< * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define getenforce_trivial_usage NOUSAGE_STR +//usage:#define getenforce_full_usage "" + #include "libbb.h" int getenforce_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/selinux/getsebool.c b/selinux/getsebool.c index 7478b79..e8f0fef 100644 --- a/selinux/getsebool.c +++ b/selinux/getsebool.c @@ -4,9 +4,14 @@ * Based on libselinux 1.33.1 * Port to BusyBox Hiroshi Shinji * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define getsebool_trivial_usage +//usage: "-a or getsebool boolean..." +//usage:#define getsebool_full_usage "\n\n" +//usage: " -a Show all selinux booleans" + #include "libbb.h" int getsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/selinux/load_policy.c b/selinux/load_policy.c index ea7c913..ce139db 100644 --- a/selinux/load_policy.c +++ b/selinux/load_policy.c @@ -2,8 +2,12 @@ * load_policy * Author: Yuichi Nakamura * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define load_policy_trivial_usage NOUSAGE_STR +//usage:#define load_policy_full_usage "" + #include "libbb.h" int load_policy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/selinux/matchpathcon.c b/selinux/matchpathcon.c index 1532429..9e5728e 100644 --- a/selinux/matchpathcon.c +++ b/selinux/matchpathcon.c @@ -3,8 +3,18 @@ * based on libselinux-1.32 * Port to busybox: KaiGai Kohei * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define matchpathcon_trivial_usage +//usage: "[-n] [-N] [-f file_contexts_file] [-p prefix] [-V]" +//usage:#define matchpathcon_full_usage "\n\n" +//usage: " -n Don't display path" +//usage: "\n -N Don't use translations" +//usage: "\n -f Use alternate file_context file" +//usage: "\n -p Use prefix to speed translations" +//usage: "\n -V Verify file context on disk matches defaults" + #include "libbb.h" static int print_matchpathcon(char *path, int noprint) diff --git a/selinux/runcon.c b/selinux/runcon.c index f8ca9a6..27f2be3 100644 --- a/selinux/runcon.c +++ b/selinux/runcon.c @@ -26,16 +26,37 @@ * Port to busybox: KaiGai Kohei * - based on coreutils-5.97 (in Fedora Core 6) * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ -#include + +//usage:#define runcon_trivial_usage +//usage: "[-c] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] PROG ARGS\n" +//usage: "runcon CONTEXT PROG ARGS" +//usage:#define runcon_full_usage "\n\n" +//usage: "Run PROG in a different security context\n" +//usage: "\n CONTEXT Complete security context\n" +//usage: IF_FEATURE_RUNCON_LONG_OPTIONS( +//usage: "\n -c,--compute Compute process transition context before modifying" +//usage: "\n -t,--type=TYPE Type (for same role as parent)" +//usage: "\n -u,--user=USER User identity" +//usage: "\n -r,--role=ROLE Role" +//usage: "\n -l,--range=RNG Levelrange" +//usage: ) +//usage: IF_NOT_FEATURE_RUNCON_LONG_OPTIONS( +//usage: "\n -c Compute process transition context before modifying" +//usage: "\n -t TYPE Type (for same role as parent)" +//usage: "\n -u USER User identity" +//usage: "\n -r ROLE Role" +//usage: "\n -l RNG Levelrange" +//usage: ) + #include #include #include "libbb.h" static context_t runcon_compute_new_context(char *user, char *role, char *type, char *range, - char *command, int compute_trans) + char *command, int compute_trans) { context_t con; security_context_t cur_context; @@ -48,9 +69,9 @@ static context_t runcon_compute_new_context(char *user, char *role, char *type, if (getfilecon(command, &file_context) < 0) bb_error_msg_and_die("can't retrieve attributes of '%s'", - command); + command); if (security_compute_create(cur_context, file_context, - SECCLASS_PROCESS, &new_context)) + SECCLASS_PROCESS, &new_context)) bb_error_msg_and_die("unable to compute a new context"); cur_context = new_context; } @@ -126,12 +147,11 @@ int runcon_main(int argc UNUSED_PARAM, char **argv) if (security_check_context(context_str(con))) bb_error_msg_and_die("'%s' is not a valid context", - context_str(con)); + context_str(con)); if (setexeccon(context_str(con))) bb_error_msg_and_die("can't set up security context '%s'", - context_str(con)); + context_str(con)); - execvp(argv[0], argv); - bb_perror_msg_and_die("can't execute '%s'", argv[0]); + BB_EXECVP_or_die(argv); } diff --git a/selinux/selinuxenabled.c b/selinux/selinuxenabled.c index 1cf93c3..ce830dc 100644 --- a/selinux/selinuxenabled.c +++ b/selinux/selinuxenabled.c @@ -4,8 +4,12 @@ * Based on libselinux 1.33.1 * Port to BusyBox Hiroshi Shinji * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ + +//usage:#define selinuxenabled_trivial_usage NOUSAGE_STR +//usage:#define selinuxenabled_full_usage "" + #include "libbb.h" int selinuxenabled_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/selinux/sestatus.c b/selinux/sestatus.c index 1a02a6b..e594318 100644 --- a/selinux/sestatus.c +++ b/selinux/sestatus.c @@ -5,17 +5,23 @@ * * Copyright (C) KaiGai Kohei * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define sestatus_trivial_usage +//usage: "[-vb]" +//usage:#define sestatus_full_usage "\n\n" +//usage: " -v Verbose" +//usage: "\n -b Display current state of booleans" + #include "libbb.h" extern char *selinux_mnt; -#define OPT_VERBOSE (1 << 0) -#define OPT_BOOLEAN (1 << 1) +#define OPT_VERBOSE (1 << 0) +#define OPT_BOOLEAN (1 << 1) -#define COL_FMT "%-31s " +#define COL_FMT "%-31s " static void display_boolean(void) { @@ -35,7 +41,7 @@ static void display_boolean(void) if (pending < 0) goto skip; printf(COL_FMT "%s", - bools[i], active == 0 ? "off" : "on"); + bools[i], active == 0 ? "off" : "on"); if (active != pending) printf(" (%sactivate pending)", pending == 0 ? "in" : ""); bb_putchar('\n'); @@ -151,7 +157,7 @@ int sestatus_main(int argc UNUSED_PARAM, char **argv) const char *pol_path; int rc; - opt_complementary = "?0"; /* no arguments are required. */ + opt_complementary = "?0"; /* no arguments are required. */ opts = getopt32(argv, "vb"); /* SELinux status: line */ diff --git a/selinux/setenforce.c b/selinux/setenforce.c index 45f8223..c5bc0a5 100644 --- a/selinux/setenforce.c +++ b/selinux/setenforce.c @@ -4,9 +4,13 @@ * Based on libselinux 1.33.1 * Port to BusyBox Hiroshi Shinji * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define setenforce_trivial_usage +//usage: "[Enforcing | Permissive | 1 | 0]" +//usage:#define setenforce_full_usage "" + #include "libbb.h" /* These strings are arranged so that odd ones diff --git a/selinux/setfiles.c b/selinux/setfiles.c index f45e41b..0173db9 100644 --- a/selinux/setfiles.c +++ b/selinux/setfiles.c @@ -4,6 +4,46 @@ Port to BusyBox (c) 2007 by Yuichi Nakamura */ +//usage:#define setfiles_trivial_usage +//usage: "[-dnpqsvW] [-e DIR]... [-o FILE] [-r alt_root_path]" +//usage: IF_FEATURE_SETFILES_CHECK_OPTION( +//usage: " [-c policyfile] spec_file" +//usage: ) +//usage: " pathname" +//usage:#define setfiles_full_usage "\n\n" +//usage: "Reset file contexts under pathname according to spec_file\n" +//usage: IF_FEATURE_SETFILES_CHECK_OPTION( +//usage: "\n -c FILE Check the validity of the contexts against the specified binary policy" +//usage: ) +//usage: "\n -d Show which specification matched each file" +//usage: "\n -l Log changes in file labels to syslog" +//usage: "\n -n Don't change any file labels" +//usage: "\n -q Suppress warnings" +//usage: "\n -r DIR Use an alternate root path" +//usage: "\n -e DIR Exclude DIR" +//usage: "\n -F Force reset of context to match file_context for customizable files" +//usage: "\n -o FILE Save list of files with incorrect context" +//usage: "\n -s Take a list of files from stdin (instead of command line)" +//usage: "\n -v Show changes in file labels, if type or role are changing" +//usage: "\n -vv Show changes in file labels, if type, role, or user are changing" +//usage: "\n -W Display warnings about entries that had no matching files" +//usage: +//usage:#define restorecon_trivial_usage +//usage: "[-iFnRv] [-e EXCLUDEDIR]... [-o FILE] [-f FILE]" +//usage:#define restorecon_full_usage "\n\n" +//usage: "Reset security contexts of files in pathname\n" +//usage: "\n -i Ignore files that don't exist" +//usage: "\n -f FILE File with list of files to process" +//usage: "\n -e DIR Directory to exclude" +//usage: "\n -R,-r Recurse" +//usage: "\n -n Don't change any file labels" +//usage: "\n -o FILE Save list of files with incorrect context" +//usage: "\n -v Verbose" +//usage: "\n -vv Show changed labels" +//usage: "\n -F Force reset of context to match file_context" +//usage: "\n for customizable files, or the user section," +//usage: "\n if it has changed" + #include "libbb.h" #if ENABLE_FEATURE_SETFILES_CHECK_OPTION #include @@ -118,7 +158,6 @@ static void add_exclude(const char *directory) if (directory == NULL || directory[0] != '/') { bb_error_msg_and_die("full path required for exclude: %s", directory); - } if (lstat(directory, &sb)) { bb_error_msg("directory \"%s\" not found, ignoring", directory); @@ -459,10 +498,11 @@ static int process_one(char *name) if (S_ISDIR(sb.st_mode) && recurse) { if (recursive_action(name, - ACTION_RECURSE, - apply_spec, - apply_spec, - NULL, 0) != TRUE) { + ACTION_RECURSE, + apply_spec, + apply_spec, + NULL, 0) != TRUE + ) { bb_error_msg("error while labeling %s", name); goto err; } @@ -545,7 +585,7 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) flags = getopt32(argv, "de:f:ilnpqr:svo:FW" IF_FEATURE_SETFILES_CHECK_OPTION("c:"), &exclude_dir, &input_filename, &rootpath, &out_filename, - IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) + IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) &verbose); } argv += optind; @@ -561,8 +601,8 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) fclose(policystream); /* Only process the specified file_contexts file, not - any .homedirs or .local files, and do not perform - context translations. */ + * any .homedirs or .local files, and do not perform + * context translations. */ set_matchpathcon_flags(MATCHPATHCON_BASEONLY | MATCHPATHCON_NOTRANS | MATCHPATHCON_VALIDATE); @@ -592,8 +632,8 @@ int setfiles_main(int argc UNUSED_PARAM, char **argv) if (applet_name[0] == 's') { /* setfiles */ /* Use our own invalid context checking function so that - we can support either checking against the active policy or - checking against a binary policy file. */ + * we can support either checking against the active policy or + * checking against a binary policy file. */ set_matchpathcon_canoncon(&canoncon); if (!argv[0]) bb_show_usage(); diff --git a/selinux/setsebool.c b/selinux/setsebool.c index b615ce7..ec682e5 100644 --- a/selinux/setsebool.c +++ b/selinux/setsebool.c @@ -5,9 +5,14 @@ * omitted in this version * Yuichi Nakamura * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ +//usage:#define setsebool_trivial_usage +//usage: "boolean value" +//usage:#define setsebool_full_usage "\n\n" +//usage: "Change boolean setting" + #include "libbb.h" int setsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; diff --git a/shell/Config.src b/shell/Config.src index 8009119..b31e62d 100644 --- a/shell/Config.src +++ b/shell/Config.src @@ -7,215 +7,6 @@ menu "Shells" INSERT -config ASH - bool "ash" - default y - depends on !NOMMU - help - Tha 'ash' shell adds about 60k in the default configuration and is - the most complete and most pedantically correct shell included with - busybox. This shell is actually a derivative of the Debian 'dash' - shell (by Herbert Xu), which was created by porting the 'ash' shell - (written by Kenneth Almquist) from NetBSD. - -config ASH_BASH_COMPAT - bool "bash-compatible extensions" - default y - depends on ASH - help - Enable bash-compatible extensions. - -config ASH_JOB_CONTROL - bool "Job control" - default y - depends on ASH - help - Enable job control in the ash shell. - -config ASH_ALIAS - bool "alias support" - default y - depends on ASH - help - Enable alias support in the ash shell. - -config ASH_GETOPTS - bool "Builtin getopt to parse positional parameters" - default y - depends on ASH - help - Enable getopts builtin in the ash shell. - -config ASH_BUILTIN_ECHO - bool "Builtin version of 'echo'" - default y - depends on ASH - help - Enable support for echo, builtin to ash. - -config ASH_BUILTIN_PRINTF - bool "Builtin version of 'printf'" - default y - depends on ASH - help - Enable support for printf, builtin to ash. - -config ASH_BUILTIN_TEST - bool "Builtin version of 'test'" - default y - depends on ASH - help - Enable support for test, builtin to ash. - -config ASH_CMDCMD - bool "'command' command to override shell builtins" - default y - depends on ASH - help - Enable support for the ash 'command' builtin, which allows - you to run the specified command with the specified arguments, - even when there is an ash builtin command with the same name. - -config ASH_MAIL - bool "Check for new mail on interactive shells" - default n - depends on ASH - help - Enable "check for new mail" in the ash shell. - -config ASH_OPTIMIZE_FOR_SIZE - bool "Optimize for size instead of speed" - default y - depends on ASH - help - Compile ash for reduced size at the price of speed. - -config ASH_RANDOM_SUPPORT - bool "Pseudorandom generator and $RANDOM variable" - default y - depends on ASH - help - Enable pseudorandom generator and dynamic variable "$RANDOM". - Each read of "$RANDOM" will generate a new pseudorandom value. - You can reset the generator by using a specified start value. - After "unset RANDOM" the generator will switch off and this - variable will no longer have special treatment. - -config ASH_EXPAND_PRMT - bool "Expand prompt string" - default y - depends on ASH - help - "PS#" may contain volatile content, such as backquote commands. - This option recreates the prompt string from the environment - variable each time it is displayed. - -config HUSH - bool "hush" - default y - help - hush is a small shell (22k). It handles the normal flow control - constructs such as if/then/elif/else/fi, for/in/do/done, while loops, - case/esac. Redirections, here documents, $((arithmetic)) - and functions are supported. - - It will compile and work on no-mmu systems. - - It does not handle select, aliases, brace expansion, - tilde expansion, &>file and >&file redirection of stdout+stderr. - -config HUSH_BASH_COMPAT - bool "bash-compatible extensions" - default y - depends on HUSH - help - Enable bash-compatible extensions. - -config HUSH_HELP - bool "help builtin" - default y - depends on HUSH - help - Enable help builtin in hush. Code size + ~1 kbyte. - -config HUSH_INTERACTIVE - bool "Interactive mode" - default y - depends on HUSH - help - Enable interactive mode (prompt and command editing). - Without this, hush simply reads and executes commands - from stdin just like a shell script from a file. - No prompt, no PS1/PS2 magic shell variables. - -config HUSH_JOB - bool "Job control" - default y - depends on HUSH_INTERACTIVE - help - Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current - command (not entire shell), fg/bg builtins work. Without this option, - "cmd &" still works by simply spawning a process and immediately - prompting for next command (or executing next command in a script), - but no separate process group is formed. - -config HUSH_TICK - bool "Process substitution" - default y - depends on HUSH - help - Enable process substitution `command` and $(command) in hush. - -config HUSH_IF - bool "Support if/then/elif/else/fi" - default y - depends on HUSH - help - Enable if/then/elif/else/fi in hush. - -config HUSH_LOOPS - bool "Support for, while and until loops" - default y - depends on HUSH - help - Enable for, while and until loops in hush. - -config HUSH_CASE - bool "Support case ... esac statement" - default y - depends on HUSH - help - Enable case ... esac statement in hush. +400 bytes. - -config HUSH_FUNCTIONS - bool "Support funcname() { commands; } syntax" - default y - depends on HUSH - help - Enable support for shell functions in hush. +800 bytes. - -config HUSH_LOCAL - bool "Support local builtin" - default y - depends on HUSH_FUNCTIONS - help - Enable support for local variables in functions. - -config HUSH_EXPORT_N - bool "Support export '-n' option" - default y - depends on HUSH - help - Enable support for export '-n' option in hush. It is a bash extension. - -config HUSH_RANDOM_SUPPORT - bool "Pseudorandom generator and $RANDOM variable" - default y - depends on HUSH - help - Enable pseudorandom generator and dynamic variable "$RANDOM". - Each read of "$RANDOM" will generate a new pseudorandom value. - choice prompt "Choose which shell is aliased to 'sh' name" @@ -271,29 +62,6 @@ config FEATURE_BASH_IS_NONE endchoice -config LASH - bool "lash (deprecated: aliased to hush)" - default n - select HUSH - help - lash is deprecated and will be removed, please migrate to hush. - -config MSH - bool "msh (deprecated: please use hush)" - default n - select HUSH - help - msh is deprecated and will be removed, please migrate to hush. - If there is a feature msh has but hush does not, please let us know. - -# The minix shell (adds just 30k) is quite complete and handles things -# like for/do/done, case/esac and all the things you expect a Bourne -# shell to do. It is not always pedantically correct about Bourne -# shell grammar (try running the shell testscript "tests/sh.testcases" -# on it and compare vs bash) but for most things it works quite well. -# It uses only vfork, so it can be used on uClinux systems. - - config SH_MATH_SUPPORT bool "POSIX math support" default y @@ -355,9 +123,9 @@ config FEATURE_SH_NOFORK default n depends on (HUSH || ASH) && FEATURE_PREFER_APPLETS help - This option causes busybox shells [currently only ash] - to not execute typical fork/exec/wait sequence, but call _main - directly, if possible. (Sometimes it is not possible: for example, + This option causes busybox shells to not execute typical + fork/exec/wait sequence, but call _main directly, + if possible. (Sometimes it is not possible: for example, this is not possible in pipes). This will be done only for some applets (those which are marked @@ -365,37 +133,17 @@ config FEATURE_SH_NOFORK This may significantly speed up some shell scripts. - This feature is relatively new. Use with care. + This feature is relatively new. Use with care. Report bugs + to project mailing list. -config CTTYHACK - bool "cttyhack" +config FEATURE_SH_HISTFILESIZE + bool "Use $HISTFILESIZE" default y + depends on HUSH || ASH help - One common problem reported on the mailing list is "can't access tty; - job control turned off" error message which typically appears when - one tries to use shell with stdin/stdout opened to /dev/console. - This device is special - it cannot be a controlling tty. - - Proper solution is to use correct device instead of /dev/console. - - cttyhack provides "quick and dirty" solution to this problem. - It analyzes stdin with various ioctls, trying to determine whether - it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). - If it detects one, it closes stdin/out/err and reopens that device. - Then it executes given program. Opening the device will make - that device a controlling tty. This may require cttyhack - to be a session leader. - - Example for /etc/inittab (for busybox init): - - ::respawn:/bin/cttyhack /bin/sh - - Giving controlling tty to shell running with PID 1: - - $ exec cttyhack sh - - Starting an interactive shell from boot shell script: + This option makes busybox shells to use $HISTFILESIZE variable + to set shell history size. Note that its max value is capped + by "History size" setting in library tuning section. - setsid cttyhack sh endmenu diff --git a/shell/Kbuild.src b/shell/Kbuild.src index d76b353..c00aec9 100644 --- a/shell/Kbuild.src +++ b/shell/Kbuild.src @@ -2,16 +2,10 @@ # # Copyright (C) 1999-2005 by Erik Andersen # -# Licensed under the GPL v2, see the file LICENSE in this tarball. +# Licensed under GPLv2, see file LICENSE in this source tree. lib-y:= INSERT -lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o -lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o -lib-$(CONFIG_CTTYHACK) += cttyhack.o - lib-$(CONFIG_SH_MATH_SUPPORT) += math.o -lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o -lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o diff --git a/shell/ash.c b/shell/ash.c index 0337a55..71ef9a6 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -13,7 +13,7 @@ * Copyright (c) 1997-2005 Herbert Xu * was re-ported from NetBSD and debianized. * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. + * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ /* @@ -23,8 +23,9 @@ * define DEBUG=1 to compile in debugging ('set -o debug' to turn on) * define DEBUG=2 to compile in and turn on debugging. * - * When debugging is on, debugging info will be written to ./trace and - * a quit signal will generate a core dump. + * When debugging is on (DEBUG is 1 and "set -o debug" was executed), + * debugging info will be written to ./trace and a quit signal + * will generate a core dump. */ #define DEBUG 0 /* Tweak debug output verbosity here */ @@ -36,14 +37,18 @@ #define JOBS ENABLE_ASH_JOB_CONTROL -#include "busybox.h" /* for applet_names */ #include #include #include #include +#include "busybox.h" /* for applet_names */ +#include "unicode.h" + #include "shell_common.h" -#include "math.h" +#if ENABLE_SH_MATH_SUPPORT +# include "math.h" +#endif #if ENABLE_ASH_RANDOM_SUPPORT # include "random.h" #else @@ -70,6 +75,124 @@ # error "Do not even bother, ash will not run on NOMMU machine" #endif +//config:config ASH +//config: bool "ash" +//config: default y +//config: depends on !NOMMU +//config: help +//config: Tha 'ash' shell adds about 60k in the default configuration and is +//config: the most complete and most pedantically correct shell included with +//config: busybox. This shell is actually a derivative of the Debian 'dash' +//config: shell (by Herbert Xu), which was created by porting the 'ash' shell +//config: (written by Kenneth Almquist) from NetBSD. +//config: +//config:config ASH_BASH_COMPAT +//config: bool "bash-compatible extensions" +//config: default y +//config: depends on ASH +//config: help +//config: Enable bash-compatible extensions. +//config: +//config:config ASH_IDLE_TIMEOUT +//config: bool "Idle timeout variable" +//config: default n +//config: depends on ASH +//config: help +//config: Enables bash-like auto-logout after $TMOUT seconds of idle time. +//config: +//config:config ASH_JOB_CONTROL +//config: bool "Job control" +//config: default y +//config: depends on ASH +//config: help +//config: Enable job control in the ash shell. +//config: +//config:config ASH_ALIAS +//config: bool "Alias support" +//config: default y +//config: depends on ASH +//config: help +//config: Enable alias support in the ash shell. +//config: +//config:config ASH_GETOPTS +//config: bool "Builtin getopt to parse positional parameters" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for getopts builtin in ash. +//config: +//config:config ASH_BUILTIN_ECHO +//config: bool "Builtin version of 'echo'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for echo builtin in ash. +//config: +//config:config ASH_BUILTIN_PRINTF +//config: bool "Builtin version of 'printf'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for printf builtin in ash. +//config: +//config:config ASH_BUILTIN_TEST +//config: bool "Builtin version of 'test'" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for test builtin in ash. +//config: +//config:config ASH_CMDCMD +//config: bool "'command' command to override shell builtins" +//config: default y +//config: depends on ASH +//config: help +//config: Enable support for the ash 'command' builtin, which allows +//config: you to run the specified command with the specified arguments, +//config: even when there is an ash builtin command with the same name. +//config: +//config:config ASH_MAIL +//config: bool "Check for new mail on interactive shells" +//config: default n +//config: depends on ASH +//config: help +//config: Enable "check for new mail" function in the ash shell. +//config: +//config:config ASH_OPTIMIZE_FOR_SIZE +//config: bool "Optimize for size instead of speed" +//config: default y +//config: depends on ASH +//config: help +//config: Compile ash for reduced size at the price of speed. +//config: +//config:config ASH_RANDOM_SUPPORT +//config: bool "Pseudorandom generator and $RANDOM variable" +//config: default y +//config: depends on ASH +//config: help +//config: Enable pseudorandom generator and dynamic variable "$RANDOM". +//config: Each read of "$RANDOM" will generate a new pseudorandom value. +//config: You can reset the generator by using a specified start value. +//config: After "unset RANDOM" the generator will switch off and this +//config: variable will no longer have special treatment. +//config: +//config:config ASH_EXPAND_PRMT +//config: bool "Expand prompt string" +//config: default y +//config: depends on ASH +//config: help +//config: "PS#" may contain volatile content, such as backquote commands. +//config: This option recreates the prompt string from the environment +//config: variable each time it is displayed. +//config: + +//applet:IF_ASH(APPLET(ash, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_ASH(APPLET_ODDNAME(bash, ash, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_ASH) += ash.o ash_ptr_hack.o shell_common.o +//kbuild:lib-$(CONFIG_ASH_RANDOM_SUPPORT) += random.o + /* ============ Hash table sizes. Configurable. */ @@ -262,6 +385,9 @@ static void trace_vprintf(const char *fmt, va_list va); /* ============ Utility functions */ #define xbarrier() do { __asm__ __volatile__ ("": : :"memory"); } while (0) +#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) +#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) + static int isdigit_str9(const char *str) { int maxlen = 9 + 1; /* max 9 digits: 999999999 */ @@ -280,6 +406,9 @@ static const char *var_end(const char *var) /* ============ Interrupts / exceptions */ + +static void exitshell(void) NORETURN; + /* * These macros allow the user to suspend the handling of interrupt signals * over a period of time. This is similar to SIGHOLD or to sigblock, but @@ -835,7 +964,8 @@ sharg(union node *arg, FILE *fp) for (p = arg->narg.text; *p; p++) { switch ((unsigned char)*p) { case CTLESC: - putc(*++p, fp); + p++; + putc(*p, fp); break; case CTLVAR: putc('$', fp); @@ -844,8 +974,10 @@ sharg(union node *arg, FILE *fp) if (subtype == VSLENGTH) putc('#', fp); - while (*p != '=') - putc(*p++, fp); + while (*p != '=') { + putc(*p, fp); + p++; + } if (subtype & VSNUL) putc(':', fp); @@ -1757,7 +1889,9 @@ change_lc_ctype(const char *value) #endif #if ENABLE_ASH_MAIL static void chkmail(void); -static void changemail(const char *) FAST_FUNC; +static void changemail(const char *var_value) FAST_FUNC; +#else +# define chkmail() ((void)0) #endif static void changepath(const char *) FAST_FUNC; #if ENABLE_ASH_RANDOM_SUPPORT @@ -1769,6 +1903,10 @@ static const struct { const char *var_text; void (*var_func)(const char *) FAST_FUNC; } varinit_data[] = { + /* + * Note: VEXPORT would not work correctly here for NOFORK applets: + * some environment strings may be constant. + */ { VSTRFIXED|VTEXTFIXED , defifsvar , NULL }, #if ENABLE_ASH_MAIL { VSTRFIXED|VTEXTFIXED|VUNSET, "MAIL" , changemail }, @@ -1864,10 +2002,6 @@ extern struct globals_var *const ash_ptr_to_globals_var; # define optindval() (voptind.var_text + 7) #endif - -#define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) -#define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) - #if ENABLE_ASH_GETOPTS static void FAST_FUNC getoptsreset(const char *value) @@ -1878,25 +2012,6 @@ getoptsreset(const char *value) #endif /* - * Return of a legal variable name (a letter or underscore followed by zero or - * more letters, underscores, and digits). - */ -static char* FAST_FUNC -endofname(const char *name) -{ - char *p; - - p = (char *) name; - if (!is_name(*p)) - return p; - while (*++p) { - if (!is_in_name(*p)) - break; - } - return p; -} - -/* * Compares two strings up to the first = or '\0'. The first * string must be terminated by '='; the second may be terminated by * either '=' or '\0'. @@ -2077,9 +2192,10 @@ setvareq(char *s, int flags) static void setvar(const char *name, const char *val, int flags) { - char *p, *q; - size_t namelen; + const char *q; + char *p; char *nameeq; + size_t namelen; size_t vallen; q = endofname(name); @@ -2093,12 +2209,13 @@ setvar(const char *name, const char *val, int flags) } else { vallen = strlen(val); } + INT_OFF; nameeq = ckmalloc(namelen + vallen + 2); - p = (char *)memcpy(nameeq, name, namelen) + namelen; + p = memcpy(nameeq, name, namelen) + namelen; if (val) { *p++ = '='; - p = (char *)memcpy(p, val, vallen) + vallen; + p = memcpy(p, val, vallen) + vallen; } *p = '\0'; setvareq(nameeq, flags | VNOSAVE); @@ -2169,7 +2286,7 @@ unsetvar(const char *s) free(vp); INT_ON; } else { - setvar(s, 0, 0); + setvar2(s, 0); vp->flags &= ~VEXPORT; } ok: @@ -2312,12 +2429,13 @@ static const char *expandstr(const char *ps); #endif static void -setprompt(int whichprompt) +setprompt_if(smallint do_set, int whichprompt) { const char *prompt; -#if ENABLE_ASH_EXPAND_PRMT - struct stackmark smark; -#endif + IF_ASH_EXPAND_PRMT(struct stackmark smark;) + + if (!do_set) + return; needprompt = 0; @@ -3360,13 +3478,18 @@ setsignal(int signo) switch (new_act) { case S_CATCH: act.sa_handler = signal_handler; - act.sa_flags = 0; /* matters only if !DFL and !IGN */ - sigfillset(&act.sa_mask); /* ditto */ break; case S_IGN: act.sa_handler = SIG_IGN; break; } + + /* flags and mask matter only if !DFL and !IGN, but we do it + * for all cases for more deterministic behavior: + */ + act.sa_flags = 0; + sigfillset(&act.sa_mask); + sigaction_set(signo, &act); *t = new_act; @@ -3403,12 +3526,12 @@ set_curjob(struct job *jp, unsigned mode) /* first remove from list */ jpp = curp = &curjob; - do { + while (1) { jp1 = *jpp; if (jp1 == jp) break; jpp = &jp1->prev_job; - } while (1); + } *jpp = jp1->prev_job; /* Then re-insert in correct position */ @@ -3423,15 +3546,16 @@ set_curjob(struct job *jp, unsigned mode) break; case CUR_RUNNING: /* newly created job or backgrounded job, - put after all stopped jobs. */ - do { + * put after all stopped jobs. + */ + while (1) { jp1 = *jpp; #if JOBS if (!jp1 || jp1->state != JOBSTOPPED) #endif break; jpp = &jp1->prev_job; - } while (1); + } /* FALLTHROUGH */ #if JOBS case CUR_STOPPED: @@ -3604,7 +3728,7 @@ setjobctl(int on) goto out; /* fd is a tty at this point */ close_on_exec_on(fd); - do { /* while we are in the background */ + while (1) { /* while we are in the background */ pgrp = tcgetpgrp(fd); if (pgrp < 0) { out: @@ -3615,7 +3739,7 @@ setjobctl(int on) if (pgrp == getpgrp()) break; killpg(0, SIGTTIN); - } while (1); + } initialpgrp = pgrp; setsignal(SIGTSTP); @@ -3647,18 +3771,51 @@ setjobctl(int on) static int FAST_FUNC killcmd(int argc, char **argv) { - int i = 1; if (argv[1] && strcmp(argv[1], "-l") != 0) { + int i = 1; do { if (argv[i][0] == '%') { - struct job *jp = getjob(argv[i], 0); - unsigned pid = jp->ps[0].ps_pid; - /* Enough space for ' -NNN' */ - argv[i] = alloca(sizeof(int)*3 + 3); - /* kill_main has matching code to expect - * leading space. Needed to not confuse - * negative pids with "kill -SIGNAL_NO" syntax */ - sprintf(argv[i], " -%u", pid); + /* + * "kill %N" - job kill + * Converting to pgrp / pid kill + */ + struct job *jp; + char *dst; + int j, n; + + jp = getjob(argv[i], 0); + /* + * In jobs started under job control, we signal + * entire process group by kill -PGRP_ID. + * This happens, f.e., in interactive shell. + * + * Otherwise, we signal each child via + * kill PID1 PID2 PID3. + * Testcases: + * sh -c 'sleep 1|sleep 1 & kill %1' + * sh -c 'true|sleep 2 & sleep 1; kill %1' + * sh -c 'true|sleep 1 & sleep 2; kill %1' + */ + n = jp->nprocs; /* can't be 0 (I hope) */ + if (jp->jobctl) + n = 1; + dst = alloca(n * sizeof(int)*4); + argv[i] = dst; + for (j = 0; j < n; j++) { + struct procstat *ps = &jp->ps[j]; + /* Skip non-running and not-stopped members + * (i.e. dead members) of the job + */ + if (ps->ps_status != -1 && !WIFSTOPPED(ps->ps_status)) + continue; + /* + * kill_main has matching code to expect + * leading space. Needed to not confuse + * negative pids with "kill -SIGNAL_NO" syntax + */ + dst += sprintf(dst, jp->jobctl ? " -%u" : " %u", (int)ps->ps_pid); + } + *dst = '\0'; } } while (argv[++i]); } @@ -3756,6 +3913,7 @@ sprint_status(char *s, int status, int sigonly) #endif } st &= 0x7f; +//TODO: use bbox's get_signame? strsignal adds ~600 bytes to text+rodata col = fmtstr(s, 32, strsignal(st)); if (WCOREDUMP(status)) { col += fmtstr(s + col, 16, " (core dumped)"); @@ -4090,8 +4248,9 @@ waitcmd(int argc UNUSED_PARAM, char **argv) break; job = job->prev_job; } - } else + } else { job = getjob(*argv, 0); + } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) blocking_wait_with_raise_on_sig(); @@ -4515,6 +4674,7 @@ clear_traps(void) INT_ON; } } + may_have_traps = 0; } /* Lives far away from here, needed for forkchild */ @@ -4586,7 +4746,7 @@ forkchild(struct job *jp, union node *n, int mode) #if JOBS /* do job control only in root shell */ doing_jobctl = 0; - if (mode != FORK_NOJOB && jp->jobctl && !oldlvl) { + if (mode != FORK_NOJOB && jp->jobctl && oldlvl == 0) { pid_t pgrp; if (jp->nprocs == 0) @@ -4612,7 +4772,7 @@ forkchild(struct job *jp, union node *n, int mode) ash_msg_and_raise_error("can't open '%s'", bb_dev_null); } } - if (!oldlvl) { + if (oldlvl == 0) { if (iflag) { /* why if iflag only? */ setsignal(SIGINT); setsignal(SIGTERM); @@ -4819,6 +4979,8 @@ stoppedjobs(void) * Code for dealing with input/output redirection. */ +#undef EMPTY +#undef CLOSED #define EMPTY -2 /* marks an unused slot in redirtab */ #define CLOSED -3 /* marks a slot of previously-closed fd */ @@ -4870,9 +5032,13 @@ noclobberopen(const char *fname) * revealed that it was a regular file, and the file has not been * replaced, return the file descriptor. */ - if (fstat(fd, &finfo2) == 0 && !S_ISREG(finfo2.st_mode) - && finfo.st_dev == finfo2.st_dev && finfo.st_ino == finfo2.st_ino) + if (fstat(fd, &finfo2) == 0 + && !S_ISREG(finfo2.st_mode) + && finfo.st_dev == finfo2.st_dev + && finfo.st_ino == finfo2.st_ino + ) { return fd; + } /* The file has been replaced. badness. */ close(fd); @@ -4927,15 +5093,14 @@ openredirect(union node *redir) char *fname; int f; + fname = redir->nfile.expfname; switch (redir->nfile.type) { case NFROM: - fname = redir->nfile.expfname; f = open(fname, O_RDONLY); if (f < 0) goto eopen; break; case NFROMTO: - fname = redir->nfile.expfname; f = open(fname, O_RDWR|O_CREAT, 0666); if (f < 0) goto ecreate; @@ -4946,7 +5111,6 @@ openredirect(union node *redir) #endif /* Take care of noclobber mode. */ if (Cflag) { - fname = redir->nfile.expfname; f = noclobberopen(fname); if (f < 0) goto ecreate; @@ -4954,13 +5118,11 @@ openredirect(union node *redir) } /* FALLTHROUGH */ case NCLOBBER: - fname = redir->nfile.expfname; f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666); if (f < 0) goto ecreate; break; case NAPPEND: - fname = redir->nfile.expfname; f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666); if (f < 0) goto ecreate; @@ -5315,25 +5477,17 @@ redirectsafe(union node *redir, int flags) static arith_t ash_arith(const char *s) { - arith_eval_hooks_t math_hooks; + arith_state_t math_state; arith_t result; - int errcode = 0; - math_hooks.lookupvar = lookupvar; - math_hooks.setvar = setvar2; - math_hooks.endofname = endofname; + math_state.lookupvar = lookupvar; + math_state.setvar = setvar2; + //math_state.endofname = endofname; INT_OFF; - result = arith(s, &errcode, &math_hooks); - if (errcode < 0) { - if (errcode == -3) - ash_msg_and_raise_error("exponent less than 0"); - if (errcode == -2) - ash_msg_and_raise_error("divide by zero"); - if (errcode == -5) - ash_msg_and_raise_error("expression recursion loop detected"); - raise_error_syntax(s); - } + result = arith(&math_state, s); + if (math_state.errmsg) + ash_msg_and_raise_error(math_state.errmsg); INT_ON; return result; @@ -5391,13 +5545,18 @@ static struct arglist exparg; /* * Our own itoa(). */ +#if !ENABLE_SH_MATH_SUPPORT +/* cvtnum() is used even if math support is off (to prepare $? values and such) */ +typedef long arith_t; +# define ARITH_FMT "%ld" +#endif static int cvtnum(arith_t num) { int len; expdest = makestrspace(32, expdest); - len = fmtstr(expdest, 32, arith_t_fmt, num); + len = fmtstr(expdest, 32, ARITH_FMT, num); STADJUST(len, expdest); return len; } @@ -5568,7 +5727,7 @@ removerecordregions(int endoff) return; if (ifsfirst.endoff > endoff) { - while (ifsfirst.next != NULL) { + while (ifsfirst.next) { struct ifsregion *ifsp; INT_OFF; ifsp = ifsfirst.next->next; @@ -5576,9 +5735,9 @@ removerecordregions(int endoff) ifsfirst.next = ifsp; INT_ON; } - if (ifsfirst.begoff > endoff) + if (ifsfirst.begoff > endoff) { ifslastp = NULL; - else { + } else { ifslastp = &ifsfirst; ifsfirst.endoff = endoff; } @@ -5587,8 +5746,8 @@ removerecordregions(int endoff) ifslastp = &ifsfirst; while (ifslastp->next && ifslastp->next->begoff < endoff) - ifslastp=ifslastp->next; - while (ifslastp->next != NULL) { + ifslastp = ifslastp->next; + while (ifslastp->next) { struct ifsregion *ifsp; INT_OFF; ifsp = ifslastp->next->next; @@ -5743,7 +5902,7 @@ expbackq(union node *cmd, int quoted, int quotes) read: if (in.fd < 0) break; - i = nonblock_safe_read(in.fd, buf, sizeof(buf)); + i = nonblock_immune_read(in.fd, buf, sizeof(buf), /*loop_on_EINTR:*/ 1); TRACE(("expbackq: read returns %d\n", i)); if (i <= 0) break; @@ -5765,9 +5924,9 @@ expbackq(union node *cmd, int quoted, int quotes) if (quoted == 0) recordregion(startloc, dest - (char *)stackblock(), 0); - TRACE(("evalbackq: size=%d: \"%.*s\"\n", - (dest - (char *)stackblock()) - startloc, - (dest - (char *)stackblock()) - startloc, + TRACE(("evalbackq: size:%d:'%.*s'\n", + (int)((dest - (char *)stackblock()) - startloc), + (int)((dest - (char *)stackblock()) - startloc), stackblock() + startloc)); } @@ -5795,7 +5954,7 @@ expari(int quotes) p = expdest - 1; *p = '\0'; p--; - do { + while (1) { int esc; while ((unsigned char)*p != CTLARI) { @@ -5813,7 +5972,7 @@ expari(int quotes) } p -= esc + 1; - } while (1); + } begoff = p - start; @@ -5882,7 +6041,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) flags &= ~EXP_TILDE; tilde: q = p; - if (*q == CTLESC && (flags & EXP_QWORD)) + if ((unsigned char)*q == CTLESC && (flags & EXP_QWORD)) q++; if (*q == '~') p = exptilde(p, q, flags); @@ -5896,9 +6055,7 @@ argstr(char *p, int flags, struct strlist *var_str_list) c = p[length]; if (c) { if (!(c & 0x80) -#if ENABLE_SH_MATH_SUPPORT - || c == CTLENDARI -#endif + IF_SH_MATH_SUPPORT(|| c == CTLENDARI) ) { /* c == '=' || c == ':' || c == CTLENDARI */ length++; @@ -5945,8 +6102,8 @@ argstr(char *p, int flags, struct strlist *var_str_list) /* "$@" syntax adherence hack */ if (!inquotes && memcmp(p, dolatstr, 4) == 0 - && ( p[4] == CTLQUOTEMARK - || (p[4] == CTLENDVAR && p[5] == CTLQUOTEMARK) + && ( p[4] == (char)CTLQUOTEMARK + || (p[4] == (char)CTLENDVAR && p[5] == (char)CTLQUOTEMARK) ) ) { p = evalvar(p + 1, flags, /* var_str_list: */ NULL) + 1; @@ -5965,7 +6122,9 @@ argstr(char *p, int flags, struct strlist *var_str_list) length++; goto addquote; case CTLVAR: + TRACE(("argstr: evalvar('%s')\n", p)); p = evalvar(p, flags, var_str_list); + TRACE(("argstr: evalvar:'%s'\n", (char *)stackblock())); goto start; case CTLBACKQ: c = '\0'; @@ -5981,47 +6140,20 @@ argstr(char *p, int flags, struct strlist *var_str_list) #endif } } - breakloop: - ; + breakloop: ; } static char * -scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int quotes, - int zero) -{ -// This commented out code was added by James Simmons -// as part of a larger change when he added support for ${var/a/b}. -// However, it broke # and % operators: -// -//var=ababcdcd -// ok bad -//echo ${var#ab} abcdcd abcdcd -//echo ${var##ab} abcdcd abcdcd -//echo ${var#a*b} abcdcd ababcdcd (!) -//echo ${var##a*b} cdcd cdcd -//echo ${var#?} babcdcd ababcdcd (!) -//echo ${var##?} babcdcd babcdcd -//echo ${var#*} ababcdcd babcdcd (!) -//echo ${var##*} -//echo ${var%cd} ababcd ababcd -//echo ${var%%cd} ababcd abab (!) -//echo ${var%c*d} ababcd ababcd -//echo ${var%%c*d} abab ababcdcd (!) -//echo ${var%?} ababcdc ababcdc -//echo ${var%%?} ababcdc ababcdcd (!) -//echo ${var%*} ababcdcd ababcdcd -//echo ${var%%*} -// -// Commenting it back out helped. Remove it completely if it really -// is not needed. - - char *loc, *loc2; //, *full; +scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, + char *pattern, int quotes, int zero) +{ + char *loc, *loc2; char c; loc = startp; loc2 = rmesc; do { - int match; // = strlen(str); + int match; const char *s = loc2; c = *loc2; @@ -6029,35 +6161,22 @@ scanleft(char *startp, char *rmesc, char *rmescend UNUSED_PARAM, char *str, int *loc2 = '\0'; s = rmesc; } - match = pmatch(str, s); // this line was deleted - -// // chop off end if its '*' -// full = strrchr(str, '*'); -// if (full && full != str) -// match--; -// -// // If str starts with '*' replace with s. -// if ((*str == '*') && strlen(s) >= match) { -// full = xstrdup(s); -// strncpy(full+strlen(s)-match+1, str+1, match-1); -// } else -// full = xstrndup(str, match); -// match = strncmp(s, full, strlen(full)); -// free(full); -// + match = pmatch(pattern, s); + *loc2 = c; - if (match) // if (!match) + if (match) return loc; if (quotes && (unsigned char)*loc == CTLESC) loc++; loc++; loc2++; } while (c); - return 0; + return NULL; } static char * -scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, int match_at_start) +scanright(char *startp, char *rmesc, char *rmescend, + char *pattern, int quotes, int match_at_start) { #if !ENABLE_ASH_OPTIMIZE_FOR_SIZE int try2optimize = match_at_start; @@ -6123,7 +6242,7 @@ scanright(char *startp, char *rmesc, char *rmescend, char *pattern, int quotes, } } } - return 0; + return NULL; } static void varunset(const char *, const char *, const char *, int) NORETURN; @@ -6143,16 +6262,18 @@ varunset(const char *end, const char *var, const char *umsg, int varflags) msg = umsg; } } - ash_msg_and_raise_error("%.*s: %s%s", end - var - 1, var, msg, tail); + ash_msg_and_raise_error("%.*s: %s%s", (int)(end - var - 1), var, msg, tail); } #if ENABLE_ASH_BASH_COMPAT static char * -parse_sub_pattern(char *arg, int inquotes) +parse_sub_pattern(char *arg, int varflags) { char *idx, *repl = NULL; unsigned char c; + //char *org_arg = arg; + //bb_error_msg("arg:'%s' varflags:%x", arg, varflags); idx = arg; while (1) { c = *arg; @@ -6166,31 +6287,48 @@ parse_sub_pattern(char *arg, int inquotes) } } *idx++ = c; - if (!inquotes && c == '\\' && arg[1] == '\\') - arg++; /* skip both \\, not just first one */ arg++; + /* + * Example: v='ab\c'; echo ${v/\\b/_\\_\z_} + * The result is a_\_z_c (not a\_\_z_c)! + * + * Enable debug prints in this function and you'll see: + * ash: arg:'\\b/_\\_z_' varflags:d + * ash: pattern:'\\b' repl:'_\_z_' + * That is, \\b is interpreted as \\b, but \\_ as \_! + * IOW: search pattern and replace string treat backslashes + * differently! That is the reason why we check repl below: + */ + if (c == '\\' && *arg == '\\' && repl && !(varflags & VSQUOTE)) + arg++; /* skip both '\', not just first one */ } *idx = c; /* NUL */ + //bb_error_msg("pattern:'%s' repl:'%s'", org_arg, repl); return repl; } #endif /* ENABLE_ASH_BASH_COMPAT */ static const char * -subevalvar(char *p, char *str, int strloc, int subtype, +subevalvar(char *p, char *varname, int strloc, int subtype, int startloc, int varflags, int quotes, struct strlist *var_str_list) { struct nodelist *saveargbackq = argbackq; char *startp; char *loc; char *rmesc, *rmescend; + char *str; IF_ASH_BASH_COMPAT(const char *repl = NULL;) IF_ASH_BASH_COMPAT(int pos, len, orig_len;) int saveherefd = herefd; - int amount, workloc, resetloc; + int amount, resetloc; + IF_ASH_BASH_COMPAT(int workloc;) int zero; char *(*scan)(char*, char*, char*, char*, int, int); + //bb_error_msg("subevalvar(p:'%s',varname:'%s',strloc:%d,subtype:%d,startloc:%d,varflags:%x,quotes:%d)", + // p, varname, strloc, subtype, startloc, varflags, quotes); + herefd = -1; argstr(p, (subtype != VSASSIGN && subtype != VSQUESTION) ? EXP_CASE : 0, var_str_list); @@ -6201,11 +6339,15 @@ subevalvar(char *p, char *str, int strloc, int subtype, switch (subtype) { case VSASSIGN: - setvar(str, startp, 0); + setvar2(varname, startp); amount = startp - expdest; STADJUST(amount, expdest); return startp; + case VSQUESTION: + varunset(p, varname, startp, varflags); + /* NOTREACHED */ + #if ENABLE_ASH_BASH_COMPAT case VSSUBSTR: loc = str = stackblock() + strloc; @@ -6266,11 +6408,8 @@ subevalvar(char *p, char *str, int strloc, int subtype, STADJUST(amount, expdest); return loc; #endif - - case VSQUESTION: - varunset(p, str, startp, varflags); - /* NOTREACHED */ } + resetloc = expdest - (char *)stackblock(); /* We'll comeback here if we grow the stack while handling @@ -6296,21 +6435,22 @@ subevalvar(char *p, char *str, int strloc, int subtype, rmescend--; str = (char *)stackblock() + strloc; preglob(str, varflags & VSQUOTE, 0); - workloc = expdest - (char *)stackblock(); #if ENABLE_ASH_BASH_COMPAT + workloc = expdest - (char *)stackblock(); if (subtype == VSREPLACE || subtype == VSREPLACEALL) { char *idx, *end; if (!repl) { - repl = parse_sub_pattern(str, varflags & VSQUOTE); + repl = parse_sub_pattern(str, varflags); + //bb_error_msg("repl:'%s'", repl); if (!repl) repl = nullstr; } /* If there's no pattern to match, return the expansion unmolested */ if (str[0] == '\0') - return 0; + return NULL; len = 0; idx = startp; @@ -6318,6 +6458,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, while (idx < end) { try_to_match: loc = scanright(idx, rmesc, rmescend, str, quotes, 1); + //bb_error_msg("scanright('%s'):'%s'", str, loc); if (!loc) { /* No match, advance */ char *restart_detect = stackblock(); @@ -6356,6 +6497,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, idx = loc; } + //bb_error_msg("repl:'%s'", repl); for (loc = (char*)repl; *loc; loc++) { char *restart_detect = stackblock(); if (quotes && *loc == '\\') { @@ -6369,12 +6511,9 @@ subevalvar(char *p, char *str, int strloc, int subtype, } if (subtype == VSREPLACE) { + //bb_error_msg("tail:'%s', quotes:%x", idx, quotes); while (*idx) { char *restart_detect = stackblock(); - if (quotes && *idx == '\\') { - STPUTC(CTLESC, expdest); - len++; - } STPUTC(*idx, expdest); if (stackblock() != restart_detect) goto restart; @@ -6391,6 +6530,7 @@ subevalvar(char *p, char *str, int strloc, int subtype, STPUTC('\0', expdest); startp = (char *)stackblock() + startloc; memmove(startp, (char *)stackblock() + workloc, len + 1); + //bb_error_msg("startp:'%s'", startp); amount = expdest - (startp + len); STADJUST(-amount, expdest); return startp; @@ -6620,8 +6760,8 @@ evalvar(char *p, int flags, struct strlist *var_str_list) vsplus: if (varlen < 0) { argstr( - p, flags | EXP_TILDE | - (quoted ? EXP_QWORD : EXP_WORD), + p, + flags | (quoted ? EXP_TILDE|EXP_QWORD : EXP_TILDE|EXP_WORD), var_str_list ); goto end; @@ -6691,10 +6831,9 @@ evalvar(char *p, int flags, struct strlist *var_str_list) */ STPUTC('\0', expdest); patloc = expdest - (char *)stackblock(); - if (NULL == subevalvar(p, /* str: */ NULL, patloc, subtype, + if (NULL == subevalvar(p, /* varname: */ NULL, patloc, subtype, startloc, varflags, -//TODO: | EXP_REDIR too? All other such places do it too - /* quotes: */ flags & (EXP_FULL | EXP_CASE), + /* quotes: */ flags & (EXP_FULL | EXP_CASE | EXP_REDIR), var_str_list) ) { int amount = expdest - ( @@ -7096,6 +7235,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag) STARTSTACKSTR(expdest); ifsfirst.next = NULL; ifslastp = NULL; + TRACE(("expandarg: argstr('%s',flags:%x)\n", arg->narg.text, flag)); argstr(arg->narg.text, flag, /* var_str_list: */ arglist ? arglist->list : NULL); p = _STPUTC('\0', expdest); @@ -7104,6 +7244,7 @@ expandarg(union node *arg, struct arglist *arglist, int flag) return; /* here document expanded */ } p = grabstackstr(p); + TRACE(("expandarg: p:'%s'\n", p)); exparg.lastp = &exparg.list; /* * TODO - EXP_REDIR @@ -7114,8 +7255,10 @@ expandarg(union node *arg, struct arglist *arglist, int flag) exparg.lastp = &exparg.list; expandmeta(exparg.list /*, flag*/); } else { - if (flag & EXP_REDIR) /*XXX - for now, just remove escapes */ + if (flag & EXP_REDIR) { /*XXX - for now, just remove escapes */ rmescapes(p, 0); + TRACE(("expandarg: rmescapes:'%s'\n", p)); + } sp = stzalloc(sizeof(*sp)); sp->text = p; *exparg.lastp = sp; @@ -7243,8 +7386,6 @@ static int builtinloc = -1; /* index in path of %builtin, or -1 */ static void tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp) { - int repeated = 0; - #if ENABLE_FEATURE_SH_STANDALONE if (applet_no >= 0) { if (APPLET_IS_NOEXEC(applet_no)) { @@ -7268,25 +7409,42 @@ tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char ** #else execve(cmd, argv, envp); #endif - if (repeated) { + if (cmd == (char*) bb_busybox_exec_path) { + /* We already visited ENOEXEC branch below, don't do it again */ +//TODO: try execve(initial_argv0_of_shell, argv, envp) before giving up? free(argv); return; } if (errno == ENOEXEC) { + /* Run "cmd" as a shell script: + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html + * "If the execve() function fails with ENOEXEC, the shell + * shall execute a command equivalent to having a shell invoked + * with the command name as its first operand, + * with any remaining arguments passed to the new shell" + * + * That is, do not use $SHELL, user's shell, or /bin/sh; + * just call ourselves. + * + * Note that bash reads ~80 chars of the file, and if it sees + * a zero byte before it sees newline, it doesn't try to + * interpret it, but fails with "cannot execute binary file" + * message and exit code 126. For one, this prevents attempts + * to interpret foreign ELF binaries as shell scripts. + */ char **ap; char **new; for (ap = argv; *ap; ap++) continue; - ap = new = ckmalloc((ap - argv + 2) * sizeof(ap[0])); - ap[1] = cmd; - ap[0] = cmd = (char *)DEFAULT_SHELL; - ap += 2; - argv++; - while ((*ap++ = *argv++) != NULL) + new = ckmalloc((ap - argv + 2) * sizeof(new[0])); + new[0] = (char*) "ash"; + new[1] = cmd; + ap = new + 2; + while ((*ap++ = *++argv) != NULL) continue; + cmd = (char*) bb_busybox_exec_path; argv = new; - repeated++; goto repeat; } } @@ -7303,9 +7461,7 @@ shellexec(char **argv, const char *path, int idx) int e; char **envp; int exerrno; -#if ENABLE_FEATURE_SH_STANDALONE - int applet_no = -1; -#endif + int applet_no = -1; /* used only by FEATURE_SH_STANDALONE */ clearredir(/*drop:*/ 1); envp = listvars(VEXPORT, VUNSET, /*end:*/ NULL); @@ -7315,8 +7471,16 @@ shellexec(char **argv, const char *path, int idx) #endif ) { tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp); + if (applet_no >= 0) { + /* We tried execing ourself, but it didn't work. + * Maybe /proc/self/exe doesn't exist? + * Try $PATH search. + */ + goto try_PATH; + } e = errno; } else { + try_PATH: e = ENOENT; while ((cmdname = path_advance(&path, argv[0])) != NULL) { if (--idx < 0 && pathopt == NULL) { @@ -7526,7 +7690,7 @@ hashcd(void) for (cmdp = *pp; cmdp; cmdp = cmdp->next) { if (cmdp->cmdtype == CMDNORMAL || (cmdp->cmdtype == CMDBUILTIN - && !IS_BUILTIN_REGULAR(cmdp->param.cmd) + && !IS_BUILTIN_REGULAR(cmdp->param.cmd) && builtinloc > 0) ) { cmdp->rehash = 1; @@ -8117,7 +8281,7 @@ static int evalstring(char *s, int mask); /* Called to execute a trap. * Single callsite - at the end of evaltree(). - * If we return non-zero, exaltree raises EXEXIT exception. + * If we return non-zero, evaltree raises EXEXIT exception. * * Perhaps we should avoid entering new trap handlers * while we are executing a trap handler. [is it a TODO?] @@ -8307,11 +8471,15 @@ evaltree(union node *n, int flags) out: exception_handler = savehandler; + out1: + /* Order of checks below is important: + * signal handlers trigger before exit caused by "set -e". + */ + if (pending_sig && dotrap()) + goto exexit; if (checkexit & exitstatus) evalskip |= SKIPEVAL; - else if (pending_sig && dotrap()) - goto exexit; if (flags & EV_EXIT) { exexit: @@ -8386,7 +8554,7 @@ evalfor(union node *n, int flags) loopnest++; flags &= EV_TESTED; for (sp = arglist.list; sp; sp = sp->next) { - setvar(n->nfor.var, sp->text, 0); + setvar2(n->nfor.var, sp->text); evaltree(n->nfor.body, flags); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { @@ -8487,9 +8655,21 @@ expredir(union node *n) case NCLOBBER: case NAPPEND: expandarg(redir->nfile.fname, &fn, EXP_TILDE | EXP_REDIR); + TRACE(("expredir expanded to '%s'\n", fn.list->text)); #if ENABLE_ASH_BASH_COMPAT store_expfname: #endif +#if 0 +// By the design of stack allocator, the loop of this kind: +// while true; do while true; do break; done nfile.expfname) + stunalloc(redir->nfile.expfname); +// It results in corrupted state of stacked allocations. +#endif redir->nfile.expfname = fn.list->text; break; case NFROMFD: @@ -8643,7 +8823,7 @@ poplocalvars(void) while ((lvp = localvars) != NULL) { localvars = lvp->next; vp = lvp->vp; - TRACE(("poplocalvar %s\n", vp ? vp->text : "-")); + TRACE(("poplocalvar %s\n", vp ? vp->var_text : "-")); if (vp == NULL) { /* $- saved */ memcpy(optlist, lvp->text, sizeof(optlist)); free((char*)lvp->text); @@ -8853,6 +9033,9 @@ static int getoptscmd(int, char **) FAST_FUNC; #if !ENABLE_FEATURE_SH_EXTRA_QUIET static int helpcmd(int, char **) FAST_FUNC; #endif +#if MAX_HISTORY +static int historycmd(int, char **) FAST_FUNC; +#endif #if ENABLE_SH_MATH_SUPPORT static int letcmd(int, char **) FAST_FUNC; #endif @@ -8926,6 +9109,9 @@ static const struct builtincmd builtintab[] = { #if !ENABLE_FEATURE_SH_EXTRA_QUIET { BUILTIN_NOSPEC "help" , helpcmd }, #endif +#if MAX_HISTORY + { BUILTIN_NOSPEC "history" , historycmd }, +#endif #if JOBS { BUILTIN_REGULAR "jobs" , jobscmd }, { BUILTIN_REGULAR "kill" , killcmd }, @@ -9125,11 +9311,11 @@ evalcommand(union node *cmd, int flags) /* Now locate the command. */ if (argc) { - const char *oldpath; int cmd_flag = DO_ERR; - +#if ENABLE_ASH_CMDCMD + const char *oldpath = path + 5; +#endif path += 5; - oldpath = path; for (;;) { find_command(argv[0], &cmdentry, cmd_flag, path); if (cmdentry.cmdtype == CMDUNKNOWN) { @@ -9265,7 +9451,7 @@ evalcommand(union node *cmd, int flags) * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ - setvar("_", lastarg, 0); + setvar2("_", lastarg); } popstackmark(&smark); } @@ -9301,7 +9487,7 @@ evalbltin(const struct builtincmd *cmd, int argc, char **argv) static int goodname(const char *p) { - return !*endofname(p); + return endofname(p)[0] == '\0'; } @@ -9451,12 +9637,33 @@ preadfd(void) #if ENABLE_FEATURE_EDITING retry: if (!iflag || g_parsefile->pf_fd != STDIN_FILENO) - nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); else { -#if ENABLE_FEATURE_TAB_COMPLETION + int timeout = -1; +# if ENABLE_ASH_IDLE_TIMEOUT + if (iflag) { + const char *tmout_var = lookupvar("TMOUT"); + if (tmout_var) { + timeout = atoi(tmout_var) * 1000; + if (timeout <= 0) + timeout = -1; + } + } +# endif +# if ENABLE_FEATURE_TAB_COMPLETION line_input_state->path_lookup = pathval(); -#endif - nr = read_line_input(cmdedit_prompt, buf, IBUFSIZ, line_input_state); +# endif + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + { + const char *s = lookupvar("LC_ALL"); + if (!s) s = lookupvar("LC_CTYPE"); + if (!s) s = lookupvar("LANG"); + reinit_unicode(s); + } + nr = read_line_input(line_input_state, cmdedit_prompt, buf, IBUFSIZ, timeout); if (nr == 0) { /* Ctrl+C pressed */ if (trap[SIGINT]) { @@ -9467,17 +9674,24 @@ preadfd(void) } goto retry; } - if (nr < 0 && errno == 0) { - /* Ctrl+D pressed */ - nr = 0; + if (nr < 0) { + if (errno == 0) { + /* Ctrl+D pressed */ + nr = 0; + } +# if ENABLE_ASH_IDLE_TIMEOUT + else if (errno == EAGAIN && timeout > 0) { + printf("\007timed out waiting for input: auto-logout\n"); + exitshell(); + } +# endif } } #else - nr = nonblock_safe_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1); + nr = nonblock_immune_read(g_parsefile->pf_fd, buf, IBUFSIZ - 1, /*loop_on_EINTR:*/ 1); #endif -#if 0 -/* nonblock_safe_read() handles this problem */ +#if 0 /* disabled: nonblock_immune_read() handles this problem */ if (nr < 0) { if (parsefile->fd == 0 && errno == EWOULDBLOCK) { int flags = fcntl(0, F_GETFL); @@ -9996,7 +10210,7 @@ options(int cmdline) else if (*argptr == NULL) setparam(argptr); } - break; /* "-" or "--" terminates options */ + break; /* "-" or "--" terminates options */ } } /* first char was + or - */ @@ -10098,10 +10312,10 @@ setcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) if (!argv[1]) return showvars(nullstr, 0, VUNSET); + INT_OFF; - retval = 1; - if (!options(0)) { /* if no parse error... */ - retval = 0; + retval = options(/*cmdline:*/ 0); + if (retval == 0) { /* if no parse error... */ optschanged(); if (*argptr != NULL) { setparam(argptr); @@ -10932,7 +11146,6 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) startlinno = g_parsefile->linno; bqlist = NULL; quotef = 0; - oldstyle = 0; prevsyntax = 0; #if ENABLE_ASH_EXPAND_PRMT pssyntax = (syntax == PSSYNTAX); @@ -10948,160 +11161,156 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) STARTSTACKSTR(out); loop: /* For each line, until end of word */ - { - CHECKEND(); /* set c to PEOF if at end of here document */ - for (;;) { /* until end of line or end of word */ - CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ - switch (SIT(c, syntax)) { - case CNL: /* '\n' */ - if (syntax == BASESYNTAX) - goto endword; /* exit outer loop */ - USTPUTC(c, out); - g_parsefile->linno++; - if (doprompt) - setprompt(2); - c = pgetc(); - goto loop; /* continue outer loop */ - case CWORD: - USTPUTC(c, out); - break; - case CCTL: - if (eofmark == NULL || dblquote) - USTPUTC(CTLESC, out); + CHECKEND(); /* set c to PEOF if at end of here document */ + for (;;) { /* until end of line or end of word */ + CHECKSTRSPACE(4, out); /* permit 4 calls to USTPUTC */ + switch (SIT(c, syntax)) { + case CNL: /* '\n' */ + if (syntax == BASESYNTAX) + goto endword; /* exit outer loop */ + USTPUTC(c, out); + g_parsefile->linno++; + setprompt_if(doprompt, 2); + c = pgetc(); + goto loop; /* continue outer loop */ + case CWORD: + USTPUTC(c, out); + break; + case CCTL: + if (eofmark == NULL || dblquote) + USTPUTC(CTLESC, out); #if ENABLE_ASH_BASH_COMPAT - if (c == '\\' && bash_dollar_squote) { - c = decode_dollar_squote(); - if (c & 0x100) { - USTPUTC('\\', out); - c = (unsigned char)c; - } + if (c == '\\' && bash_dollar_squote) { + c = decode_dollar_squote(); + if (c & 0x100) { + USTPUTC('\\', out); + c = (unsigned char)c; } + } #endif - USTPUTC(c, out); - break; - case CBACK: /* backslash */ - c = pgetc_without_PEOA(); - if (c == PEOF) { + USTPUTC(c, out); + break; + case CBACK: /* backslash */ + c = pgetc_without_PEOA(); + if (c == PEOF) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); + pungetc(); + } else if (c == '\n') { + setprompt_if(doprompt, 2); + } else { +#if ENABLE_ASH_EXPAND_PRMT + if (c == '$' && pssyntax) { USTPUTC(CTLESC, out); USTPUTC('\\', out); - pungetc(); - } else if (c == '\n') { - if (doprompt) - setprompt(2); - } else { -#if ENABLE_ASH_EXPAND_PRMT - if (c == '$' && pssyntax) { - USTPUTC(CTLESC, out); - USTPUTC('\\', out); - } + } #endif - if (dblquote && c != '\\' - && c != '`' && c != '$' - && (c != '"' || eofmark != NULL) - ) { - USTPUTC(CTLESC, out); - USTPUTC('\\', out); - } - if (SIT(c, SQSYNTAX) == CCTL) - USTPUTC(CTLESC, out); - USTPUTC(c, out); - quotef = 1; + /* Backslash is retained if we are in "str" and next char isn't special */ + if (dblquote + && c != '\\' + && c != '`' + && c != '$' + && (c != '"' || eofmark != NULL) + ) { + USTPUTC(CTLESC, out); + USTPUTC('\\', out); } - break; - case CSQUOTE: - syntax = SQSYNTAX; + if (SIT(c, SQSYNTAX) == CCTL) + USTPUTC(CTLESC, out); + USTPUTC(c, out); + quotef = 1; + } + break; + case CSQUOTE: + syntax = SQSYNTAX; quotemark: - if (eofmark == NULL) { - USTPUTC(CTLQUOTEMARK, out); + if (eofmark == NULL) { + USTPUTC(CTLQUOTEMARK, out); + } + break; + case CDQUOTE: + syntax = DQSYNTAX; + dblquote = 1; + goto quotemark; + case CENDQUOTE: + IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) + if (eofmark != NULL && arinest == 0 + && varnest == 0 + ) { + USTPUTC(c, out); + } else { + if (dqvarnest == 0) { + syntax = BASESYNTAX; + dblquote = 0; } - break; - case CDQUOTE: - syntax = DQSYNTAX; - dblquote = 1; + quotef = 1; goto quotemark; - case CENDQUOTE: - IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;) - if (eofmark != NULL && arinest == 0 - && varnest == 0 - ) { - USTPUTC(c, out); - } else { - if (dqvarnest == 0) { - syntax = BASESYNTAX; - dblquote = 0; - } - quotef = 1; - goto quotemark; - } - break; - case CVAR: /* '$' */ - PARSESUB(); /* parse substitution */ - break; - case CENDVAR: /* '}' */ - if (varnest > 0) { - varnest--; - if (dqvarnest > 0) { - dqvarnest--; - } - USTPUTC(CTLENDVAR, out); - } else { - USTPUTC(c, out); + } + break; + case CVAR: /* '$' */ + PARSESUB(); /* parse substitution */ + break; + case CENDVAR: /* '}' */ + if (varnest > 0) { + varnest--; + if (dqvarnest > 0) { + dqvarnest--; } - break; + c = CTLENDVAR; + } + USTPUTC(c, out); + break; #if ENABLE_SH_MATH_SUPPORT - case CLP: /* '(' in arithmetic */ - parenlevel++; - USTPUTC(c, out); - break; - case CRP: /* ')' in arithmetic */ - if (parenlevel > 0) { - USTPUTC(c, out); - --parenlevel; - } else { - if (pgetc() == ')') { - if (--arinest == 0) { - USTPUTC(CTLENDARI, out); - syntax = prevsyntax; - dblquote = (syntax == DQSYNTAX); - } else - USTPUTC(')', out); - } else { - /* - * unbalanced parens - * (don't 2nd guess - no error) - */ - pungetc(); - USTPUTC(')', out); + case CLP: /* '(' in arithmetic */ + parenlevel++; + USTPUTC(c, out); + break; + case CRP: /* ')' in arithmetic */ + if (parenlevel > 0) { + parenlevel--; + } else { + if (pgetc() == ')') { + if (--arinest == 0) { + syntax = prevsyntax; + dblquote = (syntax == DQSYNTAX); + c = CTLENDARI; } + } else { + /* + * unbalanced parens + * (don't 2nd guess - no error) + */ + pungetc(); } - break; + } + USTPUTC(c, out); + break; #endif - case CBQUOTE: /* '`' */ - PARSEBACKQOLD(); - break; - case CENDFILE: - goto endword; /* exit outer loop */ - case CIGN: - break; - default: - if (varnest == 0) { + case CBQUOTE: /* '`' */ + PARSEBACKQOLD(); + break; + case CENDFILE: + goto endword; /* exit outer loop */ + case CIGN: + break; + default: + if (varnest == 0) { #if ENABLE_ASH_BASH_COMPAT - if (c == '&') { - if (pgetc() == '>') - c = 0x100 + '>'; /* flag &> */ - pungetc(); - } -#endif - goto endword; /* exit outer loop */ + if (c == '&') { + if (pgetc() == '>') + c = 0x100 + '>'; /* flag &> */ + pungetc(); } - IF_ASH_ALIAS(if (c != PEOA)) - USTPUTC(c, out); - +#endif + goto endword; /* exit outer loop */ } - c = pgetc_fast(); - } /* for (;;) */ - } + IF_ASH_ALIAS(if (c != PEOA)) + USTPUTC(c, out); + } + c = pgetc_fast(); + } /* for (;;) */ endword: + #if ENABLE_SH_MATH_SUPPORT if (syntax == ARISYNTAX) raise_error_syntax("missing '))'"); @@ -11262,8 +11471,6 @@ parsesub: { unsigned char subtype; int typeloc; int flags; - char *p; - static const char types[] ALIGN1 = "}-+?="; c = pgetc(); if (c > 255 /* PEOA or PEOF */ @@ -11276,7 +11483,8 @@ parsesub: { #endif USTPUTC('$', out); pungetc(); - } else if (c == '(') { /* $(command) or $((arith)) */ + } else if (c == '(') { + /* $(command) or $((arith)) */ if (pgetc() == '(') { #if ENABLE_SH_MATH_SUPPORT PARSEARITH(); @@ -11288,6 +11496,7 @@ parsesub: { PARSEBACKQNEW(); } } else { + /* $VAR, $, ${...}, or PEOA/PEOF */ USTPUTC(CTLVAR, out); typeloc = out - (char *)stackblock(); USTPUTC(VSNORMAL, out); @@ -11297,76 +11506,90 @@ parsesub: { if (c == '#') { c = pgetc(); if (c == '}') - c = '#'; + c = '#'; /* ${#} - same as $# */ else - subtype = VSLENGTH; - } else + subtype = VSLENGTH; /* ${#VAR} */ + } else { subtype = 0; + } } if (c <= 255 /* not PEOA or PEOF */ && is_name(c)) { + /* $[{[#]]NAME[}] */ do { STPUTC(c, out); c = pgetc(); } while (c <= 255 /* not PEOA or PEOF */ && is_in_name(c)); } else if (isdigit(c)) { + /* $[{[#]]NUM[}] */ do { STPUTC(c, out); c = pgetc(); } while (isdigit(c)); } else if (is_special(c)) { + /* $[{[#]][}] */ USTPUTC(c, out); c = pgetc(); } else { badsub: raise_error_syntax("bad substitution"); } - if (c != '}' && subtype == VSLENGTH) + if (c != '}' && subtype == VSLENGTH) { + /* ${#VAR didn't end with } */ goto badsub; + } STPUTC('=', out); flags = 0; if (subtype == 0) { + /* ${VAR...} but not $VAR or ${#VAR} */ + /* c == first char after VAR */ switch (c) { case ':': c = pgetc(); #if ENABLE_ASH_BASH_COMPAT if (c == ':' || c == '$' || isdigit(c)) { - pungetc(); +//TODO: support more general format ${v:EXPR:EXPR}, +// where EXPR follows $(()) rules subtype = VSSUBSTR; - break; + pungetc(); + break; /* "goto do_pungetc" is bigger (!) */ } #endif flags = VSNUL; /*FALLTHROUGH*/ - default: - p = strchr(types, c); + default: { + static const char types[] ALIGN1 = "}-+?="; + const char *p = strchr(types, c); if (p == NULL) goto badsub; subtype = p - types + VSNORMAL; break; + } case '%': case '#': { int cc = c; - subtype = c == '#' ? VSTRIMLEFT : VSTRIMRIGHT; + subtype = (c == '#' ? VSTRIMLEFT : VSTRIMRIGHT); c = pgetc(); - if (c == cc) - subtype++; - else - pungetc(); + if (c != cc) + goto do_pungetc; + subtype++; break; } #if ENABLE_ASH_BASH_COMPAT case '/': + /* ${v/[/]pattern/repl} */ +//TODO: encode pattern and repl separately. +// Currently ${v/$var_with_slash/repl} is horribly broken subtype = VSREPLACE; c = pgetc(); - if (c == '/') - subtype++; /* VSREPLACEALL */ - else - pungetc(); + if (c != '/') + goto do_pungetc; + subtype++; /* VSREPLACEALL */ break; #endif } } else { + do_pungetc: pungetc(); } if (dblquote || arinest) @@ -11420,19 +11643,18 @@ parsebackq: { INT_ON; if (oldstyle) { /* We must read until the closing backquote, giving special - treatment to some slashes, and then push the string and - reread it as input, interpreting it normally. */ + * treatment to some slashes, and then push the string and + * reread it as input, interpreting it normally. + */ char *pout; - int pc; size_t psavelen; char *pstr; - STARTSTACKSTR(pout); for (;;) { - if (needprompt) { - setprompt(2); - } + int pc; + + setprompt_if(needprompt, 2); pc = pgetc(); switch (pc) { case '`': @@ -11442,8 +11664,7 @@ parsebackq: { pc = pgetc(); if (pc == '\n') { g_parsefile->linno++; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); /* * If eating a newline, avoid putting * the newline into the new character @@ -11606,9 +11827,7 @@ xxreadtoken(void) tokpushback = 0; return lasttoken; } - if (needprompt) { - setprompt(2); - } + setprompt_if(needprompt, 2); startlinno = g_parsefile->linno; for (;;) { /* until token or start of word found */ c = pgetc_fast(); @@ -11625,8 +11844,7 @@ xxreadtoken(void) break; /* return readtoken1(...) */ } startlinno = ++g_parsefile->linno; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); } else { const char *p; @@ -11672,9 +11890,7 @@ xxreadtoken(void) tokpushback = 0; return lasttoken; } - if (needprompt) { - setprompt(2); - } + setprompt_if(needprompt, 2); startlinno = g_parsefile->linno; for (;;) { /* until token or start of word found */ c = pgetc_fast(); @@ -11690,8 +11906,7 @@ xxreadtoken(void) case '\\': if (pgetc() == '\n') { startlinno = ++g_parsefile->linno; - if (doprompt) - setprompt(2); + setprompt_if(doprompt, 2); continue; } pungetc(); @@ -11817,8 +12032,7 @@ parsecmd(int interact) tokpushback = 0; doprompt = interact; - if (doprompt) - setprompt(doprompt); + setprompt_if(doprompt, doprompt); needprompt = 0; t = readtoken(); if (t == TEOF) @@ -11842,10 +12056,8 @@ parseheredoc(void) heredoclist = NULL; while (here) { - if (needprompt) { - setprompt(2); - } - readtoken1(pgetc(), here->here->type == NHERE? SQSYNTAX : DQSYNTAX, + setprompt_if(needprompt, 2); + readtoken1(pgetc(), here->here->type == NHERE ? SQSYNTAX : DQSYNTAX, here->eofmark, here->striptabs); n = stzalloc(sizeof(struct narg)); n->narg.type = NARG; @@ -11936,7 +12148,6 @@ evalcmd(int argc UNUSED_PARAM, char **argv) p = grabstackstr(concat); } evalstring(p, ~SKIPEVAL); - } return exitstatus; } @@ -11966,9 +12177,7 @@ cmdloop(int top) inter = 0; if (iflag && top) { inter++; -#if ENABLE_ASH_MAIL chkmail(); -#endif } n = parsecmd(inter); #if DEBUG @@ -12060,8 +12269,10 @@ dotcmd(int argc, char **argv) /* "false; . empty_file; echo $?" should print 0, not 1: */ exitstatus = 0; + /* This aborts if file isn't found, which is POSIXly correct. + * bash returns exitcode 1 instead. + */ fullname = find_dot_file(argv[1]); - argv += 2; argc -= 2; if (argc) { /* argc > 0, argv[0] != NULL */ @@ -12071,6 +12282,9 @@ dotcmd(int argc, char **argv) shellparam.p = argv; }; + /* This aborts if file can't be opened, which is POSIXly correct. + * bash returns exitcode 1 instead. + */ setinputfile(fullname, INPUT_PUSH_FILE); commandname = fullname; cmdloop(0); @@ -12228,7 +12442,7 @@ find_command(char *name, struct cmdentry *entry, int act, const char *path) } if ((act & DO_NOFUNC) || !prefix(pathopt, "func") - ) { /* ignore unimplemented options */ + ) { /* ignore unimplemented options */ continue; } } @@ -12417,6 +12631,15 @@ helpcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } #endif /* FEATURE_SH_EXTRA_QUIET */ +#if MAX_HISTORY +static int FAST_FUNC +historycmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + show_history(line_input_state); + return EXIT_SUCCESS; +} +#endif + /* * The export and readonly commands. */ @@ -12427,9 +12650,27 @@ exportcmd(int argc UNUSED_PARAM, char **argv) char *name; const char *p; char **aptr; - int flag = argv[0][0] == 'r' ? VREADONLY : VEXPORT; + char opt; + int flag; + int flag_off; + + /* "readonly" in bash accepts, but ignores -n. + * We do the same: it saves a conditional in nextopt's param. + */ + flag_off = 0; + while ((opt = nextopt("np")) != '\0') { + if (opt == 'n') + flag_off = VEXPORT; + } + flag = VEXPORT; + if (argv[0][0] == 'r') { + flag = VREADONLY; + flag_off = 0; /* readonly ignores -n */ + } + flag_off = ~flag_off; - if (nextopt("p") != 'p') { + /*if (opt_p_not_specified) - bash doesnt check this. Try "export -p NAME" */ + { aptr = argptr; name = *aptr; if (name) { @@ -12440,15 +12681,19 @@ exportcmd(int argc UNUSED_PARAM, char **argv) } else { vp = *findvar(hashvar(name), name); if (vp) { - vp->flags |= flag; + vp->flags = ((vp->flags | flag) & flag_off); continue; } } - setvar(name, p, flag); + setvar(name, p, (flag & flag_off)); } while ((name = *++aptr) != NULL); return 0; } } + + /* No arguments. Show the list of exported or readonly vars. + * -n is ignored. + */ showvars(argv[0], flag, 0); return 0; } @@ -12601,6 +12846,10 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) } } + /* "read -s" needs to save/restore termios, can't allow ^C + * to jump out of it. + */ + INT_OFF; r = shell_builtin_read(setvar2, argptr, bltinlookup("IFS"), /* can be NULL */ @@ -12610,6 +12859,7 @@ readcmd(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) opt_t, opt_u ); + INT_ON; if ((uintptr_t)r > 1) ash_msg_and_raise_error(r); @@ -12698,7 +12948,6 @@ ulimitcmd(int argc UNUSED_PARAM, char **argv) /* * Called to exit the shell. */ -static void exitshell(void) NORETURN; static void exitshell(void) { @@ -12706,6 +12955,10 @@ exitshell(void) char *p; int status; +#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(line_input_state); +#endif + status = exitstatus; TRACE(("pid %d, exitshell(%d)\n", getpid(), status)); if (setjmp(loc.loc)) { @@ -12743,7 +12996,7 @@ init(void) /* bash re-enables SIGHUP which is SIG_IGNed on entry. * Try: "trap '' HUP; bash; echo RET" and type "kill -HUP $$" */ - signal(SIGHUP, SIG_DFL); + signal(SIGHUP, SIG_DFL); /* from var.c: */ { @@ -12758,17 +13011,38 @@ init(void) } } - setvar("PPID", utoa(getppid()), 0); - + setvar2("PPID", utoa(getppid())); +#if ENABLE_ASH_BASH_COMPAT + p = lookupvar("SHLVL"); + setvar2("SHLVL", utoa(p ? atoi(p) + 1 : 1)); +#endif p = lookupvar("PWD"); - if (p) + if (p) { if (*p != '/' || stat(p, &st1) || stat(".", &st2) - || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino) + || st1.st_dev != st2.st_dev || st1.st_ino != st2.st_ino + ) { p = '\0'; + } + } setpwd(p, 0); } } + +//usage:#define ash_trivial_usage +//usage: "[-/+OPTIONS] [-/+o OPT]... [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" +//usage:#define ash_full_usage "\n\n" +//usage: "Unix shell interpreter" + +//usage:#if ENABLE_FEATURE_SH_IS_ASH +//usage:# define sh_trivial_usage ash_trivial_usage +//usage:# define sh_full_usage ash_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_ASH +//usage:# define bash_trivial_usage ash_trivial_usage +//usage:# define bash_full_usage ash_full_usage +//usage:#endif + /* * Process the shell command line arguments. */ @@ -12786,7 +13060,7 @@ procargs(char **argv) for (i = 0; i < NOPTS; i++) optlist[i] = 2; argptr = xargv; - if (options(1)) { + if (options(/*cmdline:*/ 1)) { /* it already printed err message */ raise_exception(EXERROR); } @@ -12916,10 +13190,12 @@ int ash_main(int argc UNUSED_PARAM, char **argv) if (e == EXERROR) exitstatus = 2; s = state; - if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) + if (e == EXEXIT || s == 0 || iflag == 0 || shlvl) { exitshell(); - if (e == EXINT) + } + if (e == EXINT) { outcslow('\n', stderr); + } popstackmark(&smark); FORCE_INT_ON; /* enable interrupts */ @@ -12943,28 +13219,21 @@ int ash_main(int argc UNUSED_PARAM, char **argv) setstackmark(&smark); procargs(argv); -#if ENABLE_FEATURE_EDITING_SAVEHISTORY - if (iflag) { - const char *hp = lookupvar("HISTFILE"); - - if (hp == NULL) { - hp = lookupvar("HOME"); - if (hp != NULL) { - char *defhp = concat_path_file(hp, ".ash_history"); - setvar("HISTFILE", defhp, 0); - free(defhp); - } - } - } -#endif - if (/* argv[0] && */ argv[0][0] == '-') + if (argv[0] && argv[0][0] == '-') isloginsh = 1; if (isloginsh) { + const char *hp; + state = 1; read_profile("/etc/profile"); state1: state = 2; - read_profile(".profile"); + hp = lookupvar("HOME"); + if (hp) { + hp = concat_path_file(hp, ".profile"); + read_profile(hp); + free((char*)hp); + } } state2: state = 3; @@ -12993,11 +13262,24 @@ int ash_main(int argc UNUSED_PARAM, char **argv) } if (sflag || minusc == NULL) { -#if defined MAX_HISTORY && MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY +#if MAX_HISTORY > 0 && ENABLE_FEATURE_EDITING_SAVEHISTORY if (iflag) { const char *hp = lookupvar("HISTFILE"); + if (!hp) { + hp = lookupvar("HOME"); + if (hp) { + hp = concat_path_file(hp, ".ash_history"); + setvar2("HISTFILE", hp); + free((char*)hp); + hp = lookupvar("HISTFILE"); + } + } if (hp) line_input_state->hist_file = hp; +# if ENABLE_FEATURE_SH_HISTFILESIZE + hp = lookupvar("HISTFILESIZE"); + line_input_state->max_history = size_from_HISTFILESIZE(hp); +# endif } #endif state4: /* XXX ??? - why isn't this before the "if" statement */ @@ -13012,6 +13294,7 @@ int ash_main(int argc UNUSED_PARAM, char **argv) _mcleanup(); } #endif + TRACE(("End of main reached\n")); exitshell(); /* NOTREACHED */ } diff --git a/shell/ash_ptr_hack.c b/shell/ash_ptr_hack.c index 68d9072..f698408 100644 --- a/shell/ash_ptr_hack.c +++ b/shell/ash_ptr_hack.c @@ -2,7 +2,7 @@ /* * Copyright (C) 2008 by Denys Vlasenko * - * Licensed under GPLv2, see file LICENSE in this tarball for details. + * Licensed under GPLv2, see file LICENSE in this source tree. */ struct globals_misc; diff --git a/shell/ash_test/ash-arith/arith.right b/shell/ash_test/ash-arith/arith.right index 3ea7ce6..9b9ca8e 100644 --- a/shell/ash_test/ash-arith/arith.right +++ b/shell/ash_test/ash-arith/arith.right @@ -55,28 +55,28 @@ Format: 'expected actual' 30 30 20 20 30 30 -./arith.tests: line 117: syntax error: 1 ? 20 : x+=2 +./arith.tests: line 117: arithmetic syntax error 6 6 6,5,3 6,5,3 263 263 255 255 40 40 -./arith.tests: line 163: syntax error: 7 = 43 +./arith.tests: line 163: arithmetic syntax error ./arith.tests: line 165: divide by zero -./arith.tests: let: line 166: syntax error: jv += $iv -./arith.tests: line 167: syntax error: jv += $iv -./arith.tests: let: line 168: syntax error: rv = 7 + (43 * 6 +./arith.tests: let: line 166: arithmetic syntax error +./arith.tests: line 167: arithmetic syntax error +./arith.tests: let: line 168: arithmetic syntax error abc def ghi -./arith.tests: line 191: syntax error: ( 4 + A ) + 4 +./arith.tests: line 191: arithmetic syntax error 16 16 -./arith.tests: line 196: syntax error: 4 ? : 3 + 5 -./arith.tests: line 197: syntax error: 1 ? 20 -./arith.tests: line 198: syntax error: 4 ? 20 : +./arith.tests: line 196: arithmetic syntax error +./arith.tests: line 197: malformed ?: operator +./arith.tests: line 198: arithmetic syntax error 9 9 -./arith.tests: line 205: syntax error: 0 && B=42 -./arith.tests: line 208: syntax error: 1 || B=88 +./arith.tests: line 205: arithmetic syntax error +./arith.tests: line 208: arithmetic syntax error 9 9 9 9 9 9 @@ -97,18 +97,18 @@ ghi 3 3 4 4 4 4 -./arith.tests: line 257: syntax error: 7-- -./arith.tests: line 259: syntax error: --x=7 -./arith.tests: line 260: syntax error: ++x=7 -./arith.tests: line 262: syntax error: x++=7 -./arith.tests: line 263: syntax error: x--=7 +./arith.tests: line 257: arithmetic syntax error +./arith.tests: line 259: arithmetic syntax error +./arith.tests: line 260: arithmetic syntax error +./arith.tests: line 262: arithmetic syntax error +./arith.tests: line 263: arithmetic syntax error 4 4 7 7 -7 -7 -./arith1.sub: line 2: syntax error: 4-- -./arith1.sub: line 3: syntax error: 4++ -./arith1.sub: line 4: syntax error: 4 -- -./arith1.sub: line 5: syntax error: 4 ++ +./arith1.sub: line 2: arithmetic syntax error +./arith1.sub: line 3: arithmetic syntax error +./arith1.sub: line 4: arithmetic syntax error +./arith1.sub: line 5: arithmetic syntax error 6 6 3 3 7 7 @@ -119,19 +119,19 @@ ghi 2 2 -2 -2 1 1 -./arith1.sub: line 37: syntax error: +++7 -./arith2.sub: line 2: syntax error: --7 -./arith2.sub: line 3: syntax error: ++7 -./arith2.sub: line 4: syntax error: -- 7 -./arith2.sub: line 5: syntax error: ++ 7 +./arith1.sub: line 37: arithmetic syntax error +./arith2.sub: line 2: arithmetic syntax error +./arith2.sub: line 3: arithmetic syntax error +./arith2.sub: line 4: arithmetic syntax error +./arith2.sub: line 5: arithmetic syntax error 5 5 1 1 4 4 0 0 -./arith2.sub: line 42: syntax error: -- - 7 -./arith2.sub: line 47: syntax error: ++ + 7 +./arith2.sub: line 42: arithmetic syntax error +./arith2.sub: line 47: arithmetic syntax error 8 12 -./arith.tests: line 290: syntax error: a b +./arith.tests: line 290: arithmetic syntax error 42 42 42 diff --git a/shell/ash_test/ash-misc/echo_write_error.right b/shell/ash_test/ash-misc/echo_write_error.right new file mode 100644 index 0000000..3e91a13 --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.right @@ -0,0 +1,2 @@ +ash: write error: Broken pipe +Ok: 1 diff --git a/shell/ash_test/ash-misc/echo_write_error.tests b/shell/ash_test/ash-misc/echo_write_error.tests new file mode 100644 index 0000000..0a40c9f --- /dev/null +++ b/shell/ash_test/ash-misc/echo_write_error.tests @@ -0,0 +1,7 @@ +trap "" PIPE + +{ +sleep 1 +echo Cant write this - get EPIPE +echo Ok: $? >&2 +} | { true; } diff --git a/shell/ash_test/ash-redir/redir.right b/shell/ash_test/ash-redir/redir.right index 2a02d41..c1a6e72 100644 --- a/shell/ash_test/ash-redir/redir.right +++ b/shell/ash_test/ash-redir/redir.right @@ -1 +1,2 @@ +ash: write error: Bad file descriptor TEST diff --git a/shell/ash_test/ash-redir/redir9.tests b/shell/ash_test/ash-redir/redir9.tests old mode 100644 new mode 100755 diff --git a/shell/ash_test/ash-redir/redirA.right b/shell/ash_test/ash-redir/redirA.right new file mode 100644 index 0000000..31406e3 --- /dev/null +++ b/shell/ash_test/ash-redir/redirA.right @@ -0,0 +1,2 @@ +tmp11 +tmp11 diff --git a/shell/ash_test/ash-redir/redirA.tests b/shell/ash_test/ash-redir/redirA.tests new file mode 100755 index 0000000..56833f9 --- /dev/null +++ b/shell/ash_test/ash-redir/redirA.tests @@ -0,0 +1,11 @@ +x="tmp11:tmp22" + +# Bug was incorrectly expanding variables in >redir +echo "${x%:*}" >"${x%:*}" +echo tmp1* +rm tmp1* + +# Also try unquoted +echo "${x%:*}" >${x%:*} +echo tmp1* +rm tmp1* diff --git a/shell/ash_test/ash-signals/sigint1.right b/shell/ash_test/ash-signals/sigint1.right new file mode 100644 index 0000000..a9094b0 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.right @@ -0,0 +1 @@ +Sending SIGINT to main shell PID diff --git a/shell/ash_test/ash-signals/sigint1.tests b/shell/ash_test/ash-signals/sigint1.tests new file mode 100755 index 0000000..3d483d3 --- /dev/null +++ b/shell/ash_test/ash-signals/sigint1.tests @@ -0,0 +1,41 @@ +# What should happen if non-interactive shell gets SIGINT? + +(sleep 1; echo Sending SIGINT to main shell PID; exec kill -INT $$) & + +# We create a child which exits with 0 even on SIGINT +# (The complex command is necessary only if SIGINT is generated by ^C, +# in this testcase even bare "sleep 2" would do because +# in the testcase we don't send SIGINT *to the child*...) +$THIS_SH -c 'trap "exit 0" SIGINT; sleep 2' + +# In one second, we (main shell) get SIGINT here. +# The question is whether we should, or should not, exit. + +# bash will not stop here. It will execute next command(s). + +# The rationale for this is described here: +# http://www.cons.org/cracauer/sigint.html +# +# Basically, bash will not exit on SIGINT immediately if it waits +# for a child. It will wait for the child to exit. +# If child exits NOT by dying on SIGINT, then bash will not exit. +# +# The idea is that the following script: +# | emacs file.txt +# | more cmds +# User may use ^C to interrupt editor's ops like search. But then +# emacs exits normally. User expects that script doesn't stop. +# +# This is a nice idea, but detecting "did process really exit +# with SIGINT?" is racy. Consider: +# | bash -c 'while true; do /bin/true; done' +# When ^C is pressed while bash waits for /bin/true to exit, +# it may happen that /bin/true exits with exitcode 0 before +# ^C is delivered to it as SIGINT. bash will see SIGINT, then +# it will see that child exited with 0, and bash will NOT EXIT. + +# Therefore we do not implement bash behavior. +# I'd say that emacs need to put itself into a separate pgrp +# to isolate shell from getting stray SIGINTs from ^C. + +echo Next command after SIGINT was executed diff --git a/shell/ash_test/ash-signals/signal7.right b/shell/ash_test/ash-signals/signal7.right new file mode 100644 index 0000000..ba7453e --- /dev/null +++ b/shell/ash_test/ash-signals/signal7.right @@ -0,0 +1 @@ +Bug detected: 0 diff --git a/shell/ash_test/ash-signals/signal7.tests b/shell/ash_test/ash-signals/signal7.tests new file mode 100755 index 0000000..c2b1381 --- /dev/null +++ b/shell/ash_test/ash-signals/signal7.tests @@ -0,0 +1,18 @@ +bug() { + trap : exit + # Bug was causing sh to be run in subshell, + # as if this line is replaced with (sh -c ...; exit $?) & + # here: + sh -c 'echo REAL_CHILD=$$' & + echo PARENTS_IDEA_OF_CHILD=$! + wait # make sure bkgd shell completes +} + +bug | { +while read varval; do + eval $varval +done +test x"$REAL_CHILD" != x"" \ +&& test x"$REAL_CHILD" = x"$PARENTS_IDEA_OF_CHILD" +echo "Bug detected: $?" +} diff --git a/shell/ash_test/ash-signals/signal8.right b/shell/ash_test/ash-signals/signal8.right new file mode 100644 index 0000000..39572f3 --- /dev/null +++ b/shell/ash_test/ash-signals/signal8.right @@ -0,0 +1,3 @@ +Removing traps +End of exit_func +Done: 0 diff --git a/shell/ash_test/ash-signals/signal8.tests b/shell/ash_test/ash-signals/signal8.tests new file mode 100755 index 0000000..731af74 --- /dev/null +++ b/shell/ash_test/ash-signals/signal8.tests @@ -0,0 +1,18 @@ +"$THIS_SH" -c ' +exit_func() { + echo "Removing traps" + trap - EXIT TERM INT + echo "End of exit_func" +} +set -e +trap exit_func EXIT TERM INT +sleep 2 +exit 77 +' & + +sleep 1 +# BUG: ash kills -PGRP, but in non-interactive shell we do not create pgrps! +# In this case, bash kills by PID, not PGRP. +kill -TERM %1 +wait +echo Done: $? diff --git a/shell/ash_test/ash-signals/signal9.right b/shell/ash_test/ash-signals/signal9.right new file mode 100644 index 0000000..39572f3 --- /dev/null +++ b/shell/ash_test/ash-signals/signal9.right @@ -0,0 +1,3 @@ +Removing traps +End of exit_func +Done: 0 diff --git a/shell/ash_test/ash-signals/signal9.tests b/shell/ash_test/ash-signals/signal9.tests new file mode 100755 index 0000000..18e7101 --- /dev/null +++ b/shell/ash_test/ash-signals/signal9.tests @@ -0,0 +1,21 @@ +# Note: the inner script is a test which checks for a different bug +# (ordering between INT handler and exit on "set -e"), +# but so far I did not figure out how to simulate it non-interactively. + +"$THIS_SH" -c ' +exit_func() { + echo "Removing traps" + trap - EXIT TERM INT + echo "End of exit_func" +} +set -e +trap exit_func EXIT TERM INT +sleep 2 +exit 77 +' & + +child=$! +sleep 1 +kill -TERM $child +wait +echo Done: $? diff --git a/shell/ash_test/ash-vars/var_bash3.right b/shell/ash_test/ash-vars/var_bash3.right index f7f1479..a97c850 100644 --- a/shell/ash_test/ash-vars/var_bash3.right +++ b/shell/ash_test/ash-vars/var_bash3.right @@ -1,20 +1,20 @@ -a041#c -a041#c -a\041#c -a\041#c -a\041#c -a\041#c -a\041#c -a\041#c -a\041#c -a\c -a\c -a\c -a\\c -a\\c -a\\c -a\tc -a\tc -a\tc -atc -a\tc +1 a041#c +2 a041#c +3 a\041#c +4 a\041#c +5 a\041#c +6 a\041#c +7 a\041#c +8 a\041#c +9 a\041#c +10 a\c +11 a\c +12 a\c +13 a\\c +14 a\\c +15 a\\c +16 a\tc +17 a\tc +18 a\tc +19 atc +20 a\tc diff --git a/shell/ash_test/ash-vars/var_bash3.tests b/shell/ash_test/ash-vars/var_bash3.tests index b905027..146dbb6 100755 --- a/shell/ash_test/ash-vars/var_bash3.tests +++ b/shell/ash_test/ash-vars/var_bash3.tests @@ -1,41 +1,41 @@ a='abc' r=${a//b/\041#} -echo $r -echo ${a//b/\041#} -echo "${a//b/\041#}" +echo 1 $r +echo 2 ${a//b/\041#} +echo 3 "${a//b/\041#}" a='abc' r=${a//b/\\041#} -echo $r -echo ${a//b/\\041#} -echo "${a//b/\\041#}" +echo 4 $r +echo 5 ${a//b/\\041#} +echo 6 "${a//b/\\041#}" a='abc' b='\041#' r=${a//b/$b} -echo $r -echo ${a//b/$b} -echo "${a//b/$b}" +echo 7 $r +echo 8 ${a//b/$b} +echo 9 "${a//b/$b}" a='abc' b='\' r="${a//b/$b}" -echo $r -echo ${a//b/$b} -echo "${a//b/$b}" +echo 10 $r +echo 11 ${a//b/$b} +echo 12 "${a//b/$b}" a='abc' b='\\' r="${a//b/$b}" -echo $r -echo ${a//b/$b} -echo "${a//b/$b}" +echo 13 $r +echo 14 ${a//b/$b} +echo 15 "${a//b/$b}" a='abc' b='\t' r="${a//b/$b}" -echo $r -echo ${a//b/$b} -echo "${a//b/$b}" -echo ${a//b/\t} -echo "${a//b/\t}" +echo 16 $r +echo 17 ${a//b/$b} +echo 18 "${a//b/$b}" +echo 19 ${a//b/\t} +echo 20 "${a//b/\t}" diff --git a/shell/ash_test/ash-vars/var_bash4.right b/shell/ash_test/ash-vars/var_bash4.right new file mode 100644 index 0000000..600e853 --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash4.right @@ -0,0 +1,23 @@ +Source: a*b\*c +Replace str: _\\_\z_ +Pattern: single backslash and star: "replace literal star" +In assignment: a_\_z_b\*c +Unquoted: a_\_z_b\*c +Quoted: a_\_\z_b\*c +Pattern: double backslash and star: "replace backslash and everything after it" +In assignment: a*b_\_z_ +Unquoted: a*b_\_z_ +Quoted: a*b_\_\z_ + +Source: a\bc +Replace str: _\\_\z_ +Pattern: single backslash and b: "replace b" +In assignment: a\_\_z_c +Unquoted: a\_\_z_c +Quoted: a\_\_\z_c +Pattern: double backslash and b: "replace backslash and b" +In assignment: a_\_z_c +Unquoted: a_\_z_c +Quoted: a_\_\z_c + +Done: 0 diff --git a/shell/ash_test/ash-vars/var_bash4.tests b/shell/ash_test/ash-vars/var_bash4.tests new file mode 100755 index 0000000..d547061 --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash4.tests @@ -0,0 +1,47 @@ +# This testcase demonstrates that backslashes are treated differently +# in 1st and 2nd parts of ${var/search/repl}: +# if quoted ("${var/search/repl}"), and repl contains \a (a non-special char), +# the backslash in repl stays; if unquoted, backslash is removed. +# But search part does not act like that: \a is always converted to just a, +# even in quotes. +# +# bash4 (and probably bash3 too): "Quoted:" results are different from +# unquoted and assignment expansions - they have a backslash before z. + +v='a*b\*c' +echo 'Source: ' "$v" +echo 'Replace str: ' '_\\_\z_' + +echo 'Pattern: ' 'single backslash and star: "replace literal star"' +r=${v/\*/_\\_\z_} +echo 'In assignment:' "$r" +echo 'Unquoted: ' ${v/\*/_\\_\z_} +echo 'Quoted: ' "${v/\*/_\\_\z_}" + +echo 'Pattern: ' 'double backslash and star: "replace backslash and everything after it"' +r=${v/\\*/_\\_\z_} +echo 'In assignment:' "$r" +echo 'Unquoted: ' ${v/\\*/_\\_\z_} +echo 'Quoted: ' "${v/\\*/_\\_\z_}" + +echo + +v='a\bc' +echo 'Source: ' "$v" +echo 'Replace str: ' '_\\_\z_' + +echo 'Pattern: ' 'single backslash and b: "replace b"' +r=${v/\b/_\\_\z_} +echo 'In assignment:' "$r" +echo 'Unquoted: ' ${v/\b/_\\_\z_} +echo 'Quoted: ' "${v/\b/_\\_\z_}" + +echo 'Pattern: ' 'double backslash and b: "replace backslash and b"' +r=${v/\\b/_\\_\z_} +echo 'In assignment:' "$r" +echo 'Unquoted: ' ${v/\\b/_\\_\z_} +echo 'Quoted: ' "${v/\\b/_\\_\z_}" + +echo + +echo Done: $? diff --git a/shell/ash_test/ash-vars/var_bash5.right b/shell/ash_test/ash-vars/var_bash5.right new file mode 100644 index 0000000..278ed32 --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash5.right @@ -0,0 +1,4 @@ +a/ +a/d +a/e/f +Done: 0 diff --git a/shell/ash_test/ash-vars/var_bash5.tests b/shell/ash_test/ash-vars/var_bash5.tests new file mode 100755 index 0000000..7f482a5 --- /dev/null +++ b/shell/ash_test/ash-vars/var_bash5.tests @@ -0,0 +1,11 @@ +# This testcase checks whether slashes in ${v/a/b} are parsed before +# or after expansions + +v='a/b/c' +s='b/c' +r='e/f' +echo "${v/$s}" +echo "${v/$s/d}" +echo "${v/$s/$r}" + +echo Done: $? diff --git a/shell/ash_test/recho.c b/shell/ash_test/recho.c index fb48d9c..42a5fea 100644 --- a/shell/ash_test/recho.c +++ b/shell/ash_test/recho.c @@ -29,12 +29,9 @@ void strprint(); -int -main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv) { - register int i; + int i; for (i = 1; i < argc; i++) { printf("argv[%d] = <", i); @@ -44,11 +41,9 @@ char **argv; exit(EXIT_SUCCESS); } -void -strprint(str) -char *str; +void strprint(char *str) { - register unsigned char *s; + unsigned char *s; for (s = (unsigned char *)str; s && *s; s++) { if (*s < ' ') { diff --git a/shell/ash_test/zecho.c b/shell/ash_test/zecho.c index bf876f6..cbaa59b 100644 --- a/shell/ash_test/zecho.c +++ b/shell/ash_test/zecho.c @@ -21,10 +21,7 @@ #include #include -int -main(argc, argv) -int argc; -char **argv; +int main(int argc, char **argv) { argv++; diff --git a/shell/bbsh.c b/shell/bbsh.c deleted file mode 100644 index 83132f9..0000000 --- a/shell/bbsh.c +++ /dev/null @@ -1,223 +0,0 @@ -/* vi: set ts=4 : - * - * bbsh - busybox shell - * - * Copyright 2006 Rob Landley - * - * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. - */ - -// A section of code that gets repeatedly or conditionally executed is stored -// as a string and parsed each time it's run. - - - -// Wheee, debugging. - -// Terminal control -#define ENABLE_BBSH_TTY 0 - -// &, fg, bg, jobs. (ctrl-z with tty.) -#define ENABLE_BBSH_JOBCTL 0 - -// Flow control (if, while, for, functions { }) -#define ENABLE_BBSH_FLOWCTL 0 - -#define ENABLE_BBSH_ENVVARS 0 // Environment variable support - -// Local and synthetic variables, fancy prompts, set, $?, etc. -#define ENABLE_BBSH_LOCALVARS 0 - -// Pipes and redirects: | > < >> << && || & () ; -#define ENABLE_BBSH_PIPES 0 - -/* Fun: - - echo `echo hello#comment " woot` and more -*/ - -#include "libbb.h" - -// A single executable, its arguments, and other information we know about it. -#define BBSH_FLAG_EXIT 1 -#define BBSH_FLAG_SUSPEND 2 -#define BBSH_FLAG_PIPE 4 -#define BBSH_FLAG_AND 8 -#define BBSH_FLAG_OR 16 -#define BBSH_FLAG_AMP 32 -#define BBSH_FLAG_SEMI 64 -#define BBSH_FLAG_PAREN 128 - -// What we know about a single process. -struct command { - struct command *next; - int flags; // exit, suspend, && || - int pid; // pid (or exit code) - int argc; - char *argv[]; -}; - -// A collection of processes piped into/waiting on each other. -struct pipeline { - struct pipeline *next; - int job_id; - struct command *cmd; - char *cmdline; - int cmdlinelen; -}; - -static void free_list(void *list, void (*freeit)(void *data)) -{ - while (list) { - void **next = (void **)list; - void *list_next = *next; - freeit(list); - free(list); - list = list_next; - } -} - -// Parse one word from the command line, appending one or more argv[] entries -// to struct command. Handles environment variable substitution and -// substrings. Returns pointer to next used byte, or NULL if it -// hit an ending token. -static char *parse_word(char *start, struct command **cmd) -{ - char *end; - - // Detect end of line (and truncate line at comment) - if (ENABLE_BBSH_PIPES && strchr("><&|(;", *start)) return 0; - - // Grab next word. (Add dequote and envvar logic here) - end = start; - end = skip_non_whitespace(end); - (*cmd)->argv[(*cmd)->argc++] = xstrndup(start, end-start); - - // Allocate more space if there's no room for NULL terminator. - - if (!((*cmd)->argc & 7)) - *cmd = xrealloc(*cmd, - sizeof(struct command) + ((*cmd)->argc+8)*sizeof(char *)); - (*cmd)->argv[(*cmd)->argc] = 0; - return end; -} - -// Parse a line of text into a pipeline. -// Returns a pointer to the next line. - -static char *parse_pipeline(char *cmdline, struct pipeline *line) -{ - struct command **cmd = &(line->cmd); - char *start = line->cmdline = cmdline; - - if (!cmdline) return 0; - - if (ENABLE_BBSH_JOBCTL) line->cmdline = cmdline; - - // Parse command into argv[] - for (;;) { - char *end; - - // Skip leading whitespace and detect end of line. - start = skip_whitespace(start); - if (!*start || *start=='#') { - if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline; - return 0; - } - - // Allocate next command structure if necessary - if (!*cmd) *cmd = xzalloc(sizeof(struct command)+8*sizeof(char *)); - - // Parse next argument and add the results to argv[] - end = parse_word(start, cmd); - - // If we hit the end of this command, how did it end? - if (!end) { - if (ENABLE_BBSH_PIPES && *start) { - if (*start==';') { - start++; - break; - } - // handle | & < > >> << || && - } - break; - } - start = end; - } - - if (ENABLE_BBSH_JOBCTL) line->cmdlinelen = start-cmdline; - - return start; -} - -// Execute the commands in a pipeline -static int run_pipeline(struct pipeline *line) -{ - struct command *cmd = line->cmd; - if (!cmd || !cmd->argc) return 0; - - // Handle local commands. This is totally fake and plastic. - if (cmd->argc==2 && !strcmp(cmd->argv[0],"cd")) - chdir(cmd->argv[1]); - else if (!strcmp(cmd->argv[0],"exit")) - exit(cmd->argc>1 ? atoi(cmd->argv[1]) : 0); - else { - int status; - pid_t pid=fork(); - if (!pid) { - run_applet_and_exit(cmd->argv[0],cmd->argc,cmd->argv); - execvp(cmd->argv[0],cmd->argv); - printf("No %s", cmd->argv[0]); - exit(EXIT_FAILURE); - } else waitpid(pid, &status, 0); - } - - return 0; -} - -static void free_cmd(void *data) -{ - struct command *cmd=(struct command *)data; - - while (cmd->argc) free(cmd->argv[--cmd->argc]); -} - - -static void handle(char *command) -{ - struct pipeline line; - char *start = command; - - for (;;) { - memset(&line,0,sizeof(struct pipeline)); - start = parse_pipeline(start, &line); - if (!line.cmd) break; - - run_pipeline(&line); - free_list(line.cmd, free_cmd); - } -} - -int bbsh_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int bbsh_main(int argc UNUSED_PARAM, char **argv) -{ - char *command=NULL; - FILE *f; - - getopt32(argv, "c:", &command); - - f = argv[optind] ? xfopen_for_read(argv[optind]) : NULL; - if (command) handle(command); - else { - unsigned cmdlen=0; - for (;;) { - if (!f) putchar('$'); - if (1 > getline(&command, &cmdlen, f ? f : stdin)) break; - - handle(command); - } - if (ENABLE_FEATURE_CLEAN_UP) free(command); - } - - return 1; -} diff --git a/shell/cttyhack.c b/shell/cttyhack.c index 67736ad..f9b59c2 100644 --- a/shell/cttyhack.c +++ b/shell/cttyhack.c @@ -1,11 +1,74 @@ /* vi: set sw=4 ts=4: */ /* - * Licensed under GPLv2 - * * Copyright (c) 2007 Denys Vlasenko + * + * Licensed under GPLv2, see file LICENSE in this source tree. */ #include "libbb.h" +//applet:IF_CTTYHACK(APPLET(cttyhack, BB_DIR_BIN, BB_SUID_DROP)) + +//kbuild:lib-$(CONFIG_CTTYHACK) += cttyhack.o + +//config:config CTTYHACK +//config: bool "cttyhack" +//config: default y +//config: help +//config: One common problem reported on the mailing list is the "can't +//config: access tty; job control turned off" error message, which typically +//config: appears when one tries to use a shell with stdin/stdout on +//config: /dev/console. +//config: This device is special - it cannot be a controlling tty. +//config: +//config: The proper solution is to use the correct device instead of +//config: /dev/console. +//config: +//config: cttyhack provides a "quick and dirty" solution to this problem. +//config: It analyzes stdin with various ioctls, trying to determine whether +//config: it is a /dev/ttyN or /dev/ttySN (virtual terminal or serial line). +//config: On Linux it also checks sysfs for a pointer to the active console. +//config: If cttyhack is able to find the real console device, it closes +//config: stdin/out/err and reopens that device. +//config: Then it executes the given program. Opening the device will make +//config: that device a controlling tty. This may require cttyhack +//config: to be a session leader. +//config: +//config: Example for /etc/inittab (for busybox init): +//config: +//config: ::respawn:/bin/cttyhack /bin/sh +//config: +//config: Starting an interactive shell from boot shell script: +//config: +//config: setsid cttyhack sh +//config: +//config: Giving controlling tty to shell running with PID 1: +//config: +//config: # exec cttyhack sh +//config: +//config: Without cttyhack, you need to know exact tty name, +//config: and do something like this: +//config: +//config: # exec setsid sh -c 'exec sh /dev/tty1 2>&1' +//config: +//config: Starting getty on a controlling tty from a shell script: +//config: +//config: # getty 115200 $(cttyhack) + +//usage:#define cttyhack_trivial_usage +//usage: "[PROG ARGS]" +//usage:#define cttyhack_full_usage "\n\n" +//usage: "Give PROG a controlling tty if possible." +//usage: "\nExample for /etc/inittab (for busybox init):" +//usage: "\n ::respawn:/bin/cttyhack /bin/sh" +//usage: "\nGiving controlling tty to shell running with PID 1:" +//usage: "\n $ exec cttyhack sh" +//usage: "\nStarting interactive shell from boot shell script:" +//usage: "\n setsid cttyhack sh" + +#if !defined(__linux__) && !defined(TIOCGSERIAL) && !ENABLE_WERROR +# warning cttyhack will not be able to detect a controlling tty on this system +#endif + /* From */ struct vt_stat { unsigned short v_active; /* active vt */ @@ -48,38 +111,78 @@ int cttyhack_main(int argc UNUSED_PARAM, char **argv) char paranoia[sizeof(struct serial_struct) * 3]; } u; - if (!*++argv) { - bb_show_usage(); - } - strcpy(console, "/dev/tty"); fd = open(console, O_RDWR); - if (fd >= 0) { - /* We already have ctty, nothing to do */ - close(fd); - } else { + if (fd < 0) { /* We don't have ctty (or don't have "/dev/tty" node...) */ - if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { - /* this is a serial console */ - sprintf(console + 8, "S%d", u.sr.line); - } else if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { - /* this is linux virtual tty */ - sprintf(console + 8, "S%d" + 1, u.vt.v_active); - } - if (console[8]) { - fd = xopen(console, O_RDWR); - //bb_error_msg("switching to '%s'", console); - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - while (fd > 2) - close(fd--); - /* Some other session may have it as ctty, - * steal it from them: + do { +#ifdef __linux__ + /* Note that this method does not use _stdin_. + * Thus, "cttyhack 0) { + char *last; + /* Found active console via sysfs (Linux 2.6.38+). + * It looks like "[tty0 ]ttyS0\n" so zap the newline: + */ + console[4 + s] = '\0'; + /* If there are multiple consoles, + * take the last one: + */ + last = strrchr(console + 5, ' '); + if (last) + overlapping_strcpy(console + 5, last + 1); + break; + } + + if (ioctl(0, VT_GETSTATE, &u.vt) == 0) { + /* this is linux virtual tty */ + sprintf(console + 8, "S%u" + 1, (int)u.vt.v_active); + break; + } +#endif +#ifdef TIOCGSERIAL + if (ioctl(0, TIOCGSERIAL, &u.sr) == 0) { + /* this is a serial console; assuming it is named /dev/ttySn */ + sprintf(console + 8, "S%u", (int)u.sr.line); + break; + } +#endif + /* nope, could not find it */ + console[0] = '\0'; + } while (0); } + argv++; + if (!argv[0]) { + if (!console[0]) + return EXIT_FAILURE; + puts(console); + return EXIT_SUCCESS; + } + + if (fd < 0) { + fd = open_or_warn(console, O_RDWR); + if (fd < 0) + goto ret; + } + //bb_error_msg("switching to '%s'", console); + dup2(fd, 0); + dup2(fd, 1); + dup2(fd, 2); + while (fd > 2) + close(fd--); + /* Some other session may have it as ctty, + * try to steal it from them: + */ + ioctl(0, TIOCSCTTY, 1); + ret: BB_EXECVP_or_die(argv); } diff --git a/shell/hush.c b/shell/hush.c index 31ca22a..9271934 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -8,6 +8,8 @@ * Copyright (C) 2000,2001 Larry Doolittle * Copyright (C) 2008,2009 Denys Vlasenko * + * Licensed under GPLv2 or later, see file LICENSE in this source tree. + * * Credits: * The parser routines proper are all original material, first * written Dec 2000 and Jan 2001 by Larry Doolittle. The @@ -50,8 +52,6 @@ * * Bash compat TODO: * redirection of stdout+stderr: &> and >& - * subst operator: ${var/[/]expr/expr} - * brace expansion: one/{two,three,four} * reserved words: function select * advanced test: [[ ]] * process substitution: <(list) and >(list) @@ -64,7 +64,9 @@ * The EXPR is evaluated according to ARITHMETIC EVALUATION. * This is exactly equivalent to let "EXPR". * $[EXPR]: synonym for $((EXPR)) - * export builtin should be special, its arguments are assignments + * + * Won't do: + * In bash, export builtin is special, its arguments are assignments * and therefore expansion of them should be "one-word" expansion: * $ export i=`echo 'a b'` # export has one arg: "i=a b" * compare with: @@ -78,17 +80,20 @@ * aaa bbb * $ "export" i=`echo 'aaa bbb'`; echo "$i" * aaa - * - * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ -#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ -#include /* for malloc_trim */ +#if !(defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) \ + || defined(__APPLE__) \ + ) +# include /* for malloc_trim */ +#endif #include /* #include */ #if ENABLE_HUSH_CASE # include #endif +#include "busybox.h" /* for APPLET_IS_NOFORK/NOEXEC */ +#include "unicode.h" #include "shell_common.h" #include "math.h" #include "match.h" @@ -101,6 +106,172 @@ # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif +//config:config HUSH +//config: bool "hush" +//config: default y +//config: help +//config: hush is a small shell (25k). It handles the normal flow control +//config: constructs such as if/then/elif/else/fi, for/in/do/done, while loops, +//config: case/esac. Redirections, here documents, $((arithmetic)) +//config: and functions are supported. +//config: +//config: It will compile and work on no-mmu systems. +//config: +//config: It does not handle select, aliases, tilde expansion, +//config: &>file and >&file redirection of stdout+stderr. +//config: +//config:config HUSH_BASH_COMPAT +//config: bool "bash-compatible extensions" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable bash-compatible extensions. +//config: +//config:config HUSH_BRACE_EXPANSION +//config: bool "Brace expansion" +//config: default y +//config: depends on HUSH_BASH_COMPAT +//config: help +//config: Enable {abc,def} extension. +//config: +//config:config HUSH_HELP +//config: bool "help builtin" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable help builtin in hush. Code size + ~1 kbyte. +//config: +//config:config HUSH_INTERACTIVE +//config: bool "Interactive mode" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable interactive mode (prompt and command editing). +//config: Without this, hush simply reads and executes commands +//config: from stdin just like a shell script from a file. +//config: No prompt, no PS1/PS2 magic shell variables. +//config: +//config:config HUSH_SAVEHISTORY +//config: bool "Save command history to .hush_history" +//config: default y +//config: depends on HUSH_INTERACTIVE && FEATURE_EDITING_SAVEHISTORY +//config: help +//config: Enable history saving in hush. +//config: +//config:config HUSH_JOB +//config: bool "Job control" +//config: default y +//config: depends on HUSH_INTERACTIVE +//config: help +//config: Enable job control: Ctrl-Z backgrounds, Ctrl-C interrupts current +//config: command (not entire shell), fg/bg builtins work. Without this option, +//config: "cmd &" still works by simply spawning a process and immediately +//config: prompting for next command (or executing next command in a script), +//config: but no separate process group is formed. +//config: +//config:config HUSH_TICK +//config: bool "Process substitution" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable process substitution `command` and $(command) in hush. +//config: +//config:config HUSH_IF +//config: bool "Support if/then/elif/else/fi" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable if/then/elif/else/fi in hush. +//config: +//config:config HUSH_LOOPS +//config: bool "Support for, while and until loops" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable for, while and until loops in hush. +//config: +//config:config HUSH_CASE +//config: bool "Support case ... esac statement" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable case ... esac statement in hush. +400 bytes. +//config: +//config:config HUSH_FUNCTIONS +//config: bool "Support funcname() { commands; } syntax" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable support for shell functions in hush. +800 bytes. +//config: +//config:config HUSH_LOCAL +//config: bool "Support local builtin" +//config: default y +//config: depends on HUSH_FUNCTIONS +//config: help +//config: Enable support for local variables in functions. +//config: +//config:config HUSH_RANDOM_SUPPORT +//config: bool "Pseudorandom generator and $RANDOM variable" +//config: default y +//config: depends on HUSH +//config: help +//config: Enable pseudorandom generator and dynamic variable "$RANDOM". +//config: Each read of "$RANDOM" will generate a new pseudorandom value. +//config: +//config:config HUSH_EXPORT_N +//config: bool "Support 'export -n' option" +//config: default y +//config: depends on HUSH +//config: help +//config: export -n unexports variables. It is a bash extension. +//config: +//config:config HUSH_MODE_X +//config: bool "Support 'hush -x' option and 'set -x' command" +//config: default y +//config: depends on HUSH +//config: help +//config: This instructs hush to print commands before execution. +//config: Adds ~300 bytes. +//config: +//config:config MSH +//config: bool "msh (deprecated: aliased to hush)" +//config: default n +//config: select HUSH +//config: help +//config: msh is deprecated and will be removed, please migrate to hush. +//config: + +//applet:IF_HUSH(APPLET(hush, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_MSH(APPLET(msh, BB_DIR_BIN, BB_SUID_DROP)) +//applet:IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, BB_DIR_BIN, BB_SUID_DROP, sh)) +//applet:IF_FEATURE_BASH_IS_HUSH(APPLET_ODDNAME(bash, hush, BB_DIR_BIN, BB_SUID_DROP, bash)) + +//kbuild:lib-$(CONFIG_HUSH) += hush.o match.o shell_common.o +//kbuild:lib-$(CONFIG_HUSH_RANDOM_SUPPORT) += random.o + +/* -i (interactive) and -s (read stdin) are also accepted, + * but currently do nothing, therefore aren't shown in help. + * NOMMU-specific options are not meant to be used by users, + * therefore we don't show them either. + */ +//usage:#define hush_trivial_usage +//usage: "[-nxl] [-c 'SCRIPT' [ARG0 [ARGS]] / FILE [ARGS]]" +//usage:#define hush_full_usage "\n\n" +//usage: "Unix shell interpreter" + +//usage:#define msh_trivial_usage hush_trivial_usage +//usage:#define msh_full_usage hush_full_usage + +//usage:#if ENABLE_FEATURE_SH_IS_HUSH +//usage:# define sh_trivial_usage hush_trivial_usage +//usage:# define sh_full_usage hush_full_usage +//usage:#endif +//usage:#if ENABLE_FEATURE_BASH_IS_HUSH +//usage:# define bash_trivial_usage hush_trivial_usage +//usage:# define bash_full_usage hush_full_usage +//usage:#endif + /* Build knobs */ #define LEAK_HUNTING 0 @@ -149,6 +320,8 @@ # define ENABLE_FEATURE_EDITING 0 # undef ENABLE_FEATURE_EDITING_FANCY_PROMPT # define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0 +# undef ENABLE_FEATURE_EDITING_SAVE_ON_EXIT +# define ENABLE_FEATURE_EDITING_SAVE_ON_EXIT 0 #endif /* Do we support ANY keywords? */ @@ -185,6 +358,17 @@ #define _SPECIAL_VARS_STR "_*@$!?#" #define SPECIAL_VARS_STR ("_*@$!?#" + 1) #define NUMERIC_SPECVARS_STR ("_*@$!?#" + 3) +#if ENABLE_HUSH_BASH_COMPAT +/* Support / and // replace ops */ +/* Note that // is stored as \ in "encoded" string representation */ +# define VAR_ENCODED_SUBST_OPS "\\/%#:-=+?" +# define VAR_SUBST_OPS ("\\/%#:-=+?" + 1) +# define MINUS_PLUS_EQUAL_QUESTION ("\\/%#:-=+?" + 5) +#else +# define VAR_ENCODED_SUBST_OPS "%#:-=+?" +# define VAR_SUBST_OPS "%#:-=+?" +# define MINUS_PLUS_EQUAL_QUESTION ("%#:-=+?" + 3) +#endif #define SPECIAL_VAR_SYMBOL 3 @@ -204,7 +388,7 @@ typedef struct nommu_save_t { } nommu_save_t; #endif -typedef enum reserved_style { +enum { RES_NONE = 0, #if ENABLE_HUSH_IF RES_IF , @@ -233,42 +417,54 @@ typedef enum reserved_style { #endif RES_XXXX , RES_SNTX -} reserved_style; +}; typedef struct o_string { char *data; int length; /* position where data is appended */ int maxlen; - /* Protect newly added chars against globbing - * (by prepending \ to *, ?, [, \) */ - smallint o_escape; - smallint o_glob; + int o_expflags; /* At least some part of the string was inside '' or "", * possibly empty one: word"", wo''rd etc. */ - smallint o_quoted; + smallint has_quoted_part; smallint has_empty_slot; smallint o_assignment; /* 0:maybe, 1:yes, 2:no */ } o_string; enum { - MAYBE_ASSIGNMENT = 0, + EXP_FLAG_SINGLEWORD = 0x80, /* must be 0x80 */ + EXP_FLAG_GLOB = 0x2, + /* Protect newly added chars against globbing + * by prepending \ to *, ?, [, \ */ + EXP_FLAG_ESC_GLOB_CHARS = 0x1, +}; +enum { + MAYBE_ASSIGNMENT = 0, DEFINITELY_ASSIGNMENT = 1, - NOT_ASSIGNMENT = 2, - WORD_IS_KEYWORD = 3, /* not assigment, but next word may be: "if v=xyz cmd;" */ + NOT_ASSIGNMENT = 2, + /* Not an assigment, but next word may be: "if v=xyz cmd;" */ + WORD_IS_KEYWORD = 3, }; /* Used for initialization: o_string foo = NULL_O_STRING; */ #define NULL_O_STRING { NULL } -/* I can almost use ordinary FILE*. Is open_memstream() universally - * available? Where is it documented? */ +#ifndef debug_printf_parse +static const char *const assignment_flag[] = { + "MAYBE_ASSIGNMENT", + "DEFINITELY_ASSIGNMENT", + "NOT_ASSIGNMENT", + "WORD_IS_KEYWORD", +}; +#endif + typedef struct in_str { const char *p; /* eof_flag=1: last char in ->p is really an EOF */ char eof_flag; /* meaningless if ->p == NULL */ char peek_buf[2]; #if ENABLE_HUSH_INTERACTIVE - smallint promptme; smallint promptmode; /* 0: PS1, 1: PS2 */ #endif + int last_char; FILE *file; int (*get) (struct in_str *) FAST_FUNC; int (*peek) (struct in_str *) FAST_FUNC; @@ -326,28 +522,18 @@ typedef enum redir_type { struct command { pid_t pid; /* 0 if exited */ int assignment_cnt; /* how many argv[i] are assignments? */ - smallint is_stopped; /* is the command currently running? */ smallint cmd_type; /* CMD_xxx */ #define CMD_NORMAL 0 #define CMD_SUBSHELL 1 - -/* used for "[[ EXPR ]]" */ #if ENABLE_HUSH_BASH_COMPAT +/* used for "[[ EXPR ]]" */ # define CMD_SINGLEWORD_NOGLOB 2 #endif - -/* used for "export noglob=* glob* a=`echo a b`" */ -//#define CMD_SINGLEWORD_NOGLOB_COND 3 -// It is hard to implement correctly, it adds significant amounts of tricky code, -// and all this is only useful for really obscure export statements -// almost nobody would use anyway. #ifdef CMD_SINGLEWORD_NOGLOB_COND -// guards the code which implements it, but I have doubts it works -// in all cases (especially with mixed globbed/non-globbed arguments) - #if ENABLE_HUSH_FUNCTIONS # define CMD_FUNCDEF 3 #endif + smalluint cmd_exitcode; /* if non-NULL, this "command" is { list }, ( list ), or a compound statement */ struct pipe *group; #if !BB_MMU @@ -383,7 +569,6 @@ struct command { #define IS_NULL_CMD(cmd) \ (!(cmd)->group && !(cmd)->argv && !(cmd)->redirects) - struct pipe { struct pipe *next; int num_cmds; /* total number of commands in pipe */ @@ -478,6 +663,53 @@ struct function { #endif +/* set -/+o OPT support. (TODO: make it optional) + * bash supports the following opts: + * allexport off + * braceexpand on + * emacs on + * errexit off + * errtrace off + * functrace off + * hashall on + * histexpand off + * history on + * ignoreeof off + * interactive-comments on + * keyword off + * monitor on + * noclobber off + * noexec off + * noglob off + * nolog off + * notify off + * nounset off + * onecmd off + * physical off + * pipefail off + * posix off + * privileged off + * verbose off + * vi off + * xtrace off + */ +static const char o_opt_strings[] ALIGN1 = + "pipefail\0" + "noexec\0" +#if ENABLE_HUSH_MODE_X + "xtrace\0" +#endif + ; +enum { + OPT_O_PIPEFAIL, + OPT_O_NOEXEC, +#if ENABLE_HUSH_MODE_X + OPT_O_XTRACE, +#endif + NUM_OPT_O +}; + + /* "Globals" within this file */ /* Sorted roughly by size (smaller offsets == smaller code) */ struct globals { @@ -520,6 +752,12 @@ struct globals { #else # define G_saved_tty_pgrp 0 #endif + char o_opt[NUM_OPT_O]; +#if ENABLE_HUSH_MODE_X +# define G_x_mode (G.o_opt[OPT_O_XTRACE]) +#else +# define G_x_mode 0 +#endif smallint flag_SIGINT; #if ENABLE_HUSH_LOOPS smallint flag_break_continue; @@ -531,13 +769,11 @@ struct globals { */ smallint flag_return_in_progress; #endif - smallint fake_mode; smallint exiting; /* used to prevent EXIT trap recursion */ /* These four support $?, $#, and $1 */ smalluint last_exitcode; /* are global_argv and global_argv[1..n] malloced? (note: not [0]) */ smalluint global_args_malloced; - smalluint inherited_set_is_saved; /* how many non-NULL argv's we have. NB: $# + 1 */ int global_argc; char **global_argv; @@ -550,8 +786,8 @@ struct globals { #endif const char *ifs; const char *cwd; - struct variable *top_var; /* = &G.shell_ver (set in main()) */ - struct variable shell_ver; + struct variable *top_var; + char **expanded_assignments; #if ENABLE_HUSH_FUNCTIONS struct function *top_func; # if ENABLE_HUSH_LOCAL @@ -565,15 +801,27 @@ struct globals { unsigned handled_SIGCHLD; smallint we_have_children; #endif - /* which signals have non-DFL handler (even with no traps set)? */ - unsigned non_DFL_mask; + /* Which signals have non-DFL handler (even with no traps set)? + * Set at the start to: + * (SIGQUIT + maybe SPECIAL_INTERACTIVE_SIGS + maybe SPECIAL_JOBSTOP_SIGS) + * SPECIAL_INTERACTIVE_SIGS are cleared after fork. + * The rest is cleared right before execv syscalls. + * Other than these two times, never modified. + */ + unsigned special_sig_mask; +#if ENABLE_HUSH_JOB + unsigned fatal_sig_mask; +# define G_fatal_sig_mask G.fatal_sig_mask +#else +# define G_fatal_sig_mask 0 +#endif char **traps; /* char *traps[NSIG] */ - sigset_t blocked_set; - sigset_t inherited_set; + sigset_t pending_set; #if HUSH_DEBUG unsigned long memleak_value; int debug_indent; #endif + struct sigaction sa; char user_input_buf[ENABLE_FEATURE_EDITING ? CONFIG_FEATURE_EDITING_MAX_LEN : 2]; }; #define G (*ptr_to_globals) @@ -582,6 +830,9 @@ struct globals { * is global, thus "G." prefix is a useful hint */ #define INIT_G() do { \ SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \ + /* memset(&G.sa, 0, sizeof(G.sa)); */ \ + sigfillset(&G.sa.sa_mask); \ + G.sa.sa_flags = SA_RESTART; \ } while (0) @@ -599,6 +850,9 @@ static int builtin_jobs(char **argv) FAST_FUNC; #if ENABLE_HUSH_HELP static int builtin_help(char **argv) FAST_FUNC; #endif +#if MAX_HISTORY && ENABLE_FEATURE_EDITING +static int builtin_history(char **argv) FAST_FUNC; +#endif #if ENABLE_HUSH_LOCAL static int builtin_local(char **argv) FAST_FUNC; #endif @@ -668,6 +922,9 @@ static const struct built_in_command bltins1[] = { #if ENABLE_HUSH_HELP BLTIN("help" , builtin_help , NULL), #endif +#if MAX_HISTORY && ENABLE_FEATURE_EDITING + BLTIN("history" , builtin_history , "Show command history"), +#endif #if ENABLE_HUSH_JOB BLTIN("jobs" , builtin_jobs , "List jobs"), #endif @@ -710,7 +967,7 @@ static const struct built_in_command bltins2[] = { */ #if HUSH_DEBUG /* prevent disasters with G.debug_indent < 0 */ -# define indent() fprintf(stderr, "%*s", (G.debug_indent * 2) & 0xff, "") +# define indent() fdprintf(2, "%*s", (G.debug_indent * 2) & 0xff, "") # define debug_enter() (G.debug_indent++) # define debug_leave() (G.debug_indent--) #else @@ -720,56 +977,56 @@ static const struct built_in_command bltins2[] = { #endif #ifndef debug_printf -# define debug_printf(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_parse -# define debug_printf_parse(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_parse(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_exec -#define debug_printf_exec(...) (indent(), fprintf(stderr, __VA_ARGS__)) +#define debug_printf_exec(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_env -# define debug_printf_env(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_env(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_jobs -# define debug_printf_jobs(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_jobs(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_JOBS 1 #else # define DEBUG_JOBS 0 #endif #ifndef debug_printf_expand -# define debug_printf_expand(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_expand(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_EXPAND 1 #else # define DEBUG_EXPAND 0 #endif #ifndef debug_printf_varexp -# define debug_printf_varexp(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_varexp(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_glob -# define debug_printf_glob(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_glob(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_GLOB 1 #else # define DEBUG_GLOB 0 #endif #ifndef debug_printf_list -# define debug_printf_list(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_list(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_subst -# define debug_printf_subst(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_subst(...) (indent(), fdprintf(2, __VA_ARGS__)) #endif #ifndef debug_printf_clean -# define debug_printf_clean(...) (indent(), fprintf(stderr, __VA_ARGS__)) +# define debug_printf_clean(...) (indent(), fdprintf(2, __VA_ARGS__)) # define DEBUG_CLEAN 1 #else # define DEBUG_CLEAN 0 @@ -779,9 +1036,9 @@ static const struct built_in_command bltins2[] = { static void debug_print_strings(const char *prefix, char **vv) { indent(); - fprintf(stderr, "%s:\n", prefix); + fdprintf(2, "%s:\n", prefix); while (*vv) - fprintf(stderr, " '%s'\n", *vv++); + fdprintf(2, " '%s'\n", *vv++); } #else # define debug_print_strings(prefix, vv) ((void)0) @@ -849,43 +1106,36 @@ static void die_if_script(unsigned lineno, const char *fmt, ...) xfunc_die(); } -static void syntax_error(unsigned lineno, const char *msg) +static void syntax_error(unsigned lineno UNUSED_PARAM, const char *msg) { if (msg) - die_if_script(lineno, "syntax error: %s", msg); + bb_error_msg("syntax error: %s", msg); else - die_if_script(lineno, "syntax error", NULL); + bb_error_msg("syntax error"); } -static void syntax_error_at(unsigned lineno, const char *msg) +static void syntax_error_at(unsigned lineno UNUSED_PARAM, const char *msg) { - die_if_script(lineno, "syntax error at '%s'", msg); + bb_error_msg("syntax error at '%s'", msg); } -static void syntax_error_unterm_str(unsigned lineno, const char *s) +static void syntax_error_unterm_str(unsigned lineno UNUSED_PARAM, const char *s) { - die_if_script(lineno, "syntax error: unterminated %s", s); + bb_error_msg("syntax error: unterminated %s", s); } -/* It so happens that all such cases are totally fatal - * even if shell is interactive: EOF while looking for closing - * delimiter. There is nowhere to read stuff from after that, - * it's EOF! The only choice is to terminate. - */ -static void syntax_error_unterm_ch(unsigned lineno, char ch) NORETURN; static void syntax_error_unterm_ch(unsigned lineno, char ch) { char msg[2] = { ch, '\0' }; syntax_error_unterm_str(lineno, msg); - xfunc_die(); } -static void syntax_error_unexpected_ch(unsigned lineno, int ch) +static void syntax_error_unexpected_ch(unsigned lineno UNUSED_PARAM, int ch) { char msg[2]; msg[0] = ch; msg[1] = '\0'; - die_if_script(lineno, "syntax error: unexpected %s", ch == EOF ? "EOF" : msg); + bb_error_msg("syntax error: unexpected %s", ch == EOF ? "EOF" : msg); } #if HUSH_DEBUG < 2 @@ -1060,7 +1310,7 @@ static void restore_G_args(save_arg_t *sv, char **argv) * backgrounds (i.e. stops) or kills all members of currently running * pipe. * - * Wait builtin in interruptible by signals for which user trap is set + * Wait builtin is interruptible by signals for which user trap is set * or by SIGINT in interactive shell. * * Trap handlers will execute even within trap handlers. (right?) @@ -1099,12 +1349,14 @@ static void restore_G_args(save_arg_t *sv, char **argv) * "echo $$; sleep 5 & wait; ls -l" + "kill -INT " * Example 3: this does not wait 5 sec, but executes ls: * "sleep 5; ls -l" + press ^C + * Example 4: this does not wait and does not execute ls: + * "sleep 5 & wait; ls -l" + press ^C * * (What happens to signals which are IGN on shell start?) * (What happens with signal mask on shell start?) * - * Implementation in hush - * ====================== + * Old implementation + * ================== * We use in-kernel pending signal mask to determine which signals were sent. * We block all signals which we don't want to take action immediately, * i.e. we block all signals which need to have special handling as described @@ -1112,11 +1364,11 @@ static void restore_G_args(save_arg_t *sv, char **argv) * After each pipe execution, we extract any pending signals via sigtimedwait() * and act on them. * - * unsigned non_DFL_mask: a mask of such "special" signals + * unsigned special_sig_mask: a mask of such "special" signals * sigset_t blocked_set: current blocked signal set * * "trap - SIGxxx": - * clear bit in blocked_set unless it is also in non_DFL_mask + * clear bit in blocked_set unless it is also in special_sig_mask * "trap 'cmd' SIGxxx": * set bit in blocked_set (even if 'cmd' is '') * after [v]fork, if we plan to be a shell: @@ -1135,6 +1387,49 @@ static void restore_G_args(save_arg_t *sv, char **argv) * Standard says "When a subshell is entered, traps that are not being ignored * are set to the default actions". bash interprets it so that traps which * are set to '' (ignore) are NOT reset to defaults. We do the same. + * + * Problem: the above approach makes it unwieldy to catch signals while + * we are in read builtin, or while we read commands from stdin: + * masked signals are not visible! + * + * New implementation + * ================== + * We record each signal we are interested in by installing signal handler + * for them - a bit like emulating kernel pending signal mask in userspace. + * We are interested in: signals which need to have special handling + * as described above, and all signals which have traps set. + * Signals are recorded in pending_set. + * After each pipe execution, we extract any pending signals + * and act on them. + * + * unsigned special_sig_mask: a mask of shell-special signals. + * unsigned fatal_sig_mask: a mask of signals on which we restore tty pgrp. + * char *traps[sig] if trap for sig is set (even if it's ''). + * sigset_t pending_set: set of sigs we received. + * + * "trap - SIGxxx": + * if sig is in special_sig_mask, set handler back to: + * record_pending_signo, or to IGN if it's a tty stop signal + * if sig is in fatal_sig_mask, set handler back to sigexit. + * else: set handler back to SIG_DFL + * "trap 'cmd' SIGxxx": + * set handler to record_pending_signo. + * "trap '' SIGxxx": + * set handler to SIG_IGN. + * after [v]fork, if we plan to be a shell: + * set signals with special interactive handling to SIG_DFL + * (because child shell is not interactive), + * unset all traps except '' (note: regardless of child shell's type - {}, (), etc) + * after [v]fork, if we plan to exec: + * POSIX says fork clears pending signal mask in child - no need to clear it. + * + * To make wait builtin interruptible, we handle SIGCHLD as special signal, + * otherwise (if we leave it SIG_DFL) sigsuspend in wait builtin will not wake up on it. + * + * Note (compat): + * Standard says "When a subshell is entered, traps that are not being ignored + * are set to the default actions". bash interprets it so that traps which + * are set to '' (ignore) are NOT reset to defaults. We do the same. */ enum { SPECIAL_INTERACTIVE_SIGS = 0 @@ -1142,21 +1437,43 @@ enum { | (1 << SIGINT) | (1 << SIGHUP) , - SPECIAL_JOB_SIGS = 0 + SPECIAL_JOBSTOP_SIGS = 0 #if ENABLE_HUSH_JOB | (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP) #endif + , }; -#if ENABLE_HUSH_FAST -static void SIGCHLD_handler(int sig UNUSED_PARAM) +static void record_pending_signo(int sig) { - G.count_SIGCHLD++; + sigaddset(&G.pending_set, sig); +#if ENABLE_HUSH_FAST + if (sig == SIGCHLD) { + G.count_SIGCHLD++; //bb_error_msg("[%d] SIGCHLD_handler: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); -} + } #endif +} + +static sighandler_t install_sighandler(int sig, sighandler_t handler) +{ + struct sigaction old_sa; + + /* We could use signal() to install handlers... almost: + * except that we need to mask ALL signals while handlers run. + * I saw signal nesting in strace, race window isn't small. + * SA_RESTART is also needed, but in Linux, signal() + * sets SA_RESTART too. + */ + /* memset(&G.sa, 0, sizeof(G.sa)); - already done */ + /* sigfillset(&G.sa.sa_mask); - already done */ + /* G.sa.sa_flags = SA_RESTART; - already done */ + G.sa.sa_handler = handler; + sigaction(sig, &G.sa, &old_sa); + return old_sa.sa_handler; +} #if ENABLE_HUSH_JOB @@ -1173,13 +1490,15 @@ static void SIGCHLD_handler(int sig UNUSED_PARAM) static void sigexit(int sig) NORETURN; static void sigexit(int sig) { - /* Disable all signals: job control, SIGPIPE, etc. */ - sigprocmask_allsigs(SIG_BLOCK); - /* Careful: we can end up here after [v]fork. Do not restore * tty pgrp then, only top-level shell process does that */ - if (G_saved_tty_pgrp && getpid() == G.root_pid) + if (G_saved_tty_pgrp && getpid() == G.root_pid) { + /* Disable all signals: job control, SIGPIPE, etc. + * Mostly paranoid measure, to prevent infinite SIGTTOU. + */ + sigprocmask_allsigs(SIG_BLOCK); tcsetpgrp(G_interactive_fd, G_saved_tty_pgrp); + } /* Not a signal, just exit */ if (sig <= 0) @@ -1194,21 +1513,70 @@ static void sigexit(int sig) #endif +static sighandler_t pick_sighandler(unsigned sig) +{ + sighandler_t handler = SIG_DFL; + if (sig < sizeof(unsigned)*8) { + unsigned sigmask = (1 << sig); + +#if ENABLE_HUSH_JOB + /* is sig fatal? */ + if (G_fatal_sig_mask & sigmask) + handler = sigexit; + else +#endif + /* sig has special handling? */ + if (G.special_sig_mask & sigmask) { + handler = record_pending_signo; + /* TTIN/TTOU/TSTP can't be set to record_pending_signo + * in order to ignore them: they will be raised + * in an endless loop when we try to do some + * terminal ioctls! We do have to _ignore_ these. + */ + if (SPECIAL_JOBSTOP_SIGS & sigmask) + handler = SIG_IGN; + } + } + return handler; +} + /* Restores tty foreground process group, and exits. */ static void hush_exit(int exitcode) NORETURN; static void hush_exit(int exitcode) { +#if ENABLE_FEATURE_EDITING_SAVE_ON_EXIT + save_history(G.line_input_state); +#endif + + fflush_all(); if (G.exiting <= 0 && G.traps && G.traps[0] && G.traps[0][0]) { - /* Prevent recursion: - * trap "echo Hi; exit" EXIT; exit - */ - char *argv[] = { NULL, G.traps[0], NULL }; - G.traps[0] = NULL; - G.exiting = 1; + char *argv[3]; + /* argv[0] is unused */ + argv[1] = G.traps[0]; + argv[2] = NULL; + G.exiting = 1; /* prevent EXIT trap recursion */ + /* Note: G.traps[0] is not cleared! + * "trap" will still show it, if executed + * in the handler */ builtin_eval(argv); - free(argv[1]); } +#if ENABLE_FEATURE_CLEAN_UP + { + struct variable *cur_var; + if (G.cwd != bb_msg_unknown) + free((char*)G.cwd); + cur_var = G.top_var; + while (cur_var) { + struct variable *tmp = cur_var; + if (!cur_var->max_len) + free(cur_var->varstr); + cur_var = cur_var->next; + free(tmp); + } + } +#endif + #if ENABLE_HUSH_JOB fflush_all(); sigexit(- (exitcode & 0xff)); @@ -1217,43 +1585,49 @@ static void hush_exit(int exitcode) #endif } -static int check_and_run_traps(int sig) + +//TODO: return a mask of ALL handled sigs? +static int check_and_run_traps(void) { - static const struct timespec zero_timespec; - smalluint save_rcode; int last_sig = 0; - if (sig) - goto jump_in; while (1) { - sig = sigtimedwait(&G.blocked_set, NULL, &zero_timespec); - if (sig <= 0) + int sig; + + if (sigisemptyset(&G.pending_set)) break; - jump_in: - last_sig = sig; + sig = 0; + do { + sig++; + if (sigismember(&G.pending_set, sig)) { + sigdelset(&G.pending_set, sig); + goto got_sig; + } + } while (sig < NSIG); + break; + got_sig: if (G.traps && G.traps[sig]) { if (G.traps[sig][0]) { /* We have user-defined handler */ - char *argv[] = { NULL, xstrdup(G.traps[sig]), NULL }; + smalluint save_rcode; + char *argv[3]; + /* argv[0] is unused */ + argv[1] = G.traps[sig]; + argv[2] = NULL; save_rcode = G.last_exitcode; builtin_eval(argv); - free(argv[1]); G.last_exitcode = save_rcode; + last_sig = sig; } /* else: "" trap, ignoring signal */ continue; } /* not a trap: special action */ switch (sig) { -#if ENABLE_HUSH_FAST - case SIGCHLD: - G.count_SIGCHLD++; -//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); - break; -#endif case SIGINT: /* Builtin was ^C'ed, make it look prettier: */ bb_putchar('\n'); G.flag_SIGINT = 1; + last_sig = sig; break; #if ENABLE_HUSH_JOB case SIGHUP: { @@ -1270,8 +1644,23 @@ static int check_and_run_traps(int sig) sigexit(SIGHUP); } #endif +#if ENABLE_HUSH_FAST + case SIGCHLD: + G.count_SIGCHLD++; +//bb_error_msg("[%d] check_and_run_traps: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + /* Note: + * We dont do 'last_sig = sig' here -> NOT returning this sig. + * This simplifies wait builtin a bit. + */ + break; +#endif default: /* ignored: */ /* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */ + /* Note: + * We dont do 'last_sig = sig' here -> NOT returning this sig. + * Example: wait is not interrupted by TERM + * in interactive shell, because TERM is ignored. + */ break; } } @@ -1297,13 +1686,11 @@ static const char *get_cwd(int force) /* * Shell and environment variable support */ -static struct variable **get_ptr_to_local_var(const char *name) +static struct variable **get_ptr_to_local_var(const char *name, unsigned len) { struct variable **pp; struct variable *cur; - int len; - len = strlen(name); pp = &G.top_var; while ((cur = *pp) != NULL) { if (strncmp(cur->varstr, name, len) == 0 && cur->varstr[len] == '=') @@ -1313,26 +1700,31 @@ static struct variable **get_ptr_to_local_var(const char *name) return NULL; } -static struct variable *get_local_var(const char *name) -{ - struct variable **pp = get_ptr_to_local_var(name); - if (pp) - return *pp; - return NULL; -} - static const char* FAST_FUNC get_local_var_value(const char *name) { - struct variable **pp = get_ptr_to_local_var(name); - if (pp) - return strchr((*pp)->varstr, '=') + 1; + struct variable **vpp; + unsigned len = strlen(name); + + if (G.expanded_assignments) { + char **cpp = G.expanded_assignments; + while (*cpp) { + char *cp = *cpp; + if (strncmp(cp, name, len) == 0 && cp[len] == '=') + return cp + len + 1; + cpp++; + } + } + + vpp = get_ptr_to_local_var(name, len); + if (vpp) + return (*vpp)->varstr + len + 1; + if (strcmp(name, "PPID") == 0) return utoa(G.root_ppid); // bash compat: UID? EUID? #if ENABLE_HUSH_RANDOM_SUPPORT - if (strcmp(name, "RANDOM") == 0) { + if (strcmp(name, "RANDOM") == 0) return utoa(next_random(&G.random_gen)); - } #endif return NULL; } @@ -1521,24 +1913,6 @@ static void unset_vars(char **strings) free(strings); } -#if ENABLE_SH_MATH_SUPPORT -# define is_name(c) ((c) == '_' || isalpha((unsigned char)(c))) -# define is_in_name(c) ((c) == '_' || isalnum((unsigned char)(c))) -static char* FAST_FUNC endofname(const char *name) -{ - char *p; - - p = (char *) name; - if (!is_name(*p)) - return p; - while (*++p) { - if (!is_in_name(*p)) - break; - } - return p; -} -#endif - static void FAST_FUNC set_local_var_from_halves(const char *name, const char *val) { char *var = xasprintf("%s=%s", name, val); @@ -1582,9 +1956,7 @@ static struct variable *set_vars_and_save_old(char **strings) eq = strchr(*s, '='); if (eq) { - *eq = '\0'; - var_pp = get_ptr_to_local_var(*s); - *eq = '='; + var_pp = get_ptr_to_local_var(*s, eq - *s); if (var_pp) { /* Remove variable from global linked list */ var_p = *var_pp; @@ -1610,6 +1982,7 @@ static int FAST_FUNC static_get(struct in_str *i) int ch = *i->p; if (ch != '\0') { i->p++; + i->last_char = ch; return ch; } return EOF; @@ -1636,7 +2009,7 @@ static void cmdedit_update_prompt(void) G.PS2 = "> "; } -static const char* setup_prompt_string(int promptmode) +static const char *setup_prompt_string(int promptmode) { const char *prompt_str; debug_printf("setup_prompt_string %d ", promptmode); @@ -1667,12 +2040,21 @@ static void get_user_input(struct in_str *i) /* Enable command line editing only while a command line * is actually being read */ do { + /* Unicode support should be activated even if LANG is set + * _during_ shell execution, not only if it was set when + * shell was started. Therefore, re-check LANG every time: + */ + const char *s = get_local_var_value("LC_ALL"); + if (!s) s = get_local_var_value("LC_CTYPE"); + if (!s) s = get_local_var_value("LANG"); + reinit_unicode(s); + G.flag_SIGINT = 0; /* buglet: SIGINT will not make new prompt to appear _at once_, * only after . (^C will work) */ - r = read_line_input(prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, G.line_input_state); + r = read_line_input(G.line_input_state, prompt_str, G.user_input_buf, CONFIG_FEATURE_EDITING_MAX_LEN-1, /*timeout*/ -1); /* catch *SIGINT* etc (^C is handled by read_line_input) */ - check_and_run_traps(0); + check_and_run_traps(); } while (r == 0 || G.flag_SIGINT); /* repeat if ^C or SIGINT */ i->eof_flag = (r < 0); if (i->eof_flag) { /* EOF/error detected */ @@ -1682,11 +2064,18 @@ static void get_user_input(struct in_str *i) # else do { G.flag_SIGINT = 0; - fputs(prompt_str, stdout); + if (i->last_char == '\0' || i->last_char == '\n') { + /* Why check_and_run_traps here? Try this interactively: + * $ trap 'echo INT' INT; (sleep 2; kill -INT $$) & + * $ <[enter], repeatedly...> + * Without check_and_run_traps, handler never runs. + */ + check_and_run_traps(); + fputs(prompt_str, stdout); + } fflush_all(); G.user_input_buf[0] = r = fgetc(i->file); /*G.user_input_buf[1] = '\0'; - already is and never changed */ -//do we need check_and_run_traps(0)? (maybe only if stdin) } while (G.flag_SIGINT); i->eof_flag = (r == EOF); # endif @@ -1714,22 +2103,18 @@ static int FAST_FUNC file_get(struct in_str *i) /* need to double check i->file because we might be doing something * more complicated by now, like sourcing or substituting. */ #if ENABLE_HUSH_INTERACTIVE - if (G_interactive_fd && i->promptme && i->file == stdin) { + if (G_interactive_fd && i->file == stdin) { do { get_user_input(i); } while (!*i->p); /* need non-empty line */ i->promptmode = 1; /* PS2 */ - i->promptme = 0; goto take_cached; } #endif do ch = fgetc(i->file); while (ch == '\0'); } debug_printf("file_get: got '%c' %d\n", ch, ch); -#if ENABLE_HUSH_INTERACTIVE - if (ch == '\n') - i->promptme = 1; -#endif + i->last_char = ch; return ch; } @@ -1756,26 +2141,22 @@ static int FAST_FUNC file_peek(struct in_str *i) static void setup_file_in_str(struct in_str *i, FILE *f) { + memset(i, 0, sizeof(*i)); i->peek = file_peek; i->get = file_get; -#if ENABLE_HUSH_INTERACTIVE - i->promptme = 1; - i->promptmode = 0; /* PS1 */ -#endif + /* i->promptmode = 0; - PS1 (memset did it) */ i->file = f; - i->p = NULL; + /* i->p = NULL; */ } static void setup_string_in_str(struct in_str *i, const char *s) { + memset(i, 0, sizeof(*i)); i->peek = static_peek; i->get = static_get; -#if ENABLE_HUSH_INTERACTIVE - i->promptme = 1; - i->promptmode = 0; /* PS1 */ -#endif + /* i->promptmode = 0; - PS1 (memset did it) */ i->p = s; - i->eof_flag = 0; + /* i->eof_flag = 0; */ } @@ -1787,7 +2168,7 @@ static void setup_string_in_str(struct in_str *i, const char *s) static void o_reset_to_empty_unquoted(o_string *o) { o->length = 0; - o->o_quoted = 0; + o->has_quoted_part = 0; if (o->data) o->data[0] = '\0'; } @@ -1848,22 +2229,8 @@ static void o_addstr_with_NUL(o_string *o, const char *str) o_addblock(o, str, strlen(str) + 1); } -static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) -{ - while (len) { - o_addchr(o, *str); - if (*str++ == '\\' - && (*str != '*' && *str != '?' && *str != '[') - ) { - o_addchr(o, '\\'); - } - len--; - } -} - -#undef HUSH_BRACE_EXP /* - * HUSH_BRACE_EXP code needs corresponding quoting on variable expansion side. + * HUSH_BRACE_EXPANSION code needs corresponding quoting on variable expansion side. * Currently, "v='{q,w}'; echo $v" erroneously expands braces in $v. * Apparently, on unquoted $v bash still does globbing * ("v='*.txt'; echo $v" prints all .txt files), @@ -1873,7 +2240,7 @@ static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len * We have only second one. */ -#ifdef HUSH_BRACE_EXP +#if ENABLE_HUSH_BRACE_EXPANSION # define MAYBE_BRACES "{}" #else # define MAYBE_BRACES "" @@ -1901,7 +2268,9 @@ static void o_addqchr(o_string *o, int ch) static void o_addQchr(o_string *o, int ch) { int sz = 1; - if (o->o_escape && strchr("*?[\\" MAYBE_BRACES, ch)) { + if ((o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS) + && strchr("*?[\\" MAYBE_BRACES, ch) + ) { sz++; o->data[o->length] = '\\'; o->length++; @@ -1912,12 +2281,8 @@ static void o_addQchr(o_string *o, int ch) o->data[o->length] = '\0'; } -static void o_addQstr(o_string *o, const char *str, int len) +static void o_addqblock(o_string *o, const char *str, int len) { - if (!o->o_escape) { - o_addblock(o, str, len); - return; - } while (len) { char ch; int sz; @@ -1926,7 +2291,7 @@ static void o_addQstr(o_string *o, const char *str, int len) ordinary_cnt = len; o_addblock(o, str, ordinary_cnt); if (ordinary_cnt == len) - return; + return; /* NUL is already added by o_addblock */ str += ordinary_cnt; len -= ordinary_cnt + 1; /* we are processing + 1 char below */ @@ -1940,8 +2305,22 @@ static void o_addQstr(o_string *o, const char *str, int len) o_grow_by(o, sz); o->data[o->length] = ch; o->length++; - o->data[o->length] = '\0'; } + o->data[o->length] = '\0'; +} + +static void o_addQblock(o_string *o, const char *str, int len) +{ + if (!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)) { + o_addblock(o, str, len); + return; + } + o_addqblock(o, str, len); +} + +static void o_addQstr(o_string *o, const char *str) +{ + o_addQblock(o, str, strlen(str)); } /* A special kind of o_string for $VAR and `cmd` expansion. @@ -1962,19 +2341,22 @@ static void debug_print_list(const char *prefix, o_string *o, int n) int i = 0; indent(); - fprintf(stderr, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d\n", - prefix, list, n, string_start, o->length, o->maxlen); + fdprintf(2, "%s: list:%p n:%d string_start:%d length:%d maxlen:%d glob:%d quoted:%d escape:%d\n", + prefix, list, n, string_start, o->length, o->maxlen, + !!(o->o_expflags & EXP_FLAG_GLOB), + o->has_quoted_part, + !!(o->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); while (i < n) { indent(); - fprintf(stderr, " list[%d]=%d '%s' %p\n", i, (int)list[i], - o->data + (int)list[i] + string_start, - o->data + (int)list[i] + string_start); + fdprintf(2, " list[%d]=%d '%s' %p\n", i, (int)(uintptr_t)list[i], + o->data + (int)(uintptr_t)list[i] + string_start, + o->data + (int)(uintptr_t)list[i] + string_start); i++; } if (n) { - const char *p = o->data + (int)list[n - 1] + string_start; + const char *p = o->data + (int)(uintptr_t)list[n - 1] + string_start; indent(); - fprintf(stderr, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); + fdprintf(2, " total_sz:%ld\n", (long)((p + strlen(p) + 1) - o->data)); } } #else @@ -2013,7 +2395,8 @@ static int o_save_ptr_helper(o_string *o, int n) n, string_len, string_start); o->has_empty_slot = 0; } - list[n] = (char*)(ptrdiff_t)string_len; + o->has_quoted_part = 0; + list[n] = (char*)(uintptr_t)string_len; return n + 1; } @@ -2023,10 +2406,10 @@ static int o_get_last_ptr(o_string *o, int n) char **list = (char**)o->data; int string_start = ((n + 0xf) & ~0xf) * sizeof(list[0]); - return ((int)(ptrdiff_t)list[n-1]) + string_start; + return ((int)(uintptr_t)list[n-1]) + string_start; } -#ifdef HUSH_BRACE_EXP +#if ENABLE_HUSH_BRACE_EXPANSION /* There in a GNU extension, GLOB_BRACE, but it is not usable: * first, it processes even {a} (no commas), second, * I didn't manage to make it return strings when they don't match @@ -2061,9 +2444,9 @@ static const char *next_brace_sub(const char *cp) cp++; continue; } - /*{*/ if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) + if ((*cp == '}' && depth-- == 0) || (*cp == ',' && depth == 0)) break; - if (*cp++ == '{') /*}*/ + if (*cp++ == '{') depth++; } @@ -2085,7 +2468,7 @@ static int glob_brace(char *pattern, o_string *o, int n) while (1) { if (*begin == '\0') goto simple_glob; - if (*begin == '{') /*}*/ { + if (*begin == '{') { /* Find the first sub-pattern and at the same time * find the rest after the closing brace */ next = next_brace_sub(begin); @@ -2093,7 +2476,7 @@ static int glob_brace(char *pattern, o_string *o, int n) /* An illegal expression */ goto simple_glob; } - /*{*/ if (*next == '}') { + if (*next == '}') { /* "{abc}" with no commas - illegal * brace expr, disregard and skip it */ begin = next + 1; @@ -2110,7 +2493,7 @@ static int glob_brace(char *pattern, o_string *o, int n) /* Now find the end of the whole brace expression */ rest = next; - /*{*/ while (*rest != '}') { + while (*rest != '}') { rest = next_brace_sub(rest); if (rest == NULL) { /* An illegal expression */ @@ -2146,7 +2529,7 @@ static int glob_brace(char *pattern, o_string *o, int n) * That's why we re-copy prefix every time (1st memcpy above). */ n = glob_brace(new_pattern_buf, o, n); - /*{*/ if (*next == '}') { + if (*next == '}') { /* We saw the last entry */ break; } @@ -2196,11 +2579,11 @@ static int glob_brace(char *pattern, o_string *o, int n) /* Performs globbing on last list[], * saving each result as a new list[]. */ -static int o_glob(o_string *o, int n) +static int perform_glob(o_string *o, int n) { char *pattern, *copy; - debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data); + debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); if (!o->data) return o_save_ptr_helper(o, n); pattern = o->data + o_get_last_ptr(o, n); @@ -2218,11 +2601,11 @@ static int o_glob(o_string *o, int n) n = glob_brace(copy, o, n); free(copy); if (DEBUG_GLOB) - debug_print_list("o_glob returning", o, n); + debug_print_list("perform_glob returning", o, n); return n; } -#else /* !HUSH_BRACE_EXP */ +#else /* !HUSH_BRACE_EXPANSION */ /* Helper */ static int glob_needed(const char *s) @@ -2243,13 +2626,13 @@ static int glob_needed(const char *s) /* Performs globbing on last list[], * saving each result as a new list[]. */ -static int o_glob(o_string *o, int n) +static int perform_glob(o_string *o, int n) { glob_t globdata; int gr; char *pattern; - debug_printf_glob("start o_glob: n:%d o->data:%p\n", n, o->data); + debug_printf_glob("start perform_glob: n:%d o->data:%p\n", n, o->data); if (!o->data) return o_save_ptr_helper(o, n); pattern = o->data + o_get_last_ptr(o, n); @@ -2295,22 +2678,22 @@ static int o_glob(o_string *o, int n) } globfree(&globdata); if (DEBUG_GLOB) - debug_print_list("o_glob returning", o, n); + debug_print_list("perform_glob returning", o, n); return n; } -#endif /* !HUSH_BRACE_EXP */ +#endif /* !HUSH_BRACE_EXPANSION */ -/* If o->o_glob == 1, glob the string so far remembered. +/* If o->o_expflags & EXP_FLAG_GLOB, glob the string so far remembered. * Otherwise, just finish current list[] and start new */ static int o_save_ptr(o_string *o, int n) { - if (o->o_glob) { /* if globbing is requested */ + if (o->o_expflags & EXP_FLAG_GLOB) { /* If o->has_empty_slot, list[n] was already globbed * (if it was requested back then when it was filled) * so don't do that again! */ if (!o->has_empty_slot) - return o_glob(o, n); /* o_save_ptr_helper is inside */ + return perform_glob(o, n); /* o_save_ptr_helper is inside */ } return o_save_ptr_helper(o, n); } @@ -2330,1079 +2713,851 @@ static char **o_finalize_list(o_string *o, int n) list[--n] = NULL; while (n) { n--; - list[n] = o->data + (int)(ptrdiff_t)list[n] + string_start; + list[n] = o->data + (int)(uintptr_t)list[n] + string_start; } return list; } +static void free_pipe_list(struct pipe *pi); -/* Expansion can recurse */ -#if ENABLE_HUSH_TICK -static int process_command_subs(o_string *dest, const char *s); +/* Returns pi->next - next pipe in the list */ +static struct pipe *free_pipe(struct pipe *pi) +{ + struct pipe *next; + int i; + + debug_printf_clean("free_pipe (pid %d)\n", getpid()); + for (i = 0; i < pi->num_cmds; i++) { + struct command *command; + struct redir_struct *r, *rnext; + + command = &pi->cmds[i]; + debug_printf_clean(" command %d:\n", i); + if (command->argv) { + if (DEBUG_CLEAN) { + int a; + char **p; + for (a = 0, p = command->argv; *p; a++, p++) { + debug_printf_clean(" argv[%d] = %s\n", a, *p); + } + } + free_strings(command->argv); + //command->argv = NULL; + } + /* not "else if": on syntax error, we may have both! */ + if (command->group) { + debug_printf_clean(" begin group (cmd_type:%d)\n", + command->cmd_type); + free_pipe_list(command->group); + debug_printf_clean(" end group\n"); + //command->group = NULL; + } + /* else is crucial here. + * If group != NULL, child_func is meaningless */ +#if ENABLE_HUSH_FUNCTIONS + else if (command->child_func) { + debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func); + command->child_func->parent_cmd = NULL; + } #endif -static char *expand_string_to_string(const char *str); -#if BB_MMU -#define parse_stream_dquoted(as_string, dest, input, dquote_end) \ - parse_stream_dquoted(dest, input, dquote_end) +#if !BB_MMU + free(command->group_as_string); + //command->group_as_string = NULL; +#endif + for (r = command->redirects; r; r = rnext) { + debug_printf_clean(" redirect %d%s", + r->rd_fd, redir_table[r->rd_type].descrip); + /* guard against the case >$FOO, where foo is unset or blank */ + if (r->rd_filename) { + debug_printf_clean(" fname:'%s'\n", r->rd_filename); + free(r->rd_filename); + //r->rd_filename = NULL; + } + debug_printf_clean(" rd_dup:%d\n", r->rd_dup); + rnext = r->next; + free(r); + } + //command->redirects = NULL; + } + free(pi->cmds); /* children are an array, they get freed all at once */ + //pi->cmds = NULL; +#if ENABLE_HUSH_JOB + free(pi->cmdtext); + //pi->cmdtext = NULL; #endif -static int parse_stream_dquoted(o_string *as_string, - o_string *dest, - struct in_str *input, - int dquote_end); -/* expand_strvec_to_strvec() takes a list of strings, expands - * all variable references within and returns a pointer to - * a list of expanded strings, possibly with larger number - * of strings. (Think VAR="a b"; echo $VAR). - * This new list is allocated as a single malloc block. - * NULL-terminated list of char* pointers is at the beginning of it, - * followed by strings themself. - * Caller can deallocate entire list by single free(list). */ + next = pi->next; + free(pi); + return next; +} -/* Store given string, finalizing the word and starting new one whenever - * we encounter IFS char(s). This is used for expanding variable values. - * End-of-string does NOT finalize word: think about 'echo -$VAR-' */ -static int expand_on_ifs(o_string *output, int n, const char *str) +static void free_pipe_list(struct pipe *pi) { - while (1) { - int word_len = strcspn(str, G.ifs); - if (word_len) { - if (output->o_escape || !output->o_glob) - o_addQstr(output, str, word_len); - else /* protect backslashes against globbing up :) */ - o_addblock_duplicate_backslash(output, str, word_len); - str += word_len; - } - if (!*str) /* EOL - do not finalize word */ - break; - o_addchr(output, '\0'); - debug_print_list("expand_on_ifs", output, n); - n = o_save_ptr(output, n); - str += strspn(str, G.ifs); /* skip ifs chars */ + while (pi) { +#if HAS_KEYWORDS + debug_printf_clean("pipe reserved word %d\n", pi->res_word); +#endif + debug_printf_clean("pipe followup code %d\n", pi->followup); + pi = free_pipe(pi); } - debug_print_list("expand_on_ifs[1]", output, n); - return n; } -/* Helper to expand $((...)) and heredoc body. These act as if - * they are in double quotes, with the exception that they are not :). - * Just the rules are similar: "expand only $var and `cmd`" - * - * Returns malloced string. - * As an optimization, we return NULL if expansion is not needed. - */ -static char *expand_pseudo_dquoted(const char *str) + +/*** Parsing routines ***/ + +#ifndef debug_print_tree +static void debug_print_tree(struct pipe *pi, int lvl) { - char *exp_str; - struct in_str input; - o_string dest = NULL_O_STRING; + static const char *const PIPE[] = { + [PIPE_SEQ] = "SEQ", + [PIPE_AND] = "AND", + [PIPE_OR ] = "OR" , + [PIPE_BG ] = "BG" , + }; + static const char *RES[] = { + [RES_NONE ] = "NONE" , +# if ENABLE_HUSH_IF + [RES_IF ] = "IF" , + [RES_THEN ] = "THEN" , + [RES_ELIF ] = "ELIF" , + [RES_ELSE ] = "ELSE" , + [RES_FI ] = "FI" , +# endif +# if ENABLE_HUSH_LOOPS + [RES_FOR ] = "FOR" , + [RES_WHILE] = "WHILE", + [RES_UNTIL] = "UNTIL", + [RES_DO ] = "DO" , + [RES_DONE ] = "DONE" , +# endif +# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE + [RES_IN ] = "IN" , +# endif +# if ENABLE_HUSH_CASE + [RES_CASE ] = "CASE" , + [RES_CASE_IN ] = "CASE_IN" , + [RES_MATCH] = "MATCH", + [RES_CASE_BODY] = "CASE_BODY", + [RES_ESAC ] = "ESAC" , +# endif + [RES_XXXX ] = "XXXX" , + [RES_SNTX ] = "SNTX" , + }; + static const char *const CMDTYPE[] = { + "{}", + "()", + "[noglob]", +# if ENABLE_HUSH_FUNCTIONS + "func()", +# endif + }; - if (strchr(str, '$') == NULL -#if ENABLE_HUSH_TICK - && strchr(str, '`') == NULL -#endif - ) { - return NULL; + int pin, prn; + + pin = 0; + while (pi) { + fdprintf(2, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", + pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); + prn = 0; + while (prn < pi->num_cmds) { + struct command *command = &pi->cmds[prn]; + char **argv = command->argv; + + fdprintf(2, "%*s cmd %d assignment_cnt:%d", + lvl*2, "", prn, + command->assignment_cnt); + if (command->group) { + fdprintf(2, " group %s: (argv=%p)%s%s\n", + CMDTYPE[command->cmd_type], + argv +# if !BB_MMU + , " group_as_string:", command->group_as_string +# else + , "", "" +# endif + ); + debug_print_tree(command->group, lvl+1); + prn++; + continue; + } + if (argv) while (*argv) { + fdprintf(2, " '%s'", *argv); + argv++; + } + fdprintf(2, "\n"); + prn++; + } + pi = pi->next; + pin++; } +} +#endif /* debug_print_tree */ - /* We need to expand. Example: - * echo $(($a + `echo 1`)) $((1 + $((2)) )) - */ - setup_string_in_str(&input, str); - parse_stream_dquoted(NULL, &dest, &input, EOF); - //bb_error_msg("'%s' -> '%s'", str, dest.data); - exp_str = expand_string_to_string(dest.data); - //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); - o_free_unsafe(&dest); - return exp_str; +static struct pipe *new_pipe(void) +{ + struct pipe *pi; + pi = xzalloc(sizeof(struct pipe)); + /*pi->followup = 0; - deliberately invalid value */ + /*pi->res_word = RES_NONE; - RES_NONE is 0 anyway */ + return pi; } -#if ENABLE_SH_MATH_SUPPORT -static arith_t expand_and_evaluate_arith(const char *arg, int *errcode_p) +/* Command (member of a pipe) is complete, or we start a new pipe + * if ctx->command is NULL. + * No errors possible here. + */ +static int done_command(struct parse_context *ctx) { - arith_eval_hooks_t hooks; - arith_t res; - char *exp_str; + /* The command is really already in the pipe structure, so + * advance the pipe counter and make a new, null command. */ + struct pipe *pi = ctx->pipe; + struct command *command = ctx->command; - hooks.lookupvar = get_local_var_value; - hooks.setvar = set_local_var_from_halves; - hooks.endofname = endofname; - exp_str = expand_pseudo_dquoted(arg); - res = arith(exp_str ? exp_str : arg, errcode_p, &hooks); - free(exp_str); - return res; + if (command) { + if (IS_NULL_CMD(command)) { + debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); + goto clear_and_ret; + } + pi->num_cmds++; + debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); + //debug_print_tree(ctx->list_head, 20); + } else { + debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); + } + + /* Only real trickiness here is that the uncommitted + * command structure is not counted in pi->num_cmds. */ + pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); + ctx->command = command = &pi->cmds[pi->num_cmds]; + clear_and_ret: + memset(command, 0, sizeof(*command)); + return pi->num_cmds; /* used only for 0/nonzero check */ } -#endif -/* Expand all variable references in given string, adding words to list[] - * at n, n+1,... positions. Return updated n (so that list[n] is next one - * to be filled). This routine is extremely tricky: has to deal with - * variables/parameters with whitespace, $* and $@, and constructs like - * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ -static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg, char or_mask) +static void done_pipe(struct parse_context *ctx, pipe_style type) { - /* or_mask is either 0 (normal case) or 0x80 - - * expansion of right-hand side of assignment == 1-element expand. - * It will also do no globbing, and thus we must not backslash-quote! - */ - char ored_ch; - char *p; - - ored_ch = 0; + int not_null; - debug_printf_expand("expand_vars_to_list: arg:'%s' or_mask:%x\n", arg, or_mask); - debug_print_list("expand_vars_to_list", output, n); - n = o_save_ptr(output, n); - debug_print_list("expand_vars_to_list[0]", output, n); + debug_printf_parse("done_pipe entered, followup %d\n", type); + /* Close previous command */ + not_null = done_command(ctx); + ctx->pipe->followup = type; +#if HAS_KEYWORDS + ctx->pipe->pi_inverted = ctx->ctx_inverted; + ctx->ctx_inverted = 0; + ctx->pipe->res_word = ctx->ctx_res_w; +#endif - while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { - char first_ch; - int i; - char *to_be_freed = NULL; - const char *val = NULL; -#if ENABLE_HUSH_TICK - o_string subst_result = NULL_O_STRING; + /* Without this check, even just on command line generates + * tree of three NOPs (!). Which is harmless but annoying. + * IOW: it is safe to do it unconditionally. */ + if (not_null +#if ENABLE_HUSH_IF + || ctx->ctx_res_w == RES_FI #endif -#if ENABLE_SH_MATH_SUPPORT - char arith_buf[sizeof(arith_t)*3 + 2]; +#if ENABLE_HUSH_LOOPS + || ctx->ctx_res_w == RES_DONE + || ctx->ctx_res_w == RES_FOR + || ctx->ctx_res_w == RES_IN #endif - o_addblock(output, arg, p - arg); - debug_print_list("expand_vars_to_list[1]", output, n); - arg = ++p; - p = strchr(p, SPECIAL_VAR_SYMBOL); +#if ENABLE_HUSH_CASE + || ctx->ctx_res_w == RES_ESAC +#endif + ) { + struct pipe *new_p; + debug_printf_parse("done_pipe: adding new pipe: " + "not_null:%d ctx->ctx_res_w:%d\n", + not_null, ctx->ctx_res_w); + new_p = new_pipe(); + ctx->pipe->next = new_p; + ctx->pipe = new_p; + /* RES_THEN, RES_DO etc are "sticky" - + * they remain set for pipes inside if/while. + * This is used to control execution. + * RES_FOR and RES_IN are NOT sticky (needed to support + * cases where variable or value happens to match a keyword): + */ +#if ENABLE_HUSH_LOOPS + if (ctx->ctx_res_w == RES_FOR + || ctx->ctx_res_w == RES_IN) + ctx->ctx_res_w = RES_NONE; +#endif +#if ENABLE_HUSH_CASE + if (ctx->ctx_res_w == RES_MATCH) + ctx->ctx_res_w = RES_CASE_BODY; + if (ctx->ctx_res_w == RES_CASE) + ctx->ctx_res_w = RES_CASE_IN; +#endif + ctx->command = NULL; /* trick done_command below */ + /* Create the memory for command, roughly: + * ctx->pipe->cmds = new struct command; + * ctx->command = &ctx->pipe->cmds[0]; + */ + done_command(ctx); + //debug_print_tree(ctx->list_head, 10); + } + debug_printf_parse("done_pipe return\n"); +} - first_ch = arg[0] | or_mask; /* forced to "quoted" if or_mask = 0x80 */ - /* "$@" is special. Even if quoted, it can still - * expand to nothing (not even an empty string) */ - if ((first_ch & 0x7f) != '@') - ored_ch |= first_ch; +static void initialize_context(struct parse_context *ctx) +{ + memset(ctx, 0, sizeof(*ctx)); + ctx->pipe = ctx->list_head = new_pipe(); + /* Create the memory for command, roughly: + * ctx->pipe->cmds = new struct command; + * ctx->command = &ctx->pipe->cmds[0]; + */ + done_command(ctx); +} - switch (first_ch & 0x7f) { - /* Highest bit in first_ch indicates that var is double-quoted */ - case '*': - case '@': - i = 1; - if (!G.global_argv[i]) - break; - ored_ch |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ - if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ - smallint sv = output->o_escape; - /* unquoted var's contents should be globbed, so don't escape */ - output->o_escape = 0; - while (G.global_argv[i]) { - n = expand_on_ifs(output, n, G.global_argv[i]); - debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); - if (G.global_argv[i++][0] && G.global_argv[i]) { - /* this argv[] is not empty and not last: - * put terminating NUL, start new word */ - o_addchr(output, '\0'); - debug_print_list("expand_vars_to_list[2]", output, n); - n = o_save_ptr(output, n); - debug_print_list("expand_vars_to_list[3]", output, n); - } - } - output->o_escape = sv; - } else - /* If or_mask is nonzero, we handle assignment 'a=....$@.....' - * and in this case should treat it like '$*' - see 'else...' below */ - if (first_ch == ('@'|0x80) && !or_mask) { /* quoted $@ */ - while (1) { - o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i])); - if (++i >= G.global_argc) - break; - o_addchr(output, '\0'); - debug_print_list("expand_vars_to_list[4]", output, n); - n = o_save_ptr(output, n); - } - } else { /* quoted $*: add as one word */ - while (1) { - o_addQstr(output, G.global_argv[i], strlen(G.global_argv[i])); - if (!G.global_argv[++i]) - break; - if (G.ifs[0]) - o_addchr(output, G.ifs[0]); - } - } - break; - case SPECIAL_VAR_SYMBOL: /* */ - /* "Empty variable", used to make "" etc to not disappear */ - arg++; - ored_ch = 0x80; - break; -#if ENABLE_HUSH_TICK - case '`': /* `cmd */ - *p = '\0'; - arg++; - /* Can't just stuff it into output o_string, - * expanded result may need to be globbed - * and $IFS-splitted */ - debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); - G.last_exitcode = process_command_subs(&subst_result, arg); - debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data); - val = subst_result.data; - goto store_val; -#endif -#if ENABLE_SH_MATH_SUPPORT - case '+': { /* +cmd */ - arith_t res; - int errcode; - - arg++; /* skip '+' */ - *p = '\0'; /* replace trailing */ - debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); - res = expand_and_evaluate_arith(arg, &errcode); - - if (errcode < 0) { - const char *msg = "error in arithmetic"; - switch (errcode) { - case -3: - msg = "exponent less than 0"; - break; - case -2: - msg = "divide by 0"; - break; - case -5: - msg = "expression recursion loop detected"; - break; - } - die_if_script(msg); - } - debug_printf_subst("ARITH RES '"arith_t_fmt"'\n", res); - sprintf(arith_buf, arith_t_fmt, res); - val = arith_buf; - break; - } -#endif - default: { /* varname */ - char *var; - char first_char; - char exp_op; - char exp_save = exp_save; /* for compiler */ - char *exp_saveptr; /* points to expansion operator */ - char *exp_word = exp_word; /* for compiler */ - - var = arg; - *p = '\0'; - exp_saveptr = arg[1] ? strchr("%#:-=+?", arg[1]) : NULL; - first_char = arg[0] = first_ch & 0x7f; - exp_op = 0; - - if (first_char == '#' && arg[1] && !exp_saveptr) { - /* handle length expansion ${#var} */ - var++; - exp_op = 'L'; - } else { - /* maybe handle parameter expansion */ - if (exp_saveptr /* if 2nd char is one of expansion operators */ - && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ - ) { - /* ${?:0}, ${#[:]%0} etc */ - exp_saveptr = var + 1; - } else { - /* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */ - exp_saveptr = var+1 + strcspn(var+1, "%#:-=+?"); - } - exp_op = exp_save = *exp_saveptr; - if (exp_op) { - exp_word = exp_saveptr + 1; - if (exp_op == ':') { - exp_op = *exp_word++; - if (ENABLE_HUSH_BASH_COMPAT - && (exp_op == '\0' || !strchr("%#:-=+?"+3, exp_op)) - ) { - /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ - exp_op = ':'; - exp_word--; - } - } - *exp_saveptr = '\0'; - } /* else: it's not an expansion op, but bare ${var} */ - } - - /* lookup the variable in question */ - if (isdigit(var[0])) { - /* parse_dollar() should have vetted var for us */ - i = xatoi_u(var); - if (i < G.global_argc) - val = G.global_argv[i]; - /* else val remains NULL: $N with too big N */ - } else { - switch (var[0]) { - case '$': /* pid */ - val = utoa(G.root_pid); - break; - case '!': /* bg pid */ - val = G.last_bg_pid ? utoa(G.last_bg_pid) : (char*)""; - break; - case '?': /* exitcode */ - val = utoa(G.last_exitcode); - break; - case '#': /* argc */ - val = utoa(G.global_argc ? G.global_argc-1 : 0); - break; - default: - val = get_local_var_value(var); - } - } +/* If a reserved word is found and processed, parse context is modified + * and 1 is returned. + */ +#if HAS_KEYWORDS +struct reserved_combo { + char literal[6]; + unsigned char res; + unsigned char assignment_flag; + int flag; +}; +enum { + FLAG_END = (1 << RES_NONE ), +# if ENABLE_HUSH_IF + FLAG_IF = (1 << RES_IF ), + FLAG_THEN = (1 << RES_THEN ), + FLAG_ELIF = (1 << RES_ELIF ), + FLAG_ELSE = (1 << RES_ELSE ), + FLAG_FI = (1 << RES_FI ), +# endif +# if ENABLE_HUSH_LOOPS + FLAG_FOR = (1 << RES_FOR ), + FLAG_WHILE = (1 << RES_WHILE), + FLAG_UNTIL = (1 << RES_UNTIL), + FLAG_DO = (1 << RES_DO ), + FLAG_DONE = (1 << RES_DONE ), + FLAG_IN = (1 << RES_IN ), +# endif +# if ENABLE_HUSH_CASE + FLAG_MATCH = (1 << RES_MATCH), + FLAG_ESAC = (1 << RES_ESAC ), +# endif + FLAG_START = (1 << RES_XXXX ), +}; - /* handle any expansions */ - if (exp_op == 'L') { - debug_printf_expand("expand: length(%s)=", val); - val = utoa(val ? strlen(val) : 0); - debug_printf_expand("%s\n", val); - } else if (exp_op) { - if (exp_op == '%' || exp_op == '#') { - /* Standard-mandated substring removal ops: - * ${parameter%word} - remove smallest suffix pattern - * ${parameter%%word} - remove largest suffix pattern - * ${parameter#word} - remove smallest prefix pattern - * ${parameter##word} - remove largest prefix pattern - * - * Word is expanded to produce a glob pattern. - * Then var's value is matched to it and matching part removed. - */ - if (val) { - bool match_at_left; - char *loc; - scan_t scan = pick_scan(exp_op, *exp_word, &match_at_left); - if (exp_op == *exp_word) /* ## or %% */ - exp_word++; - val = to_be_freed = xstrdup(val); - { - char *exp_exp_word = expand_pseudo_dquoted(exp_word); - if (exp_exp_word) - exp_word = exp_exp_word; - loc = scan(to_be_freed, exp_word, match_at_left); - //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", - // exp_op, to_be_freed, exp_word, loc); - free(exp_exp_word); - } - if (loc) { /* match was found */ - if (match_at_left) /* # or ## */ - val = loc; - else /* % or %% */ - *loc = '\0'; - } - } - } else if (exp_op == ':') { -#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT - /* It's ${var:N[:M]} bashism. - * Note that in encoded form it has TWO parts: - * var:NM - */ - arith_t beg, len; - int errcode = 0; - - beg = expand_and_evaluate_arith(exp_word, &errcode); - debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); - *p++ = SPECIAL_VAR_SYMBOL; - exp_word = p; - p = strchr(p, SPECIAL_VAR_SYMBOL); - *p = '\0'; - len = expand_and_evaluate_arith(exp_word, &errcode); - debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); - - if (errcode >= 0 && len >= 0) { /* bash compat: len < 0 is illegal */ - if (beg < 0) /* bash compat */ - beg = 0; - debug_printf_varexp("from val:'%s'\n", val); - if (len == 0 || !val || beg >= strlen(val)) - val = ""; - else { - /* Paranoia. What if user entered 9999999999999 - * which fits in arith_t but not int? */ - if (len >= INT_MAX) - len = INT_MAX; - val = to_be_freed = xstrndup(val + beg, len); - } - debug_printf_varexp("val:'%s'\n", val); - } else -#endif - { - die_if_script("malformed ${%s:...}", var); - val = ""; - } - } else { /* one of "-=+?" */ - /* Standard-mandated substitution ops: - * ${var?word} - indicate error if unset - * If var is unset, word (or a message indicating it is unset - * if word is null) is written to standard error - * and the shell exits with a non-zero exit status. - * Otherwise, the value of var is substituted. - * ${var-word} - use default value - * If var is unset, word is substituted. - * ${var=word} - assign and use default value - * If var is unset, word is assigned to var. - * In all cases, final value of var is substituted. - * ${var+word} - use alternative value - * If var is unset, null is substituted. - * Otherwise, word is substituted. - * - * Word is subjected to tilde expansion, parameter expansion, - * command substitution, and arithmetic expansion. - * If word is not needed, it is not expanded. - * - * Colon forms (${var:-word}, ${var:=word} etc) do the same, - * but also treat null var as if it is unset. +static const struct reserved_combo* match_reserved_word(o_string *word) +{ + /* Mostly a list of accepted follow-up reserved words. + * FLAG_END means we are done with the sequence, and are ready + * to turn the compound list into a command. + * FLAG_START means the word must start a new compound list. */ - int use_word = (!val || ((exp_save == ':') && !val[0])); - if (exp_op == '+') - use_word = !use_word; - debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, - (exp_save == ':') ? "true" : "false", use_word); - if (use_word) { - to_be_freed = expand_pseudo_dquoted(exp_word); - if (to_be_freed) - exp_word = to_be_freed; - if (exp_op == '?') { - /* mimic bash message */ - die_if_script("%s: %s", - var, - exp_word[0] ? exp_word : "parameter null or not set" - ); -//TODO: how interactive bash aborts expansion mid-command? - } else { - val = exp_word; - } - - if (exp_op == '=') { - /* ${var=[word]} or ${var:=[word]} */ - if (isdigit(var[0]) || var[0] == '#') { - /* mimic bash message */ - die_if_script("$%s: cannot assign in this way", var); - val = NULL; - } else { - char *new_var = xasprintf("%s=%s", var, val); - set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); - } - } - } - } /* one of "-=+?" */ + static const struct reserved_combo reserved_list[] = { +# if ENABLE_HUSH_IF + { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, + { "if", RES_IF, MAYBE_ASSIGNMENT, FLAG_THEN | FLAG_START }, + { "then", RES_THEN, MAYBE_ASSIGNMENT, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, + { "elif", RES_ELIF, MAYBE_ASSIGNMENT, FLAG_THEN }, + { "else", RES_ELSE, MAYBE_ASSIGNMENT, FLAG_FI }, + { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, +# endif +# if ENABLE_HUSH_LOOPS + { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, + { "while", RES_WHILE, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, + { "until", RES_UNTIL, MAYBE_ASSIGNMENT, FLAG_DO | FLAG_START }, + { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, + { "do", RES_DO, MAYBE_ASSIGNMENT, FLAG_DONE }, + { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, +# endif +# if ENABLE_HUSH_CASE + { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, + { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, +# endif + }; + const struct reserved_combo *r; - *exp_saveptr = exp_save; - } /* if (exp_op) */ + for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) { + if (strcmp(word->data, r->literal) == 0) + return r; + } + return NULL; +} +/* Return 0: not a keyword, 1: keyword + */ +static int reserved_word(o_string *word, struct parse_context *ctx) +{ +# if ENABLE_HUSH_CASE + static const struct reserved_combo reserved_match = { + "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC + }; +# endif + const struct reserved_combo *r; - arg[0] = first_ch; -#if ENABLE_HUSH_TICK - store_val: -#endif - if (!(first_ch & 0x80)) { /* unquoted $VAR */ - debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, output->o_escape); - if (val) { - /* unquoted var's contents should be globbed, so don't escape */ - smallint sv = output->o_escape; - output->o_escape = 0; - n = expand_on_ifs(output, n, val); - val = NULL; - output->o_escape = sv; - } - } else { /* quoted $VAR, val will be appended below */ - debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, output->o_escape); - } - } /* default: */ - } /* switch (char after ) */ + if (word->has_quoted_part) + return 0; + r = match_reserved_word(word); + if (!r) + return 0; - if (val) { - o_addQstr(output, val, strlen(val)); + debug_printf("found reserved word %s, res %d\n", r->literal, r->res); +# if ENABLE_HUSH_CASE + if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) { + /* "case word IN ..." - IN part starts first MATCH part */ + r = &reserved_match; + } else +# endif + if (r->flag == 0) { /* '!' */ + if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ + syntax_error("! ! command"); + ctx->ctx_res_w = RES_SNTX; } - free(to_be_freed); - /* Do the check to avoid writing to a const string */ - if (*p != SPECIAL_VAR_SYMBOL) - *p = SPECIAL_VAR_SYMBOL; - -#if ENABLE_HUSH_TICK - o_free(&subst_result); -#endif - arg = ++p; - } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ + ctx->ctx_inverted = 1; + return 1; + } + if (r->flag & FLAG_START) { + struct parse_context *old; - if (arg[0]) { - debug_print_list("expand_vars_to_list[a]", output, n); - /* this part is literal, and it was already pre-quoted - * if needed (much earlier), do not use o_addQstr here! */ - o_addstr_with_NUL(output, arg); - debug_print_list("expand_vars_to_list[b]", output, n); - } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ - && !(ored_ch & 0x80) /* and all vars were not quoted. */ - ) { - n--; - /* allow to reuse list[n] later without re-growth */ - output->has_empty_slot = 1; + old = xmalloc(sizeof(*old)); + debug_printf_parse("push stack %p\n", old); + *old = *ctx; /* physical copy */ + initialize_context(ctx); + ctx->stack = old; + } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { + syntax_error_at(word->data); + ctx->ctx_res_w = RES_SNTX; + return 1; } else { - o_addchr(output, '\0'); + /* "{...} fi" is ok. "{...} if" is not + * Example: + * if { echo foo; } then { echo bar; } fi */ + if (ctx->command->group) + done_pipe(ctx, PIPE_SEQ); } - return n; -} -static char **expand_variables(char **argv, int or_mask) -{ - int n; - char **list; - char **v; - o_string output = NULL_O_STRING; + ctx->ctx_res_w = r->res; + ctx->old_flag = r->flag; + word->o_assignment = r->assignment_flag; + debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); - if (or_mask & 0x100) { - output.o_escape = 1; /* protect against globbing for "$var" */ - /* (unquoted $var will temporarily switch it off) */ - output.o_glob = 1; - } + if (ctx->old_flag & FLAG_END) { + struct parse_context *old; - n = 0; - v = argv; - while (*v) { - n = expand_vars_to_list(&output, n, *v, (unsigned char)or_mask); - v++; + done_pipe(ctx, PIPE_SEQ); + debug_printf_parse("pop stack %p\n", ctx->stack); + old = ctx->stack; + old->command->group = ctx->list_head; + old->command->cmd_type = CMD_NORMAL; +# if !BB_MMU + o_addstr(&old->as_string, ctx->as_string.data); + o_free_unsafe(&ctx->as_string); + old->command->group_as_string = xstrdup(old->as_string.data); + debug_printf_parse("pop, remembering as:'%s'\n", + old->command->group_as_string); +# endif + *ctx = *old; /* physical copy */ + free(old); } - debug_print_list("expand_variables", &output, n); - - /* output.data (malloced in one block) gets returned in "list" */ - list = o_finalize_list(&output, n); - debug_print_strings("expand_variables[1]", list); - return list; + return 1; } +#endif /* HAS_KEYWORDS */ -static char **expand_strvec_to_strvec(char **argv) +/* Word is complete, look at it and update parsing context. + * Normal return is 0. Syntax errors return 1. + * Note: on return, word is reset, but not o_free'd! + */ +static int done_word(o_string *word, struct parse_context *ctx) { - return expand_variables(argv, 0x100); -} + struct command *command = ctx->command; -#if ENABLE_HUSH_BASH_COMPAT -static char **expand_strvec_to_strvec_singleword_noglob(char **argv) -{ - return expand_variables(argv, 0x80); -} -#endif + debug_printf_parse("done_word entered: '%s' %p\n", word->data, command); + if (word->length == 0 && !word->has_quoted_part) { + debug_printf_parse("done_word return 0: true null, ignored\n"); + return 0; + } -#ifdef CMD_SINGLEWORD_NOGLOB_COND -static char **expand_strvec_to_strvec_singleword_noglob_cond(char **argv) -{ - int n; - char **list; - char **v; - o_string output = NULL_O_STRING; - - n = 0; - v = argv; - while (*v) { - int is_var = is_well_formed_var_name(*v, '='); - /* is_var * 0x80: singleword expansion for vars */ - n = expand_vars_to_list(&output, n, *v, is_var * 0x80); - - /* Subtle! expand_vars_to_list did not glob last word yet. - * It does this only when fed with further data. - * Therefore we set globbing flags AFTER it, not before: + if (ctx->pending_redirect) { + /* We do not glob in e.g. >*.tmp case. bash seems to glob here + * only if run as "bash", not "sh" */ + /* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html + * "2.7 Redirection + * ...the word that follows the redirection operator + * shall be subjected to tilde expansion, parameter expansion, + * command substitution, arithmetic expansion, and quote + * removal. Pathname expansion shall not be performed + * on the word by a non-interactive shell; an interactive + * shell may perform it, but shall do so only when + * the expansion would result in one word." + */ + ctx->pending_redirect->rd_filename = xstrdup(word->data); + /* Cater for >\file case: + * >\a creates file a; >\\a, >"\a", >"\\a" create file \a + * Same with heredocs: + * for <<\H delim is H; <<\\H, <<"\H", <<"\\H" - \H */ + if (ctx->pending_redirect->rd_type == REDIRECT_HEREDOC) { + unbackslash(ctx->pending_redirect->rd_filename); + /* Is it <<"HEREDOC"? */ + if (word->has_quoted_part) { + ctx->pending_redirect->rd_dup |= HEREDOC_QUOTED; + } + } + debug_printf_parse("word stored in rd_filename: '%s'\n", word->data); + ctx->pending_redirect = NULL; + } else { +#if HAS_KEYWORDS +# if ENABLE_HUSH_CASE + if (ctx->ctx_dsemicolon + && strcmp(word->data, "esac") != 0 /* not "... pattern) cmd;; esac" */ + ) { + /* already done when ctx_dsemicolon was set to 1: */ + /* ctx->ctx_res_w = RES_MATCH; */ + ctx->ctx_dsemicolon = 0; + } else +# endif + if (!command->argv /* if it's the first word... */ +# if ENABLE_HUSH_LOOPS + && ctx->ctx_res_w != RES_FOR /* ...not after FOR or IN */ + && ctx->ctx_res_w != RES_IN +# endif +# if ENABLE_HUSH_CASE + && ctx->ctx_res_w != RES_CASE +# endif + ) { + int reserved = reserved_word(word, ctx); + debug_printf_parse("checking for reserved-ness: %d\n", reserved); + if (reserved) { + o_reset_to_empty_unquoted(word); + debug_printf_parse("done_word return %d\n", + (ctx->ctx_res_w == RES_SNTX)); + return (ctx->ctx_res_w == RES_SNTX); + } +# if ENABLE_HUSH_BASH_COMPAT + if (strcmp(word->data, "[[") == 0) { + command->cmd_type = CMD_SINGLEWORD_NOGLOB; + } + /* fall through */ +# endif + } +#endif + if (command->group) { + /* "{ echo foo; } echo bar" - bad */ + syntax_error_at(word->data); + debug_printf_parse("done_word return 1: syntax error, " + "groups and arglists don't mix\n"); + return 1; + } - /* if it is not recognizably abc=...; then: */ - output.o_escape = !is_var; /* protect against globbing for "$var" */ - /* (unquoted $var will temporarily switch it off) */ - output.o_glob = !is_var; /* and indeed do globbing */ - v++; + /* If this word wasn't an assignment, next ones definitely + * can't be assignments. Even if they look like ones. */ + if (word->o_assignment != DEFINITELY_ASSIGNMENT + && word->o_assignment != WORD_IS_KEYWORD + ) { + word->o_assignment = NOT_ASSIGNMENT; + } else { + if (word->o_assignment == DEFINITELY_ASSIGNMENT) { + command->assignment_cnt++; + debug_printf_parse("++assignment_cnt=%d\n", command->assignment_cnt); + } + debug_printf_parse("word->o_assignment was:'%s'\n", assignment_flag[word->o_assignment]); + word->o_assignment = MAYBE_ASSIGNMENT; + } + debug_printf_parse("word->o_assignment='%s'\n", assignment_flag[word->o_assignment]); + + if (word->has_quoted_part + /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */ + && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL) + /* (otherwise it's known to be not empty and is already safe) */ + ) { + /* exclude "$@" - it can expand to no word despite "" */ + char *p = word->data; + while (p[0] == SPECIAL_VAR_SYMBOL + && (p[1] & 0x7f) == '@' + && p[2] == SPECIAL_VAR_SYMBOL + ) { + p += 3; + } + } + command->argv = add_string_to_strings(command->argv, xstrdup(word->data)); + debug_print_strings("word appended to argv", command->argv); } - debug_print_list("expand_cond", &output, n); - /* output.data (malloced in one block) gets returned in "list" */ - list = o_finalize_list(&output, n); - debug_print_strings("expand_cond[1]", list); - return list; -} +#if ENABLE_HUSH_LOOPS + if (ctx->ctx_res_w == RES_FOR) { + if (word->has_quoted_part + || !is_well_formed_var_name(command->argv[0], '\0') + ) { + /* bash says just "not a valid identifier" */ + syntax_error("not a valid identifier in for"); + return 1; + } + /* Force FOR to have just one word (variable name) */ + /* NB: basically, this makes hush see "for v in ..." + * syntax as if it is "for v; in ...". FOR and IN become + * two pipe structs in parse tree. */ + done_pipe(ctx, PIPE_SEQ); + } +#endif +#if ENABLE_HUSH_CASE + /* Force CASE to have just one word */ + if (ctx->ctx_res_w == RES_CASE) { + done_pipe(ctx, PIPE_SEQ); + } #endif -/* Used for expansion of right hand of assignments */ -/* NB: should NOT do globbing! "export v=/bin/c*; env | grep ^v=" outputs - * "v=/bin/c*" */ -static char *expand_string_to_string(const char *str) -{ - char *argv[2], **list; + o_reset_to_empty_unquoted(word); - argv[0] = (char*)str; - argv[1] = NULL; - list = expand_variables(argv, 0x80); /* 0x80: singleword expansion */ - if (HUSH_DEBUG) - if (!list[0] || list[1]) - bb_error_msg_and_die("BUG in varexp2"); - /* actually, just move string 2*sizeof(char*) bytes back */ - overlapping_strcpy((char*)list, list[0]); - unbackslash((char*)list); - debug_printf_expand("string_to_string='%s'\n", (char*)list); - return (char*)list; + debug_printf_parse("done_word return 0\n"); + return 0; } -/* Used for "eval" builtin */ -static char* expand_strvec_to_string(char **argv) + +/* Peek ahead in the input to find out if we have a "&n" construct, + * as in "2>&1", that represents duplicating a file descriptor. + * Return: + * REDIRFD_CLOSE if >&- "close fd" construct is seen, + * REDIRFD_SYNTAX_ERR if syntax error, + * REDIRFD_TO_FILE if no & was seen, + * or the number found. + */ +#if BB_MMU +#define parse_redir_right_fd(as_string, input) \ + parse_redir_right_fd(input) +#endif +static int parse_redir_right_fd(o_string *as_string, struct in_str *input) { - char **list; + int ch, d, ok; - list = expand_variables(argv, 0x80); - /* Convert all NULs to spaces */ - if (list[0]) { - int n = 1; - while (list[n]) { - if (HUSH_DEBUG) - if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) - bb_error_msg_and_die("BUG in varexp3"); - /* bash uses ' ' regardless of $IFS contents */ - list[n][-1] = ' '; - n++; - } - } - overlapping_strcpy((char*)list, list[0]); - debug_printf_expand("strvec_to_string='%s'\n", (char*)list); - return (char*)list; -} + ch = i_peek(input); + if (ch != '&') + return REDIRFD_TO_FILE; -static char **expand_assignments(char **argv, int count) -{ - int i; - char **p = NULL; - /* Expand assignments into one string each */ - for (i = 0; i < count; i++) { - p = add_string_to_strings(p, expand_string_to_string(argv[i])); + ch = i_getch(input); /* get the & */ + nommu_addchr(as_string, ch); + ch = i_peek(input); + if (ch == '-') { + ch = i_getch(input); + nommu_addchr(as_string, ch); + return REDIRFD_CLOSE; } - return p; -} + d = 0; + ok = 0; + while (ch != EOF && isdigit(ch)) { + d = d*10 + (ch-'0'); + ok = 1; + ch = i_getch(input); + nommu_addchr(as_string, ch); + ch = i_peek(input); + } + if (ok) return d; +//TODO: this is the place to catch ">&file" bashism (redirect both fd 1 and 2) -#if BB_MMU -/* never called */ -void re_execute_shell(char ***to_free, const char *s, - char *g_argv0, char **g_argv, - char **builtin_argv) NORETURN; + bb_error_msg("ambiguous redirect"); + return REDIRFD_SYNTAX_ERR; +} -static void reset_traps_to_defaults(void) +/* Return code is 0 normal, 1 if a syntax error is detected + */ +static int parse_redirect(struct parse_context *ctx, + int fd, + redir_type style, + struct in_str *input) { - /* This function is always called in a child shell - * after fork (not vfork, NOMMU doesn't use this function). - */ - unsigned sig; - unsigned mask; + struct command *command = ctx->command; + struct redir_struct *redir; + struct redir_struct **redirp; + int dup_num; - /* Child shells are not interactive. - * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. - * Testcase: (while :; do :; done) + ^Z should background. - * Same goes for SIGTERM, SIGHUP, SIGINT. - */ - if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS)) - return; /* already no traps and no SPECIAL_INTERACTIVE_SIGS */ - - /* Switching off SPECIAL_INTERACTIVE_SIGS. - * Stupid. It can be done with *single* &= op, but we can't use - * the fact that G.blocked_set is implemented as a bitmask - * in libc... */ - mask = (SPECIAL_INTERACTIVE_SIGS >> 1); - sig = 1; - while (1) { - if (mask & 1) { - /* Careful. Only if no trap or trap is not "" */ - if (!G.traps || !G.traps[sig] || G.traps[sig][0]) - sigdelset(&G.blocked_set, sig); + dup_num = REDIRFD_TO_FILE; + if (style != REDIRECT_HEREDOC) { + /* Check for a '>&1' type redirect */ + dup_num = parse_redir_right_fd(&ctx->as_string, input); + if (dup_num == REDIRFD_SYNTAX_ERR) + return 1; + } else { + int ch = i_peek(input); + dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ + if (dup_num) { /* <<-... */ + ch = i_getch(input); + nommu_addchr(&ctx->as_string, ch); + ch = i_peek(input); } - mask >>= 1; - if (!mask) - break; - sig++; - } - /* Our homegrown sig mask is saner to work with :) */ - G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS; - - /* Resetting all traps to default except empty ones */ - mask = G.non_DFL_mask; - if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) { - if (!G.traps[sig] || !G.traps[sig][0]) - continue; - free(G.traps[sig]); - G.traps[sig] = NULL; - /* There is no signal for 0 (EXIT) */ - if (sig == 0) - continue; - /* There was a trap handler, we just removed it. - * But if sig still has non-DFL handling, - * we should not unblock the sig. */ - if (mask & 1) - continue; - sigdelset(&G.blocked_set, sig); } - sigprocmask(SIG_SETMASK, &G.blocked_set, NULL); -} - -#else /* !BB_MMU */ -static void re_execute_shell(char ***to_free, const char *s, - char *g_argv0, char **g_argv, - char **builtin_argv) NORETURN; -static void re_execute_shell(char ***to_free, const char *s, - char *g_argv0, char **g_argv, - char **builtin_argv) -{ -# define NOMMU_HACK_FMT ("-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x")) - /* delims + 2 * (number of bytes in printed hex numbers) */ - char param_buf[sizeof(NOMMU_HACK_FMT) + 2 * (sizeof(int)*6 + sizeof(long long)*1)]; - char *heredoc_argv[4]; - struct variable *cur; -# if ENABLE_HUSH_FUNCTIONS - struct function *funcp; -# endif - char **argv, **pp; - unsigned cnt; - unsigned long long empty_trap_mask; + if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { + int ch = i_peek(input); + if (ch == '|') { + /* >|FILE redirect ("clobbering" >). + * Since we do not support "set -o noclobber" yet, + * >| and > are the same for now. Just eat |. + */ + ch = i_getch(input); + nommu_addchr(&ctx->as_string, ch); + } + } - if (!g_argv0) { /* heredoc */ - argv = heredoc_argv; - argv[0] = (char *) G.argv0_for_re_execing; - argv[1] = (char *) "-<"; - argv[2] = (char *) s; - argv[3] = NULL; - pp = &argv[3]; /* used as pointer to empty environment */ - goto do_exec; + /* Create a new redir_struct and append it to the linked list */ + redirp = &command->redirects; + while ((redir = *redirp) != NULL) { + redirp = &(redir->next); } + *redirp = redir = xzalloc(sizeof(*redir)); + /* redir->next = NULL; */ + /* redir->rd_filename = NULL; */ + redir->rd_type = style; + redir->rd_fd = (fd == -1) ? redir_table[style].default_fd : fd; - cnt = 0; - pp = builtin_argv; - if (pp) while (*pp++) - cnt++; + debug_printf_parse("redirect type %d %s\n", redir->rd_fd, + redir_table[style].descrip); - empty_trap_mask = 0; - if (G.traps) { - int sig; - for (sig = 1; sig < NSIG; sig++) { - if (G.traps[sig] && !G.traps[sig][0]) - empty_trap_mask |= 1LL << sig; - } + redir->rd_dup = dup_num; + if (style != REDIRECT_HEREDOC && dup_num != REDIRFD_TO_FILE) { + /* Erik had a check here that the file descriptor in question + * is legit; I postpone that to "run time" + * A "-" representation of "close me" shows up as a -3 here */ + debug_printf_parse("duplicating redirect '%d>&%d'\n", + redir->rd_fd, redir->rd_dup); + } else { + /* Set ctx->pending_redirect, so we know what to do at the + * end of the next parsed word. */ + ctx->pending_redirect = redir; } + return 0; +} - sprintf(param_buf, NOMMU_HACK_FMT - , (unsigned) G.root_pid - , (unsigned) G.root_ppid - , (unsigned) G.last_bg_pid - , (unsigned) G.last_exitcode - , cnt - , empty_trap_mask - IF_HUSH_LOOPS(, G.depth_of_loop) - ); -# undef NOMMU_HACK_FMT - /* 1:hush 2:-$::: - * 3:-c 4: 5: 6:NULL - */ - cnt += 6; - for (cur = G.top_var; cur; cur = cur->next) { - if (!cur->flg_export || cur->flg_read_only) - cnt += 2; - } -# if ENABLE_HUSH_FUNCTIONS - for (funcp = G.top_func; funcp; funcp = funcp->next) - cnt += 3; -# endif - pp = g_argv; - while (*pp++) - cnt++; - *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt); - *pp++ = (char *) G.argv0_for_re_execing; - *pp++ = param_buf; - for (cur = G.top_var; cur; cur = cur->next) { - if (cur->varstr == hush_version_str) - continue; - if (cur->flg_read_only) { - *pp++ = (char *) "-R"; - *pp++ = cur->varstr; - } else if (!cur->flg_export) { - *pp++ = (char *) "-V"; - *pp++ = cur->varstr; - } - } -# if ENABLE_HUSH_FUNCTIONS - for (funcp = G.top_func; funcp; funcp = funcp->next) { - *pp++ = (char *) "-F"; - *pp++ = funcp->name; - *pp++ = funcp->body_as_string; - } -# endif - /* We can pass activated traps here. Say, -Tnn:trap_string - * - * However, POSIX says that subshells reset signals with traps - * to SIG_DFL. - * I tested bash-3.2 and it not only does that with true subshells - * of the form ( list ), but with any forked children shells. - * I set trap "echo W" WINCH; and then tried: - * - * { echo 1; sleep 20; echo 2; } & - * while true; do echo 1; sleep 20; echo 2; break; done & - * true | { echo 1; sleep 20; echo 2; } | cat - * - * In all these cases sending SIGWINCH to the child shell - * did not run the trap. If I add trap "echo V" WINCH; - * _inside_ group (just before echo 1), it works. - * - * I conclude it means we don't need to pass active traps here. - * Even if we would use signal handlers instead of signal masking - * in order to implement trap handling, - * exec syscall below resets signals to SIG_DFL for us. - */ - *pp++ = (char *) "-c"; - *pp++ = (char *) s; - if (builtin_argv) { - while (*++builtin_argv) - *pp++ = *builtin_argv; - *pp++ = (char *) ""; - } - *pp++ = g_argv0; - while (*g_argv) - *pp++ = *g_argv++; - /* *pp = NULL; - is already there */ - pp = environ; +/* If a redirect is immediately preceded by a number, that number is + * supposed to tell which file descriptor to redirect. This routine + * looks for such preceding numbers. In an ideal world this routine + * needs to handle all the following classes of redirects... + * echo 2>foo # redirects fd 2 to file "foo", nothing passed to echo + * echo 49>foo # redirects fd 49 to file "foo", nothing passed to echo + * echo -2>foo # redirects fd 1 to file "foo", "-2" passed to echo + * echo 49x>foo # redirects fd 1 to file "foo", "49x" passed to echo + * + * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html + * "2.7 Redirection + * ... If n is quoted, the number shall not be recognized as part of + * the redirection expression. For example: + * echo \2>a + * writes the character 2 into file a" + * We are getting it right by setting ->has_quoted_part on any \ + * + * A -1 return means no valid number was found, + * the caller should use the appropriate default for this redirection. + */ +static int redirect_opt_num(o_string *o) +{ + int num; - do_exec: - debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); - execve(bb_busybox_exec_path, argv, pp); - /* Fallback. Useful for init=/bin/hush usage etc */ - if (argv[0][0] == '/') - execve(argv[0], argv, pp); - xfunc_error_retval = 127; - bb_error_msg_and_die("can't re-execute the shell"); + if (o->data == NULL) + return -1; + num = bb_strtou(o->data, NULL, 10); + if (errno || num < 0) + return -1; + o_reset_to_empty_unquoted(o); + return num; } -#endif /* !BB_MMU */ - -static void setup_heredoc(struct redir_struct *redir) -{ - struct fd_pair pair; - pid_t pid; - int len, written; - /* the _body_ of heredoc (misleading field name) */ - const char *heredoc = redir->rd_filename; - char *expanded; -#if !BB_MMU - char **to_free; +#if BB_MMU +#define fetch_till_str(as_string, input, word, skip_tabs) \ + fetch_till_str(input, word, skip_tabs) #endif +static char *fetch_till_str(o_string *as_string, + struct in_str *input, + const char *word, + int heredoc_flags) +{ + o_string heredoc = NULL_O_STRING; + unsigned past_EOL; + int prev = 0; /* not \ */ + int ch; - expanded = NULL; - if (!(redir->rd_dup & HEREDOC_QUOTED)) { - expanded = expand_pseudo_dquoted(heredoc); - if (expanded) - heredoc = expanded; - } - len = strlen(heredoc); - - close(redir->rd_fd); /* often saves dup2+close in xmove_fd */ - xpiped_pair(pair); - xmove_fd(pair.rd, redir->rd_fd); + goto jump_in; - /* Try writing without forking. Newer kernels have - * dynamically growing pipes. Must use non-blocking write! */ - ndelay_on(pair.wr); while (1) { - written = write(pair.wr, heredoc, len); - if (written <= 0) - break; - len -= written; - if (len == 0) { - close(pair.wr); - free(expanded); - return; + ch = i_getch(input); + if (ch != EOF) + nommu_addchr(as_string, ch); + if ((ch == '\n' || ch == EOF) + && ((heredoc_flags & HEREDOC_QUOTED) || prev != '\\') + ) { + if (strcmp(heredoc.data + past_EOL, word) == 0) { + heredoc.data[past_EOL] = '\0'; + debug_printf_parse("parsed heredoc '%s'\n", heredoc.data); + return heredoc.data; + } + while (ch == '\n') { + o_addchr(&heredoc, ch); + prev = ch; + jump_in: + past_EOL = heredoc.length; + do { + ch = i_getch(input); + if (ch != EOF) + nommu_addchr(as_string, ch); + } while ((heredoc_flags & HEREDOC_SKIPTABS) && ch == '\t'); + } } - heredoc += written; + if (ch == EOF) { + o_free_unsafe(&heredoc); + return NULL; + } + o_addchr(&heredoc, ch); + nommu_addchr(as_string, ch); + if (prev == '\\' && ch == '\\') + /* Correctly handle foo\\ (not a line cont.) */ + prev = 0; /* not \ */ + else + prev = ch; } - ndelay_off(pair.wr); +} - /* Okay, pipe buffer was not big enough */ - /* Note: we must not create a stray child (bastard? :) - * for the unsuspecting parent process. Child creates a grandchild - * and exits before parent execs the process which consumes heredoc - * (that exec happens after we return from this function) */ -#if !BB_MMU - to_free = NULL; -#endif - pid = xvfork(); - if (pid == 0) { - /* child */ - disable_restore_tty_pgrp_on_exit(); - pid = BB_MMU ? xfork() : xvfork(); - if (pid != 0) - _exit(0); - /* grandchild */ - close(redir->rd_fd); /* read side of the pipe */ -#if BB_MMU - full_write(pair.wr, heredoc, len); /* may loop or block */ - _exit(0); -#else - /* Delegate blocking writes to another process */ - xmove_fd(pair.wr, STDOUT_FILENO); - re_execute_shell(&to_free, heredoc, NULL, NULL, NULL); -#endif - } - /* parent */ -#if ENABLE_HUSH_FAST - G.count_SIGCHLD++; -//bb_error_msg("[%d] fork in setup_heredoc: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); -#endif - enable_restore_tty_pgrp_on_exit(); -#if !BB_MMU - free(to_free); -#endif - close(pair.wr); - free(expanded); - wait(NULL); /* wait till child has died */ -} - -/* squirrel != NULL means we squirrel away copies of stdin, stdout, - * and stderr if they are redirected. */ -static int setup_redirects(struct command *prog, int squirrel[]) -{ - int openfd, mode; - struct redir_struct *redir; - - for (redir = prog->redirects; redir; redir = redir->next) { - if (redir->rd_type == REDIRECT_HEREDOC2) { - /* rd_fd<rd_fd < 3 - && squirrel[redir->rd_fd] < 0 - ) { - squirrel[redir->rd_fd] = dup(redir->rd_fd); - } - /* for REDIRECT_HEREDOC2, rd_filename holds _contents_ - * of the heredoc */ - debug_printf_parse("set heredoc '%s'\n", - redir->rd_filename); - setup_heredoc(redir); - continue; - } - - if (redir->rd_dup == REDIRFD_TO_FILE) { - /* rd_fd<*>file case (<*> is <,>,>>,<>) */ - char *p; - if (redir->rd_filename == NULL) { - /* Something went wrong in the parse. - * Pretend it didn't happen */ - bb_error_msg("bug in redirect parse"); - continue; - } - mode = redir_table[redir->rd_type].mode; - p = expand_string_to_string(redir->rd_filename); - openfd = open_or_warn(p, mode); - free(p); - if (openfd < 0) { - /* this could get lost if stderr has been redirected, but - * bash and ash both lose it as well (though zsh doesn't!) */ -//what the above comment tries to say? - return 1; - } - } else { - /* rd_fd<*>rd_dup or rd_fd<*>- cases */ - openfd = redir->rd_dup; - } - - if (openfd != redir->rd_fd) { - if (squirrel && redir->rd_fd < 3 - && squirrel[redir->rd_fd] < 0 - ) { - squirrel[redir->rd_fd] = dup(redir->rd_fd); - } - if (openfd == REDIRFD_CLOSE) { - /* "n>-" means "close me" */ - close(redir->rd_fd); - } else { - xdup2(openfd, redir->rd_fd); - if (redir->rd_dup == REDIRFD_TO_FILE) - close(openfd); - } - } - } - return 0; -} - -static void restore_redirects(int squirrel[]) +/* Look at entire parse tree for not-yet-loaded REDIRECT_HEREDOCs + * and load them all. There should be exactly heredoc_cnt of them. + */ +static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_str *input) { - int i, fd; - for (i = 0; i < 3; i++) { - fd = squirrel[i]; - if (fd != -1) { - /* We simply die on error */ - xmove_fd(fd, i); - } - } -} + struct pipe *pi = ctx->list_head; + while (pi && heredoc_cnt) { + int i; + struct command *cmd = pi->cmds; -static void free_pipe_list(struct pipe *head); + debug_printf_parse("fetch_heredocs: num_cmds:%d cmd argv0:'%s'\n", + pi->num_cmds, + cmd->argv ? cmd->argv[0] : "NONE"); + for (i = 0; i < pi->num_cmds; i++) { + struct redir_struct *redir = cmd->redirects; -/* Return code is the exit status of the pipe */ -static void free_pipe(struct pipe *pi) -{ - char **p; - struct command *command; - struct redir_struct *r, *rnext; - int a, i; + debug_printf_parse("fetch_heredocs: %d cmd argv0:'%s'\n", + i, cmd->argv ? cmd->argv[0] : "NONE"); + while (redir) { + if (redir->rd_type == REDIRECT_HEREDOC) { + char *p; - if (pi->stopped_cmds > 0) /* why? */ - return; - debug_printf_clean("run pipe: (pid %d)\n", getpid()); - for (i = 0; i < pi->num_cmds; i++) { - command = &pi->cmds[i]; - debug_printf_clean(" command %d:\n", i); - if (command->argv) { - for (a = 0, p = command->argv; *p; a++, p++) { - debug_printf_clean(" argv[%d] = %s\n", a, *p); - } - free_strings(command->argv); - command->argv = NULL; - } - /* not "else if": on syntax error, we may have both! */ - if (command->group) { - debug_printf_clean(" begin group (cmd_type:%d)\n", - command->cmd_type); - free_pipe_list(command->group); - debug_printf_clean(" end group\n"); - command->group = NULL; - } - /* else is crucial here. - * If group != NULL, child_func is meaningless */ -#if ENABLE_HUSH_FUNCTIONS - else if (command->child_func) { - debug_printf_exec("cmd %p releases child func at %p\n", command, command->child_func); - command->child_func->parent_cmd = NULL; - } -#endif -#if !BB_MMU - free(command->group_as_string); - command->group_as_string = NULL; -#endif - for (r = command->redirects; r; r = rnext) { - debug_printf_clean(" redirect %d%s", - r->rd_fd, redir_table[r->rd_type].descrip); - /* guard against the case >$FOO, where foo is unset or blank */ - if (r->rd_filename) { - debug_printf_clean(" fname:'%s'\n", r->rd_filename); - free(r->rd_filename); - r->rd_filename = NULL; + redir->rd_type = REDIRECT_HEREDOC2; + /* redir->rd_dup is (ab)used to indicate <<- */ + p = fetch_till_str(&ctx->as_string, input, + redir->rd_filename, redir->rd_dup); + if (!p) { + syntax_error("unexpected EOF in here document"); + return 1; + } + free(redir->rd_filename); + redir->rd_filename = p; + heredoc_cnt--; + } + redir = redir->next; } - debug_printf_clean(" rd_dup:%d\n", r->rd_dup); - rnext = r->next; - free(r); + cmd++; } - command->redirects = NULL; + pi = pi->next; } - free(pi->cmds); /* children are an array, they get freed all at once */ - pi->cmds = NULL; -#if ENABLE_HUSH_JOB - free(pi->cmdtext); - pi->cmdtext = NULL; -#endif -} - -static void free_pipe_list(struct pipe *head) -{ - struct pipe *pi, *next; - - for (pi = head; pi; pi = next) { -#if HAS_KEYWORDS - debug_printf_clean(" pipe reserved word %d\n", pi->res_word); +#if 0 + /* Should be 0. If it isn't, it's a parse error */ + if (heredoc_cnt) + bb_error_msg_and_die("heredoc BUG 2"); #endif - free_pipe(pi); - debug_printf_clean("pipe followup code %d\n", pi->followup); - next = pi->next; - /*pi->next = NULL;*/ - free(pi); - } + return 0; } @@ -3414,3518 +3569,4165 @@ static int run_list(struct pipe *pi); static struct pipe *parse_stream(char **pstring, struct in_str *input, int end_trigger); -static void parse_and_run_string(const char *s); -static char *find_in_path(const char *arg) +#if !ENABLE_HUSH_FUNCTIONS +#define parse_group(dest, ctx, input, ch) \ + parse_group(ctx, input, ch) +#endif +static int parse_group(o_string *dest, struct parse_context *ctx, + struct in_str *input, int ch) { - char *ret = NULL; - const char *PATH = get_local_var_value("PATH"); - - if (!PATH) - return NULL; - - while (1) { - const char *end = strchrnul(PATH, ':'); - int sz = end - PATH; /* must be int! */ + /* dest contains characters seen prior to ( or {. + * Typically it's empty, but for function defs, + * it contains function name (without '()'). */ + struct pipe *pipe_list; + int endch; + struct command *command = ctx->command; - free(ret); - if (sz != 0) { - ret = xasprintf("%.*s/%s", sz, PATH, arg); - } else { - /* We have xxx::yyyy in $PATH, - * it means "use current dir" */ - ret = xstrdup(arg); + debug_printf_parse("parse_group entered\n"); +#if ENABLE_HUSH_FUNCTIONS + if (ch == '(' && !dest->has_quoted_part) { + if (dest->length) + if (done_word(dest, ctx)) + return 1; + if (!command->argv) + goto skip; /* (... */ + if (command->argv[1]) { /* word word ... (... */ + syntax_error_unexpected_ch('('); + return 1; } - if (access(ret, F_OK) == 0) - break; - - if (*end == '\0') { - free(ret); - return NULL; + /* it is "word(..." or "word (..." */ + do + ch = i_getch(input); + while (ch == ' ' || ch == '\t'); + if (ch != ')') { + syntax_error_unexpected_ch(ch); + return 1; } - PATH = end + 1; - } - - return ret; -} - -static const struct built_in_command* find_builtin_helper(const char *name, - const struct built_in_command *x, - const struct built_in_command *end) -{ - while (x != end) { - if (strcmp(name, x->b_cmd) != 0) { - x++; - continue; + nommu_addchr(&ctx->as_string, ch); + do + ch = i_getch(input); + while (ch == ' ' || ch == '\t' || ch == '\n'); + if (ch != '{') { + syntax_error_unexpected_ch(ch); + return 1; } - debug_printf_exec("found builtin '%s'\n", name); - return x; + nommu_addchr(&ctx->as_string, ch); + command->cmd_type = CMD_FUNCDEF; + goto skip; } - return NULL; -} -static const struct built_in_command* find_builtin1(const char *name) -{ - return find_builtin_helper(name, bltins1, &bltins1[ARRAY_SIZE(bltins1)]); -} -static const struct built_in_command* find_builtin(const char *name) -{ - const struct built_in_command *x = find_builtin1(name); - if (x) - return x; - return find_builtin_helper(name, bltins2, &bltins2[ARRAY_SIZE(bltins2)]); -} +#endif + +#if 0 /* Prevented by caller */ + if (command->argv /* word [word]{... */ + || dest->length /* word{... */ + || dest->has_quoted_part /* ""{... */ + ) { + syntax_error(NULL); + debug_printf_parse("parse_group return 1: " + "syntax error, groups and arglists don't mix\n"); + return 1; + } +#endif #if ENABLE_HUSH_FUNCTIONS -static struct function **find_function_slot(const char *name) -{ - struct function **funcpp = &G.top_func; - while (*funcpp) { - if (strcmp(name, (*funcpp)->name) == 0) { - break; + skip: +#endif + endch = '}'; + if (ch == '(') { + endch = ')'; + command->cmd_type = CMD_SUBSHELL; + } else { + /* bash does not allow "{echo...", requires whitespace */ + ch = i_getch(input); + if (ch != ' ' && ch != '\t' && ch != '\n') { + syntax_error_unexpected_ch(ch); + return 1; } - funcpp = &(*funcpp)->next; + nommu_addchr(&ctx->as_string, ch); } - return funcpp; + + { +#if BB_MMU +# define as_string NULL +#else + char *as_string = NULL; +#endif + pipe_list = parse_stream(&as_string, input, endch); +#if !BB_MMU + if (as_string) + o_addstr(&ctx->as_string, as_string); +#endif + /* empty ()/{} or parse error? */ + if (!pipe_list || pipe_list == ERR_PTR) { + /* parse_stream already emitted error msg */ + if (!BB_MMU) + free(as_string); + debug_printf_parse("parse_group return 1: " + "parse_stream returned %p\n", pipe_list); + return 1; + } + command->group = pipe_list; +#if !BB_MMU + as_string[strlen(as_string) - 1] = '\0'; /* plink ')' or '}' */ + command->group_as_string = as_string; + debug_printf_parse("end of group, remembering as:'%s'\n", + command->group_as_string); +#endif +#undef as_string + } + debug_printf_parse("parse_group return 0\n"); + return 0; + /* command remains "open", available for possible redirects */ } -static const struct function *find_function(const char *name) +#if ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS +/* Subroutines for copying $(...) and `...` things */ +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); +/* '...' */ +static int add_till_single_quote(o_string *dest, struct in_str *input) { - const struct function *funcp = *find_function_slot(name); - if (funcp) - debug_printf_exec("found function '%s'\n", name); - return funcp; + while (1) { + int ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch('\''); + return 0; + } + if (ch == '\'') + return 1; + o_addchr(dest, ch); + } } - -/* Note: takes ownership on name ptr */ -static struct function *new_function(char *name) +/* "...\"...`..`...." - do we need to handle "...$(..)..." too? */ +static int add_till_double_quote(o_string *dest, struct in_str *input) { - struct function **funcpp = find_function_slot(name); - struct function *funcp = *funcpp; - - if (funcp != NULL) { - struct command *cmd = funcp->parent_cmd; - debug_printf_exec("func %p parent_cmd %p\n", funcp, cmd); - if (!cmd) { - debug_printf_exec("freeing & replacing function '%s'\n", funcp->name); - free(funcp->name); - /* Note: if !funcp->body, do not free body_as_string! - * This is a special case of "-F name body" function: - * body_as_string was not malloced! */ - if (funcp->body) { - free_pipe_list(funcp->body); -# if !BB_MMU - free(funcp->body_as_string); -# endif - } - } else { - debug_printf_exec("reinserting in tree & replacing function '%s'\n", funcp->name); - cmd->argv[0] = funcp->name; - cmd->group = funcp->body; -# if !BB_MMU - cmd->group_as_string = funcp->body_as_string; -# endif + while (1) { + int ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch('"'); + return 0; } - } else { - debug_printf_exec("remembering new function '%s'\n", name); - funcp = *funcpp = xzalloc(sizeof(*funcp)); - /*funcp->next = NULL;*/ + if (ch == '"') + return 1; + if (ch == '\\') { /* \x. Copy both chars. */ + o_addchr(dest, ch); + ch = i_getch(input); + } + o_addchr(dest, ch); + if (ch == '`') { + if (!add_till_backquote(dest, input, /*in_dquote:*/ 1)) + return 0; + o_addchr(dest, ch); + continue; + } + //if (ch == '$') ... } - - funcp->name = name; - return funcp; } - -static void unset_func(const char *name) +/* Process `cmd` - copy contents until "`" is seen. Complicated by + * \` quoting. + * "Within the backquoted style of command substitution, backslash + * shall retain its literal meaning, except when followed by: '$', '`', or '\'. + * The search for the matching backquote shall be satisfied by the first + * backquote found without a preceding backslash; during this search, + * if a non-escaped backquote is encountered within a shell comment, + * a here-document, an embedded command substitution of the $(command) + * form, or a quoted string, undefined results occur. A single-quoted + * or double-quoted string that begins, but does not end, within the + * "`...`" sequence produces undefined results." + * Example Output + * echo `echo '\'TEST\`echo ZZ\`BEST` \TESTZZBEST + */ +static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote) { - struct function **funcpp = find_function_slot(name); - struct function *funcp = *funcpp; - - if (funcp != NULL) { - debug_printf_exec("freeing function '%s'\n", funcp->name); - *funcpp = funcp->next; - /* funcp is unlinked now, deleting it. - * Note: if !funcp->body, the function was created by - * "-F name body", do not free ->body_as_string - * and ->name as they were not malloced. */ - if (funcp->body) { - free_pipe_list(funcp->body); - free(funcp->name); -# if !BB_MMU - free(funcp->body_as_string); -# endif + while (1) { + int ch = i_getch(input); + if (ch == '`') + return 1; + if (ch == '\\') { + /* \x. Copy both unless it is \`, \$, \\ and maybe \" */ + ch = i_getch(input); + if (ch != '`' + && ch != '$' + && ch != '\\' + && (!in_dquote || ch != '"') + ) { + o_addchr(dest, '\\'); + } } - free(funcp); + if (ch == EOF) { + syntax_error_unterm_ch('`'); + return 0; + } + o_addchr(dest, ch); } } - -# if BB_MMU -#define exec_function(to_free, funcp, argv) \ - exec_function(funcp, argv) -# endif -static void exec_function(char ***to_free, - const struct function *funcp, - char **argv) NORETURN; -static void exec_function(char ***to_free, - const struct function *funcp, - char **argv) +/* Process $(cmd) - copy contents until ")" is seen. Complicated by + * quoting and nested ()s. + * "With the $(command) style of command substitution, all characters + * following the open parenthesis to the matching closing parenthesis + * constitute the command. Any valid shell script can be used for command, + * except a script consisting solely of redirections which produces + * unspecified results." + * Example Output + * echo $(echo '(TEST)' BEST) (TEST) BEST + * echo $(echo 'TEST)' BEST) TEST) BEST + * echo $(echo \(\(TEST\) BEST) ((TEST) BEST + * + * Also adapted to eat ${var%...} and $((...)) constructs, since ... part + * can contain arbitrary constructs, just like $(cmd). + * In bash compat mode, it needs to also be able to stop on ':' or '/' + * for ${var:N[:M]} and ${var/P[/R]} parsing. + */ +#define DOUBLE_CLOSE_CHAR_FLAG 0x80 +static int add_till_closing_bracket(o_string *dest, struct in_str *input, unsigned end_ch) { -# if BB_MMU - int n = 1; + int ch; + char dbl = end_ch & DOUBLE_CLOSE_CHAR_FLAG; +# if ENABLE_HUSH_BASH_COMPAT + char end_char2 = end_ch >> 8; +# endif + end_ch &= (DOUBLE_CLOSE_CHAR_FLAG - 1); - argv[0] = G.global_argv[0]; - G.global_argv = argv; - while (*++argv) - n++; - G.global_argc = n; - /* On MMU, funcp->body is always non-NULL */ - n = run_list(funcp->body); - fflush_all(); - _exit(n); -# else - re_execute_shell(to_free, - funcp->body_as_string, - G.global_argv[0], - argv + 1, - NULL); -# endif -} - -static int run_function(const struct function *funcp, char **argv) -{ - int rc; - save_arg_t sv; - smallint sv_flg; - - save_and_replace_G_args(&sv, argv); - - /* "we are in function, ok to use return" */ - sv_flg = G.flag_return_in_progress; - G.flag_return_in_progress = -1; -# if ENABLE_HUSH_LOCAL - G.func_nest_level++; -# endif - - /* On MMU, funcp->body is always non-NULL */ -# if !BB_MMU - if (!funcp->body) { - /* Function defined by -F */ - parse_and_run_string(funcp->body_as_string); - rc = G.last_exitcode; - } else -# endif - { - rc = run_list(funcp->body); - } - -# if ENABLE_HUSH_LOCAL - { - struct variable *var; - struct variable **var_pp; - - var_pp = &G.top_var; - while ((var = *var_pp) != NULL) { - if (var->func_nest_level < G.func_nest_level) { - var_pp = &var->next; - continue; + while (1) { + ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch(end_ch); + return 0; + } + if (ch == end_ch IF_HUSH_BASH_COMPAT( || ch == end_char2)) { + if (!dbl) + break; + /* we look for closing )) of $((EXPR)) */ + if (i_peek(input) == end_ch) { + i_getch(input); /* eat second ')' */ + break; } - /* Unexport */ - if (var->flg_export) - bb_unsetenv(var->varstr); - /* Remove from global list */ - *var_pp = var->next; - /* Free */ - if (!var->max_len) - free(var->varstr); - free(var); } - G.func_nest_level--; + o_addchr(dest, ch); + if (ch == '(' || ch == '{') { + ch = (ch == '(' ? ')' : '}'); + if (!add_till_closing_bracket(dest, input, ch)) + return 0; + o_addchr(dest, ch); + continue; + } + if (ch == '\'') { + if (!add_till_single_quote(dest, input)) + return 0; + o_addchr(dest, ch); + continue; + } + if (ch == '"') { + if (!add_till_double_quote(dest, input)) + return 0; + o_addchr(dest, ch); + continue; + } + if (ch == '`') { + if (!add_till_backquote(dest, input, /*in_dquote:*/ 0)) + return 0; + o_addchr(dest, ch); + continue; + } + if (ch == '\\') { + /* \x. Copy verbatim. Important for \(, \) */ + ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch(')'); + return 0; + } + o_addchr(dest, ch); + continue; + } } -# endif - G.flag_return_in_progress = sv_flg; - - restore_G_args(&sv, argv); - - return rc; + return ch; } -#endif /* ENABLE_HUSH_FUNCTIONS */ - +#endif /* ENABLE_HUSH_TICK || ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_DOLLAR_OPS */ +/* Return code: 0 for OK, 1 for syntax error */ #if BB_MMU -#define exec_builtin(to_free, x, argv) \ - exec_builtin(x, argv) -#else -#define exec_builtin(to_free, x, argv) \ - exec_builtin(to_free, argv) +#define parse_dollar(as_string, dest, input, quote_mask) \ + parse_dollar(dest, input, quote_mask) +#define as_string NULL #endif -static void exec_builtin(char ***to_free, - const struct built_in_command *x, - char **argv) NORETURN; -static void exec_builtin(char ***to_free, - const struct built_in_command *x, - char **argv) +static int parse_dollar(o_string *as_string, + o_string *dest, + struct in_str *input, unsigned char quote_mask) { -#if BB_MMU - int rcode = x->b_function(argv); - fflush_all(); - _exit(rcode); -#else - /* On NOMMU, we must never block! - * Example: { sleep 99 | read line; } & echo Ok - */ - re_execute_shell(to_free, - argv[0], - G.global_argv[0], - G.global_argv + 1, - argv); -#endif -} + int ch = i_peek(input); /* first character after the $ */ + debug_printf_parse("parse_dollar entered: ch='%c'\n", ch); + if (isalpha(ch)) { + ch = i_getch(input); + nommu_addchr(as_string, ch); + make_var: + o_addchr(dest, SPECIAL_VAR_SYMBOL); + while (1) { + debug_printf_parse(": '%c'\n", ch); + o_addchr(dest, ch | quote_mask); + quote_mask = 0; + ch = i_peek(input); + if (!isalnum(ch) && ch != '_') + break; + ch = i_getch(input); + nommu_addchr(as_string, ch); + } + o_addchr(dest, SPECIAL_VAR_SYMBOL); + } else if (isdigit(ch)) { + make_one_char_var: + ch = i_getch(input); + nommu_addchr(as_string, ch); + o_addchr(dest, SPECIAL_VAR_SYMBOL); + debug_printf_parse(": '%c'\n", ch); + o_addchr(dest, ch | quote_mask); + o_addchr(dest, SPECIAL_VAR_SYMBOL); + } else switch (ch) { + case '$': /* pid */ + case '!': /* last bg pid */ + case '?': /* last exit code */ + case '#': /* number of args */ + case '*': /* args */ + case '@': /* args */ + goto make_one_char_var; + case '{': { + o_addchr(dest, SPECIAL_VAR_SYMBOL); -static void execvp_or_die(char **argv) NORETURN; -static void execvp_or_die(char **argv) -{ - debug_printf_exec("execing '%s'\n", argv[0]); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); - execvp(argv[0], argv); - bb_perror_msg("can't execute '%s'", argv[0]); - _exit(127); /* bash compat */ -} + ch = i_getch(input); /* eat '{' */ + nommu_addchr(as_string, ch); -#if BB_MMU -#define pseudo_exec_argv(nommu_save, argv, assignment_cnt, argv_expanded) \ - pseudo_exec_argv(argv, assignment_cnt, argv_expanded) -#define pseudo_exec(nommu_save, command, argv_expanded) \ - pseudo_exec(command, argv_expanded) -#endif + ch = i_getch(input); /* first char after '{' */ + /* It should be ${?}, or ${#var}, + * or even ${?+subst} - operator acting on a special variable, + * or the beginning of variable name. + */ + if (ch == EOF + || (!strchr(_SPECIAL_VARS_STR, ch) && !isalnum(ch)) /* not one of those */ + ) { + bad_dollar_syntax: + syntax_error_unterm_str("${name}"); + debug_printf_parse("parse_dollar return 0: unterminated ${name}\n"); + return 0; + } + nommu_addchr(as_string, ch); + ch |= quote_mask; -/* Called after [v]fork() in run_pipe, or from builtin_exec. - * Never returns. - * Don't exit() here. If you don't exec, use _exit instead. - * The at_exit handlers apparently confuse the calling process, - * in particular stdin handling. Not sure why? -- because of vfork! (vda) */ -static void pseudo_exec_argv(nommu_save_t *nommu_save, - char **argv, int assignment_cnt, - char **argv_expanded) NORETURN; -static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, - char **argv, int assignment_cnt, - char **argv_expanded) -{ - char **new_env; + /* It's possible to just call add_till_closing_bracket() at this point. + * However, this regresses some of our testsuite cases + * which check invalid constructs like ${%}. + * Oh well... let's check that the var name part is fine... */ - /* Case when we are here: ... | var=val | ... */ - if (!argv[assignment_cnt]) - _exit(EXIT_SUCCESS); + while (1) { + unsigned pos; - new_env = expand_assignments(argv, assignment_cnt); -#if BB_MMU - set_vars_and_save_old(new_env); - free(new_env); /* optional */ - /* we can also destroy set_vars_and_save_old's return value, - * to save memory */ -#else - nommu_save->new_env = new_env; - nommu_save->old_vars = set_vars_and_save_old(new_env); -#endif - if (argv_expanded) { - argv = argv_expanded; - } else { - argv = expand_strvec_to_strvec(argv + assignment_cnt); -#if !BB_MMU - nommu_save->argv = argv; -#endif - } + o_addchr(dest, ch); + debug_printf_parse(": '%c'\n", ch); -#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU - if (strchr(argv[0], '/') != NULL) - goto skip; -#endif + ch = i_getch(input); + nommu_addchr(as_string, ch); + if (ch == '}') + break; - /* Check if the command matches any of the builtins. - * Depending on context, this might be redundant. But it's - * easier to waste a few CPU cycles than it is to figure out - * if this is one of those cases. - */ - { - /* On NOMMU, it is more expensive to re-execute shell - * just in order to run echo or test builtin. - * It's better to skip it here and run corresponding - * non-builtin later. */ - const struct built_in_command *x; - x = BB_MMU ? find_builtin(argv[0]) : find_builtin1(argv[0]); - if (x) { - exec_builtin(&nommu_save->argv_from_re_execing, x, argv); - } - } -#if ENABLE_HUSH_FUNCTIONS - /* Check if the command matches any functions */ - { - const struct function *funcp = find_function(argv[0]); - if (funcp) { - exec_function(&nommu_save->argv_from_re_execing, funcp, argv); + if (!isalnum(ch) && ch != '_') { + unsigned end_ch; + unsigned char last_ch; + /* handle parameter expansions + * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_06_02 + */ + if (!strchr(VAR_SUBST_OPS, ch)) /* ${var... */ + goto bad_dollar_syntax; + + /* Eat everything until closing '}' (or ':') */ + end_ch = '}'; + if (ENABLE_HUSH_BASH_COMPAT + && ch == ':' + && !strchr(MINUS_PLUS_EQUAL_QUESTION, i_peek(input)) + ) { + /* It's ${var:N[:M]} thing */ + end_ch = '}' * 0x100 + ':'; + } + if (ENABLE_HUSH_BASH_COMPAT + && ch == '/' + ) { + /* It's ${var/[/]pattern[/repl]} thing */ + if (i_peek(input) == '/') { /* ${var//pattern[/repl]}? */ + i_getch(input); + nommu_addchr(as_string, '/'); + ch = '\\'; + } + end_ch = '}' * 0x100 + '/'; + } + o_addchr(dest, ch); + again: + if (!BB_MMU) + pos = dest->length; +#if ENABLE_HUSH_DOLLAR_OPS + last_ch = add_till_closing_bracket(dest, input, end_ch); + if (last_ch == 0) /* error? */ + return 0; +#else +#error Simple code to only allow ${var} is not implemented +#endif + if (as_string) { + o_addstr(as_string, dest->data + pos); + o_addchr(as_string, last_ch); + } + + if (ENABLE_HUSH_BASH_COMPAT && (end_ch & 0xff00)) { + /* close the first block: */ + o_addchr(dest, SPECIAL_VAR_SYMBOL); + /* while parsing N from ${var:N[:M]} + * or pattern from ${var/[/]pattern[/repl]} */ + if ((end_ch & 0xff) == last_ch) { + /* got ':' or '/'- parse the rest */ + end_ch = '}'; + goto again; + } + /* got '}' */ + if (end_ch == '}' * 0x100 + ':') { + /* it's ${var:N} - emulate :999999999 */ + o_addstr(dest, "999999999"); + } /* else: it's ${var/[/]pattern} */ + } + break; + } } + o_addchr(dest, SPECIAL_VAR_SYMBOL); + break; } -#endif +#if ENABLE_SH_MATH_SUPPORT || ENABLE_HUSH_TICK + case '(': { + unsigned pos; -#if ENABLE_FEATURE_SH_STANDALONE - /* Check if the command matches any busybox applets */ - { - int a = find_applet_by_name(argv[0]); - if (a >= 0) { -# if BB_MMU /* see above why on NOMMU it is not allowed */ - if (APPLET_IS_NOEXEC(a)) { - debug_printf_exec("running applet '%s'\n", argv[0]); - run_applet_no_and_exit(a, argv); + ch = i_getch(input); + nommu_addchr(as_string, ch); +# if ENABLE_SH_MATH_SUPPORT + if (i_peek(input) == '(') { + ch = i_getch(input); + nommu_addchr(as_string, ch); + o_addchr(dest, SPECIAL_VAR_SYMBOL); + o_addchr(dest, /*quote_mask |*/ '+'); + if (!BB_MMU) + pos = dest->length; + if (!add_till_closing_bracket(dest, input, ')' | DOUBLE_CLOSE_CHAR_FLAG)) + return 0; /* error */ + if (as_string) { + o_addstr(as_string, dest->data + pos); + o_addchr(as_string, ')'); + o_addchr(as_string, ')'); } + o_addchr(dest, SPECIAL_VAR_SYMBOL); + break; + } # endif - /* Re-exec ourselves */ - debug_printf_exec("re-execing applet '%s'\n", argv[0]); - sigprocmask(SIG_SETMASK, &G.inherited_set, NULL); - execv(bb_busybox_exec_path, argv); - /* If they called chroot or otherwise made the binary no longer - * executable, fall through */ +# if ENABLE_HUSH_TICK + o_addchr(dest, SPECIAL_VAR_SYMBOL); + o_addchr(dest, quote_mask | '`'); + if (!BB_MMU) + pos = dest->length; + if (!add_till_closing_bracket(dest, input, ')')) + return 0; /* error */ + if (as_string) { + o_addstr(as_string, dest->data + pos); + o_addchr(as_string, ')'); } + o_addchr(dest, SPECIAL_VAR_SYMBOL); +# endif + break; } #endif - -#if ENABLE_FEATURE_SH_STANDALONE || BB_MMU - skip: -#endif - execvp_or_die(argv); + case '_': + ch = i_getch(input); + nommu_addchr(as_string, ch); + ch = i_peek(input); + if (isalnum(ch)) { /* it's $_name or $_123 */ + ch = '_'; + goto make_var; + } + /* else: it's $_ */ + /* TODO: $_ and $-: */ + /* $_ Shell or shell script name; or last argument of last command + * (if last command wasn't a pipe; if it was, bash sets $_ to ""); + * but in command's env, set to full pathname used to invoke it */ + /* $- Option flags set by set builtin or shell options (-i etc) */ + default: + o_addQchr(dest, '$'); + } + debug_printf_parse("parse_dollar return 1 (ok)\n"); + return 1; +#undef as_string } -/* Called after [v]fork() in run_pipe - */ -static void pseudo_exec(nommu_save_t *nommu_save, - struct command *command, - char **argv_expanded) NORETURN; -static void pseudo_exec(nommu_save_t *nommu_save, - struct command *command, - char **argv_expanded) +#if BB_MMU +# if ENABLE_HUSH_BASH_COMPAT +#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ + encode_string(dest, input, dquote_end, process_bkslash) +# else +/* only ${var/pattern/repl} (its pattern part) needs additional mode */ +#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ + encode_string(dest, input, dquote_end) +# endif +#define as_string NULL + +#else /* !MMU */ + +# if ENABLE_HUSH_BASH_COMPAT +/* all parameters are needed, no macro tricks */ +# else +#define encode_string(as_string, dest, input, dquote_end, process_bkslash) \ + encode_string(as_string, dest, input, dquote_end) +# endif +#endif +static int encode_string(o_string *as_string, + o_string *dest, + struct in_str *input, + int dquote_end, + int process_bkslash) { - if (command->argv) { - pseudo_exec_argv(nommu_save, command->argv, - command->assignment_cnt, argv_expanded); - } +#if !ENABLE_HUSH_BASH_COMPAT + const int process_bkslash = 1; +#endif + int ch; + int next; - if (command->group) { - /* Cases when we are here: - * ( list ) - * { list } & - * ... | ( list ) | ... - * ... | { list } | ... + again: + ch = i_getch(input); + if (ch != EOF) + nommu_addchr(as_string, ch); + if (ch == dquote_end) { /* may be only '"' or EOF */ + debug_printf_parse("encode_string return 1 (ok)\n"); + return 1; + } + /* note: can't move it above ch == dquote_end check! */ + if (ch == EOF) { + syntax_error_unterm_ch('"'); + return 0; /* error */ + } + next = '\0'; + if (ch != '\n') { + next = i_peek(input); + } + debug_printf_parse("\" ch=%c (%d) escape=%d\n", + ch, ch, !!(dest->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); + if (process_bkslash && ch == '\\') { + if (next == EOF) { + syntax_error("\\"); + xfunc_die(); + } + /* bash: + * "The backslash retains its special meaning [in "..."] + * only when followed by one of the following characters: + * $, `, ", \, or . A double quote may be quoted + * within double quotes by preceding it with a backslash." + * NB: in (unquoted) heredoc, above does not apply to ", + * therefore we check for it by "next == dquote_end" cond. */ -#if BB_MMU - int rcode; - debug_printf_exec("pseudo_exec: run_list\n"); - reset_traps_to_defaults(); - rcode = run_list(command->group); - /* OK to leak memory by not calling free_pipe_list, - * since this process is about to exit */ - _exit(rcode); -#else - re_execute_shell(&nommu_save->argv_from_re_execing, - command->group_as_string, - G.global_argv[0], - G.global_argv + 1, - NULL); -#endif + if (next == dquote_end || strchr("$`\\\n", next)) { + ch = i_getch(input); /* eat next */ + if (ch == '\n') + goto again; /* skip \ */ + } /* else: ch remains == '\\', and we double it below: */ + o_addqchr(dest, ch); /* \c if c is a glob char, else just c */ + nommu_addchr(as_string, ch); + goto again; } - - /* Case when we are here: ... | >file */ - debug_printf_exec("pseudo_exec'ed null command\n"); - _exit(EXIT_SUCCESS); + if (ch == '$') { + if (!parse_dollar(as_string, dest, input, /*quote_mask:*/ 0x80)) { + debug_printf_parse("encode_string return 0: " + "parse_dollar returned 0 (error)\n"); + return 0; + } + goto again; + } +#if ENABLE_HUSH_TICK + if (ch == '`') { + //unsigned pos = dest->length; + o_addchr(dest, SPECIAL_VAR_SYMBOL); + o_addchr(dest, 0x80 | '`'); + if (!add_till_backquote(dest, input, /*in_dquote:*/ dquote_end == '"')) + return 0; /* error */ + o_addchr(dest, SPECIAL_VAR_SYMBOL); + //debug_printf_subst("SUBST RES3 '%s'\n", dest->data + pos); + goto again; + } +#endif + o_addQchr(dest, ch); + goto again; +#undef as_string } -#if ENABLE_HUSH_JOB -static const char *get_cmdtext(struct pipe *pi) +/* + * Scan input until EOF or end_trigger char. + * Return a list of pipes to execute, or NULL on EOF + * or if end_trigger character is met. + * On syntax error, exit if shell is not interactive, + * reset parsing machinery and start parsing anew, + * or return ERR_PTR. + */ +static struct pipe *parse_stream(char **pstring, + struct in_str *input, + int end_trigger) { - char **argv; - char *p; - int len; + struct parse_context ctx; + o_string dest = NULL_O_STRING; + int heredoc_cnt; - /* This is subtle. ->cmdtext is created only on first backgrounding. - * (Think "cat, , fg, , fg, ...." here...) - * On subsequent bg argv is trashed, but we won't use it */ - if (pi->cmdtext) - return pi->cmdtext; - argv = pi->cmds[0].argv; - if (!argv || !argv[0]) { - pi->cmdtext = xzalloc(1); - return pi->cmdtext; - } - - len = 0; - do { - len += strlen(*argv) + 1; - } while (*++argv); - p = xmalloc(len); - pi->cmdtext = p; - argv = pi->cmds[0].argv; - do { - len = strlen(*argv); - memcpy(p, *argv, len); - p += len; - *p++ = ' '; - } while (*++argv); - p[-1] = '\0'; - return pi->cmdtext; -} - -static void insert_bg_job(struct pipe *pi) -{ - struct pipe *job, **jobp; - int i; - - /* Linear search for the ID of the job to use */ - pi->jobid = 1; - for (job = G.job_list; job; job = job->next) - if (job->jobid >= pi->jobid) - pi->jobid = job->jobid + 1; - - /* Add job to the list of running jobs */ - jobp = &G.job_list; - while ((job = *jobp) != NULL) - jobp = &job->next; - job = *jobp = xmalloc(sizeof(*job)); + /* Single-quote triggers a bypass of the main loop until its mate is + * found. When recursing, quote state is passed in via dest->o_expflags. + */ + debug_printf_parse("parse_stream entered, end_trigger='%c'\n", + end_trigger ? end_trigger : 'X'); + debug_enter(); - *job = *pi; /* physical copy */ - job->next = NULL; - job->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds); - /* Cannot copy entire pi->cmds[] vector! This causes double frees */ - for (i = 0; i < pi->num_cmds; i++) { - job->cmds[i].pid = pi->cmds[i].pid; - /* all other fields are not used and stay zero */ - } - job->cmdtext = xstrdup(get_cmdtext(pi)); + /* If very first arg is "" or '', dest.data may end up NULL. + * Preventing this: */ + o_addchr(&dest, '\0'); + dest.length = 0; - if (G_interactive_fd) - printf("[%d] %d %s\n", job->jobid, job->cmds[0].pid, job->cmdtext); - /* Last command's pid goes to $! */ - G.last_bg_pid = job->cmds[job->num_cmds - 1].pid; - G.last_jobid = job->jobid; -} + /* We used to separate words on $IFS here. This was wrong. + * $IFS is used only for word splitting when $var is expanded, + * here we should use blank chars as separators, not $IFS + */ -static void remove_bg_job(struct pipe *pi) -{ - struct pipe *prev_pipe; + if (MAYBE_ASSIGNMENT != 0) + dest.o_assignment = MAYBE_ASSIGNMENT; + initialize_context(&ctx); + heredoc_cnt = 0; + while (1) { + const char *is_blank; + const char *is_special; + int ch; + int next; + int redir_fd; + redir_type redir_style; - if (pi == G.job_list) { - G.job_list = pi->next; - } else { - prev_pipe = G.job_list; - while (prev_pipe->next != pi) - prev_pipe = prev_pipe->next; - prev_pipe->next = pi->next; - } - if (G.job_list) - G.last_jobid = G.job_list->jobid; - else - G.last_jobid = 0; -} + ch = i_getch(input); + debug_printf_parse(": ch=%c (%d) escape=%d\n", + ch, ch, !!(dest.o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); + if (ch == EOF) { + struct pipe *pi; -/* Remove a backgrounded job */ -static void delete_finished_bg_job(struct pipe *pi) -{ - remove_bg_job(pi); - pi->stopped_cmds = 0; - free_pipe(pi); - free(pi); -} -#endif /* JOB */ + if (heredoc_cnt) { + syntax_error_unterm_str("here document"); + goto parse_error; + } + /* end_trigger == '}' case errors out earlier, + * checking only ')' */ + if (end_trigger == ')') { + syntax_error_unterm_ch('('); + goto parse_error; + } -/* Check to see if any processes have exited -- if they - * have, figure out why and see if a job has completed */ -static int checkjobs(struct pipe* fg_pipe) -{ - int attributes; - int status; -#if ENABLE_HUSH_JOB - struct pipe *pi; + if (done_word(&dest, &ctx)) { + goto parse_error; + } + o_free(&dest); + done_pipe(&ctx, PIPE_SEQ); + pi = ctx.list_head; + /* If we got nothing... */ + /* (this makes bare "&" cmd a no-op. + * bash says: "syntax error near unexpected token '&'") */ + if (pi->num_cmds == 0 + IF_HAS_KEYWORDS(&& pi->res_word == RES_NONE) + ) { + free_pipe_list(pi); + pi = NULL; + } +#if !BB_MMU + debug_printf_parse("as_string '%s'\n", ctx.as_string.data); + if (pstring) + *pstring = ctx.as_string.data; + else + o_free_unsafe(&ctx.as_string); #endif - pid_t childpid; - int rcode = 0; - - debug_printf_jobs("checkjobs %p\n", fg_pipe); + debug_leave(); + debug_printf_parse("parse_stream return %p\n", pi); + return pi; + } + nommu_addchr(&ctx.as_string, ch); - attributes = WUNTRACED; - if (fg_pipe == NULL) - attributes |= WNOHANG; + next = '\0'; + if (ch != '\n') + next = i_peek(input); - errno = 0; -#if ENABLE_HUSH_FAST - if (G.handled_SIGCHLD == G.count_SIGCHLD) { -//bb_error_msg("[%d] checkjobs: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d children?:%d fg_pipe:%p", -//getpid(), G.count_SIGCHLD, G.handled_SIGCHLD, G.we_have_children, fg_pipe); - /* There was neither fork nor SIGCHLD since last waitpid */ - /* Avoid doing waitpid syscall if possible */ - if (!G.we_have_children) { - errno = ECHILD; - return -1; - } - if (fg_pipe == NULL) { /* is WNOHANG set? */ - /* We have children, but they did not exit - * or stop yet (we saw no SIGCHLD) */ - return 0; + is_special = "{}<>;&|()#'" /* special outside of "str" */ + "\\$\"" IF_HUSH_TICK("`"); /* always special */ + /* Are { and } special here? */ + if (ctx.command->argv /* word [word]{... - non-special */ + || dest.length /* word{... - non-special */ + || dest.has_quoted_part /* ""{... - non-special */ + || (next != ';' /* }; - special */ + && next != ')' /* }) - special */ + && next != '&' /* }& and }&& ... - special */ + && next != '|' /* }|| ... - special */ + && !strchr(defifs, next) /* {word - non-special */ + ) + ) { + /* They are not special, skip "{}" */ + is_special += 2; } - /* else: !WNOHANG, waitpid will block, can't short-circuit */ - } -#endif - -/* Do we do this right? - * bash-3.00# sleep 20 | false - * - * [3]+ Stopped sleep 20 | false - * bash-3.00# echo $? - * 1 <========== bg pipe is not fully done, but exitcode is already known! - * [hush 1.14.0: yes we do it right] - */ - wait_more: - while (1) { - int i; - int dead; + is_special = strchr(is_special, ch); + is_blank = strchr(defifs, ch); -#if ENABLE_HUSH_FAST - i = G.count_SIGCHLD; -#endif - childpid = waitpid(-1, &status, attributes); - if (childpid <= 0) { - if (childpid && errno != ECHILD) - bb_perror_msg("waitpid"); -#if ENABLE_HUSH_FAST - else { /* Until next SIGCHLD, waitpid's are useless */ - G.we_have_children = (childpid == 0); - G.handled_SIGCHLD = i; -//bb_error_msg("[%d] checkjobs: waitpid returned <= 0, G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + if (!is_special && !is_blank) { /* ordinary char */ + ordinary_char: + o_addQchr(&dest, ch); + if ((dest.o_assignment == MAYBE_ASSIGNMENT + || dest.o_assignment == WORD_IS_KEYWORD) + && ch == '=' + && is_well_formed_var_name(dest.data, '=') + ) { + dest.o_assignment = DEFINITELY_ASSIGNMENT; + debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); } -#endif - break; + continue; } - dead = WIFEXITED(status) || WIFSIGNALED(status); -#if DEBUG_JOBS - if (WIFSTOPPED(status)) - debug_printf_jobs("pid %d stopped by sig %d (exitcode %d)\n", - childpid, WSTOPSIG(status), WEXITSTATUS(status)); - if (WIFSIGNALED(status)) - debug_printf_jobs("pid %d killed by sig %d (exitcode %d)\n", - childpid, WTERMSIG(status), WEXITSTATUS(status)); - if (WIFEXITED(status)) - debug_printf_jobs("pid %d exited, exitcode %d\n", - childpid, WEXITSTATUS(status)); -#endif - /* Were we asked to wait for fg pipe? */ - if (fg_pipe) { - for (i = 0; i < fg_pipe->num_cmds; i++) { - debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid); - if (fg_pipe->cmds[i].pid != childpid) - continue; - if (dead) { - fg_pipe->cmds[i].pid = 0; - fg_pipe->alive_cmds--; - if (i == fg_pipe->num_cmds - 1) { - /* last process gives overall exitstatus */ - rcode = WEXITSTATUS(status); - /* bash prints killer signal's name for *last* - * process in pipe (prints just newline for SIGINT). - * Mimic this. Example: "sleep 5" + (^\ or kill -QUIT) - */ - if (WIFSIGNALED(status)) { - int sig = WTERMSIG(status); - printf("%s\n", sig == SIGINT ? "" : get_signame(sig)); - /* TODO: MIPS has 128 sigs (1..128), what if sig==128 here? - * Maybe we need to use sig | 128? */ - rcode = sig + 128; - } - IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;) + if (is_blank) { + if (done_word(&dest, &ctx)) { + goto parse_error; + } + if (ch == '\n') { + /* Is this a case when newline is simply ignored? + * Some examples: + * "cmd | cmd ..." + * "case ... in word) ..." + */ + if (IS_NULL_CMD(ctx.command) + && dest.length == 0 && !dest.has_quoted_part + ) { + /* This newline can be ignored. But... + * Without check #1, interactive shell + * ignores even bare , + * and shows the continuation prompt: + * ps1_prompt$ + * ps2> _ <=== wrong, should be ps1 + * Without check #2, "cmd & " + * is similarly mistreated. + * (BTW, this makes "cmd & cmd" + * and "cmd && cmd" non-orthogonal. + * Really, ask yourself, why + * "cmd && " doesn't start + * cmd but waits for more input? + * No reason...) + */ + struct pipe *pi = ctx.list_head; + if (pi->num_cmds != 0 /* check #1 */ + && pi->followup != PIPE_BG /* check #2 */ + ) { + continue; } - } else { - fg_pipe->cmds[i].is_stopped = 1; - fg_pipe->stopped_cmds++; } - debug_printf_jobs("fg_pipe: alive_cmds %d stopped_cmds %d\n", - fg_pipe->alive_cmds, fg_pipe->stopped_cmds); - if (fg_pipe->alive_cmds - fg_pipe->stopped_cmds <= 0) { - /* All processes in fg pipe have exited or stopped */ -/* Note: *non-interactive* bash does not continue if all processes in fg pipe - * are stopped. Testcase: "cat | cat" in a script (not on command line!) - * and "killall -STOP cat" */ - if (G_interactive_fd) { -#if ENABLE_HUSH_JOB - if (fg_pipe->alive_cmds) - insert_bg_job(fg_pipe); -#endif - return rcode; - } - if (!fg_pipe->alive_cmds) - return rcode; + /* Treat newline as a command separator. */ + done_pipe(&ctx, PIPE_SEQ); + debug_printf_parse("heredoc_cnt:%d\n", heredoc_cnt); + if (heredoc_cnt) { + if (fetch_heredocs(heredoc_cnt, &ctx, input)) { + goto parse_error; + } + heredoc_cnt = 0; } - /* There are still running processes in the fg pipe */ - goto wait_more; /* do waitpid again */ - } - /* it wasnt fg_pipe, look for process in bg pipes */ - } - -#if ENABLE_HUSH_JOB - /* We asked to wait for bg or orphaned children */ - /* No need to remember exitcode in this case */ - for (pi = G.job_list; pi; pi = pi->next) { - for (i = 0; i < pi->num_cmds; i++) { - if (pi->cmds[i].pid == childpid) - goto found_pi_and_prognum; + dest.o_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + ch = ';'; + /* note: if (is_blank) continue; + * will still trigger for us */ } } - /* Happens when shell is used as init process (init=/bin/sh) */ - debug_printf("checkjobs: pid %d was not in our list!\n", childpid); - continue; /* do waitpid again */ - found_pi_and_prognum: - if (dead) { - /* child exited */ - pi->cmds[i].pid = 0; - pi->alive_cmds--; - if (!pi->alive_cmds) { - if (G_interactive_fd) - printf(JOB_STATUS_FORMAT, pi->jobid, - "Done", pi->cmdtext); - delete_finished_bg_job(pi); + /* "cmd}" or "cmd }..." without semicolon or &: + * } is an ordinary char in this case, even inside { cmd; } + * Pathological example: { ""}; } should exec "}" cmd + */ + if (ch == '}') { + if (!IS_NULL_CMD(ctx.command) /* cmd } */ + || dest.length != 0 /* word} */ + || dest.has_quoted_part /* ""} */ + ) { + goto ordinary_char; } - } else { - /* child stopped */ - pi->cmds[i].is_stopped = 1; - pi->stopped_cmds++; - } -#endif - } /* while (waitpid succeeds)... */ - - return rcode; -} - -#if ENABLE_HUSH_JOB -static int checkjobs_and_fg_shell(struct pipe* fg_pipe) -{ - pid_t p; - int rcode = checkjobs(fg_pipe); - if (G_saved_tty_pgrp) { - /* Job finished, move the shell to the foreground */ - p = getpgrp(); /* our process group id */ - debug_printf_jobs("fg'ing ourself: getpgrp()=%d\n", (int)p); - tcsetpgrp(G_interactive_fd, p); - } - return rcode; -} -#endif - -/* Start all the jobs, but don't wait for anything to finish. - * See checkjobs(). - * - * Return code is normally -1, when the caller has to wait for children - * to finish to determine the exit status of the pipe. If the pipe - * is a simple builtin command, however, the action is done by the - * time run_pipe returns, and the exit code is provided as the - * return value. - * - * Returns -1 only if started some children. IOW: we have to - * mask out retvals of builtins etc with 0xff! - * - * The only case when we do not need to [v]fork is when the pipe - * is single, non-backgrounded, non-subshell command. Examples: - * cmd ; ... { list } ; ... - * cmd && ... { list } && ... - * cmd || ... { list } || ... - * If it is, then we can run cmd as a builtin, NOFORK [do we do this?], - * or (if SH_STANDALONE) an applet, and we can run the { list } - * with run_list. If it isn't one of these, we fork and exec cmd. - * - * Cases when we must fork: - * non-single: cmd | cmd - * backgrounded: cmd & { list } & - * subshell: ( list ) [&] - */ -static NOINLINE int run_pipe(struct pipe *pi) -{ - static const char *const null_ptr = NULL; - int i; - int nextin; - struct command *command; - char **argv_expanded; - char **argv; - char *p; - /* it is not always needed, but we aim to smaller code */ - int squirrel[] = { -1, -1, -1 }; - int rcode; - - debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds); - debug_enter(); - - IF_HUSH_JOB(pi->pgrp = -1;) - pi->stopped_cmds = 0; - command = &(pi->cmds[0]); - argv_expanded = NULL; - - if (pi->num_cmds != 1 - || pi->followup == PIPE_BG - || command->cmd_type == CMD_SUBSHELL - ) { - goto must_fork; - } - - pi->alive_cmds = 1; - - debug_printf_exec(": group:%p argv:'%s'\n", - command->group, command->argv ? command->argv[0] : "NONE"); - - if (command->group) { -#if ENABLE_HUSH_FUNCTIONS - if (command->cmd_type == CMD_FUNCDEF) { - /* "executing" func () { list } */ - struct function *funcp; - - funcp = new_function(command->argv[0]); - /* funcp->name is already set to argv[0] */ - funcp->body = command->group; -# if !BB_MMU - funcp->body_as_string = command->group_as_string; - command->group_as_string = NULL; -# endif - command->group = NULL; - command->argv[0] = NULL; - debug_printf_exec("cmd %p has child func at %p\n", command, funcp); - funcp->parent_cmd = command; - command->child_func = funcp; - - debug_printf_exec("run_pipe: return EXIT_SUCCESS\n"); - debug_leave(); - return EXIT_SUCCESS; - } -#endif - /* { list } */ - debug_printf("non-subshell group\n"); - rcode = 1; /* exitcode if redir failed */ - if (setup_redirects(command, squirrel) == 0) { - debug_printf_exec(": run_list\n"); - rcode = run_list(command->group) & 0xff; + if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */ + goto skip_end_trigger; + /* else: } does terminate a group */ } - restore_redirects(squirrel); - IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) - debug_leave(); - debug_printf_exec("run_pipe: return %d\n", rcode); - return rcode; - } - argv = command->argv ? command->argv : (char **) &null_ptr; - { - const struct built_in_command *x; -#if ENABLE_HUSH_FUNCTIONS - const struct function *funcp; -#else - enum { funcp = 0 }; + if (end_trigger && end_trigger == ch + && (ch != ';' || heredoc_cnt == 0) +#if ENABLE_HUSH_CASE + && (ch != ')' + || ctx.ctx_res_w != RES_MATCH + || (!dest.has_quoted_part && strcmp(dest.data, "esac") == 0) + ) #endif - char **new_env = NULL; - struct variable *old_vars = NULL; - - if (argv[command->assignment_cnt] == NULL) { - /* Assignments, but no command */ - /* Ensure redirects take effect (that is, create files). - * Try "a=t >file": */ - rcode = setup_redirects(command, squirrel); - restore_redirects(squirrel); - /* Set shell variables */ - while (*argv) { - p = expand_string_to_string(*argv); - debug_printf_exec("set shell var:'%s'->'%s'\n", - *argv, p); - set_local_var(p, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); - argv++; + ) { + if (heredoc_cnt) { + /* This is technically valid: + * { cat <pi_inverted) rcode = !rcode;) - debug_leave(); - debug_printf_exec("run_pipe: return %d\n", rcode); - return rcode; - } - - /* Expand the rest into (possibly) many strings each */ - if (0) {} -#if ENABLE_HUSH_BASH_COMPAT - else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB) { - argv_expanded = expand_strvec_to_strvec_singleword_noglob(argv + command->assignment_cnt); - } -#endif -#ifdef CMD_SINGLEWORD_NOGLOB_COND - else if (command->cmd_type == CMD_SINGLEWORD_NOGLOB_COND) { - argv_expanded = expand_strvec_to_strvec_singleword_noglob_cond(argv + command->assignment_cnt); - - } + if (done_word(&dest, &ctx)) { + goto parse_error; + } + done_pipe(&ctx, PIPE_SEQ); + dest.o_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + /* Do we sit outside of any if's, loops or case's? */ + if (!HAS_KEYWORDS + IF_HAS_KEYWORDS(|| (ctx.ctx_res_w == RES_NONE && ctx.old_flag == 0)) + ) { + o_free(&dest); +#if !BB_MMU + debug_printf_parse("as_string '%s'\n", ctx.as_string.data); + if (pstring) + *pstring = ctx.as_string.data; + else + o_free_unsafe(&ctx.as_string); #endif - else { - argv_expanded = expand_strvec_to_strvec(argv + command->assignment_cnt); - } - - /* if someone gives us an empty string: `cmd with empty output` */ - if (!argv_expanded[0]) { - free(argv_expanded); - debug_leave(); - return G.last_exitcode; + debug_leave(); + debug_printf_parse("parse_stream return %p: " + "end_trigger char found\n", + ctx.list_head); + return ctx.list_head; + } } + skip_end_trigger: + if (is_blank) + continue; - x = find_builtin(argv_expanded[0]); -#if ENABLE_HUSH_FUNCTIONS - funcp = NULL; - if (!x) - funcp = find_function(argv_expanded[0]); + /* Catch <, > before deciding whether this word is + * an assignment. a=1 2>z b=2: b=2 is still assignment */ + switch (ch) { + case '>': + redir_fd = redirect_opt_num(&dest); + if (done_word(&dest, &ctx)) { + goto parse_error; + } + redir_style = REDIRECT_OVERWRITE; + if (next == '>') { + redir_style = REDIRECT_APPEND; + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + } +#if 0 + else if (next == '(') { + syntax_error(">(process) not supported"); + goto parse_error; + } #endif - if (x || funcp) { - if (!funcp) { - if (x->b_function == builtin_exec && argv_expanded[1] == NULL) { - debug_printf("exec with redirects only\n"); - rcode = setup_redirects(command, NULL); - goto clean_up_and_ret1; - } + if (parse_redirect(&ctx, redir_fd, redir_style, input)) + goto parse_error; + continue; /* back to top of while (1) */ + case '<': + redir_fd = redirect_opt_num(&dest); + if (done_word(&dest, &ctx)) { + goto parse_error; + } + redir_style = REDIRECT_INPUT; + if (next == '<') { + redir_style = REDIRECT_HEREDOC; + heredoc_cnt++; + debug_printf_parse("++heredoc_cnt=%d\n", heredoc_cnt); + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + } else if (next == '>') { + redir_style = REDIRECT_IO; + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + } +#if 0 + else if (next == '(') { + syntax_error("<(process) not supported"); + goto parse_error; } - /* setup_redirects acts on file descriptors, not FILEs. - * This is perfect for work that comes after exec(). - * Is it really safe for inline use? Experimentally, - * things seem to work. */ - rcode = setup_redirects(command, squirrel); - if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - old_vars = set_vars_and_save_old(new_env); - if (!funcp) { - debug_printf_exec(": builtin '%s' '%s'...\n", - x->b_cmd, argv_expanded[1]); - rcode = x->b_function(argv_expanded) & 0xff; - fflush_all(); - } -#if ENABLE_HUSH_FUNCTIONS - else { -# if ENABLE_HUSH_LOCAL - struct variable **sv; - sv = G.shadowed_vars_pp; - G.shadowed_vars_pp = &old_vars; -# endif - debug_printf_exec(": function '%s' '%s'...\n", - funcp->name, argv_expanded[1]); - rcode = run_function(funcp, argv_expanded) & 0xff; -# if ENABLE_HUSH_LOCAL - G.shadowed_vars_pp = sv; -# endif - } #endif + if (parse_redirect(&ctx, redir_fd, redir_style, input)) + goto parse_error; + continue; /* back to top of while (1) */ + case '#': + if (dest.length == 0 && !dest.has_quoted_part) { + /* skip "#comment" */ + while (1) { + ch = i_peek(input); + if (ch == EOF || ch == '\n') + break; + i_getch(input); + /* note: we do not add it to &ctx.as_string */ + } + nommu_addchr(&ctx.as_string, '\n'); + continue; /* back to top of while (1) */ } -#if ENABLE_FEATURE_SH_STANDALONE - clean_up_and_ret: + break; + case '\\': + if (next == '\n') { + /* It's "\" */ +#if !BB_MMU + /* Remove trailing '\' from ctx.as_string */ + ctx.as_string.data[--ctx.as_string.length] = '\0'; #endif - restore_redirects(squirrel); - unset_vars(new_env); - add_vars(old_vars); - clean_up_and_ret1: - free(argv_expanded); - IF_HAS_KEYWORDS(if (pi->pi_inverted) rcode = !rcode;) - debug_leave(); - debug_printf_exec("run_pipe return %d\n", rcode); - return rcode; - } - -#if ENABLE_FEATURE_SH_STANDALONE - i = find_applet_by_name(argv_expanded[0]); - if (i >= 0 && APPLET_IS_NOFORK(i)) { - rcode = setup_redirects(command, squirrel); - if (rcode == 0) { - new_env = expand_assignments(argv, command->assignment_cnt); - old_vars = set_vars_and_save_old(new_env); - debug_printf_exec(": run_nofork_applet '%s' '%s'...\n", - argv_expanded[0], argv_expanded[1]); - rcode = run_nofork_applet(i, argv_expanded); + ch = i_getch(input); /* eat it */ + continue; /* back to top of while (1) */ } - goto clean_up_and_ret; + break; } -#endif - /* It is neither builtin nor applet. We must fork. */ - } - must_fork: - /* NB: argv_expanded may already be created, and that - * might include `cmd` runs! Do not rerun it! We *must* - * use argv_expanded if it's non-NULL */ - - /* Going to fork a child per each pipe member */ - pi->alive_cmds = 0; - nextin = 0; - - for (i = 0; i < pi->num_cmds; i++) { - struct fd_pair pipefds; -#if !BB_MMU - volatile nommu_save_t nommu_save; - nommu_save.new_env = NULL; - nommu_save.old_vars = NULL; - nommu_save.argv = NULL; - nommu_save.argv_from_re_execing = NULL; -#endif - command = &(pi->cmds[i]); - if (command->argv) { - debug_printf_exec(": pipe member '%s' '%s'...\n", - command->argv[0], command->argv[1]); - } else { - debug_printf_exec(": pipe member with no argv\n"); + if (dest.o_assignment == MAYBE_ASSIGNMENT + /* check that we are not in word in "a=1 2>word b=1": */ + && !ctx.pending_redirect + ) { + /* ch is a special char and thus this word + * cannot be an assignment */ + dest.o_assignment = NOT_ASSIGNMENT; + debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); } - /* pipes are inserted between pairs of commands */ - pipefds.rd = 0; - pipefds.wr = 1; - if ((i + 1) < pi->num_cmds) - xpiped_pair(pipefds); + /* Note: nommu_addchr(&ctx.as_string, ch) is already done */ - command->pid = BB_MMU ? fork() : vfork(); - if (!command->pid) { /* child */ -#if ENABLE_HUSH_JOB - disable_restore_tty_pgrp_on_exit(); - CLEAR_RANDOM_T(&G.random_gen); /* or else $RANDOM repeats in child */ + switch (ch) { + case '#': /* non-comment #: "echo a#b" etc */ + o_addQchr(&dest, ch); + break; + case '\\': + if (next == EOF) { + syntax_error("\\"); + xfunc_die(); + } + ch = i_getch(input); + /* note: ch != '\n' (that case does not reach this place) */ + o_addchr(&dest, '\\'); + /*nommu_addchr(&ctx.as_string, '\\'); - already done */ + o_addchr(&dest, ch); + nommu_addchr(&ctx.as_string, ch); + /* Example: echo Hello \2>file + * we need to know that word 2 is quoted */ + dest.has_quoted_part = 1; + break; + case '$': + if (!parse_dollar(&ctx.as_string, &dest, input, /*quote_mask:*/ 0)) { + debug_printf_parse("parse_stream parse error: " + "parse_dollar returned 0 (error)\n"); + goto parse_error; + } + break; + case '\'': + dest.has_quoted_part = 1; + if (next == '\'' && !ctx.pending_redirect) { + insert_empty_quoted_str_marker: + nommu_addchr(&ctx.as_string, next); + i_getch(input); /* eat second ' */ + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + } else { + while (1) { + ch = i_getch(input); + if (ch == EOF) { + syntax_error_unterm_ch('\''); + goto parse_error; + } + nommu_addchr(&ctx.as_string, ch); + if (ch == '\'') + break; + o_addqchr(&dest, ch); + } + } + break; + case '"': + dest.has_quoted_part = 1; + if (next == '"' && !ctx.pending_redirect) + goto insert_empty_quoted_str_marker; + if (dest.o_assignment == NOT_ASSIGNMENT) + dest.o_expflags |= EXP_FLAG_ESC_GLOB_CHARS; + if (!encode_string(&ctx.as_string, &dest, input, '"', /*process_bkslash:*/ 1)) + goto parse_error; + dest.o_expflags &= ~EXP_FLAG_ESC_GLOB_CHARS; + break; +#if ENABLE_HUSH_TICK + case '`': { + USE_FOR_NOMMU(unsigned pos;) - /* Every child adds itself to new process group - * with pgid == pid_of_first_child_in_pipe */ - if (G.run_list_level == 1 && G_interactive_fd) { - pid_t pgrp; - pgrp = pi->pgrp; - if (pgrp < 0) /* true for 1st process only */ - pgrp = getpid(); - if (setpgid(0, pgrp) == 0 - && pi->followup != PIPE_BG - && G_saved_tty_pgrp /* we have ctty */ - ) { - /* We do it in *every* child, not just first, - * to avoid races */ - tcsetpgrp(G_interactive_fd, pgrp); + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + o_addchr(&dest, '`'); + USE_FOR_NOMMU(pos = dest.length;) + if (!add_till_backquote(&dest, input, /*in_dquote:*/ 0)) + goto parse_error; +# if !BB_MMU + o_addstr(&ctx.as_string, dest.data + pos); + o_addchr(&ctx.as_string, '`'); +# endif + o_addchr(&dest, SPECIAL_VAR_SYMBOL); + //debug_printf_subst("SUBST RES3 '%s'\n", dest.data + pos); + break; + } +#endif + case ';': +#if ENABLE_HUSH_CASE + case_semi: +#endif + if (done_word(&dest, &ctx)) { + goto parse_error; + } + done_pipe(&ctx, PIPE_SEQ); +#if ENABLE_HUSH_CASE + /* Eat multiple semicolons, detect + * whether it means something special */ + while (1) { + ch = i_peek(input); + if (ch != ';') + break; + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + if (ctx.ctx_res_w == RES_CASE_BODY) { + ctx.ctx_dsemicolon = 1; + ctx.ctx_res_w = RES_MATCH; + break; } } #endif - if (pi->alive_cmds == 0 && pi->followup == PIPE_BG) { - /* 1st cmd in backgrounded pipe - * should have its stdin /dev/null'ed */ - close(0); - if (open(bb_dev_null, O_RDONLY)) - xopen("/", O_RDONLY); + new_cmd: + /* We just finished a cmd. New one may start + * with an assignment */ + dest.o_assignment = MAYBE_ASSIGNMENT; + debug_printf_parse("dest.o_assignment='%s'\n", assignment_flag[dest.o_assignment]); + break; + case '&': + if (done_word(&dest, &ctx)) { + goto parse_error; + } + if (next == '&') { + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + done_pipe(&ctx, PIPE_AND); } else { - xmove_fd(nextin, 0); + done_pipe(&ctx, PIPE_BG); } - xmove_fd(pipefds.wr, 1); - if (pipefds.rd > 1) - close(pipefds.rd); - /* Like bash, explicit redirects override pipes, - * and the pipe fd is available for dup'ing. */ - if (setup_redirects(command, NULL)) - _exit(1); - - /* Restore default handlers just prior to exec */ - /*signal(SIGCHLD, SIG_DFL); - so far we don't have any handlers */ - - /* Stores to nommu_save list of env vars putenv'ed - * (NOMMU, on MMU we don't need that) */ - /* cast away volatility... */ - pseudo_exec((nommu_save_t*) &nommu_save, command, argv_expanded); - /* pseudo_exec() does not return */ - } - - /* parent or error */ -#if ENABLE_HUSH_FAST - G.count_SIGCHLD++; -//bb_error_msg("[%d] fork in run_pipe: G.count_SIGCHLD:%d G.handled_SIGCHLD:%d", getpid(), G.count_SIGCHLD, G.handled_SIGCHLD); + goto new_cmd; + case '|': + if (done_word(&dest, &ctx)) { + goto parse_error; + } +#if ENABLE_HUSH_CASE + if (ctx.ctx_res_w == RES_MATCH) + break; /* we are in case's "word | word)" */ #endif - enable_restore_tty_pgrp_on_exit(); + if (next == '|') { /* || */ + ch = i_getch(input); + nommu_addchr(&ctx.as_string, ch); + done_pipe(&ctx, PIPE_OR); + } else { + /* we could pick up a file descriptor choice here + * with redirect_opt_num(), but bash doesn't do it. + * "echo foo 2| cat" yields "foo 2". */ + done_command(&ctx); #if !BB_MMU - /* Clean up after vforked child */ - free(nommu_save.argv); - free(nommu_save.argv_from_re_execing); - unset_vars(nommu_save.new_env); - add_vars(nommu_save.old_vars); + o_reset_to_empty_unquoted(&ctx.as_string); #endif - free(argv_expanded); - argv_expanded = NULL; - if (command->pid < 0) { /* [v]fork failed */ - /* Clearly indicate, was it fork or vfork */ - bb_perror_msg(BB_MMU ? "vfork"+1 : "vfork"); - } else { - pi->alive_cmds++; -#if ENABLE_HUSH_JOB - /* Second and next children need to know pid of first one */ - if (pi->pgrp < 0) - pi->pgrp = command->pid; + } + goto new_cmd; + case '(': +#if ENABLE_HUSH_CASE + /* "case... in [(]word)..." - skip '(' */ + if (ctx.ctx_res_w == RES_MATCH + && ctx.command->argv == NULL /* not (word|(... */ + && dest.length == 0 /* not word(... */ + && dest.has_quoted_part == 0 /* not ""(... */ + ) { + continue; + } +#endif + case '{': + if (parse_group(&dest, &ctx, input, ch) != 0) { + goto parse_error; + } + goto new_cmd; + case ')': +#if ENABLE_HUSH_CASE + if (ctx.ctx_res_w == RES_MATCH) + goto case_semi; #endif + case '}': + /* proper use of this character is caught by end_trigger: + * if we see {, we call parse_group(..., end_trigger='}') + * and it will match } earlier (not here). */ + syntax_error_unexpected_ch(ch); + goto parse_error; + default: + if (HUSH_DEBUG) + bb_error_msg_and_die("BUG: unexpected %c\n", ch); } + } /* while (1) */ - if (i) - close(nextin); - if ((i + 1) < pi->num_cmds) - close(pipefds.wr); - /* Pass read (output) pipe end to next iteration */ - nextin = pipefds.rd; - } + parse_error: + { + struct parse_context *pctx; + IF_HAS_KEYWORDS(struct parse_context *p2;) - if (!pi->alive_cmds) { + /* Clean up allocated tree. + * Sample for finding leaks on syntax error recovery path. + * Run it from interactive shell, watch pmap `pidof hush`. + * while if false; then false; fi; do break; fi + * Samples to catch leaks at execution: + * while if (true | {true;}); then echo ok; fi; do break; done + * while if (true | {true;}); then echo ok; fi; do (if echo ok; break; then :; fi) | cat; break; done + */ + pctx = &ctx; + do { + /* Update pipe/command counts, + * otherwise freeing may miss some */ + done_pipe(pctx, PIPE_SEQ); + debug_printf_clean("freeing list %p from ctx %p\n", + pctx->list_head, pctx); + debug_print_tree(pctx->list_head, 0); + free_pipe_list(pctx->list_head); + debug_printf_clean("freed list %p\n", pctx->list_head); +#if !BB_MMU + o_free_unsafe(&pctx->as_string); +#endif + IF_HAS_KEYWORDS(p2 = pctx->stack;) + if (pctx != &ctx) { + free(pctx); + } + IF_HAS_KEYWORDS(pctx = p2;) + } while (HAS_KEYWORDS && pctx); + + o_free(&dest); + G.last_exitcode = 1; +#if !BB_MMU + if (pstring) + *pstring = NULL; +#endif debug_leave(); - debug_printf_exec("run_pipe return 1 (all forks failed, no children)\n"); - return 1; + return ERR_PTR; } - - debug_leave(); - debug_printf_exec("run_pipe return -1 (%u children started)\n", pi->alive_cmds); - return -1; } -#ifndef debug_print_tree -static void debug_print_tree(struct pipe *pi, int lvl) -{ - static const char *const PIPE[] = { - [PIPE_SEQ] = "SEQ", - [PIPE_AND] = "AND", - [PIPE_OR ] = "OR" , - [PIPE_BG ] = "BG" , - }; - static const char *RES[] = { - [RES_NONE ] = "NONE" , -# if ENABLE_HUSH_IF - [RES_IF ] = "IF" , - [RES_THEN ] = "THEN" , - [RES_ELIF ] = "ELIF" , - [RES_ELSE ] = "ELSE" , - [RES_FI ] = "FI" , -# endif -# if ENABLE_HUSH_LOOPS - [RES_FOR ] = "FOR" , - [RES_WHILE] = "WHILE", - [RES_UNTIL] = "UNTIL", - [RES_DO ] = "DO" , - [RES_DONE ] = "DONE" , -# endif -# if ENABLE_HUSH_LOOPS || ENABLE_HUSH_CASE - [RES_IN ] = "IN" , -# endif -# if ENABLE_HUSH_CASE - [RES_CASE ] = "CASE" , - [RES_CASE_IN ] = "CASE_IN" , - [RES_MATCH] = "MATCH", - [RES_CASE_BODY] = "CASE_BODY", - [RES_ESAC ] = "ESAC" , -# endif - [RES_XXXX ] = "XXXX" , - [RES_SNTX ] = "SNTX" , - }; - static const char *const CMDTYPE[] = { - "{}", - "()", - "[noglob]", -# if ENABLE_HUSH_FUNCTIONS - "func()", -# endif - }; - int pin, prn; +/*** Execution routines ***/ + +/* Expansion can recurse, need forward decls: */ +#if !ENABLE_HUSH_BASH_COMPAT +/* only ${var/pattern/repl} (its pattern part) needs additional mode */ +#define expand_string_to_string(str, do_unbackslash) \ + expand_string_to_string(str) +#endif +static char *expand_string_to_string(const char *str, int do_unbackslash); +#if ENABLE_HUSH_TICK +static int process_command_subs(o_string *dest, const char *s); +#endif + +/* expand_strvec_to_strvec() takes a list of strings, expands + * all variable references within and returns a pointer to + * a list of expanded strings, possibly with larger number + * of strings. (Think VAR="a b"; echo $VAR). + * This new list is allocated as a single malloc block. + * NULL-terminated list of char* pointers is at the beginning of it, + * followed by strings themselves. + * Caller can deallocate entire list by single free(list). */ - pin = 0; - while (pi) { - fprintf(stderr, "%*spipe %d res_word=%s followup=%d %s\n", lvl*2, "", - pin, RES[pi->res_word], pi->followup, PIPE[pi->followup]); - prn = 0; - while (prn < pi->num_cmds) { - struct command *command = &pi->cmds[prn]; - char **argv = command->argv; +/* A horde of its helpers come first: */ - fprintf(stderr, "%*s cmd %d assignment_cnt:%d", - lvl*2, "", prn, - command->assignment_cnt); - if (command->group) { - fprintf(stderr, " group %s: (argv=%p)%s%s\n", - CMDTYPE[command->cmd_type], - argv -# if !BB_MMU - , " group_as_string:", command->group_as_string -# else - , "", "" -# endif - ); - debug_print_tree(command->group, lvl+1); - prn++; - continue; - } - if (argv) while (*argv) { - fprintf(stderr, " '%s'", *argv); - argv++; +static void o_addblock_duplicate_backslash(o_string *o, const char *str, int len) +{ + while (--len >= 0) { + char c = *str++; + +#if ENABLE_HUSH_BRACE_EXPANSION + if (c == '{' || c == '}') { + /* { -> \{, } -> \} */ + o_addchr(o, '\\'); + /* And now we want to add { or } and continue: + * o_addchr(o, c); + * continue; + * luckily, just falling throught achieves this. + */ + } +#endif + o_addchr(o, c); + if (c == '\\') { + /* \z -> \\\z; \ -> \\ */ + o_addchr(o, '\\'); + if (len) { + len--; + o_addchr(o, '\\'); + o_addchr(o, *str++); } - fprintf(stderr, "\n"); - prn++; } - pi = pi->next; - pin++; } } -#endif /* debug_print_tree */ -/* NB: called by pseudo_exec, and therefore must not modify any - * global data until exec/_exit (we can be a child after vfork!) */ -static int run_list(struct pipe *pi) +/* Store given string, finalizing the word and starting new one whenever + * we encounter IFS char(s). This is used for expanding variable values. + * End-of-string does NOT finalize word: think about 'echo -$VAR-'. + * Return in *ended_with_ifs: + * 1 - ended with IFS char, else 0 (this includes case of empty str). + */ +static int expand_on_ifs(int *ended_with_ifs, o_string *output, int n, const char *str) { -#if ENABLE_HUSH_CASE - char *case_word = NULL; -#endif -#if ENABLE_HUSH_LOOPS - struct pipe *loop_top = NULL; - char **for_lcur = NULL; - char **for_list = NULL; -#endif - smallint last_followup; - smalluint rcode; -#if ENABLE_HUSH_IF || ENABLE_HUSH_CASE - smalluint cond_code = 0; -#else - enum { cond_code = 0 }; -#endif -#if HAS_KEYWORDS - smallint rword; /* enum reserved_style */ - smallint last_rword; /* ditto */ -#endif + int last_is_ifs = 0; - debug_printf_exec("run_list start lvl %d\n", G.run_list_level); - debug_enter(); + while (1) { + int word_len; -#if ENABLE_HUSH_LOOPS - /* Check syntax for "for" */ - for (struct pipe *cpipe = pi; cpipe; cpipe = cpipe->next) { - if (cpipe->res_word != RES_FOR && cpipe->res_word != RES_IN) - continue; - /* current word is FOR or IN (BOLD in comments below) */ - if (cpipe->next == NULL) { - syntax_error("malformed for"); - debug_leave(); - debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); - return 1; + if (!*str) /* EOL - do not finalize word */ + break; + word_len = strcspn(str, G.ifs); + if (word_len) { + /* We have WORD_LEN leading non-IFS chars */ + if (!(output->o_expflags & EXP_FLAG_GLOB)) { + o_addblock(output, str, word_len); + } else { + /* Protect backslashes against globbing up :) + * Example: "v='\*'; echo b$v" prints "b\*" + * (and does not try to glob on "*") + */ + o_addblock_duplicate_backslash(output, str, word_len); + /*/ Why can't we do it easier? */ + /*o_addblock(output, str, word_len); - WRONG: "v='\*'; echo Z$v" prints "Z*" instead of "Z\*" */ + /*o_addqblock(output, str, word_len); - WRONG: "v='*'; echo Z$v" prints "Z*" instead of Z* files */ + } + last_is_ifs = 0; + str += word_len; + if (!*str) /* EOL - do not finalize word */ + break; } - /* "FOR v; do ..." and "for v IN a b; do..." are ok */ - if (cpipe->next->res_word == RES_DO) - continue; - /* next word is not "do". It must be "in" then ("FOR v in ...") */ - if (cpipe->res_word == RES_IN /* "for v IN a b; not_do..."? */ - || cpipe->next->res_word != RES_IN /* FOR v not_do_and_not_in..."? */ + + /* We know str here points to at least one IFS char */ + last_is_ifs = 1; + str += strspn(str, G.ifs); /* skip IFS chars */ + if (!*str) /* EOL - do not finalize word */ + break; + + /* Start new word... but not always! */ + /* Case "v=' a'; echo ''$v": we do need to finalize empty word: */ + if (output->has_quoted_part + /* Case "v=' a'; echo $v": + * here nothing precedes the space in $v expansion, + * therefore we should not finish the word + * (IOW: if there *is* word to finalize, only then do it): + */ + || (n > 0 && output->data[output->length - 1]) ) { - syntax_error("malformed for"); - debug_leave(); - debug_printf_exec("run_list lvl %d return 1\n", G.run_list_level); - return 1; + o_addchr(output, '\0'); + debug_print_list("expand_on_ifs", output, n); + n = o_save_ptr(output, n); } } -#endif - /* Past this point, all code paths should jump to ret: label - * in order to return, no direct "return" statements please. - * This helps to ensure that no memory is leaked. */ + if (ended_with_ifs) + *ended_with_ifs = last_is_ifs; + debug_print_list("expand_on_ifs[1]", output, n); + return n; +} -#if ENABLE_HUSH_JOB - G.run_list_level++; +/* Helper to expand $((...)) and heredoc body. These act as if + * they are in double quotes, with the exception that they are not :). + * Just the rules are similar: "expand only $var and `cmd`" + * + * Returns malloced string. + * As an optimization, we return NULL if expansion is not needed. + */ +#if !ENABLE_HUSH_BASH_COMPAT +/* only ${var/pattern/repl} (its pattern part) needs additional mode */ +#define encode_then_expand_string(str, process_bkslash, do_unbackslash) \ + encode_then_expand_string(str) #endif +static char *encode_then_expand_string(const char *str, int process_bkslash, int do_unbackslash) +{ + char *exp_str; + struct in_str input; + o_string dest = NULL_O_STRING; -#if HAS_KEYWORDS - rword = RES_NONE; - last_rword = RES_XXXX; + if (!strchr(str, '$') + && !strchr(str, '\\') +#if ENABLE_HUSH_TICK + && !strchr(str, '`') #endif - last_followup = PIPE_SEQ; - rcode = G.last_exitcode; + ) { + return NULL; + } - /* Go through list of pipes, (maybe) executing them. */ - for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) { - if (G.flag_SIGINT) - break; + /* We need to expand. Example: + * echo $(($a + `echo 1`)) $((1 + $((2)) )) + */ + setup_string_in_str(&input, str); + encode_string(NULL, &dest, &input, EOF, process_bkslash); +//TODO: error check (encode_string returns 0 on error)? + //bb_error_msg("'%s' -> '%s'", str, dest.data); + exp_str = expand_string_to_string(dest.data, /*unbackslash:*/ do_unbackslash); + //bb_error_msg("'%s' -> '%s'", dest.data, exp_str); + o_free_unsafe(&dest); + return exp_str; +} - IF_HAS_KEYWORDS(rword = pi->res_word;) - debug_printf_exec(": rword=%d cond_code=%d last_rword=%d\n", - rword, cond_code, last_rword); -#if ENABLE_HUSH_LOOPS - if ((rword == RES_WHILE || rword == RES_UNTIL || rword == RES_FOR) - && loop_top == NULL /* avoid bumping G.depth_of_loop twice */ - ) { - /* start of a loop: remember where loop starts */ - loop_top = pi; - G.depth_of_loop++; - } +#if ENABLE_SH_MATH_SUPPORT +static arith_t expand_and_evaluate_arith(const char *arg, const char **errmsg_p) +{ + arith_state_t math_state; + arith_t res; + char *exp_str; + + math_state.lookupvar = get_local_var_value; + math_state.setvar = set_local_var_from_halves; + //math_state.endofname = endofname; + exp_str = encode_then_expand_string(arg, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); + res = arith(&math_state, exp_str ? exp_str : arg); + free(exp_str); + if (errmsg_p) + *errmsg_p = math_state.errmsg; + if (math_state.errmsg) + die_if_script(math_state.errmsg); + return res; +} #endif - /* Still in the same "if...", "then..." or "do..." branch? */ - if (IF_HAS_KEYWORDS(rword == last_rword &&) 1) { - if ((rcode == 0 && last_followup == PIPE_OR) - || (rcode != 0 && last_followup == PIPE_AND) - ) { - /* It is " || CMD" or " && CMD" - * and we should not execute CMD */ - debug_printf_exec("skipped cmd because of || or &&\n"); - last_followup = pi->followup; - continue; - } - } - last_followup = pi->followup; - IF_HAS_KEYWORDS(last_rword = rword;) -#if ENABLE_HUSH_IF - if (cond_code) { - if (rword == RES_THEN) { - /* if false; then ... fi has exitcode 0! */ - G.last_exitcode = rcode = EXIT_SUCCESS; - /* "if THEN cmd": skip cmd */ - continue; - } - } else { - if (rword == RES_ELSE || rword == RES_ELIF) { - /* "if then ... ELSE/ELIF cmd": - * skip cmd and all following ones */ - break; - } + +#if ENABLE_HUSH_BASH_COMPAT +/* ${var/[/]pattern[/repl]} helpers */ +static char *strstr_pattern(char *val, const char *pattern, int *size) +{ + while (1) { + char *end = scan_and_match(val, pattern, SCAN_MOVE_FROM_RIGHT + SCAN_MATCH_LEFT_HALF); + debug_printf_varexp("val:'%s' pattern:'%s' end:'%s'\n", val, pattern, end); + if (end) { + *size = end - val; + return val; } -#endif -#if ENABLE_HUSH_LOOPS - if (rword == RES_FOR) { /* && pi->num_cmds - always == 1 */ - if (!for_lcur) { - /* first loop through for */ + if (*val == '\0') + return NULL; + /* Optimization: if "*pat" did not match the start of "string", + * we know that "tring", "ring" etc will not match too: + */ + if (pattern[0] == '*') + return NULL; + val++; + } +} +static char *replace_pattern(char *val, const char *pattern, const char *repl, char exp_op) +{ + char *result = NULL; + unsigned res_len = 0; + unsigned repl_len = strlen(repl); - static const char encoded_dollar_at[] ALIGN1 = { - SPECIAL_VAR_SYMBOL, '@' | 0x80, SPECIAL_VAR_SYMBOL, '\0' - }; /* encoded representation of "$@" */ - static const char *const encoded_dollar_at_argv[] = { - encoded_dollar_at, NULL - }; /* argv list with one element: "$@" */ - char **vals; + while (1) { + int size; + char *s = strstr_pattern(val, pattern, &size); + if (!s) + break; - vals = (char**)encoded_dollar_at_argv; - if (pi->next->res_word == RES_IN) { - /* if no variable values after "in" we skip "for" */ - if (!pi->next->cmds[0].argv) { - G.last_exitcode = rcode = EXIT_SUCCESS; - debug_printf_exec(": null FOR: exitcode EXIT_SUCCESS\n"); - break; - } - vals = pi->next->cmds[0].argv; - } /* else: "for var; do..." -> assume "$@" list */ - /* create list of variable values */ - debug_print_strings("for_list made from", vals); - for_list = expand_strvec_to_strvec(vals); - for_lcur = for_list; - debug_print_strings("for_list", for_list); - } - if (!*for_lcur) { - /* "for" loop is over, clean up */ - free(for_list); - for_list = NULL; - for_lcur = NULL; - break; - } - /* Insert next value from for_lcur */ - /* note: *for_lcur already has quotes removed, $var expanded, etc */ - set_local_var(xasprintf("%s=%s", pi->cmds[0].argv[0], *for_lcur++), /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); - continue; - } - if (rword == RES_IN) { - continue; /* "for v IN list;..." - "in" has no cmds anyway */ - } - if (rword == RES_DONE) { - continue; /* "done" has no cmds too */ - } + result = xrealloc(result, res_len + (s - val) + repl_len + 1); + memcpy(result + res_len, val, s - val); + res_len += s - val; + strcpy(result + res_len, repl); + res_len += repl_len; + debug_printf_varexp("val:'%s' s:'%s' result:'%s'\n", val, s, result); + + val = s + size; + if (exp_op == '/') + break; + } + if (val[0] && result) { + result = xrealloc(result, res_len + strlen(val) + 1); + strcpy(result + res_len, val); + debug_printf_varexp("val:'%s' result:'%s'\n", val, result); + } + debug_printf_varexp("result:'%s'\n", result); + return result; +} #endif -#if ENABLE_HUSH_CASE - if (rword == RES_CASE) { - case_word = expand_strvec_to_string(pi->cmds->argv); - continue; - } - if (rword == RES_MATCH) { - char **argv; - if (!case_word) /* "case ... matched_word) ... WORD)": we executed selected branch, stop */ - break; - /* all prev words didn't match, does this one match? */ - argv = pi->cmds->argv; - while (*argv) { - char *pattern = expand_string_to_string(*argv); - /* TODO: which FNM_xxx flags to use? */ - cond_code = (fnmatch(pattern, case_word, /*flags:*/ 0) != 0); - free(pattern); - if (cond_code == 0) { /* match! we will execute this branch */ - free(case_word); /* make future "word)" stop */ - case_word = NULL; - break; +/* Helper: + * Handles varname... construct. + */ +static NOINLINE const char *expand_one_var(char **to_be_freed_pp, char *arg, char **pp) +{ + const char *val = NULL; + char *to_be_freed = NULL; + char *p = *pp; + char *var; + char first_char; + char exp_op; + char exp_save = exp_save; /* for compiler */ + char *exp_saveptr; /* points to expansion operator */ + char *exp_word = exp_word; /* for compiler */ + char arg0; + + *p = '\0'; /* replace trailing SPECIAL_VAR_SYMBOL */ + var = arg; + exp_saveptr = arg[1] ? strchr(VAR_ENCODED_SUBST_OPS, arg[1]) : NULL; + arg0 = arg[0]; + first_char = arg[0] = arg0 & 0x7f; + exp_op = 0; + + if (first_char == '#' /* ${#... */ + && arg[1] && !exp_saveptr /* not ${#} and not ${#...} */ + ) { + /* It must be length operator: ${#var} */ + var++; + exp_op = 'L'; + } else { + /* Maybe handle parameter expansion */ + if (exp_saveptr /* if 2nd char is one of expansion operators */ + && strchr(NUMERIC_SPECVARS_STR, first_char) /* 1st char is special variable */ + ) { + /* ${?:0}, ${#[:]%0} etc */ + exp_saveptr = var + 1; + } else { + /* ${?}, ${var}, ${var:0}, ${var[:]%0} etc */ + exp_saveptr = var+1 + strcspn(var+1, VAR_ENCODED_SUBST_OPS); + } + exp_op = exp_save = *exp_saveptr; + if (exp_op) { + exp_word = exp_saveptr + 1; + if (exp_op == ':') { + exp_op = *exp_word++; +//TODO: try ${var:} and ${var:bogus} in non-bash config + if (ENABLE_HUSH_BASH_COMPAT + && (!exp_op || !strchr(MINUS_PLUS_EQUAL_QUESTION, exp_op)) + ) { + /* oops... it's ${var:N[:M]}, not ${var:?xxx} or some such */ + exp_op = ':'; + exp_word--; + } + } + *exp_saveptr = '\0'; + } /* else: it's not an expansion op, but bare ${var} */ + } + + /* Look up the variable in question */ + if (isdigit(var[0])) { + /* parse_dollar should have vetted var for us */ + int n = xatoi_positive(var); + if (n < G.global_argc) + val = G.global_argv[n]; + /* else val remains NULL: $N with too big N */ + } else { + switch (var[0]) { + case '$': /* pid */ + val = utoa(G.root_pid); + break; + case '!': /* bg pid */ + val = G.last_bg_pid ? utoa(G.last_bg_pid) : ""; + break; + case '?': /* exitcode */ + val = utoa(G.last_exitcode); + break; + case '#': /* argc */ + val = utoa(G.global_argc ? G.global_argc-1 : 0); + break; + default: + val = get_local_var_value(var); + } + } + + /* Handle any expansions */ + if (exp_op == 'L') { + debug_printf_expand("expand: length(%s)=", val); + val = utoa(val ? strlen(val) : 0); + debug_printf_expand("%s\n", val); + } else if (exp_op) { + if (exp_op == '%' || exp_op == '#') { + /* Standard-mandated substring removal ops: + * ${parameter%word} - remove smallest suffix pattern + * ${parameter%%word} - remove largest suffix pattern + * ${parameter#word} - remove smallest prefix pattern + * ${parameter##word} - remove largest prefix pattern + * + * Word is expanded to produce a glob pattern. + * Then var's value is matched to it and matching part removed. + */ + if (val && val[0]) { + char *t; + char *exp_exp_word; + char *loc; + unsigned scan_flags = pick_scan(exp_op, *exp_word); + if (exp_op == *exp_word) /* ## or %% */ + exp_word++; + exp_exp_word = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); + if (exp_exp_word) + exp_word = exp_exp_word; + /* HACK ALERT. We depend here on the fact that + * G.global_argv and results of utoa and get_local_var_value + * are actually in writable memory: + * scan_and_match momentarily stores NULs there. */ + t = (char*)val; + loc = scan_and_match(t, exp_word, scan_flags); + //bb_error_msg("op:%c str:'%s' pat:'%s' res:'%s'", + // exp_op, t, exp_word, loc); + free(exp_exp_word); + if (loc) { /* match was found */ + if (scan_flags & SCAN_MATCH_LEFT_HALF) /* #[#] */ + val = loc; /* take right part */ + else /* %[%] */ + val = to_be_freed = xstrndup(val, loc - val); /* left */ } - argv++; } - continue; - } - if (rword == RES_CASE_BODY) { /* inside of a case branch */ - if (cond_code != 0) - continue; /* not matched yet, skip this pipe */ } -#endif - /* Just pressing in shell should check for jobs. - * OTOH, in non-interactive shell this is useless - * and only leads to extra job checks */ - if (pi->num_cmds == 0) { - if (G_interactive_fd) - goto check_jobs_and_continue; - continue; +#if ENABLE_HUSH_BASH_COMPAT + else if (exp_op == '/' || exp_op == '\\') { + /* It's ${var/[/]pattern[/repl]} thing. + * Note that in encoded form it has TWO parts: + * var/patternrepl + * and if // is used, it is encoded as \: + * var\patternrepl + */ + /* Empty variable always gives nothing: */ + // "v=''; echo ${v/*/w}" prints "", not "w" + if (val && val[0]) { + /* pattern uses non-standard expansion. + * repl should be unbackslashed and globbed + * by the usual expansion rules: + * >az; >bz; + * v='a bz'; echo "${v/a*z/a*z}" prints "a*z" + * v='a bz'; echo "${v/a*z/\z}" prints "\z" + * v='a bz'; echo ${v/a*z/a*z} prints "az" + * v='a bz'; echo ${v/a*z/\z} prints "z" + * (note that a*z _pattern_ is never globbed!) + */ + char *pattern, *repl, *t; + pattern = encode_then_expand_string(exp_word, /*process_bkslash:*/ 0, /*unbackslash:*/ 0); + if (!pattern) + pattern = xstrdup(exp_word); + debug_printf_varexp("pattern:'%s'->'%s'\n", exp_word, pattern); + *p++ = SPECIAL_VAR_SYMBOL; + exp_word = p; + p = strchr(p, SPECIAL_VAR_SYMBOL); + *p = '\0'; + repl = encode_then_expand_string(exp_word, /*process_bkslash:*/ arg0 & 0x80, /*unbackslash:*/ 1); + debug_printf_varexp("repl:'%s'->'%s'\n", exp_word, repl); + /* HACK ALERT. We depend here on the fact that + * G.global_argv and results of utoa and get_local_var_value + * are actually in writable memory: + * replace_pattern momentarily stores NULs there. */ + t = (char*)val; + to_be_freed = replace_pattern(t, + pattern, + (repl ? repl : exp_word), + exp_op); + if (to_be_freed) /* at least one replace happened */ + val = to_be_freed; + free(pattern); + free(repl); + } } - - /* After analyzing all keywords and conditions, we decided - * to execute this pipe. NB: have to do checkjobs(NULL) - * after run_pipe to collect any background children, - * even if list execution is to be stopped. */ - debug_printf_exec(": run_pipe with %d members\n", pi->num_cmds); - { - int r; -#if ENABLE_HUSH_LOOPS - G.flag_break_continue = 0; #endif - rcode = r = run_pipe(pi); /* NB: rcode is a smallint */ - if (r != -1) { - /* We ran a builtin, function, or group. - * rcode is already known - * and we don't need to wait for anything. */ - G.last_exitcode = rcode; - debug_printf_exec(": builtin/func exitcode %d\n", rcode); - check_and_run_traps(0); -#if ENABLE_HUSH_LOOPS - /* Was it "break" or "continue"? */ - if (G.flag_break_continue) { - smallint fbc = G.flag_break_continue; - /* We might fall into outer *loop*, - * don't want to break it too */ - if (loop_top) { - G.depth_break_continue--; - if (G.depth_break_continue == 0) - G.flag_break_continue = 0; - /* else: e.g. "continue 2" should *break* once, *then* continue */ - } /* else: "while... do... { we are here (innermost list is not a loop!) };...done" */ - if (G.depth_break_continue != 0 || fbc == BC_BREAK) - goto check_jobs_and_break; - /* "continue": simulate end of loop */ - rword = RES_DONE; - continue; + else if (exp_op == ':') { +#if ENABLE_HUSH_BASH_COMPAT && ENABLE_SH_MATH_SUPPORT + /* It's ${var:N[:M]} bashism. + * Note that in encoded form it has TWO parts: + * var:NM + */ + arith_t beg, len; + const char *errmsg; + + beg = expand_and_evaluate_arith(exp_word, &errmsg); + if (errmsg) + goto arith_err; + debug_printf_varexp("beg:'%s'=%lld\n", exp_word, (long long)beg); + *p++ = SPECIAL_VAR_SYMBOL; + exp_word = p; + p = strchr(p, SPECIAL_VAR_SYMBOL); + *p = '\0'; + len = expand_and_evaluate_arith(exp_word, &errmsg); + if (errmsg) + goto arith_err; + debug_printf_varexp("len:'%s'=%lld\n", exp_word, (long long)len); + if (len >= 0) { /* bash compat: len < 0 is illegal */ + if (beg < 0) /* bash compat */ + beg = 0; + debug_printf_varexp("from val:'%s'\n", val); + if (len == 0 || !val || beg >= strlen(val)) { + arith_err: + val = NULL; + } else { + /* Paranoia. What if user entered 9999999999999 + * which fits in arith_t but not int? */ + if (len >= INT_MAX) + len = INT_MAX; + val = to_be_freed = xstrndup(val + beg, len); } + debug_printf_varexp("val:'%s'\n", val); + } else #endif -#if ENABLE_HUSH_FUNCTIONS - if (G.flag_return_in_progress == 1) { - /* same as "goto check_jobs_and_break" */ - checkjobs(NULL); - break; + { + die_if_script("malformed ${%s:...}", var); + val = NULL; + } + } else { /* one of "-=+?" */ + /* Standard-mandated substitution ops: + * ${var?word} - indicate error if unset + * If var is unset, word (or a message indicating it is unset + * if word is null) is written to standard error + * and the shell exits with a non-zero exit status. + * Otherwise, the value of var is substituted. + * ${var-word} - use default value + * If var is unset, word is substituted. + * ${var=word} - assign and use default value + * If var is unset, word is assigned to var. + * In all cases, final value of var is substituted. + * ${var+word} - use alternative value + * If var is unset, null is substituted. + * Otherwise, word is substituted. + * + * Word is subjected to tilde expansion, parameter expansion, + * command substitution, and arithmetic expansion. + * If word is not needed, it is not expanded. + * + * Colon forms (${var:-word}, ${var:=word} etc) do the same, + * but also treat null var as if it is unset. + */ + int use_word = (!val || ((exp_save == ':') && !val[0])); + if (exp_op == '+') + use_word = !use_word; + debug_printf_expand("expand: op:%c (null:%s) test:%i\n", exp_op, + (exp_save == ':') ? "true" : "false", use_word); + if (use_word) { + to_be_freed = encode_then_expand_string(exp_word, /*process_bkslash:*/ 1, /*unbackslash:*/ 1); + if (to_be_freed) + exp_word = to_be_freed; + if (exp_op == '?') { + /* mimic bash message */ + die_if_script("%s: %s", + var, + exp_word[0] ? exp_word : "parameter null or not set" + ); +//TODO: how interactive bash aborts expansion mid-command? + } else { + val = exp_word; } -#endif - } else if (pi->followup == PIPE_BG) { - /* What does bash do with attempts to background builtins? */ - /* even bash 3.2 doesn't do that well with nested bg: - * try "{ { sleep 10; echo DEEP; } & echo HERE; } &". - * I'm NOT treating inner &'s as jobs */ - check_and_run_traps(0); -#if ENABLE_HUSH_JOB - if (G.run_list_level == 1) - insert_bg_job(pi); -#endif - G.last_exitcode = rcode = EXIT_SUCCESS; - debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n"); - } else { -#if ENABLE_HUSH_JOB - if (G.run_list_level == 1 && G_interactive_fd) { - /* Waits for completion, then fg's main shell */ - rcode = checkjobs_and_fg_shell(pi); - debug_printf_exec(": checkjobs_and_fg_shell exitcode %d\n", rcode); - check_and_run_traps(0); - } else -#endif - { /* This one just waits for completion */ - rcode = checkjobs(pi); - debug_printf_exec(": checkjobs exitcode %d\n", rcode); - check_and_run_traps(0); + + if (exp_op == '=') { + /* ${var=[word]} or ${var:=[word]} */ + if (isdigit(var[0]) || var[0] == '#') { + /* mimic bash message */ + die_if_script("$%s: cannot assign in this way", var); + val = NULL; + } else { + char *new_var = xasprintf("%s=%s", var, val); + set_local_var(new_var, /*exp:*/ 0, /*lvl:*/ 0, /*ro:*/ 0); + } } - G.last_exitcode = rcode; } - } + } /* one of "-=+?" */ - /* Analyze how result affects subsequent commands */ -#if ENABLE_HUSH_IF - if (rword == RES_IF || rword == RES_ELIF) - cond_code = rcode; + *exp_saveptr = exp_save; + } /* if (exp_op) */ + + arg[0] = arg0; + + *pp = p; + *to_be_freed_pp = to_be_freed; + return val; +} + +/* Expand all variable references in given string, adding words to list[] + * at n, n+1,... positions. Return updated n (so that list[n] is next one + * to be filled). This routine is extremely tricky: has to deal with + * variables/parameters with whitespace, $* and $@, and constructs like + * 'echo -$*-'. If you play here, you must run testsuite afterwards! */ +static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) +{ + /* output->o_expflags & EXP_FLAG_SINGLEWORD (0x80) if we are in + * expansion of right-hand side of assignment == 1-element expand. + */ + char cant_be_null = 0; /* only bit 0x80 matters */ + int ended_in_ifs = 0; /* did last unquoted expansion end with IFS chars? */ + char *p; + + debug_printf_expand("expand_vars_to_list: arg:'%s' singleword:%x\n", arg, + !!(output->o_expflags & EXP_FLAG_SINGLEWORD)); + debug_print_list("expand_vars_to_list", output, n); + n = o_save_ptr(output, n); + debug_print_list("expand_vars_to_list[0]", output, n); + + while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) { + char first_ch; + char *to_be_freed = NULL; + const char *val = NULL; +#if ENABLE_HUSH_TICK + o_string subst_result = NULL_O_STRING; #endif -#if ENABLE_HUSH_LOOPS - /* Beware of "while false; true; do ..."! */ - if (pi->next && pi->next->res_word == RES_DO) { - if (rword == RES_WHILE) { - if (rcode) { - /* "while false; do...done" - exitcode 0 */ - G.last_exitcode = rcode = EXIT_SUCCESS; - debug_printf_exec(": while expr is false: breaking (exitcode:EXIT_SUCCESS)\n"); - goto check_jobs_and_break; +#if ENABLE_SH_MATH_SUPPORT + char arith_buf[sizeof(arith_t)*3 + 2]; +#endif + + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + ended_in_ifs = 0; + } + + o_addblock(output, arg, p - arg); + debug_print_list("expand_vars_to_list[1]", output, n); + arg = ++p; + p = strchr(p, SPECIAL_VAR_SYMBOL); + + /* Fetch special var name (if it is indeed one of them) + * and quote bit, force the bit on if singleword expansion - + * important for not getting v=$@ expand to many words. */ + first_ch = arg[0] | (output->o_expflags & EXP_FLAG_SINGLEWORD); + + /* Is this variable quoted and thus expansion can't be null? + * "$@" is special. Even if quoted, it can still + * expand to nothing (not even an empty string), + * thus it is excluded. */ + if ((first_ch & 0x7f) != '@') + cant_be_null |= first_ch; + + switch (first_ch & 0x7f) { + /* Highest bit in first_ch indicates that var is double-quoted */ + case '*': + case '@': { + int i; + if (!G.global_argv[1]) + break; + i = 1; + cant_be_null |= first_ch; /* do it for "$@" _now_, when we know it's not empty */ + if (!(first_ch & 0x80)) { /* unquoted $* or $@ */ + while (G.global_argv[i]) { + n = expand_on_ifs(NULL, output, n, G.global_argv[i]); + debug_printf_expand("expand_vars_to_list: argv %d (last %d)\n", i, G.global_argc - 1); + if (G.global_argv[i++][0] && G.global_argv[i]) { + /* this argv[] is not empty and not last: + * put terminating NUL, start new word */ + o_addchr(output, '\0'); + debug_print_list("expand_vars_to_list[2]", output, n); + n = o_save_ptr(output, n); + debug_print_list("expand_vars_to_list[3]", output, n); + } } - } - if (rword == RES_UNTIL) { - if (!rcode) { - debug_printf_exec(": until expr is true: breaking\n"); - check_jobs_and_break: - checkjobs(NULL); - break; + } else + /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....' + * and in this case should treat it like '$*' - see 'else...' below */ + if (first_ch == ('@'|0x80) /* quoted $@ */ + && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */ + ) { + while (1) { + o_addQstr(output, G.global_argv[i]); + if (++i >= G.global_argc) + break; + o_addchr(output, '\0'); + debug_print_list("expand_vars_to_list[4]", output, n); + n = o_save_ptr(output, n); + } + } else { /* quoted $* (or v="$@" case): add as one word */ + while (1) { + o_addQstr(output, G.global_argv[i]); + if (!G.global_argv[++i]) + break; + if (G.ifs[0]) + o_addchr(output, G.ifs[0]); } + output->has_quoted_part = 1; } + break; } + case SPECIAL_VAR_SYMBOL: /* */ + /* "Empty variable", used to make "" etc to not disappear */ + output->has_quoted_part = 1; + arg++; + cant_be_null = 0x80; + break; +#if ENABLE_HUSH_TICK + case '`': /* `cmd */ + *p = '\0'; /* replace trailing */ + arg++; + /* Can't just stuff it into output o_string, + * expanded result may need to be globbed + * and $IFS-splitted */ + debug_printf_subst("SUBST '%s' first_ch %x\n", arg, first_ch); + G.last_exitcode = process_command_subs(&subst_result, arg); + debug_printf_subst("SUBST RES:%d '%s'\n", G.last_exitcode, subst_result.data); + val = subst_result.data; + goto store_val; #endif +#if ENABLE_SH_MATH_SUPPORT + case '+': { /* +cmd */ + arith_t res; - check_jobs_and_continue: - checkjobs(NULL); - } /* for (pi) */ - -#if ENABLE_HUSH_JOB - G.run_list_level--; -#endif -#if ENABLE_HUSH_LOOPS - if (loop_top) - G.depth_of_loop--; - free(for_list); + arg++; /* skip '+' */ + *p = '\0'; /* replace trailing */ + debug_printf_subst("ARITH '%s' first_ch %x\n", arg, first_ch); + res = expand_and_evaluate_arith(arg, NULL); + debug_printf_subst("ARITH RES '"ARITH_FMT"'\n", res); + sprintf(arith_buf, ARITH_FMT, res); + val = arith_buf; + break; + } #endif -#if ENABLE_HUSH_CASE - free(case_word); + default: + val = expand_one_var(&to_be_freed, arg, &p); + IF_HUSH_TICK(store_val:) + if (!(first_ch & 0x80)) { /* unquoted $VAR */ + debug_printf_expand("unquoted '%s', output->o_escape:%d\n", val, + !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); + if (val && val[0]) { + n = expand_on_ifs(&ended_in_ifs, output, n, val); + val = NULL; + } + } else { /* quoted $VAR, val will be appended below */ + output->has_quoted_part = 1; + debug_printf_expand("quoted '%s', output->o_escape:%d\n", val, + !!(output->o_expflags & EXP_FLAG_ESC_GLOB_CHARS)); + } + break; + + } /* switch (char after ) */ + + if (val && val[0]) { + o_addQstr(output, val); + } + free(to_be_freed); + + /* Restore NULL'ed SPECIAL_VAR_SYMBOL. + * Do the check to avoid writing to a const string. */ + if (*p != SPECIAL_VAR_SYMBOL) + *p = SPECIAL_VAR_SYMBOL; + +#if ENABLE_HUSH_TICK + o_free(&subst_result); #endif - debug_leave(); - debug_printf_exec("run_list lvl %d return %d\n", G.run_list_level + 1, rcode); - return rcode; + arg = ++p; + } /* end of "while (SPECIAL_VAR_SYMBOL is found) ..." */ + + if (arg[0]) { + if (ended_in_ifs) { + o_addchr(output, '\0'); + n = o_save_ptr(output, n); + } + debug_print_list("expand_vars_to_list[a]", output, n); + /* this part is literal, and it was already pre-quoted + * if needed (much earlier), do not use o_addQstr here! */ + o_addstr_with_NUL(output, arg); + debug_print_list("expand_vars_to_list[b]", output, n); + } else if (output->length == o_get_last_ptr(output, n) /* expansion is empty */ + && !(cant_be_null & 0x80) /* and all vars were not quoted. */ + ) { + n--; + /* allow to reuse list[n] later without re-growth */ + output->has_empty_slot = 1; + } else { + o_addchr(output, '\0'); + } + + return n; } -/* Select which version we will use */ -static int run_and_free_list(struct pipe *pi) +static char **expand_variables(char **argv, unsigned expflags) { - int rcode = 0; - debug_printf_exec("run_and_free_list entered\n"); - if (!G.fake_mode) { - debug_printf_exec(": run_list: 1st pipe with %d cmds\n", pi->num_cmds); - rcode = run_list(pi); + int n; + char **list; + o_string output = NULL_O_STRING; + + output.o_expflags = expflags; + + n = 0; + while (*argv) { + n = expand_vars_to_list(&output, n, *argv); + argv++; } - /* free_pipe_list has the side effect of clearing memory. - * In the long run that function can be merged with run_list, - * but doing that now would hobble the debugging effort. */ - free_pipe_list(pi); - debug_printf_exec("run_and_free_list return %d\n", rcode); - return rcode; + debug_print_list("expand_variables", &output, n); + + /* output.data (malloced in one block) gets returned in "list" */ + list = o_finalize_list(&output, n); + debug_print_strings("expand_variables[1]", list); + return list; } +static char **expand_strvec_to_strvec(char **argv) +{ + return expand_variables(argv, EXP_FLAG_GLOB | EXP_FLAG_ESC_GLOB_CHARS); +} -static struct pipe *new_pipe(void) +#if ENABLE_HUSH_BASH_COMPAT +static char **expand_strvec_to_strvec_singleword_noglob(char **argv) { - struct pipe *pi; - pi = xzalloc(sizeof(struct pipe)); - /*pi->followup = 0; - deliberately invalid value */ - /*pi->res_word = RES_NONE; - RES_NONE is 0 anyway */ - return pi; + return expand_variables(argv, EXP_FLAG_SINGLEWORD); } +#endif -/* Command (member of a pipe) is complete, or we start a new pipe - * if ctx->command is NULL. - * No errors possible here. +/* Used for expansion of right hand of assignments, + * $((...)), heredocs, variable espansion parts. + * + * NB: should NOT do globbing! + * "export v=/bin/c*; env | grep ^v=" outputs "v=/bin/c*" */ -static int done_command(struct parse_context *ctx) +static char *expand_string_to_string(const char *str, int do_unbackslash) { - /* The command is really already in the pipe structure, so - * advance the pipe counter and make a new, null command. */ - struct pipe *pi = ctx->pipe; - struct command *command = ctx->command; +#if !ENABLE_HUSH_BASH_COMPAT + const int do_unbackslash = 1; +#endif + char *argv[2], **list; - if (command) { - if (IS_NULL_CMD(command)) { - debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds); - goto clear_and_ret; - } - pi->num_cmds++; - debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds); - //debug_print_tree(ctx->list_head, 20); - } else { - debug_printf_parse("done_command: initializing, num_cmds=%d\n", pi->num_cmds); + debug_printf_expand("string_to_string<='%s'\n", str); + /* This is generally an optimization, but it also + * handles "", which otherwise trips over !list[0] check below. + * (is this ever happens that we actually get str="" here?) + */ + if (!strchr(str, SPECIAL_VAR_SYMBOL) && !strchr(str, '\\')) { + //TODO: Can use on strings with \ too, just unbackslash() them? + debug_printf_expand("string_to_string(fast)=>'%s'\n", str); + return xstrdup(str); } - /* Only real trickiness here is that the uncommitted - * command structure is not counted in pi->num_cmds. */ - pi->cmds = xrealloc(pi->cmds, sizeof(*pi->cmds) * (pi->num_cmds+1)); - ctx->command = command = &pi->cmds[pi->num_cmds]; - clear_and_ret: - memset(command, 0, sizeof(*command)); - return pi->num_cmds; /* used only for 0/nonzero check */ + argv[0] = (char*)str; + argv[1] = NULL; + list = expand_variables(argv, do_unbackslash + ? EXP_FLAG_ESC_GLOB_CHARS | EXP_FLAG_SINGLEWORD + : EXP_FLAG_SINGLEWORD + ); + if (HUSH_DEBUG) + if (!list[0] || list[1]) + bb_error_msg_and_die("BUG in varexp2"); + /* actually, just move string 2*sizeof(char*) bytes back */ + overlapping_strcpy((char*)list, list[0]); + if (do_unbackslash) + unbackslash((char*)list); + debug_printf_expand("string_to_string=>'%s'\n", (char*)list); + return (char*)list; } -static void done_pipe(struct parse_context *ctx, pipe_style type) +/* Used for "eval" builtin */ +static char* expand_strvec_to_string(char **argv) { - int not_null; + char **list; - debug_printf_parse("done_pipe entered, followup %d\n", type); - /* Close previous command */ - not_null = done_command(ctx); - ctx->pipe->followup = type; -#if HAS_KEYWORDS - ctx->pipe->pi_inverted = ctx->ctx_inverted; - ctx->ctx_inverted = 0; - ctx->pipe->res_word = ctx->ctx_res_w; -#endif + list = expand_variables(argv, EXP_FLAG_SINGLEWORD); + /* Convert all NULs to spaces */ + if (list[0]) { + int n = 1; + while (list[n]) { + if (HUSH_DEBUG) + if (list[n-1] + strlen(list[n-1]) + 1 != list[n]) + bb_error_msg_and_die("BUG in varexp3"); + /* bash uses ' ' regardless of $IFS contents */ + list[n][-1] = ' '; + n++; + } + } + overlapping_strcpy((char*)list, list[0]); + debug_printf_expand("strvec_to_string='%s'\n", (char*)list); + return (char*)list; +} - /* Without this check, even just on command line generates - * tree of three NOPs (!). Which is harmless but annoying. - * IOW: it is safe to do it unconditionally. */ - if (not_null -#if ENABLE_HUSH_IF - || ctx->ctx_res_w == RES_FI -#endif -#if ENABLE_HUSH_LOOPS - || ctx->ctx_res_w == RES_DONE - || ctx->ctx_res_w == RES_FOR - || ctx->ctx_res_w == RES_IN -#endif -#if ENABLE_HUSH_CASE - || ctx->ctx_res_w == RES_ESAC -#endif - ) { - struct pipe *new_p; - debug_printf_parse("done_pipe: adding new pipe: " - "not_null:%d ctx->ctx_res_w:%d\n", - not_null, ctx->ctx_res_w); - new_p = new_pipe(); - ctx->pipe->next = new_p; - ctx->pipe = new_p; - /* RES_THEN, RES_DO etc are "sticky" - - * they remain set for pipes inside if/while. - * This is used to control execution. - * RES_FOR and RES_IN are NOT sticky (needed to support - * cases where variable or value happens to match a keyword): - */ -#if ENABLE_HUSH_LOOPS - if (ctx->ctx_res_w == RES_FOR - || ctx->ctx_res_w == RES_IN) - ctx->ctx_res_w = RES_NONE; -#endif -#if ENABLE_HUSH_CASE - if (ctx->ctx_res_w == RES_MATCH) - ctx->ctx_res_w = RES_CASE_BODY; - if (ctx->ctx_res_w == RES_CASE) - ctx->ctx_res_w = RES_CASE_IN; -#endif - ctx->command = NULL; /* trick done_command below */ - /* Create the memory for command, roughly: - * ctx->pipe->cmds = new struct command; - * ctx->command = &ctx->pipe->cmds[0]; - */ - done_command(ctx); - //debug_print_tree(ctx->list_head, 10); +static char **expand_assignments(char **argv, int count) +{ + int i; + char **p; + + G.expanded_assignments = p = NULL; + /* Expand assignments into one string each */ + for (i = 0; i < count; i++) { + G.expanded_assignments = p = add_string_to_strings(p, expand_string_to_string(argv[i], /*unbackslash:*/ 1)); } - debug_printf_parse("done_pipe return\n"); + G.expanded_assignments = NULL; + return p; } -static void initialize_context(struct parse_context *ctx) + +static void switch_off_special_sigs(unsigned mask) { - memset(ctx, 0, sizeof(*ctx)); - ctx->pipe = ctx->list_head = new_pipe(); - /* Create the memory for command, roughly: - * ctx->pipe->cmds = new struct command; - * ctx->command = &ctx->pipe->cmds[0]; - */ - done_command(ctx); + unsigned sig = 0; + while ((mask >>= 1) != 0) { + sig++; + if (!(mask & 1)) + continue; + if (G.traps) { + if (G.traps[sig] && !G.traps[sig][0]) + /* trap is '', has to remain SIG_IGN */ + continue; + free(G.traps[sig]); + G.traps[sig] = NULL; + } + /* We are here only if no trap or trap was not '' */ + install_sighandler(sig, SIG_DFL); + } } -/* If a reserved word is found and processed, parse context is modified - * and 1 is returned. - */ -#if HAS_KEYWORDS -struct reserved_combo { - char literal[6]; - unsigned char res; - unsigned char assignment_flag; - int flag; -}; -enum { - FLAG_END = (1 << RES_NONE ), -# if ENABLE_HUSH_IF - FLAG_IF = (1 << RES_IF ), - FLAG_THEN = (1 << RES_THEN ), - FLAG_ELIF = (1 << RES_ELIF ), - FLAG_ELSE = (1 << RES_ELSE ), - FLAG_FI = (1 << RES_FI ), -# endif -# if ENABLE_HUSH_LOOPS - FLAG_FOR = (1 << RES_FOR ), - FLAG_WHILE = (1 << RES_WHILE), - FLAG_UNTIL = (1 << RES_UNTIL), - FLAG_DO = (1 << RES_DO ), - FLAG_DONE = (1 << RES_DONE ), - FLAG_IN = (1 << RES_IN ), -# endif -# if ENABLE_HUSH_CASE - FLAG_MATCH = (1 << RES_MATCH), - FLAG_ESAC = (1 << RES_ESAC ), -# endif - FLAG_START = (1 << RES_XXXX ), -}; +#if BB_MMU +/* never called */ +void re_execute_shell(char ***to_free, const char *s, + char *g_argv0, char **g_argv, + char **builtin_argv) NORETURN; -static const struct reserved_combo* match_reserved_word(o_string *word) +static void reset_traps_to_defaults(void) { - /* Mostly a list of accepted follow-up reserved words. - * FLAG_END means we are done with the sequence, and are ready - * to turn the compound list into a command. - * FLAG_START means the word must start a new compound list. + /* This function is always called in a child shell + * after fork (not vfork, NOMMU doesn't use this function). + */ + unsigned sig; + unsigned mask; + + /* Child shells are not interactive. + * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling. + * Testcase: (while :; do :; done) + ^Z should background. + * Same goes for SIGTERM, SIGHUP, SIGINT. */ - static const struct reserved_combo reserved_list[] = { -# if ENABLE_HUSH_IF - { "!", RES_NONE, NOT_ASSIGNMENT , 0 }, - { "if", RES_IF, WORD_IS_KEYWORD, FLAG_THEN | FLAG_START }, - { "then", RES_THEN, WORD_IS_KEYWORD, FLAG_ELIF | FLAG_ELSE | FLAG_FI }, - { "elif", RES_ELIF, WORD_IS_KEYWORD, FLAG_THEN }, - { "else", RES_ELSE, WORD_IS_KEYWORD, FLAG_FI }, - { "fi", RES_FI, NOT_ASSIGNMENT , FLAG_END }, -# endif -# if ENABLE_HUSH_LOOPS - { "for", RES_FOR, NOT_ASSIGNMENT , FLAG_IN | FLAG_DO | FLAG_START }, - { "while", RES_WHILE, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, - { "until", RES_UNTIL, WORD_IS_KEYWORD, FLAG_DO | FLAG_START }, - { "in", RES_IN, NOT_ASSIGNMENT , FLAG_DO }, - { "do", RES_DO, WORD_IS_KEYWORD, FLAG_DONE }, - { "done", RES_DONE, NOT_ASSIGNMENT , FLAG_END }, -# endif -# if ENABLE_HUSH_CASE - { "case", RES_CASE, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_START }, - { "esac", RES_ESAC, NOT_ASSIGNMENT , FLAG_END }, -# endif - }; - const struct reserved_combo *r; + mask = (G.special_sig_mask & SPECIAL_INTERACTIVE_SIGS) | G_fatal_sig_mask; + if (!G.traps && !mask) + return; /* already no traps and no special sigs */ - for (r = reserved_list; r < reserved_list + ARRAY_SIZE(reserved_list); r++) { - if (strcmp(word->data, r->literal) == 0) - return r; + /* Switch off special sigs */ + switch_off_special_sigs(mask); +#if ENABLE_HUSH_JOB + G_fatal_sig_mask = 0; +#endif + G.special_sig_mask &= ~SPECIAL_INTERACTIVE_SIGS; + /* SIGQUIT,SIGCHLD and maybe SPECIAL_JOBSTOP_SIGS + * remain set in G.special_sig_mask */ + + if (!G.traps) + return; + + /* Reset all sigs to default except ones with empty traps */ + for (sig = 0; sig < NSIG; sig++) { + if (!G.traps[sig]) + continue; /* no trap: nothing to do */ + if (!G.traps[sig][0]) + continue; /* empty trap: has to remain SIG_IGN */ + /* sig has non-empty trap, reset it: */ + free(G.traps[sig]); + G.traps[sig] = NULL; + /* There is no signal for trap 0 (EXIT) */ + if (sig == 0) + continue; + install_sighandler(sig, pick_sighandler(sig)); } - return NULL; } -/* Return 0: not a keyword, 1: keyword - */ -static int reserved_word(o_string *word, struct parse_context *ctx) + +#else /* !BB_MMU */ + +static void re_execute_shell(char ***to_free, const char *s, + char *g_argv0, char **g_argv, + char **builtin_argv) NORETURN; +static void re_execute_shell(char ***to_free, const char *s, + char *g_argv0, char **g_argv, + char **builtin_argv) { -# if ENABLE_HUSH_CASE - static const struct reserved_combo reserved_match = { - "", RES_MATCH, NOT_ASSIGNMENT , FLAG_MATCH | FLAG_ESAC - }; +# define NOMMU_HACK_FMT ("-$%x:%x:%x:%x:%x:%llx" IF_HUSH_LOOPS(":%x")) + /* delims + 2 * (number of bytes in printed hex numbers) */ + char param_buf[sizeof(NOMMU_HACK_FMT) + 2 * (sizeof(int)*6 + sizeof(long long)*1)]; + char *heredoc_argv[4]; + struct variable *cur; +# if ENABLE_HUSH_FUNCTIONS + struct function *funcp; # endif - const struct reserved_combo *r; + char **argv, **pp; + unsigned cnt; + unsigned long long empty_trap_mask; - if (word->o_quoted) - return 0; - r = match_reserved_word(word); - if (!r) - return 0; + if (!g_argv0) { /* heredoc */ + argv = heredoc_argv; + argv[0] = (char *) G.argv0_for_re_execing; + argv[1] = (char *) "-<"; + argv[2] = (char *) s; + argv[3] = NULL; + pp = &argv[3]; /* used as pointer to empty environment */ + goto do_exec; + } - debug_printf("found reserved word %s, res %d\n", r->literal, r->res); -# if ENABLE_HUSH_CASE - if (r->res == RES_IN && ctx->ctx_res_w == RES_CASE_IN) { - /* "case word IN ..." - IN part starts first MATCH part */ - r = &reserved_match; - } else -# endif - if (r->flag == 0) { /* '!' */ - if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */ - syntax_error("! ! command"); - ctx->ctx_res_w = RES_SNTX; + cnt = 0; + pp = builtin_argv; + if (pp) while (*pp++) + cnt++; + + empty_trap_mask = 0; + if (G.traps) { + int sig; + for (sig = 1; sig < NSIG; sig++) { + if (G.traps[sig] && !G.traps[sig][0]) + empty_trap_mask |= 1LL << sig; } - ctx->ctx_inverted = 1; - return 1; } - if (r->flag & FLAG_START) { - struct parse_context *old; - old = xmalloc(sizeof(*old)); - debug_printf_parse("push stack %p\n", old); - *old = *ctx; /* physical copy */ - initialize_context(ctx); - ctx->stack = old; - } else if (/*ctx->ctx_res_w == RES_NONE ||*/ !(ctx->old_flag & (1 << r->res))) { - syntax_error_at(word->data); - ctx->ctx_res_w = RES_SNTX; - return 1; - } else { - /* "{...} fi" is ok. "{...} if" is not - * Example: - * if { echo foo; } then { echo bar; } fi */ - if (ctx->command->group) - done_pipe(ctx, PIPE_SEQ); + sprintf(param_buf, NOMMU_HACK_FMT + , (unsigned) G.root_pid + , (unsigned) G.root_ppid + , (unsigned) G.last_bg_pid + , (unsigned) G.last_exitcode + , cnt + , empty_trap_mask + IF_HUSH_LOOPS(, G.depth_of_loop) + ); +# undef NOMMU_HACK_FMT + /* 1:hush 2:-$::: + * 3:-c 4: 5: 6:NULL + */ + cnt += 6; + for (cur = G.top_var; cur; cur = cur->next) { + if (!cur->flg_export || cur->flg_read_only) + cnt += 2; + } +# if ENABLE_HUSH_FUNCTIONS + for (funcp = G.top_func; funcp; funcp = funcp->next) + cnt += 3; +# endif + pp = g_argv; + while (*pp++) + cnt++; + *to_free = argv = pp = xzalloc(sizeof(argv[0]) * cnt); + *pp++ = (char *) G.argv0_for_re_execing; + *pp++ = param_buf; + for (cur = G.top_var; cur; cur = cur->next) { + if (strcmp(cur->varstr, hush_version_str) == 0) + continue; + if (cur->flg_read_only) { + *pp++ = (char *) "-R"; + *pp++ = cur->varstr; + } else if (!cur->flg_export) { + *pp++ = (char *) "-V"; + *pp++ = cur->varstr; + } + } +# if ENABLE_HUSH_FUNCTIONS + for (funcp = G.top_func; funcp; funcp = funcp->next) { + *pp++ = (char *) "-F"; + *pp++ = funcp->name; + *pp++ = funcp->body_as_string; + } +# endif + /* We can pass activated traps here. Say, -Tnn:trap_string + * + * However, POSIX says that subshells reset signals with traps + * to SIG_DFL. + * I tested bash-3.2 and it not only does that with true subshells + * of the form ( list ), but with any forked children shells. + * I set trap "echo W" WINCH; and then tried: + * + * { echo 1; sleep 20; echo 2; } & + * while true; do echo 1; sleep 20; echo 2; break; done & + * true | { echo 1; sleep 20; echo 2; } | cat + * + * In all these cases sending SIGWINCH to the child shell + * did not run the trap. If I add trap "echo V" WINCH; + * _inside_ group (just before echo 1), it works. + * + * I conclude it means we don't need to pass active traps here. + */ + *pp++ = (char *) "-c"; + *pp++ = (char *) s; + if (builtin_argv) { + while (*++builtin_argv) + *pp++ = *builtin_argv; + *pp++ = (char *) ""; } + *pp++ = g_argv0; + while (*g_argv) + *pp++ = *g_argv++; + /* *pp = NULL; - is already there */ + pp = environ; - ctx->ctx_res_w = r->res; - ctx->old_flag = r->flag; - word->o_assignment = r->assignment_flag; + do_exec: + debug_printf_exec("re_execute_shell pid:%d cmd:'%s'\n", getpid(), s); + /* Don't propagate SIG_IGN to the child */ + if (SPECIAL_JOBSTOP_SIGS != 0) + switch_off_special_sigs(G.special_sig_mask & SPECIAL_JOBSTOP_SIGS); + execve(bb_busybox_exec_path, argv, pp); + /* Fallback. Useful for init=/bin/hush usage etc */ + if (argv[0][0] == '/') + execve(argv[0], argv, pp); + xfunc_error_retval = 127; + bb_error_msg_and_die("can't re-execute the shell"); +} +#endif /* !BB_MMU */ - if (ctx->old_flag & FLAG_END) { - struct parse_context *old; - done_pipe(ctx, PIPE_SEQ); - debug_printf_parse("pop stack %p\n", ctx->stack); - old = ctx->stack; - old->command->group = ctx->list_head; - old->command->cmd_type = CMD_NORMAL; -# if !BB_MMU - o_addstr(&old->as_string, ctx->as_string.data); - o_free_unsafe(&ctx->as_string); - old->command->group_as_string = xstrdup(old->as_string.data); - debug_printf_parse("pop, remembering as:'%s'\n", - old->command->group_as_string); -# endif - *ctx = *old; /* physical copy */ - free(old); +static int run_and_free_list(struct pipe *pi); + +/* Executing from string: eval, sh -c '...' + * or from file: /etc/profile, . file, sh