------------------------------------------------------------------------
r26240 | vda | 2009-04-29 07:02:57 -0500 (Wed, 29 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/miscutils/flash_eraseall.c
   M /trunk/busybox/networking/ifplugd.c
   M /trunk/busybox/networking/tc.c
   M /trunk/busybox/util-linux/mkfs_vfat.c

*: bb_error_msg's messages should not be capitalized


 ------------------------------------------------------------------------

Index: networking/ifplugd.c
===================================================================
--- networking/ifplugd.c	(revision 26239)
+++ networking/ifplugd.c	(revision 26240)
@@ -258,7 +258,7 @@
 	if (network_ioctl(SIOCGIFADDR, &ifrequest) < 0) {
 		bb_error_msg("can't get interface address");
 	} else if (ifrequest.ifr_addr.sa_family != AF_INET) {
-		bb_perror_msg("The interface is not IP-based");
+		bb_perror_msg("the interface is not IP-based");
 	} else {
 		((struct sockaddr_in*)(&ifrequest.ifr_addr))->sin_addr.s_addr = INADDR_ANY;
 		if (network_ioctl(SIOCSIFADDR, &ifrequest) < 0)
@@ -299,7 +299,7 @@
 				(uint8_t)(ifrequest.ifr_hwaddr.sa_data[5]));
 		}
 
-		bb_error_msg("Using interface %s%s with driver<%s> (version: %s)",
+		bb_error_msg("using interface %s%s with driver<%s> (version: %s)",
 			G.iface, buf, driver_info.driver, driver_info.version);
 	}
 #endif
Index: networking/tc.c
===================================================================
--- networking/tc.c	(revision 26239)
+++ networking/tc.c	(revision 26240)
@@ -284,12 +284,12 @@
 	char *name;
 
 	if (hdr->nlmsg_type != RTM_NEWQDISC && hdr->nlmsg_type != RTM_DELQDISC) {
-		/* bb_error_msg("Not a qdisc"); */
+		/* bb_error_msg("not a qdisc"); */
 		return 0; /* ??? mimic upstream; should perhaps return -1 */
 	}
 	len -= NLMSG_LENGTH(sizeof(*msg));
 	if (len < 0) {
-		/* bb_error_msg("Wrong len %d", len); */
+		/* bb_error_msg("wrong len %d", len); */
 		return -1;
 	}
 	/* not the desired interface? */
@@ -342,12 +342,12 @@
 	/*XXX Eventually factor out common code */
 
 	if (hdr->nlmsg_type != RTM_NEWTCLASS && hdr->nlmsg_type != RTM_DELTCLASS) {
-		/* bb_error_msg("Not a class"); */
+		/* bb_error_msg("not a class"); */
 		return 0; /* ??? mimic upstream; should perhaps return -1 */
 	}
 	len -= NLMSG_LENGTH(sizeof(*msg));
 	if (len < 0) {
-		/* bb_error_msg("Wrong len %d", len); */
+		/* bb_error_msg("wrong len %d", len); */
 		return -1;
 	}
 	/* not the desired interface? */
Index: miscutils/flash_eraseall.c
===================================================================
--- miscutils/flash_eraseall.c	(revision 26239)
+++ miscutils/flash_eraseall.c	(revision 26240)
@@ -97,7 +97,7 @@
 				if (clmlen > 8)
 					clmlen = 8;
 				if (clmlen == 0)
-					bb_error_msg_and_die("Autoplacement selected and no empty space in oob");
+					bb_error_msg_and_die("autoplacement selected and no empty space in oob");
 			} else {
 				/* Legacy mode */
 				switch (meminfo.oobsize) {
Index: util-linux/mkfs_vfat.c
===================================================================
--- util-linux/mkfs_vfat.c	(revision 26239)
+++ util-linux/mkfs_vfat.c	(revision 26240)
@@ -273,10 +273,10 @@
 			device_num == 0x0d00 || // xd
 			device_num == 0x1600 )  // hdc, hdd
 		)
-			bb_error_msg_and_die("Will not try to make filesystem on full-disk device (use -I if wanted)");
+			bb_error_msg_and_die("will not try to make filesystem on full-disk device (use -I if wanted)");
 		// can't work on mounted filesystems
 		if (find_mount_point(device_name, NULL))
-			bb_error_msg_and_die("Can't format mounted filesystem");
+			bb_error_msg_and_die("can't format mounted filesystem");
 #endif
 		// get true sector size
 		// (parameter must be int*, not long* or size_t*)
@@ -562,7 +562,7 @@
 		start_data_sector = (reserved_sect + NUM_FATS * sect_per_fat) * (bytes_per_sect / SECTOR_SIZE);
 		start_data_block = (start_data_sector + SECTORS_PER_BLOCK - 1) / SECTORS_PER_BLOCK;
 
-		bb_info_msg("Searching for bad blocks ");
+		bb_info_msg("searching for bad blocks ");
 		currently_testing = 0;
 		try = TEST_BUFFER_BLOCKS;
 		while (currently_testing < volume_size_blocks) {
@@ -577,7 +577,7 @@
 			if (got < 0)
 				got = 0;
 			if (got & (BLOCK_SIZE - 1))
-				bb_error_msg("Unexpected values in do_check: probably bugs");
+				bb_error_msg("unexpected values in do_check: probably bugs");
 			got /= BLOCK_SIZE;
 			currently_testing += got;
 			if (got == try) {
@@ -592,7 +592,7 @@
 			for (i = 0; i < SECTORS_PER_BLOCK; i++) {
 				int cluster = (currently_testing * SECTORS_PER_BLOCK + i - start_data_sector) / (int) (sect_per_clust) / (bytes_per_sect / SECTOR_SIZE);
 				if (cluster < 0)
-					bb_error_msg_and_die("Invalid cluster number in mark_sector: probably bug!");
+					bb_error_msg_and_die("invalid cluster number in mark_sector: probably bug!");
 				MARK_CLUSTER(cluster, BAD_FAT32);
 			}
 			badblocks++;

 ------------------------------------------------------------------------
r26239 | vda | 2009-04-29 07:01:51 -0500 (Wed, 29 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/archival/Config.in
   M /trunk/busybox/archival/Kbuild
   A /trunk/busybox/archival/liblzo.h
   A /trunk/busybox/archival/liblzo_interface.h
   A /trunk/busybox/archival/lzo1x_1.c
   A /trunk/busybox/archival/lzo1x_1o.c
   A /trunk/busybox/archival/lzo1x_9x.c
   A /trunk/busybox/archival/lzo1x_c.c
   A /trunk/busybox/archival/lzo1x_d.c
   A /trunk/busybox/archival/lzop.c
   M /trunk/busybox/include/applets.h
   M /trunk/busybox/include/usage.h

lzop: new applet. Busyboxed by Alain Knaff. +7700 bytes.


 ------------------------------------------------------------------------

Index: archival/liblzo.h
===================================================================
--- archival/liblzo.h	(revision 0)
+++ archival/liblzo.h	(revision 26239)
@@ -0,0 +1,93 @@
+/*
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/config1x.h */
+#define M2_MIN_LEN      3
+#define M2_MAX_LEN      8
+#define M3_MAX_LEN      33
+#define M4_MAX_LEN      9
+#define M1_MAX_OFFSET   0x0400
+#define M2_MAX_OFFSET   0x0800
+#define M3_MAX_OFFSET   0x4000
+#define M4_MAX_OFFSET   0xbfff
+#define M1_MARKER       0
+#define M3_MARKER       32
+#define M4_MARKER       16
+
+#define MX_MAX_OFFSET   (M1_MAX_OFFSET + M2_MAX_OFFSET)
+#define MIN_LOOKAHEAD   (M2_MAX_LEN + 1)
+
+#define LZO_EOF_CODE
+
+/* lzo-2.03/src/lzo_dict.h */
+#define GINDEX(m_pos,m_off,dict,dindex,in)    m_pos = dict[dindex]
+#define DX2(p,s1,s2) \
+        (((((unsigned)((p)[2]) << (s2)) ^ (p)[1]) << (s1)) ^ (p)[0])
+//#define DA3(p,s1,s2,s3) ((DA2((p)+1,s2,s3) << (s1)) + (p)[0])
+//#define DS3(p,s1,s2,s3) ((DS2((p)+1,s2,s3) << (s1)) - (p)[0])
+#define DX3(p,s1,s2,s3) ((DX2((p)+1,s2,s3) << (s1)) ^ (p)[0])
+
+#define D_SIZE        (1U << D_BITS)
+#define D_MASK        ((1U << D_BITS) - 1)
+#define D_HIGH        ((D_MASK >> 1) + 1)
+
+#define LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,max_offset) \
+    ( \
+        m_pos = ip - (unsigned)(ip - m_pos), \
+        ((uintptr_t)m_pos < (uintptr_t)in \
+	|| (m_off = (unsigned)(ip - m_pos)) <= 0 \
+	|| m_off > max_offset) \
+    )
+
+#define DENTRY(p,in)                      (p)
+#define UPDATE_I(dict,drun,index,p,in)    dict[index] = DENTRY(p,in)
+
+#define DMS(v,s)  ((unsigned) (((v) & (D_MASK >> (s))) << (s)))
+#define DM(v)     ((unsigned) ((v) & D_MASK))
+#define DMUL(a,b) ((unsigned) ((a) * (b)))
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)  ((unsigned)((a)-(b)))
+
+#    define TEST_IP             (ip < ip_end)
+#    define NEED_IP(x) \
+            if ((unsigned)(ip_end - ip) < (unsigned)(x))  goto input_overrun
+
+#    undef TEST_OP              /* don't need both of the tests here */
+#    define TEST_OP             1
+#    define NEED_OP(x) \
+            if ((unsigned)(op_end - op) < (unsigned)(x))  goto output_overrun
+
+#define HAVE_ANY_OP 1
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+#  define TEST_LB(m_pos)        if (m_pos < out || m_pos >= op) goto lookbehind_overrun
+//#  define TEST_LBO(m_pos,o)     if (m_pos < out || m_pos >= op - (o)) goto lookbehind_overrun
+//#else
+//#  define TEST_LB(m_pos)        ((void) 0)
+//#  define TEST_LBO(m_pos,o)     ((void) 0)
+//#endif
Index: archival/lzo1x_1o.c
===================================================================
--- archival/lzo1x_1o.c	(revision 0)
+++ archival/lzo1x_1o.c	(revision 26239)
@@ -0,0 +1,35 @@
+/* LZO1X-1(15) compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          15
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_15_compress
+
+#include "lzo1x_c.c"
Index: archival/lzo1x_c.c
===================================================================
--- archival/lzo1x_c.c	(revision 0)
+++ archival/lzo1x_c.c	(revision 26239)
@@ -0,0 +1,296 @@
+/* implementation of the LZO1[XY]-1 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+/***********************************************************************
+// compress a block of data.
+************************************************************************/
+static NOINLINE unsigned
+do_compress(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem)
+{
+	register const uint8_t* ip;
+	uint8_t* op;
+	const uint8_t* const in_end = in + in_len;
+	const uint8_t* const ip_end = in + in_len - M2_MAX_LEN - 5;
+	const uint8_t* ii;
+	const void* *const dict = (const void**) wrkmem;
+
+	op = out;
+	ip = in;
+	ii = ip;
+
+	ip += 4;
+	for (;;) {
+		register const uint8_t* m_pos;
+		unsigned m_off;
+		unsigned m_len;
+		unsigned dindex;
+
+		D_INDEX1(dindex,ip);
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+#if 1
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		D_INDEX2(dindex,ip);
+#endif
+		GINDEX(m_pos,m_off,dict,dindex,in);
+		if (LZO_CHECK_MPOS_NON_DET(m_pos,m_off,in,ip,M4_MAX_OFFSET))
+			goto literal;
+		if (m_off <= M2_MAX_OFFSET || m_pos[3] == ip[3])
+			goto try_match;
+		goto literal;
+
+ try_match:
+#if 1 && defined(LZO_UNALIGNED_OK_2)
+		if (* (const lzo_ushortp) m_pos != * (const lzo_ushortp) ip)
+#else
+		if (m_pos[0] != ip[0] || m_pos[1] != ip[1])
+#endif
+		{
+		} else {
+			if (m_pos[2] == ip[2]) {
+#if 0
+				if (m_off <= M2_MAX_OFFSET)
+					goto match;
+				if (lit <= 3)
+					goto match;
+				if (lit == 3) {			  /* better compression, but slower */
+					assert(op - 2 > out); op[-2] |= (uint8_t)(3);
+					*op++ = *ii++; *op++ = *ii++; *op++ = *ii++;
+					goto code_match;
+				}
+				if (m_pos[3] == ip[3])
+#endif
+					goto match;
+			}
+			else {
+				/* still need a better way for finding M1 matches */
+#if 0
+				/* a M1 match */
+#if 0
+				if (m_off <= M1_MAX_OFFSET && lit > 0 && lit <= 3)
+#else
+				if (m_off <= M1_MAX_OFFSET && lit == 3)
+#endif
+				{
+					register unsigned t;
+
+					t = lit;
+					assert(op - 2 > out); op[-2] |= (uint8_t)(t);
+					do *op++ = *ii++; while (--t > 0);
+					assert(ii == ip);
+					m_off -= 1;
+					*op++ = (uint8_t)(M1_MARKER | ((m_off & 3) << 2));
+					*op++ = (uint8_t)(m_off >> 2);
+					ip += 2;
+					goto match_done;
+				}
+#endif
+			}
+		}
+
+		/* a literal */
+ literal:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		++ip;
+		if (ip >= ip_end)
+			break;
+		continue;
+
+		/* a match */
+match:
+		UPDATE_I(dict, 0, dindex, ip, in);
+		/* store current literal run */
+		if (pd(ip, ii) > 0) {
+			register unsigned t = pd(ip, ii);
+
+			if (t <= 3) {
+				assert(op - 2 > out);
+				op[-2] |= (uint8_t)(t);
+			}
+			else if (t <= 18)
+				*op++ = (uint8_t)(t - 3);
+			else {
+				register unsigned tt = t - 18;
+
+				*op++ = 0;
+				while (tt > 255) {
+					tt -= 255;
+					*op++ = 0;
+				}
+				assert(tt > 0);
+				*op++ = (uint8_t)(tt);
+			}
+			do *op++ = *ii++; while (--t > 0);
+		}
+
+		/* code the match */
+		assert(ii == ip);
+		ip += 3;
+		if (m_pos[3] != *ip++ || m_pos[4] != *ip++ || m_pos[5] != *ip++
+		 || m_pos[6] != *ip++ || m_pos[7] != *ip++ || m_pos[8] != *ip++
+#ifdef LZO1Y
+		 || m_pos[ 9] != *ip++ || m_pos[10] != *ip++ || m_pos[11] != *ip++
+		 || m_pos[12] != *ip++ || m_pos[13] != *ip++ || m_pos[14] != *ip++
+#endif
+		) {
+			--ip;
+			m_len = pd(ip, ii);
+			assert(m_len >= 3);
+			assert(m_len <= M2_MAX_LEN);
+
+			if (m_off <= M2_MAX_OFFSET) {
+				m_off -= 1;
+#if defined(LZO1X)
+				*op++ = (uint8_t)(((m_len - 1) << 5) | ((m_off & 7) << 2));
+				*op++ = (uint8_t)(m_off >> 3);
+#elif defined(LZO1Y)
+				*op++ = (uint8_t)(((m_len + 1) << 4) | ((m_off & 3) << 2));
+				*op++ = (uint8_t)(m_off >> 2);
+#endif
+			}
+			else if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+				goto m3_m4_offset;
+			} else {
+#if defined(LZO1X)
+				m_off -= 0x4000;
+				assert(m_off > 0);
+				assert(m_off <= 0x7fff);
+				*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+				goto m3_m4_offset;
+#elif defined(LZO1Y)
+				goto m4_match;
+#endif
+			}
+		}
+		else {
+			{
+				const uint8_t* end = in_end;
+				const uint8_t* m = m_pos + M2_MAX_LEN + 1;
+				while (ip < end && *m == *ip)
+					m++, ip++;
+				m_len = pd(ip, ii);
+			}
+			assert(m_len > M2_MAX_LEN);
+
+			if (m_off <= M3_MAX_OFFSET) {
+				m_off -= 1;
+				if (m_len <= 33)
+					*op++ = (uint8_t)(M3_MARKER | (m_len - 2));
+				else {
+					m_len -= 33;
+					*op++ = M3_MARKER | 0;
+					goto m3_m4_len;
+				}
+			} else {
+#if defined(LZO1Y)
+ m4_match:
+#endif
+				m_off -= 0x4000;
+				assert(m_off > 0);
+				assert(m_off <= 0x7fff);
+				if (m_len <= M4_MAX_LEN)
+					*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11) | (m_len - 2));
+				else {
+					m_len -= M4_MAX_LEN;
+					*op++ = (uint8_t)(M4_MARKER | ((m_off & 0x4000) >> 11));
+ m3_m4_len:
+					while (m_len > 255) {
+						m_len -= 255;
+						*op++ = 0;
+					}
+					assert(m_len > 0);
+					*op++ = (uint8_t)(m_len);
+				}
+			}
+ m3_m4_offset:
+			*op++ = (uint8_t)((m_off & 63) << 2);
+			*op++ = (uint8_t)(m_off >> 6);
+		}
+#if 0
+ match_done:
+#endif
+		ii = ip;
+		if (ip >= ip_end)
+			break;
+	}
+
+	*out_len = pd(op, out);
+	return pd(in_end, ii);
+}
+
+/***********************************************************************
+// public entry point
+************************************************************************/
+int DO_COMPRESS(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem)
+{
+	uint8_t* op = out;
+	unsigned t;
+
+	if (in_len <= M2_MAX_LEN + 5)
+		t = in_len;
+	else {
+		t = do_compress(in,in_len,op,out_len,wrkmem);
+		op += *out_len;
+	}
+
+	if (t > 0) {
+		const uint8_t* ii = in + in_len - t;
+
+		if (op == out && t <= 238)
+			*op++ = (uint8_t)(17 + t);
+		else if (t <= 3)
+			op[-2] |= (uint8_t)(t);
+		else if (t <= 18)
+			*op++ = (uint8_t)(t - 3);
+		else {
+			unsigned tt = t - 18;
+
+			*op++ = 0;
+			while (tt > 255) {
+				tt -= 255;
+				*op++ = 0;
+			}
+			assert(tt > 0);
+			*op++ = (uint8_t)(tt);
+		}
+		do *op++ = *ii++; while (--t > 0);
+	}
+
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+
+	*out_len = pd(op, out);
+	return 0; /*LZO_E_OK*/
+}
Index: archival/lzo1x_d.c
===================================================================
--- archival/lzo1x_d.c	(revision 0)
+++ archival/lzo1x_d.c	(revision 26239)
@@ -0,0 +1,420 @@
+/* implementation of the LZO1X decompression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+/***********************************************************************
+// decompress a block of data.
+************************************************************************/
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem UNUSED_PARAM)
+{
+	register uint8_t* op;
+	register const uint8_t* ip;
+	register unsigned t;
+#if defined(COPY_DICT)
+	unsigned m_off;
+	const uint8_t* dict_end;
+#else
+	register const uint8_t* m_pos = NULL; /* possibly not needed */
+#endif
+	const uint8_t* const ip_end = in + in_len;
+#if defined(HAVE_ANY_OP)
+	uint8_t* const op_end = out + *out_len;
+#endif
+#if defined(LZO1Z)
+	unsigned last_m_off = 0;
+#endif
+
+//	LZO_UNUSED(wrkmem);
+
+#if defined(COPY_DICT)
+	if (dict) {
+		if (dict_len > M4_MAX_OFFSET) {
+			dict += dict_len - M4_MAX_OFFSET;
+			dict_len = M4_MAX_OFFSET;
+		}
+		dict_end = dict + dict_len;
+	} else {
+		dict_len = 0;
+		dict_end = NULL;
+	}
+#endif /* COPY_DICT */
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		assert(t > 0); NEED_OP(t); NEED_IP(t+1);
+		do *op++ = *ip++; while (--t > 0);
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		/* a literal run */
+		if (t == 0) {
+			NEED_IP(1);
+			while (*ip == 0) {
+				t += 255;
+				ip++;
+				NEED_IP(1);
+			}
+			t += 15 + *ip++;
+		}
+		/* copy literals */
+		assert(t > 0);
+		NEED_OP(t+3);
+		NEED_IP(t+4);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+		if (PTR_ALIGNED2_4(op, ip))
+# endif
+		{
+			COPY4(op, ip);
+			op += 4;
+			ip += 4;
+			if (--t > 0) {
+				if (t >= 4) {
+					do {
+						COPY4(op, ip);
+						op += 4;
+						ip += 4;
+						t -= 4;
+					} while (t >= 4);
+					if (t > 0)
+						do *op++ = *ip++; while (--t > 0);
+				} else {
+					do *op++ = *ip++; while (--t > 0);
+				}
+			}
+		}
+# if !defined(LZO_UNALIGNED_OK_4)
+		else
+# endif
+#endif
+#if !defined(LZO_UNALIGNED_OK_4)
+		{
+			*op++ = *ip++;
+			*op++ = *ip++;
+			*op++ = *ip++;
+			do *op++ = *ip++; while (--t > 0);
+		}
+#endif
+
+ first_literal_run:
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+		m_off = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		last_m_off = m_off;
+#else
+		m_off = (1 + M2_MAX_OFFSET) + (t >> 2) + (*ip++ << 2);
+#endif
+		NEED_OP(3);
+		t = 3; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+		t = (1 + M2_MAX_OFFSET) + (t << 6) + (*ip++ >> 2);
+		m_pos = op - t;
+		last_m_off = t;
+#else
+		m_pos = op - (1 + M2_MAX_OFFSET);
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+#endif
+		TEST_LB(m_pos); NEED_OP(3);
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos;
+#endif /* COPY_DICT */
+		goto match_done;
+
+		/* handle matches */
+		do {
+ match:
+			if (t >= 64) {		/* a M2 match */
+#if defined(COPY_DICT)
+#if defined(LZO1X)
+				m_off = 1 + ((t >> 2) & 7) + (*ip++ << 3);
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_off = 1 + ((t >> 2) & 3) + (*ip++ << 2);
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				m_off = t & 0x1f;
+				if (m_off >= 0x1c)
+					m_off = last_m_off;
+				else {
+					m_off = 1 + (m_off << 6) + (*ip++ >> 2);
+					last_m_off = m_off;
+				}
+				t = (t >> 5) - 1;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1X)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 7;
+				m_pos -= *ip++ << 3;
+				t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+				m_pos = op - 1;
+				m_pos -= (t >> 2) & 3;
+				m_pos -= *ip++ << 2;
+				t = (t >> 4) - 3;
+#elif defined(LZO1Z)
+				{
+					unsigned off = t & 0x1f;
+					m_pos = op;
+					if (off >= 0x1c) {
+						assert(last_m_off > 0);
+						m_pos -= last_m_off;
+					} else {
+						off = 1 + (off << 6) + (*ip++ >> 2);
+						m_pos -= off;
+						last_m_off = off;
+					}
+				}
+				t = (t >> 5) - 1;
+#endif
+				TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+				goto copy_match;
+#endif /* COPY_DICT */
+			}
+			else if (t >= 32) {			/* a M3 match */
+				t &= 31;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 31 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				{
+					unsigned off = 1 + (ip[0] << 6) + (ip[1] >> 2);
+					m_pos = op - off;
+					last_m_off = off;
+				}
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+				m_pos = op - 1;
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos = op - 1;
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+#endif /* COPY_DICT */
+				ip += 2;
+			}
+			else if (t >= 16) {			/* a M4 match */
+#if defined(COPY_DICT)
+				m_off = (t & 8) << 11;
+#else /* !COPY_DICT */
+				m_pos = op;
+				m_pos -= (t & 8) << 11;
+#endif /* COPY_DICT */
+				t &= 7;
+				if (t == 0) {
+					NEED_IP(1);
+					while (*ip == 0) {
+						t += 255;
+						ip++;
+						NEED_IP(1);
+					}
+					t += 7 + *ip++;
+				}
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off += (ip[0] << 6) + (ip[1] >> 2);
+#else
+				m_off += (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_off == 0)
+					goto eof_found;
+				m_off += 0x4000;
+#if defined(LZO1Z)
+				last_m_off = m_off;
+#endif
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				m_pos -= (ip[0] << 6) + (ip[1] >> 2);
+#elif defined(LZO_UNALIGNED_OK_2) && defined(LZO_ABI_LITTLE_ENDIAN)
+				m_pos -= (* (const lzo_ushortp) ip) >> 2;
+#else
+				m_pos -= (ip[0] >> 2) + (ip[1] << 6);
+#endif
+				ip += 2;
+				if (m_pos == op)
+					goto eof_found;
+				m_pos -= 0x4000;
+#if defined(LZO1Z)
+				last_m_off = pd((const uint8_t*)op, m_pos);
+#endif
+#endif /* COPY_DICT */
+			}
+			else {				/* a M1 match */
+#if defined(COPY_DICT)
+#if defined(LZO1Z)
+				m_off = 1 + (t << 6) + (*ip++ >> 2);
+				last_m_off = m_off;
+#else
+				m_off = 1 + (t >> 2) + (*ip++ << 2);
+#endif
+				NEED_OP(2);
+				t = 2; COPY_DICT(t,m_off)
+#else /* !COPY_DICT */
+#if defined(LZO1Z)
+				t = 1 + (t << 6) + (*ip++ >> 2);
+				m_pos = op - t;
+				last_m_off = t;
+#else
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+#endif
+				TEST_LB(m_pos); NEED_OP(2);
+				*op++ = *m_pos++;
+				*op++ = *m_pos;
+#endif /* COPY_DICT */
+				goto match_done;
+			}
+
+			/* copy match */
+#if defined(COPY_DICT)
+
+			NEED_OP(t+3-1);
+			t += 3-1; COPY_DICT(t,m_off)
+
+#else /* !COPY_DICT */
+
+			TEST_LB(m_pos); assert(t > 0); NEED_OP(t+3-1);
+#if defined(LZO_UNALIGNED_OK_4) || defined(LZO_ALIGNED_OK_4)
+# if !defined(LZO_UNALIGNED_OK_4)
+			if (t >= 2 * 4 - (3 - 1) && PTR_ALIGNED2_4(op,m_pos)) {
+				assert((op - m_pos) >= 4);	/* both pointers are aligned */
+# else
+			if (t >= 2 * 4 - (3 - 1) && (op - m_pos) >= 4) {
+# endif
+				COPY4(op,m_pos);
+				op += 4; m_pos += 4; t -= 4 - (3 - 1);
+				do {
+					COPY4(op,m_pos);
+					op += 4; m_pos += 4; t -= 4;
+				} while (t >= 4);
+				if (t > 0)
+					do *op++ = *m_pos++; while (--t > 0);
+			}
+			else
+#endif
+			{
+ copy_match:
+				*op++ = *m_pos++; *op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+#endif /* COPY_DICT */
+
+ match_done:
+#if defined(LZO1Z)
+			t = ip[-1] & 3;
+#else
+			t = ip[-2] & 3;
+#endif
+			if (t == 0)
+				break;
+
+			/* copy literals */
+ match_next:
+			assert(t > 0);
+			assert(t < 4);
+			NEED_OP(t);
+			NEED_IP(t+1);
+#if 0
+			do *op++ = *ip++; while (--t > 0);
+#else
+			*op++ = *ip++;
+			if (t > 1) {
+				*op++ = *ip++;
+				if (t > 2)
+					*op++ = *ip++;
+			}
+#endif
+			t = *ip++;
+		} while (TEST_IP && TEST_OP);
+	}
+
+//#if defined(HAVE_TEST_IP) || defined(HAVE_TEST_OP)
+	/* no EOF code was found */
+	*out_len = pd(op, out);
+	return LZO_E_EOF_NOT_FOUND;
+//#endif
+
+ eof_found:
+	assert(t == 1);
+	*out_len = pd(op, out);
+	return (ip == ip_end ? LZO_E_OK :
+		   (ip < ip_end	 ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+
+//#if defined(HAVE_NEED_IP)
+ input_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_INPUT_OVERRUN;
+//#endif
+
+//#if defined(HAVE_NEED_OP)
+ output_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_OUTPUT_OVERRUN;
+//#endif
+
+//#if defined(LZO_TEST_OVERRUN_LOOKBEHIND)
+ lookbehind_overrun:
+	*out_len = pd(op, out);
+	return LZO_E_LOOKBEHIND_OVERRUN;
+//#endif
+}
Index: archival/liblzo_interface.h
===================================================================
--- archival/liblzo_interface.h	(revision 0)
+++ archival/liblzo_interface.h	(revision 26239)
@@ -0,0 +1,71 @@
+/*
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#define LZO1X
+#undef LZO1Y
+
+#undef assert
+/*
+static void die_at(int line)
+{
+        bb_error_msg_and_die("internal error at %d", line);
+}
+#define assert(v) if (!(v)) die_at(__LINE__)
+*/
+#define assert(v) ((void)0)
+
+int lzo1x_1_compress(const uint8_t* src, unsigned src_len,
+		uint8_t* dst, unsigned* dst_len,
+		void* wrkmem);
+int lzo1x_1_15_compress(const uint8_t* src, unsigned src_len,
+		uint8_t* dst, unsigned* dst_len,
+		void* wrkmem);
+int lzo1x_999_compress_level(const uint8_t* in, unsigned in_len,
+		uint8_t* out, unsigned* out_len,
+		void* wrkmem,
+		int compression_level);
+
+/* decompression */
+//int lzo1x_decompress(const uint8_t* src, unsigned src_len,
+//		uint8_t* dst, unsigned* dst_len,
+//		void* wrkmem /* NOT USED */);
+/* safe decompression with overrun testing */
+int lzo1x_decompress_safe(const uint8_t* src, unsigned src_len,
+		uint8_t* dst, unsigned* dst_len,
+		void* wrkmem /* NOT USED */);
+
+#define LZO_E_OK                    0
+#define LZO_E_ERROR                 (-1)
+#define LZO_E_OUT_OF_MEMORY         (-2)    /* [not used right now] */
+#define LZO_E_NOT_COMPRESSIBLE      (-3)    /* [not used right now] */
+#define LZO_E_INPUT_OVERRUN         (-4)
+#define LZO_E_OUTPUT_OVERRUN        (-5)
+#define LZO_E_LOOKBEHIND_OVERRUN    (-6)
+#define LZO_E_EOF_NOT_FOUND         (-7)
+#define LZO_E_INPUT_NOT_CONSUMED    (-8)
+#define LZO_E_NOT_YET_IMPLEMENTED   (-9)    /* [not used right now] */
+
+/* lzo-2.03/include/lzo/lzoconf.h */
+#define LZO_VERSION   0x2030
Index: archival/lzop.c
===================================================================
--- archival/lzop.c	(revision 0)
+++ archival/lzop.c	(revision 26239)
@@ -0,0 +1,1075 @@
+/*
+   This file is part of the lzop file compressor.
+
+   Copyright (C) 1996..2003 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzop/
+
+   lzop and the LZO library are free software; you can redistribute them
+   and/or modify them under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+   "Minimalized" for busybox by Alain Knaff
+*/
+
+#include "libbb.h"
+#include "unarchive.h"
+#include "liblzo_interface.h"
+
+/* lzo-2.03/src/lzo_ptr.h */
+#define pd(a,b)	 ((unsigned)((a)-(b)))
+
+#define lzo_version()			LZO_VERSION
+#define lzo_sizeof_dict_t		(sizeof(uint8_t*))
+
+/* lzo-2.03/include/lzo/lzo1x.h */
+#define LZO1X_1_MEM_COMPRESS	(16384 * lzo_sizeof_dict_t)
+#define LZO1X_1_15_MEM_COMPRESS (32768 * lzo_sizeof_dict_t)
+#define LZO1X_999_MEM_COMPRESS	(14 * 16384 * sizeof(short))
+
+/* lzo-2.03/src/lzo1x_oo.c */
+#define NO_LIT UINT_MAX
+
+/**********************************************************************/
+static void copy2(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+	ip[0] = m_pos[0];
+	if (off == 1)
+		ip[1] = m_pos[0];
+	else
+		ip[1] = m_pos[1];
+}
+
+static void copy3(uint8_t* ip, const uint8_t* m_pos, unsigned off)
+{
+	ip[0] = m_pos[0];
+	if (off == 1) {
+		ip[2] = ip[1] = m_pos[0];
+	}
+	else if (off == 2) {
+		ip[1] = m_pos[1];
+		ip[2] = m_pos[0];
+	}
+	else {
+		ip[1] = m_pos[1];
+		ip[2] = m_pos[2];
+	}
+}
+
+/**********************************************************************/
+// optimize a block of data.
+/**********************************************************************/
+#define TEST_IP		(ip < ip_end)
+#define TEST_OP		(op <= op_end)
+
+static int lzo1x_optimize(uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void* wrkmem UNUSED_PARAM)
+{
+	uint8_t* op;
+	uint8_t* ip;
+	unsigned t;
+	uint8_t* m_pos;
+	uint8_t* const ip_end = in + in_len;
+	uint8_t* const op_end = out + *out_len;
+	uint8_t* litp = NULL;
+	unsigned lit = 0;
+	unsigned next_lit = NO_LIT;
+	unsigned nl;
+	unsigned long o_m1_a = 0, o_m1_b = 0, o_m2 = 0, o_m3_a = 0, o_m3_b = 0;
+
+//	  LZO_UNUSED(wrkmem);
+
+	*out_len = 0;
+
+	op = out;
+	ip = in;
+
+	if (*ip > 17) {
+		t = *ip++ - 17;
+		if (t < 4)
+			goto match_next;
+		goto first_literal_run;
+	}
+
+	while (TEST_IP && TEST_OP) {
+		t = *ip++;
+		if (t >= 16)
+			goto match;
+		/* a literal run */
+		litp = ip - 1;
+		if (t == 0) {
+			t = 15;
+			while (*ip == 0)
+				t += 255, ip++;
+			t += *ip++;
+		}
+		lit = t + 3;
+		/* copy literals */
+ copy_literal_run:
+		*op++ = *ip++;
+		*op++ = *ip++;
+		*op++ = *ip++;
+ first_literal_run:
+		do *op++ = *ip++; while (--t > 0);
+
+		t = *ip++;
+
+		if (t >= 16)
+			goto match;
+#if defined(LZO1X)
+		m_pos = op - 1 - 0x800;
+#elif defined(LZO1Y)
+		m_pos = op - 1 - 0x400;
+#endif
+		m_pos -= t >> 2;
+		m_pos -= *ip++ << 2;
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		*op++ = *m_pos++;
+		lit = 0;
+		goto match_done;
+
+
+		/* handle matches */
+		do {
+			if (t < 16) { /* a M1 match */
+				m_pos = op - 1;
+				m_pos -= t >> 2;
+				m_pos -= *ip++ << 2;
+
+				if (litp == NULL)
+					goto copy_m1;
+
+				nl = ip[-2] & 3;
+				/* test if a match follows */
+				if (nl == 0 && lit == 1 && ip[0] >= 16) {
+					next_lit = nl;
+					/* adjust length of previous short run */
+					lit += 2;
+					*litp = (unsigned char)((*litp & ~3) | lit);
+					/* copy over the 2 literals that replace the match */
+					copy2(ip-2, m_pos, pd(op, m_pos));
+					o_m1_a++;
+				}
+				/* test if a literal run follows */
+				else if (nl == 0 && ip[0] < 16 && ip[0] != 0 &&
+						 (lit + 2 + ip[0] < 16))
+				{
+					t = *ip++;
+					/* remove short run */
+					*litp &= ~3;
+					/* copy over the 2 literals that replace the match */
+					copy2(ip-3+1,m_pos,pd(op,m_pos));
+					/* move literals 1 byte ahead */
+					litp += 2;
+					if (lit > 0)
+						memmove(litp+1, litp, lit);
+					/* insert new length of long literal run */
+					lit += 2 + t + 3;
+					*litp = (unsigned char)(lit - 3);
+
+					o_m1_b++;
+					*op++ = *m_pos++; *op++ = *m_pos++;
+					goto copy_literal_run;
+				}
+ copy_m1:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+			} else {
+ match:
+				if (t >= 64) {				/* a M2 match */
+					m_pos = op - 1;
+#if defined(LZO1X)
+					m_pos -= (t >> 2) & 7;
+					m_pos -= *ip++ << 3;
+					t = (t >> 5) - 1;
+#elif defined(LZO1Y)
+					m_pos -= (t >> 2) & 3;
+					m_pos -= *ip++ << 2;
+					t = (t >> 4) - 3;
+#endif
+					if (litp == NULL)
+						goto copy_m;
+
+					nl = ip[-2] & 3;
+					/* test if in beetween two long literal runs */
+					if (t == 1 && lit > 3 && nl == 0
+					 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+					) {
+						t = *ip++;
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-1-2,m_pos,pd(op,m_pos));
+						/* set new length of previous literal run */
+						lit += 3 + t + 3;
+						*litp = (unsigned char)(lit - 3);
+						o_m2++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						goto copy_literal_run;
+					}
+				} else {
+					if (t >= 32) {			/* a M3 match */
+						t &= 31;
+						if (t == 0) {
+							t = 31;
+							while (*ip == 0)
+								t += 255, ip++;
+							t += *ip++;
+						}
+						m_pos = op - 1;
+						m_pos -= *ip++ >> 2;
+						m_pos -= *ip++ << 6;
+					} else {					/* a M4 match */
+						m_pos = op;
+						m_pos -= (t & 8) << 11;
+						t &= 7;
+						if (t == 0) {
+							t = 7;
+							while (*ip == 0)
+								t += 255, ip++;
+							t += *ip++;
+						}
+						m_pos -= *ip++ >> 2;
+						m_pos -= *ip++ << 6;
+						if (m_pos == op)
+							goto eof_found;
+						m_pos -= 0x4000;
+					}
+					if (litp == NULL)
+						goto copy_m;
+
+					nl = ip[-2] & 3;
+					/* test if in beetween two matches */
+					if (t == 1 && lit == 0 && nl == 0 && ip[0] >= 16) {
+						next_lit = nl;
+						/* make a previous short run */
+						lit += 3;
+						*litp = (unsigned char)((*litp & ~3) | lit);
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-3,m_pos,pd(op,m_pos));
+						o_m3_a++;
+					}
+					/* test if a literal run follows */
+					else if (t == 1 && lit <= 3 && nl == 0
+					 && ip[0] < 16 && ip[0] != 0 && (lit + 3 + ip[0] < 16)
+					) {
+						t = *ip++;
+						/* remove short run */
+						*litp &= ~3;
+						/* copy over the 3 literals that replace the match */
+						copy3(ip-4+1,m_pos,pd(op,m_pos));
+						/* move literals 1 byte ahead */
+						litp += 2;
+						if (lit > 0)
+							memmove(litp+1,litp,lit);
+						/* insert new length of long literal run */
+						lit += 3 + t + 3;
+						*litp = (unsigned char)(lit - 3);
+
+						o_m3_b++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						*op++ = *m_pos++;
+						goto copy_literal_run;
+					}
+				}
+ copy_m:
+				*op++ = *m_pos++;
+				*op++ = *m_pos++;
+				do *op++ = *m_pos++; while (--t > 0);
+			}
+
+ match_done:
+			if (next_lit == NO_LIT) {
+				t = ip[-2] & 3;
+				lit = t;
+				litp = ip - 2;
+			}
+			else
+				t = next_lit;
+			next_lit = NO_LIT;
+			if (t == 0)
+				break;
+			/* copy literals */
+ match_next:
+			do *op++ = *ip++; while (--t > 0);
+			t = *ip++;
+		} while (TEST_IP && TEST_OP);
+	}
+
+	/* no EOF code was found */
+	*out_len = pd(op, out);
+	return LZO_E_EOF_NOT_FOUND;
+
+ eof_found:
+//	  LZO_UNUSED(o_m1_a); LZO_UNUSED(o_m1_b); LZO_UNUSED(o_m2);
+//	  LZO_UNUSED(o_m3_a); LZO_UNUSED(o_m3_b);
+	*out_len = pd(op, out);
+	return (ip == ip_end ? LZO_E_OK :
+		   (ip < ip_end	 ? LZO_E_INPUT_NOT_CONSUMED : LZO_E_INPUT_OVERRUN));
+}
+
+/**********************************************************************/
+#define F_OS F_OS_UNIX
+#define F_CS F_CS_NATIVE
+
+/**********************************************************************/
+#define ADLER32_INIT_VALUE 1
+#define CRC32_INIT_VALUE   0
+
+/**********************************************************************/
+enum {
+	M_LZO1X_1    = 1,
+	M_LZO1X_1_15 = 2,
+	M_LZO1X_999  = 3,
+};
+
+/**********************************************************************/
+/* header flags */
+#define F_ADLER32_D     0x00000001L
+#define F_ADLER32_C     0x00000002L
+#define F_H_EXTRA_FIELD 0x00000040L
+#define F_H_GMTDIFF     0x00000080L
+#define F_CRC32_D       0x00000100L
+#define F_CRC32_C       0x00000200L
+#define F_H_FILTER      0x00000800L
+#define F_H_CRC32       0x00001000L
+#define F_MASK          0x00003FFFL
+
+/* operating system & file system that created the file [mostly unused] */
+#define F_OS_UNIX       0x03000000L
+#define F_OS_SHIFT      24
+#define F_OS_MASK       0xff000000L
+
+/* character set for file name encoding [mostly unused] */
+#define F_CS_NATIVE     0x00000000L
+#define F_CS_SHIFT      20
+#define F_CS_MASK       0x00f00000L
+
+/* these bits must be zero */
+#define F_RESERVED      ((F_MASK | F_OS_MASK | F_CS_MASK) ^ 0xffffffffL)
+
+typedef struct chksum_t {
+	uint32_t f_adler32;
+	uint32_t f_crc32;
+} chksum_t;
+
+typedef struct header_t {
+	unsigned version;
+	unsigned lib_version;
+	unsigned version_needed_to_extract;
+	uint32_t flags;
+	uint32_t mode;
+	uint32_t mtime;
+	uint32_t gmtdiff;
+	uint32_t header_checksum;
+
+	uint32_t extra_field_len;
+	uint32_t extra_field_checksum;
+
+	unsigned char method;
+	unsigned char level;
+
+	/* info */
+	char name[255+1];
+} header_t;
+
+struct globals {
+	const uint32_t *lzo_crc32_table;
+	chksum_t chksum_in;
+	chksum_t chksum_out;
+};
+#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)
+
+
+/**********************************************************************/
+#define LZOP_VERSION            0x1010
+//#define LZOP_VERSION_STRING     "1.01"
+//#define LZOP_VERSION_DATE       "Apr 27th 2003"
+
+#define OPTION_STRING "cfvdt123456789CF"
+
+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),
+};
+
+/**********************************************************************/
+// adler32 checksum
+// adapted from free code by Mark Adler 
+// see http://www.zlib.org/
+/**********************************************************************/
+static FAST_FUNC uint32_t
+lzo_adler32(uint32_t adler, const uint8_t* buf, unsigned len)
+{
+	enum {
+		LZO_BASE = 65521, /* largest prime smaller than 65536 */
+		/* NMAX is the largest n such that
+		 * 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */
+		LZO_NMAX = 5552,
+	};
+	uint32_t s1 = adler & 0xffff;
+	uint32_t s2 = (adler >> 16) & 0xffff;
+	unsigned k;
+
+	if (buf == NULL)
+		return 1;
+
+	while (len > 0) {
+		k = len < LZO_NMAX ? (unsigned) len : LZO_NMAX;
+		len -= k;
+		if (k != 0) do {
+			s1 += *buf++;
+			s2 += s1;
+		} while (--k > 0);
+		s1 %= LZO_BASE;
+		s2 %= LZO_BASE;
+	}
+	return (s2 << 16) | s1;
+}
+
+static FAST_FUNC uint32_t
+lzo_crc32(uint32_t c, const uint8_t* buf, unsigned len)
+{
+	uint32_t crc;
+
+	if (buf == NULL)
+		return 0;
+
+	crc = ~c;
+	if (len != 0) do {
+	crc = G.lzo_crc32_table[((int)crc ^ *buf) & 0xff] ^ (crc >> 8);
+		buf += 1;
+		len -= 1;
+	} while (len > 0);
+
+	return ~crc;
+}
+
+/**********************************************************************/
+static void init_chksum(chksum_t *ct)
+{
+	ct->f_adler32 = ADLER32_INIT_VALUE;
+	ct->f_crc32 = CRC32_INIT_VALUE;
+}
+
+static void add_bytes_to_chksum(chksum_t *ct, const void* buf, int cnt)
+{
+	/* We need to handle the two checksums at once, because at the
+	 * beginning of the header, we don't know yet which one we'll
+	 * eventually need */
+	ct->f_adler32 = lzo_adler32(ct->f_adler32, (const uint8_t*)buf, cnt);
+	ct->f_crc32 = lzo_crc32(ct->f_crc32, (const uint8_t*)buf, cnt);
+}
+
+static uint32_t chksum_getresult(chksum_t *ct, const header_t *h)
+{
+	return (h->flags & F_H_CRC32) ? ct->f_crc32 : ct->f_adler32;
+}
+
+/**********************************************************************/
+static uint32_t read32(void)
+{
+	uint32_t v;
+	xread(0, &v, 4);
+	return ntohl(v);
+}
+
+static void write32(uint32_t v)
+{
+	v = htonl(v);
+	xwrite(1, &v, 4);
+}
+
+static void f_write(const void* buf, int cnt)
+{
+	xwrite(1, buf, cnt);
+	add_bytes_to_chksum(&G.chksum_out, buf, cnt);
+}
+
+static void f_read(void* buf, int cnt)
+{
+	xread(0, buf, cnt);
+	add_bytes_to_chksum(&G.chksum_in, buf, cnt);
+}
+
+static int f_read8(void)
+{
+	uint8_t v;
+	f_read(&v, 1);
+	return v;
+}
+
+static void f_write8(uint8_t v)
+{
+	f_write(&v, 1);
+}
+
+static unsigned f_read16(void)
+{
+	uint16_t v;
+	f_read(&v, 2);
+	return ntohs(v);
+}
+
+static void f_write16(uint16_t v)
+{
+	v = htons(v);
+	f_write(&v, 2);
+}
+
+static uint32_t f_read32(void)
+{
+	uint32_t v;
+	f_read(&v, 4);
+	return ntohl(v);
+}
+
+static void f_write32(uint32_t v)
+{
+	v = htonl(v);
+	f_write(&v, 4);
+}
+
+/**********************************************************************/
+static int lzo_get_method(header_t *h)
+{
+	/* check method */
+	if (h->method == M_LZO1X_1) {
+		if (h->level == 0)
+			h->level = 3;
+	} else if (h->method == M_LZO1X_1_15) {
+		if (h->level == 0)
+			h->level = 1;
+	} else if (h->method == M_LZO1X_999) {
+		if (h->level == 0)
+			h->level = 9;
+	} else
+		return -1;		/* not a LZO method */
+
+	/* check compression level */
+	if (h->level < 1 || h->level > 9)
+		return 15;
+
+	return 0;
+}
+
+/**********************************************************************/
+#define LZO_BLOCK_SIZE	(256 * 1024l)
+#define MAX_BLOCK_SIZE	(64 * 1024l * 1024l)	/* DO NOT CHANGE */
+
+/* LZO may expand uncompressible data by a small amount */
+#define MAX_COMPRESSED_SIZE(x)	((x) + (x) / 16 + 64 + 3)
+
+/**********************************************************************/
+// compress a file
+/**********************************************************************/
+static smallint lzo_compress(const header_t *h)
+{
+	unsigned block_size = LZO_BLOCK_SIZE;
+	int r = 0; /* LZO_E_OK */
+	uint8_t *const b1 = xzalloc(block_size);
+	uint8_t *const b2 = xzalloc(MAX_COMPRESSED_SIZE(block_size));
+	unsigned src_len = 0, dst_len = 0;
+	uint32_t d_adler32 = ADLER32_INIT_VALUE;
+	uint32_t d_crc32 = CRC32_INIT_VALUE;
+	int l;
+	smallint ok = 1;
+	uint8_t *wrk_mem = NULL;
+
+	if (h->method == M_LZO1X_1)
+		wrk_mem = xzalloc(LZO1X_1_MEM_COMPRESS);
+	else if (h->method == M_LZO1X_1_15)
+		wrk_mem = xzalloc(LZO1X_1_15_MEM_COMPRESS);
+	else if (h->method == M_LZO1X_999)
+		wrk_mem = xzalloc(LZO1X_999_MEM_COMPRESS);
+
+	for (;;) {
+		/* read a block */
+		l = full_read(0, b1, block_size);
+		src_len = (l > 0 ? l : 0);
+
+		/* write uncompressed block size */
+		write32(src_len);
+
+		/* exit if last block */
+		if (src_len == 0)
+			break;
+
+		/* compute checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			d_adler32 = lzo_adler32(ADLER32_INIT_VALUE, b1, src_len);
+		if (h->flags & F_CRC32_D)
+			d_crc32 = lzo_crc32(CRC32_INIT_VALUE, b1, src_len);
+
+		/* compress */
+		if (h->method == M_LZO1X_1)
+			r = lzo1x_1_compress(b1, src_len, b2, &dst_len, wrk_mem);
+		else if (h->method == M_LZO1X_1_15)
+			r = lzo1x_1_15_compress(b1, src_len, b2, &dst_len, wrk_mem);
+#if ENABLE_LZOP_COMPR_HIGH
+		else if (h->method == M_LZO1X_999)
+			r = lzo1x_999_compress_level(b1, src_len, b2, &dst_len,
+						wrk_mem, h->level);
+#endif
+		else
+			bb_error_msg_and_die("internal error");
+
+		if (r != 0) /* not LZO_E_OK */
+			bb_error_msg_and_die("internal error - compression failed");
+
+		/* write compressed block size */
+		if (dst_len < src_len) {
+			/* optimize */
+			if (h->method == M_LZO1X_999) {
+				unsigned new_len = src_len;
+				r = lzo1x_optimize(b2, dst_len, b1, &new_len, NULL);
+				if (r != 0 /*LZO_E_OK*/ || new_len != src_len)
+					bb_error_msg_and_die("internal error - optimization failed");
+			}
+			write32(dst_len);
+		} else {
+			/* data actually expanded => store data uncompressed */
+			write32(src_len);
+		}
+
+		/* write checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			write32(d_adler32);
+		if (h->flags & F_CRC32_D)
+			write32(d_crc32);
+
+		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));
+			if (h->flags & F_CRC32_C)
+				write32(lzo_crc32(CRC32_INIT_VALUE, b2, dst_len));
+			/* write compressed block data */
+			xwrite(1, b2, dst_len);
+		} else {
+			/* write uncompressed block data */
+			xwrite(1, b1, src_len);
+		}
+	}
+
+	free(wrk_mem);
+	free(b1);
+	free(b2);
+	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)
+{
+	uint32_t c = fn(init, buf, len);
+	if (c != ref)
+		bb_error_msg_and_die("checksum error");
+}
+
+/**********************************************************************/
+// decompress a file
+/**********************************************************************/
+static smallint lzo_decompress(const header_t *h)
+{
+	unsigned block_size = LZO_BLOCK_SIZE;
+	int r;
+	uint32_t src_len, dst_len;
+	uint32_t c_adler32 = ADLER32_INIT_VALUE;
+	uint32_t d_adler32 = ADLER32_INIT_VALUE;
+	uint32_t c_crc32 = CRC32_INIT_VALUE, d_crc32 = CRC32_INIT_VALUE;
+	smallint ok = 1;
+	uint8_t *b1;
+	uint32_t mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+	uint8_t *b2 = NULL;
+
+	for (;;) {
+		uint8_t *dst;
+
+		/* read uncompressed block size */
+		dst_len = read32();
+
+		/* exit if last block */
+		if (dst_len == 0)
+			break;
+
+		/* error if split file */
+		if (dst_len == 0xffffffffL)
+			/* should not happen - not yet implemented */
+			bb_error_msg_and_die("this file is a split lzop file");
+
+		if (dst_len > MAX_BLOCK_SIZE)
+			bb_error_msg_and_die("lzop file corrupted");
+
+		/* read compressed block size */
+		src_len = read32();
+		if (src_len <= 0 || src_len > dst_len)
+			bb_error_msg_and_die("lzop file corrupted");
+
+		if (dst_len > block_size) {
+			if (b2) {
+//FIXME!
+				b2 = NULL;
+				free(b2);
+			}
+			block_size = dst_len;
+			mcs_block_size = MAX_COMPRESSED_SIZE(block_size);
+		}
+
+		/* read checksum of uncompressed block */
+		if (h->flags & F_ADLER32_D)
+			d_adler32 = read32();
+		if (h->flags & F_CRC32_D)
+			d_crc32 = read32();
+
+		/* read checksum of compressed block */
+		if (src_len < dst_len) {
+			if (h->flags & F_ADLER32_C)
+				c_adler32 = read32();
+			if (h->flags & F_CRC32_C)
+				c_crc32 = read32();
+		}
+
+		if (b2 == NULL)
+			b2 = xzalloc(mcs_block_size);
+		/* read the block into the end of our buffer */
+		b1 = b2 + mcs_block_size - src_len;
+		xread(0, b1, src_len);
+
+		if (src_len < dst_len) {
+			unsigned d = dst_len;
+
+			if (!(option_mask32 & OPT_F)) {
+				/* verify checksum of compressed block */
+				if (h->flags & F_ADLER32_C)
+					lzo_check(lzo_adler32, c_adler32,
+							ADLER32_INIT_VALUE,
+							b1, src_len);
+				if (h->flags & F_CRC32_C)
+					lzo_check(lzo_crc32, c_crc32,
+							CRC32_INIT_VALUE,
+							b1, src_len);
+			}
+
+			/* decompress */
+//			if (option_mask32 & OPT_F)
+//				r = lzo1x_decompress(b1, src_len, b2, &d, NULL);
+//			else
+				r = lzo1x_decompress_safe(b1, src_len, b2, &d, NULL);
+
+			if (r != 0 /*LZO_E_OK*/ || dst_len != d) {
+				bb_error_msg_and_die("corrupted compressed data");
+			}
+			dst = b2;
+		} else {
+			/* "stored" block => no decompression */
+			dst = b1;
+		}
+
+		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);
+			if (h->flags & F_CRC32_D)
+				lzo_check(lzo_crc32, d_crc32, CRC32_INIT_VALUE,
+					  dst, dst_len);
+		}
+
+		/* write uncompressed block data */
+		xwrite(1, dst, dst_len);
+	}
+
+	free(b2);
+	return ok;
+}
+
+/**********************************************************************/
+// lzop file signature (shamelessly borrowed from PNG)
+/**********************************************************************/
+/*
+ * The first nine bytes of a lzop file always contain the following values:
+ *
+ *                                 0   1   2   3   4   5   6   7   8
+ *                               --- --- --- --- --- --- --- --- ---
+ * (hex)                          89  4c  5a  4f  00  0d  0a  1a  0a
+ * (decimal)                     137  76  90  79   0  13  10  26  10
+ * (C notation - ASCII)         \211   L   Z   O  \0  \r  \n \032 \n
+ */
+
+/* (vda) comparison with lzop v1.02rc1 ("lzop -1 version);
+	f_write16(h->lib_version);
+	f_write16(h->version_needed_to_extract);
+	f_write8(h->method);
+	f_write8(h->level);
+	f_write32(h->flags);
+	f_write32(h->mode);
+	f_write32(h->mtime);
+	f_write32(h->gmtdiff);
+
+	l = (int) strlen(h->name);
+	f_write8(l);
+	if (l)
+		f_write(h->name, l);
+
+	f_write32(chksum_getresult(&G.chksum_out, h));
+}
+
+static int read_header(header_t *h)
+{
+	int r;
+	int l;
+	uint32_t checksum;
+
+	memset(h, 0, sizeof(*h));
+	h->version_needed_to_extract = 0x0900;	/* first lzop version */
+	h->level = 0;
+
+	init_chksum(&G.chksum_in);
+
+	h->version = f_read16();
+	if (h->version < 0x0900)
+		return 3;
+	h->lib_version = f_read16();
+	if (h->version >= 0x0940) {
+		h->version_needed_to_extract = f_read16();
+		if (h->version_needed_to_extract > LZOP_VERSION)
+			return 16;
+		if (h->version_needed_to_extract < 0x0900)
+			return 3;
+	}
+	h->method = f_read8();
+	if (h->version >= 0x0940)
+		h->level = f_read8();
+	h->flags = f_read32();
+	if (h->flags & F_H_FILTER)
+		return 16; /* filter not supported */
+	h->mode = f_read32();
+	h->mtime = f_read32();
+	if (h->version >= 0x0940)
+		h->gmtdiff = f_read32();
+
+	l = f_read8();
+	if (l > 0)
+		f_read(h->name, l);
+	h->name[l] = 0;
+
+	checksum = chksum_getresult(&G.chksum_in, h);
+	h->header_checksum = f_read32();
+	if (h->header_checksum != checksum)
+		return 2;
+
+	if (h->method <= 0)
+		return 14;
+	r = lzo_get_method(h);
+	if (r != 0)
+		return r;
+
+	/* check reserved flags */
+	if (h->flags & F_RESERVED)
+		return -13;
+
+	/* skip extra field [not used yet] */
+	if (h->flags & F_H_EXTRA_FIELD) {
+		uint32_t k;
+		
+		/* note: the checksum also covers the length */
+		init_chksum(&G.chksum_in);
+		h->extra_field_len = f_read32();
+		for (k = 0; k < h->extra_field_len; k++)
+			f_read8();
+		checksum = chksum_getresult(&G.chksum_in, h);
+		h->extra_field_checksum = f_read32();
+		if (h->extra_field_checksum != checksum)
+			return 3;
+	}
+
+	return 0;
+}
+
+static void p_header(header_t *h)
+{
+	int r;
+
+	r = read_header(h);
+	if (r == 0)
+		return;
+	bb_error_msg_and_die("header_error %d", r);
+}
+
+/**********************************************************************/
+// compress
+/**********************************************************************/
+static void lzo_set_method(header_t *h)
+{
+	int level = 1;
+
+	if (option_mask32 & OPT_1) {
+		h->method = M_LZO1X_1_15;
+	} else if (option_mask32 & OPT_789) {
+#if ENABLE_LZOP_COMPR_HIGH
+		h->method = M_LZO1X_999;
+		if (option_mask32 & OPT_7)
+			level = 7;
+		else if (option_mask32 & OPT_8)
+			level = 8;
+		else
+			level = 9;
+#else
+		bb_error_msg_and_die("high compression not compiled in");
+#endif
+	} else { /* levels 2..6 or none (defaults to level 3) */
+		h->method = M_LZO1X_1;
+		level = 5; /* levels 2-6 are actually the same */
+	}
+
+	h->level = level;
+}
+
+static smallint do_lzo_compress(void)
+{
+	header_t header;
+
+#define h (&header)
+	memset(h, 0, sizeof(*h));
+
+	lzo_set_method(h);
+
+	h->version = (LZOP_VERSION & 0xffff);
+	h->version_needed_to_extract = 0x0940;
+	h->lib_version = lzo_version() & 0xffff;
+
+	h->flags = (F_OS & F_OS_MASK) | (F_CS & F_CS_MASK);
+
+	if (!(option_mask32 & OPT_F) || h->method == M_LZO1X_999) {
+		h->flags |= F_ADLER32_D;
+		if (option_mask32 & OPT_C)
+			h->flags |= F_ADLER32_C;
+	}
+	write_header(h);
+	return lzo_compress(h);
+#undef h
+}
+
+/**********************************************************************/
+// decompress
+/**********************************************************************/
+static smallint do_lzo_decompress(void)
+{
+	header_t header;
+	
+	check_magic();
+	p_header(&header);
+	return lzo_decompress(&header);
+}
+
+static char* make_new_name_lzop(char *filename)
+{
+	if (option_mask32 & OPT_DECOMPRESS) {
+		char *extension = strrchr(filename, '.');
+		if (!extension || strcmp(extension + 1, "lzo") != 0)
+			return xasprintf("%s.out", filename);
+		*extension = '\0';
+		return filename;
+	}
+	return xasprintf("%s.lzo", filename);
+}
+
+static IF_DESKTOP(long long) int pack_lzop(unpack_info_t *info UNUSED_PARAM)
+{
+	if (option_mask32 & OPT_DECOMPRESS)
+		return do_lzo_decompress();
+	return do_lzo_compress();
+}
+
+int lzop_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int lzop_main(int argc UNUSED_PARAM, char **argv)
+{
+	getopt32(argv, OPTION_STRING);
+	argv += optind;
+	/* lzopcat? */
+	if (applet_name[4] == 'c')
+		option_mask32 |= (OPT_STDOUT | OPT_DECOMPRESS);
+	/* unlzop? */
+	if (applet_name[0] == 'u')
+		option_mask32 |= OPT_DECOMPRESS;
+
+	G.lzo_crc32_table = crc32_filltable(NULL, 0);
+	return bbunpack(argv, make_new_name_lzop, pack_lzop);
+}
Index: archival/Kbuild
===================================================================
--- archival/Kbuild	(revision 26238)
+++ archival/Kbuild	(revision 26239)
@@ -16,6 +16,8 @@
 lib-$(CONFIG_DPKG_DEB)		+= dpkg_deb.o
 lib-$(CONFIG_GUNZIP)		+= bbunzip.o
 lib-$(CONFIG_GZIP)		+= gzip.o bbunzip.o
+lib-$(CONFIG_LZOP)		+= lzop.o lzo1x_1.o lzo1x_1o.o lzo1x_d.o
+lib-$(CONFIG_LZOP_COMPR_HIGH)	+= lzo1x_9x.o
 lib-$(CONFIG_RPM2CPIO)		+= rpm2cpio.o
 lib-$(CONFIG_RPM)		+= rpm.o
 lib-$(CONFIG_TAR)		+= tar.o
Index: archival/Config.in
===================================================================
--- archival/Config.in	(revision 26238)
+++ archival/Config.in	(revision 26239)
@@ -165,6 +165,21 @@
 	  gzip is used to compress files.
 	  It's probably the most widely used UNIX compression program.
 
+config LZOP
+	bool "lzop"
+	default n
+	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 n
Index: archival/lzo1x_1.c
===================================================================
--- archival/lzo1x_1.c	(revision 0)
+++ archival/lzo1x_1.c	(revision 26239)
@@ -0,0 +1,35 @@
+/* LZO1X-1 compression
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 1996..2008 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   Markus F.X.J. Oberhumer 
+   http://www.oberhumer.com/opensource/lzo/
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+#include "libbb.h"
+#include "liblzo.h"
+
+#define D_BITS          14
+#define D_INDEX1(d,p)   d = DM(DMUL(0x21,DX3(p,5,5,6)) >> 5)
+#define D_INDEX2(d,p)   d = (d & (D_MASK & 0x7ff)) ^ (D_HIGH | 0x1f)
+
+#define DO_COMPRESS     lzo1x_1_compress
+
+#include "lzo1x_c.c"
Index: archival/lzo1x_9x.c
===================================================================
--- archival/lzo1x_9x.c	(revision 0)
+++ archival/lzo1x_9x.c	(revision 26239)
@@ -0,0 +1,920 @@
+/* lzo1x_9x.c -- implementation of the LZO1X-999 compression algorithm
+
+   This file is part of the LZO real-time data compression library.
+
+   Copyright (C) 2008 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2007 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2006 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2005 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2004 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2003 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2002 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2001 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 2000 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1999 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1998 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1997 Markus Franz Xaver Johannes Oberhumer
+   Copyright (C) 1996 Markus Franz Xaver Johannes Oberhumer
+   All Rights Reserved.
+
+   The LZO library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2 of
+   the License, or (at your option) any later version.
+
+   The LZO library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with the LZO library; see the file COPYING.
+   If not, write to the Free Software Foundation, Inc.,
+   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+   Markus F.X.J. Oberhumer
+   
+   http://www.oberhumer.com/opensource/lzo/
+*/
+#include "libbb.h"
+
+/* The following is probably only safe on Intel-compatible processors ... */
+#define LZO_UNALIGNED_OK_2
+#define LZO_UNALIGNED_OK_4
+
+#include "liblzo.h"
+
+#define LZO_MAX(a,b)        ((a) >= (b) ? (a) : (b))
+#define LZO_MIN(a,b)        ((a) <= (b) ? (a) : (b))
+#define LZO_MAX3(a,b,c)     ((a) >= (b) ? LZO_MAX(a,c) : LZO_MAX(b,c))
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_N           M4_MAX_OFFSET   /* size of ring buffer */
+#define SWD_F           2048           /* upper limit for match length */
+
+#define SWD_BEST_OFF    (LZO_MAX3(M2_MAX_LEN, M3_MAX_LEN, M4_MAX_LEN) + 1)
+
+typedef struct {
+	int init;
+
+	unsigned look;          /* bytes in lookahead buffer */
+
+	unsigned m_len;
+	unsigned m_off;
+
+	const uint8_t *bp;
+	const uint8_t *ip;
+	const uint8_t *in;
+	const uint8_t *in_end;
+	uint8_t *out;
+
+	unsigned r1_lit;
+
+} lzo1x_999_t;
+
+#define getbyte(c)  ((c).ip < (c).in_end ? *((c).ip)++ : (-1))
+
+/* lzo_swd.c -- sliding window dictionary */
+
+/***********************************************************************
+//
+************************************************************************/
+#define SWD_UINT_MAX      USHRT_MAX
+
+#ifndef SWD_HSIZE
+#  define SWD_HSIZE         16384
+#endif
+#ifndef SWD_MAX_CHAIN
+#  define SWD_MAX_CHAIN     2048
+#endif
+
+#define HEAD3(b, p) \
+	( ((0x9f5f * ((((b[p]<<5)^b[p+1])<<5) ^ b[p+2])) >> 5) & (SWD_HSIZE-1) )
+
+#if defined(LZO_UNALIGNED_OK_2)
+#  define HEAD2(b,p)      (* (uint16_t *) &(b[p]))
+#else
+#  define HEAD2(b,p)      (b[p] ^ ((unsigned)b[p+1]<<8))
+#endif
+#define NIL2              SWD_UINT_MAX
+
+typedef struct lzo_swd {
+	/* public - "built-in" */
+
+	/* public - configuration */
+	unsigned max_chain;
+	int use_best_off;
+
+	/* public - output */
+	unsigned m_len;
+	unsigned m_off;
+	unsigned look;
+	int b_char;
+#if defined(SWD_BEST_OFF)
+	unsigned best_off[SWD_BEST_OFF];
+#endif
+
+	/* semi public */
+	lzo1x_999_t *c;
+	unsigned m_pos;
+#if defined(SWD_BEST_OFF)
+	unsigned best_pos[SWD_BEST_OFF];
+#endif
+
+	/* private */
+	unsigned ip;                /* input pointer (lookahead) */
+	unsigned bp;                /* buffer pointer */
+	unsigned rp;                /* remove pointer */
+
+	unsigned node_count;
+	unsigned first_rp;
+
+	uint8_t b[SWD_N + SWD_F];
+	uint8_t b_wrap[SWD_F]; /* must follow b */
+	uint16_t head3[SWD_HSIZE];
+	uint16_t succ3[SWD_N + SWD_F];
+	uint16_t best3[SWD_N + SWD_F];
+	uint16_t llen3[SWD_HSIZE];
+#ifdef HEAD2
+	uint16_t head2[65536L];
+#endif
+} lzo_swd_t, *lzo_swd_p;
+
+#define SIZEOF_LZO_SWD_T    (sizeof(lzo_swd_t))
+
+
+/* Access macro for head3.
+ * head3[key] may be uninitialized, but then its value will never be used.
+ */
+#define s_get_head3(s,key)    s->head3[key]
+
+
+/***********************************************************************
+//
+************************************************************************/
+#define B_SIZE (SWD_N + SWD_F)
+
+static int swd_init(lzo_swd_p s)
+{
+	/* defaults */
+	s->node_count = SWD_N;
+
+	memset(s->llen3, 0, sizeof(s->llen3[0]) * (unsigned)SWD_HSIZE);
+#ifdef HEAD2
+	memset(s->head2, 0xff, sizeof(s->head2[0]) * 65536L);
+	assert(s->head2[0] == NIL2);
+#endif
+
+	s->ip = 0;
+	s->bp = s->ip;
+	s->first_rp = s->ip;
+
+	assert(s->ip + SWD_F <= B_SIZE);
+	s->look = (unsigned) (s->c->in_end - s->c->ip);
+	if (s->look > 0) {
+		if (s->look > SWD_F)
+			s->look = SWD_F;
+		memcpy(&s->b[s->ip],s->c->ip,s->look);
+		s->c->ip += s->look;
+		s->ip += s->look;
+	}
+	if (s->ip == B_SIZE)
+		s->ip = 0;
+
+	s->rp = s->first_rp;
+	if (s->rp >= s->node_count)
+		s->rp -= s->node_count;
+	else
+		s->rp += B_SIZE - s->node_count;
+
+	return LZO_E_OK;
+}
+
+#define swd_pos2off(s,pos) \
+	(s->bp > (pos) ? s->bp - (pos) : B_SIZE - ((pos) - s->bp))
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_getbyte(lzo_swd_p s)
+{
+	int c;
+
+	if ((c = getbyte(*(s->c))) < 0) {
+		if (s->look > 0)
+			--s->look;
+	} else {
+		s->b[s->ip] = c;
+		if (s->ip < SWD_F)
+			s->b_wrap[s->ip] = c;
+	}
+	if (++s->ip == B_SIZE)
+		s->ip = 0;
+	if (++s->bp == B_SIZE)
+		s->bp = 0;
+	if (++s->rp == B_SIZE)
+		s->rp = 0;
+}
+
+
+/***********************************************************************
+// remove node from lists
+************************************************************************/
+static void swd_remove_node(lzo_swd_p s, unsigned node)
+{
+	if (s->node_count == 0) {
+		unsigned key;
+
+		key = HEAD3(s->b,node);
+		assert(s->llen3[key] > 0);
+		--s->llen3[key];
+
+#ifdef HEAD2
+		key = HEAD2(s->b,node);
+		assert(s->head2[key] != NIL2);
+		if ((unsigned) s->head2[key] == node)
+			s->head2[key] = NIL2;
+#endif
+	} else
+		--s->node_count;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_accept(lzo_swd_p s, unsigned n)
+{
+	assert(n <= s->look);
+
+	while (n--) {
+		unsigned key;
+
+		swd_remove_node(s,s->rp);
+
+		/* add bp into HEAD3 */
+		key = HEAD3(s->b,s->bp);
+		s->succ3[s->bp] = s_get_head3(s,key);
+		s->head3[key] = s->bp;
+		s->best3[s->bp] = SWD_F + 1;
+		s->llen3[key]++;
+		assert(s->llen3[key] <= SWD_N);
+
+#ifdef HEAD2
+		/* add bp into HEAD2 */
+		key = HEAD2(s->b,s->bp);
+		s->head2[key] = s->bp;
+#endif
+
+		swd_getbyte(s);
+	}
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_search(lzo_swd_p s, unsigned node, unsigned cnt)
+{
+	const uint8_t *p1;
+	const uint8_t *p2;
+	const uint8_t *px;
+	unsigned m_len = s->m_len;
+	const uint8_t *b  = s->b;
+	const uint8_t *bp = s->b + s->bp;
+	const uint8_t *bx = s->b + s->bp + s->look;
+	unsigned char scan_end1;
+
+	assert(s->m_len > 0);
+
+	scan_end1 = bp[m_len - 1];
+	for ( ; cnt-- > 0; node = s->succ3[node]) {
+		p1 = bp;
+		p2 = b + node;
+		px = bx;
+
+		assert(m_len < s->look);
+
+		if (p2[m_len - 1] == scan_end1 &&
+		    p2[m_len] == p1[m_len] &&
+		    p2[0] == p1[0] &&
+		    p2[1] == p1[1]) {
+			unsigned i;
+			assert(lzo_memcmp(bp,&b[node],3) == 0);
+				
+			p1 += 2; p2 += 2;
+			do {} while (++p1 < px && *p1 == *++p2);
+			i = p1-bp;
+
+			assert(lzo_memcmp(bp,&b[node],i) == 0);
+
+#if defined(SWD_BEST_OFF)
+			if (i < SWD_BEST_OFF) {
+				if (s->best_pos[i] == 0)
+					s->best_pos[i] = node + 1;
+			}
+#endif
+			if (i > m_len) {
+				s->m_len = m_len = i;
+				s->m_pos = node;
+				if (m_len == s->look)
+					return;
+				if (m_len >= SWD_F)
+					return;
+				if (m_len > (unsigned) s->best3[node])
+					return;
+				scan_end1 = bp[m_len - 1];
+			}
+		}
+	}
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#ifdef HEAD2
+
+static int swd_search2(lzo_swd_p s)
+{
+	unsigned key;
+
+	assert(s->look >= 2);
+	assert(s->m_len > 0);
+
+	key = s->head2[ HEAD2(s->b,s->bp) ];
+	if (key == NIL2)
+		return 0;
+	assert(lzo_memcmp(&s->b[s->bp],&s->b[key],2) == 0);
+#if defined(SWD_BEST_OFF)
+	if (s->best_pos[2] == 0)
+		s->best_pos[2] = key + 1;
+#endif
+
+	if (s->m_len < 2) {
+		s->m_len = 2;
+		s->m_pos = key;
+	}
+	return 1;
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static void swd_findbest(lzo_swd_p s)
+{
+	unsigned key;
+	unsigned cnt, node;
+	unsigned len;
+
+	assert(s->m_len > 0);
+
+	/* get current head, add bp into HEAD3 */
+	key = HEAD3(s->b,s->bp);
+	node = s->succ3[s->bp] = s_get_head3(s,key);
+	cnt = s->llen3[key]++;
+	assert(s->llen3[key] <= SWD_N + SWD_F);
+	if (cnt > s->max_chain)
+		cnt = s->max_chain;
+	s->head3[key] = s->bp;
+
+	s->b_char = s->b[s->bp];
+	len = s->m_len;
+	if (s->m_len >= s->look) {
+		if (s->look == 0)
+			s->b_char = -1;
+		s->m_off = 0;
+		s->best3[s->bp] = SWD_F + 1;
+	} else {
+#ifdef HEAD2
+		if (swd_search2(s))
+#endif
+			if (s->look >= 3)
+				swd_search(s,node,cnt);
+		if (s->m_len > len)
+			s->m_off = swd_pos2off(s,s->m_pos);
+		s->best3[s->bp] = s->m_len;
+
+#if defined(SWD_BEST_OFF)
+		if (s->use_best_off) {
+			int i;
+			for (i = 2; i < SWD_BEST_OFF; i++)
+				if (s->best_pos[i] > 0)
+					s->best_off[i] = swd_pos2off(s,s->best_pos[i]-1);
+				else
+					s->best_off[i] = 0;
+		}
+#endif
+	}
+
+	swd_remove_node(s,s->rp);
+
+#ifdef HEAD2
+	/* add bp into HEAD2 */
+	key = HEAD2(s->b,s->bp);
+	s->head2[key] = s->bp;
+#endif
+}
+
+#undef HEAD3
+#undef HEAD2
+#undef s_get_head3
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int init_match(lzo1x_999_t *c, lzo_swd_p s, uint32_t use_best_off)
+{
+	int r;
+
+	assert(!c->init);
+	c->init = 1;
+
+	s->c = c;
+
+	r = swd_init(s);
+	if (r != 0)
+		return r;
+
+	s->use_best_off = use_best_off;
+	return r;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int find_match(lzo1x_999_t *c, lzo_swd_p s,
+		unsigned this_len, unsigned skip)
+{
+	assert(c->init);
+
+	if (skip > 0) {
+		assert(this_len >= skip);
+		swd_accept(s, this_len - skip);
+	} else {
+		assert(this_len <= 1);
+	}
+
+	s->m_len = 1;
+	s->m_len = 1;
+#ifdef SWD_BEST_OFF
+	if (s->use_best_off)
+		memset(s->best_pos,0,sizeof(s->best_pos));
+#endif
+	swd_findbest(s);
+	c->m_len = s->m_len;
+	c->m_off = s->m_off;
+
+	swd_getbyte(s);
+
+	if (s->b_char < 0) {
+		c->look = 0;
+		c->m_len = 0;
+	} else {
+		c->look = s->look + 1;
+	}
+	c->bp = c->ip - c->look;
+
+	return LZO_E_OK;
+}
+
+/* this is a public functions, but there is no prototype in a header file */
+static int lzo1x_999_compress_internal(const uint8_t *in , unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		unsigned good_length,
+		unsigned max_lazy,
+		unsigned max_chain,
+		uint32_t use_best_off);
+
+
+/***********************************************************************
+//
+************************************************************************/
+static uint8_t *code_match(lzo1x_999_t *c,
+		uint8_t *op, unsigned m_len, unsigned m_off)
+{
+	assert(op > c->out);
+	if (m_len == 2) {
+		assert(m_off <= M1_MAX_OFFSET);
+		assert(c->r1_lit > 0); assert(c->r1_lit < 4);
+		m_off -= 1;
+		*op++ = M1_MARKER | ((m_off & 3) << 2);
+		*op++ = m_off >> 2;
+	} else if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET) {
+		assert(m_len >= 3);
+		m_off -= 1;
+		*op++ = ((m_len - 1) << 5) | ((m_off & 7) << 2);
+		*op++ = m_off >> 3;
+		assert(op[-2] >= M2_MARKER);
+	} else if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && c->r1_lit >= 4) {
+		assert(m_len == 3);
+		assert(m_off > M2_MAX_OFFSET);
+		m_off -= 1 + M2_MAX_OFFSET;
+		*op++ = M1_MARKER | ((m_off & 3) << 2);
+		*op++ = m_off >> 2;
+	} else if (m_off <= M3_MAX_OFFSET) {
+		assert(m_len >= 3);
+		m_off -= 1;
+		if (m_len <= M3_MAX_LEN)
+			*op++ = M3_MARKER | (m_len - 2);
+		else {
+			m_len -= M3_MAX_LEN;
+			*op++ = M3_MARKER | 0;
+			while (m_len > 255)
+				{
+					m_len -= 255;
+					*op++ = 0;
+				}
+			assert(m_len > 0);
+			*op++ = m_len;
+		}
+		*op++ = m_off << 2;
+		*op++ = m_off >> 6;
+	} else {
+		unsigned k;
+
+		assert(m_len >= 3);
+		assert(m_off > 0x4000); assert(m_off <= 0xbfff);
+		m_off -= 0x4000;
+		k = (m_off & 0x4000) >> 11;
+		if (m_len <= M4_MAX_LEN)
+			*op++ = M4_MARKER | k | (m_len - 2);
+		else {
+			m_len -= M4_MAX_LEN;
+			*op++ = M4_MARKER | k | 0;
+			while (m_len > 255)
+				{
+					m_len -= 255;
+					*op++ = 0;
+				}
+			assert(m_len > 0);
+			*op++ = m_len;
+		}
+		*op++ = m_off << 2;
+		*op++ = m_off >> 6;
+	}
+
+	return op;
+}
+
+
+static uint8_t *STORE_RUN(lzo1x_999_t *c, uint8_t *op,
+		const uint8_t *ii, unsigned t)
+{
+	if (op == c->out && t <= 238) {
+		*op++ = 17 + t;
+	} else if (t <= 3) {
+		op[-2] |= t;
+	} else if (t <= 18) {
+		*op++ = t - 3;
+	} else {
+		unsigned tt = t - 18;
+
+		*op++ = 0;
+		while (tt > 255) {
+			tt -= 255;
+			*op++ = 0;
+		}
+		assert(tt > 0);
+		*op++ = tt;
+	}
+	do *op++ = *ii++; while (--t > 0);
+
+	return op;
+}
+
+
+static uint8_t *code_run(lzo1x_999_t *c, uint8_t *op, const uint8_t *ii,
+		unsigned lit)
+{
+	if (lit > 0) {
+		assert(m_len >= 2);
+		op = STORE_RUN(c,op,ii,lit);
+	} else {
+		assert(m_len >= 3);
+	}
+	c->r1_lit = lit;
+
+	return op;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int len_of_coded_match(unsigned m_len, unsigned m_off, unsigned lit)
+{
+	int n = 4;
+
+	if (m_len < 2)
+		return -1;
+	if (m_len == 2)
+		return (m_off <= M1_MAX_OFFSET && lit > 0 && lit < 4) ? 2 : -1;
+	if (m_len <= M2_MAX_LEN && m_off <= M2_MAX_OFFSET)
+		return 2;
+	if (m_len == M2_MIN_LEN && m_off <= MX_MAX_OFFSET && lit >= 4)
+		return 2;
+	if (m_off <= M3_MAX_OFFSET) {
+		if (m_len <= M3_MAX_LEN)
+			return 3;
+		m_len -= M3_MAX_LEN;
+	} else if (m_off <= M4_MAX_OFFSET) {
+		if (m_len <= M4_MAX_LEN)
+			return 3;
+		m_len -= M4_MAX_LEN;
+	} else
+		return -1;
+	while (m_len > 255) {
+		m_len -= 255;
+		n++;
+	}
+	return n;
+}
+
+
+static int min_gain(unsigned ahead, unsigned lit1,
+		    unsigned lit2, int l1, int l2, int l3)
+{
+	int lazy_match_min_gain = 0;
+
+	assert (ahead >= 1);
+	lazy_match_min_gain += ahead;
+
+	if (lit1 <= 3)
+		lazy_match_min_gain += (lit2 <= 3) ? 0 : 2;
+	else if (lit1 <= 18)
+		lazy_match_min_gain += (lit2 <= 18) ? 0 : 1;
+
+	lazy_match_min_gain += (l2 - l1) * 2;
+	if (l3 > 0)
+		lazy_match_min_gain -= (ahead - l3) * 2;
+
+	if (lazy_match_min_gain < 0)
+		lazy_match_min_gain = 0;
+
+	return lazy_match_min_gain;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+#if defined(SWD_BEST_OFF)
+
+static void better_match(const lzo_swd_p swd,
+			   unsigned *m_len, unsigned *m_off)
+{
+
+	if (*m_len <= M2_MIN_LEN)
+		return;
+
+	if (*m_off <= M2_MAX_OFFSET)
+		return;
+
+	/* M3/M4 -> M2 */
+	if (*m_off > M2_MAX_OFFSET &&
+	    *m_len >= M2_MIN_LEN + 1 && *m_len <= M2_MAX_LEN + 1 &&
+	    swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M2_MAX_OFFSET)
+		{
+			*m_len = *m_len - 1;
+			*m_off = swd->best_off[*m_len];
+			return;
+		}
+
+	/* M4 -> M2 */
+	if (*m_off > M3_MAX_OFFSET &&
+	    *m_len >= M4_MAX_LEN + 1 && *m_len <= M2_MAX_LEN + 2 &&
+	    swd->best_off[*m_len-2] && swd->best_off[*m_len-2] <= M2_MAX_OFFSET)
+		{
+			*m_len = *m_len - 2;
+			*m_off = swd->best_off[*m_len];
+			return;
+		}
+	/* M4 -> M3 */
+	if (*m_off > M3_MAX_OFFSET &&
+	    *m_len >= M4_MAX_LEN + 1 && *m_len <= M3_MAX_LEN + 1 &&
+	    swd->best_off[*m_len-1] && swd->best_off[*m_len-1] <= M3_MAX_OFFSET)
+		{
+			*m_len = *m_len - 1;
+			*m_off = swd->best_off[*m_len];
+		}
+}
+
+#endif
+
+
+/***********************************************************************
+//
+************************************************************************/
+static int lzo1x_999_compress_internal(const uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		unsigned good_length,
+		unsigned max_lazy,
+		unsigned max_chain,
+		uint32_t use_best_off)
+{
+	uint8_t *op;
+	const uint8_t *ii;
+	unsigned lit;
+	unsigned m_len, m_off;
+	lzo1x_999_t cc;
+	lzo1x_999_t * const c = &cc;
+	lzo_swd_p const swd = (lzo_swd_p) wrkmem;
+	int r;
+
+	c->init = 0;
+	c->ip = c->in = in;
+	c->in_end = in + in_len;
+	c->out = out;
+
+	op = out;
+	ii = c->ip;             /* point to start of literal run */
+	lit = 0;
+	c->r1_lit = 0;
+
+	r = init_match(c, swd, use_best_off);
+	if (r != 0)
+		return r;
+	swd->max_chain = max_chain;
+
+	r = find_match(c, swd, 0, 0);
+	if (r != 0)
+		return r;
+
+	while (c->look > 0) {
+		unsigned ahead;
+		unsigned max_ahead;
+		int l1, l2, l3;
+
+		m_len = c->m_len;
+		m_off = c->m_off;
+
+		assert(c->bp == c->ip - c->look);
+		assert(c->bp >= in);
+		if (lit == 0)
+			ii = c->bp;
+		assert(ii + lit == c->bp);
+		assert(swd->b_char == *(c->bp));
+
+		if ( m_len < 2 ||
+		     (m_len == 2 && (m_off > M1_MAX_OFFSET || lit == 0 || lit >= 4)) ||
+		     /* Do not accept this match for compressed-data compatibility
+		      * with LZO v1.01 and before
+		      * [ might be a problem for decompress() and optimize() ]
+		      */
+		     (m_len == 2 && op == out) ||
+		     (op == out && lit == 0))
+			{
+				/* a literal */
+				m_len = 0;
+			}
+		else if (m_len == M2_MIN_LEN) {
+			/* compression ratio improves if we code a literal in some cases */
+			if (m_off > MX_MAX_OFFSET && lit >= 4)
+				m_len = 0;
+		}
+
+		if (m_len == 0) {
+			/* a literal */
+			lit++;
+			swd->max_chain = max_chain;
+			r = find_match(c,swd,1,0);
+			assert(r == 0);
+			continue;
+		}
+
+		/* a match */
+#if defined(SWD_BEST_OFF)
+		if (swd->use_best_off)
+			better_match(swd,&m_len,&m_off);
+#endif
+
+		/* shall we try a lazy match ? */
+		ahead = 0;
+		if (m_len >= max_lazy) {
+			/* no */
+			l1 = 0;
+			max_ahead = 0;
+		} else {
+			/* yes, try a lazy match */
+			l1 = len_of_coded_match(m_len,m_off,lit);
+			assert(l1 > 0);
+			max_ahead = LZO_MIN(2, (unsigned)l1 - 1);
+		}
+
+
+		while (ahead < max_ahead && c->look > m_len) {
+			int lazy_match_min_gain;
+
+			if (m_len >= good_length)
+				swd->max_chain = max_chain >> 2;
+			else
+				swd->max_chain = max_chain;
+			r = find_match(c,swd,1,0);
+			ahead++;
+
+			assert(r == 0);
+			assert(c->look > 0);
+			assert(ii + lit + ahead == c->bp);
+
+			if (c->m_len < m_len)
+				continue;
+			if (c->m_len == m_len && c->m_off >= m_off)
+				continue;
+#if defined(SWD_BEST_OFF)
+			if (swd->use_best_off)
+				better_match(swd,&c->m_len,&c->m_off);
+#endif
+			l2 = len_of_coded_match(c->m_len,c->m_off,lit+ahead);
+			if (l2 < 0)
+				continue;
+
+			/* compressed-data compatibility [see above] */
+			l3 = (op == out) ? -1 : len_of_coded_match(ahead,m_off,lit);
+
+			lazy_match_min_gain = min_gain(ahead,lit,lit+ahead,l1,l2,l3);
+			if (c->m_len >= m_len + lazy_match_min_gain) {
+				if (l3 > 0) {
+					/* code previous run */
+					op = code_run(c,op,ii,lit);
+					lit = 0;
+					/* code shortened match */
+					op = code_match(c,op,ahead,m_off);
+				} else {
+					lit += ahead;
+					assert(ii + lit == c->bp);
+				}
+				goto lazy_match_done;
+			}
+		}
+
+		assert(ii + lit + ahead == c->bp);
+
+		/* 1 - code run */
+		op = code_run(c,op,ii,lit);
+		lit = 0;
+
+		/* 2 - code match */
+		op = code_match(c,op,m_len,m_off);
+		swd->max_chain = max_chain;
+		r = find_match(c,swd,m_len,1+ahead);
+		assert(r == 0);
+
+ lazy_match_done: ;
+	}
+
+	/* store final run */
+	if (lit > 0)
+		op = STORE_RUN(c,op,ii,lit);
+
+#if defined(LZO_EOF_CODE)
+	*op++ = M4_MARKER | 1;
+	*op++ = 0;
+	*op++ = 0;
+#endif
+
+	*out_len = op - out;
+
+	return LZO_E_OK;
+}
+
+
+/***********************************************************************
+//
+************************************************************************/
+int lzo1x_999_compress_level(const uint8_t *in, unsigned in_len,
+		uint8_t *out, unsigned *out_len,
+		void *wrkmem,
+		int compression_level)
+{
+	static const struct {
+		uint16_t good_length;
+		uint16_t max_lazy;
+		uint16_t max_chain;
+		uint16_t use_best_off;
+	} c[3] = {
+		{     8,    32,  256,   0 },
+		{    32,   128, 2048,   1 },
+		{ SWD_F, SWD_F, 4096,   1 }       /* max. compression */
+	};
+
+	if (compression_level < 7 || compression_level > 9)
+		return LZO_E_ERROR;
+
+	compression_level -= 7;
+	return lzo1x_999_compress_internal(in, in_len, out, out_len, wrkmem,
+					   c[compression_level].good_length,
+					   c[compression_level].max_lazy,
+					   c[compression_level].max_chain,
+					   c[compression_level].use_best_off);
+}
Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26238)
+++ include/usage.h	(revision 26239)
@@ -202,6 +202,31 @@
 #define busybox_notes_usage \
        "Hello world!\n"
 
+#define lzop_trivial_usage \
+       "[-cfvd123456789CF] [file..]"
+#define lzop_full_usage "\n\n" \
+       "	-c	Write to standard output" \
+     "\n	-f	Force" \
+     "\n	-v	Verbose" \
+     "\n	-d	Decompress" \
+     "\n	-F	Don't store or verify checksum" \
+     "\n	-C	Also write checksum of compressed block" \
+     "\n	-1..9	Compression level" \
+
+#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" \
+       "	-c	Write to standard output" \
+     "\n	-f	Force" \
+     "\n	-v	Verbose" \
+     "\n	-F	Don't store or verify checksum" \
+
 #define bzcat_trivial_usage \
        "FILE"
 #define bzcat_full_usage "\n\n" \
Index: include/applets.h
===================================================================
--- include/applets.h	(revision 26238)
+++ include/applets.h	(revision 26239)
@@ -242,6 +242,8 @@
 IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
 IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
 IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+IF_LZOP(APPLET(lzop, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_LZOP(APPLET_ODDNAME(lzopcat, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzopcat))
 IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
 IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER))
 IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
@@ -401,6 +403,7 @@
 IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos))
 IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_LZOP(APPLET_ODDNAME(unlzop, lzop, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unlzop))
 IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep))

 ------------------------------------------------------------------------
r26223 | vda | 2009-04-27 18:29:14 -0500 (Mon, 27 Apr 2009) | 17 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: make it possible to have interactive shell on non-ctty.
 init=/bin/hush: shows prompt, history works, etc.

function                                             old     new   delta
hush_main                                            888     925     +37
block_signals                                        139     152     +13
builtin_fg_bg                                        284     293      +9
checkjobs_and_fg_shell                                35      41      +6
sigexit                                               65      66      +1
reset_traps_to_defaults                              165     164      -1
parse_stream                                        2200    2184     -16
run_list                                            2502    2475     -27
getpgid                                               35       -     -35
 ------------------------------------------------------------------------------

(add/remove: 0/1 grow/shrink: 5/3 up/down: 66/-79)            Total: -13 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26222)
+++ shell/hush.c	(revision 26223)
@@ -417,15 +417,26 @@
 /* "Globals" within this file */
 /* Sorted roughly by size (smaller offsets == smaller code) */
 struct globals {
+	/* interactive_fd != 0 means we are an interactive shell.
+	 * If we are, then saved_tty_pgrp can also be != 0, meaning
+	 * that controlling tty is available. With saved_tty_pgrp == 0,
+	 * job control still works, but terminal signals
+	 * (^C, ^Z, ^Y, ^\) won't work at all, and background
+	 * process groups can only be created with "cmd &".
+	 * With saved_tty_pgrp != 0, hush will use tcsetpgrp()
+	 * to give tty to the foreground process group,
+	 * and will take it back when the group is stopped (^Z)
+	 * or killed (^C).
+	 */
 #if ENABLE_HUSH_INTERACTIVE
 	/* 'interactive_fd' is a fd# open to ctty, if we have one
 	 * _AND_ if we decided to act interactively */
 	int interactive_fd;
 	const char *PS1;
 	const char *PS2;
-#define G_interactive_fd (G.interactive_fd)
+# define G_interactive_fd (G.interactive_fd)
 #else
-#define G_interactive_fd 0
+# define G_interactive_fd 0
 #endif
 #if ENABLE_FEATURE_EDITING
 	line_input_t *line_input_state;
@@ -434,10 +445,9 @@
 	pid_t last_bg_pid;
 #if ENABLE_HUSH_JOB
 	int run_list_level;
+	int last_jobid;
 	pid_t saved_tty_pgrp;
-	int last_jobid;
 	struct pipe *job_list;
-	struct pipe *toplevel_list;
 #endif
 	smallint flag_SIGINT;
 #if ENABLE_HUSH_LOOPS
@@ -446,7 +456,7 @@
 #if ENABLE_HUSH_FUNCTIONS
 	/* 0: outside of a function (or sourced file)
 	 * -1: inside of a function, ok to use return builtin
-	 * 1: return is invoked, skip all till end of func.
+	 * 1: return is invoked, skip all till end of func
 	 */
 	smallint flag_return_in_progress;
 #endif
@@ -1089,12 +1099,16 @@
  */
 enum {
 	SPECIAL_INTERACTIVE_SIGS = 0
+		| (1 << SIGTERM)
+		| (1 << SIGINT)
+		| (1 << SIGHUP)
+		,
 #if ENABLE_HUSH_JOB
-		| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
-		| (1 << SIGHUP)
+	SPECIAL_JOB_SIGS = 0
+		| (1 << SIGTTIN)
+		| (1 << SIGTTOU)
+		| (1 << SIGTSTP)
 #endif
-		| (1 << SIGTERM)
-		| (1 << SIGINT)
 };
 
 //static void SIGCHLD_handler(int sig UNUSED_PARAM)
@@ -1122,7 +1136,7 @@
 
 	/* Careful: we can end up here after [v]fork. Do not restore
 	 * tty pgrp then, only top-level shell process does that */
-	if (G_interactive_fd && getpid() == G.root_pid)
+	if (G.saved_tty_pgrp && getpid() == G.root_pid)
 		tcsetpgrp(G_interactive_fd, G.saved_tty_pgrp);
 
 	/* Not a signal, just exit */
@@ -3131,7 +3145,7 @@
 		len += strlen(*argv) + 1;
 	} while (*++argv);
 	p = xmalloc(len);
-	pi->cmdtext = p;// = xmalloc(len);
+	pi->cmdtext = p;
 	argv = pi->cmds[0].argv;
 	do {
 		len = strlen(*argv);
@@ -3351,10 +3365,12 @@
 {
 	pid_t p;
 	int rcode = checkjobs(fg_pipe);
-	/* Job finished, move the shell to the foreground */
-	p = getpgid(0); /* pgid of our process */
-	debug_printf_jobs("fg'ing ourself: getpgid(0)=%d\n", (int)p);
-	tcsetpgrp(G_interactive_fd, p);
+	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
@@ -3606,7 +3622,10 @@
 				pgrp = pi->pgrp;
 				if (pgrp < 0) /* true for 1st process only */
 					pgrp = getpid();
-				if (setpgid(0, pgrp) == 0 && pi->followup != PIPE_BG) {
+				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);
@@ -4023,11 +4042,7 @@
 				check_and_run_traps(0);
 #if ENABLE_HUSH_JOB
 				if (G.run_list_level == 1)
-{
-debug_printf_exec("insert_bg_job1\n");
 					insert_bg_job(pi);
-debug_printf_exec("insert_bg_job2\n");
-}
 #endif
 				G.last_exitcode = rcode = EXIT_SUCCESS;
 				debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
@@ -5896,8 +5911,11 @@
 	unsigned mask;
 
 	mask = (1 << SIGQUIT);
-	if (G_interactive_fd)
+	if (G_interactive_fd) {
 		mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS;
+		if (G.saved_tty_pgrp) /* we have ctty, job control sigs work */
+			mask |= SPECIAL_JOB_SIGS;
+	}
 	G.non_DFL_mask = mask;
 
 	if (!second_time)
@@ -6179,52 +6197,55 @@
 	if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) {
 		G.saved_tty_pgrp = tcgetpgrp(STDIN_FILENO);
 		debug_printf("saved_tty_pgrp:%d\n", G.saved_tty_pgrp);
-//TODO: "interactive" and "have job control" are two different things.
-//If tcgetpgrp fails here, "have job control" is false, but "interactive"
-//should stay on! Currently, we mix these into one.
-		if (G.saved_tty_pgrp >= 0) {
-			/* try to dup stdin to high fd#, >= 255 */
-			G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
+		if (G.saved_tty_pgrp < 0)
+			G.saved_tty_pgrp = 0;
+
+		/* try to dup stdin to high fd#, >= 255 */
+		G_interactive_fd = fcntl(STDIN_FILENO, F_DUPFD, 255);
+		if (G_interactive_fd < 0) {
+			/* try to dup to any fd */
+			G_interactive_fd = dup(STDIN_FILENO);
 			if (G_interactive_fd < 0) {
-				/* try to dup to any fd */
-				G_interactive_fd = dup(STDIN_FILENO);
-				if (G_interactive_fd < 0)
-					/* give up */
-					G_interactive_fd = 0;
+				/* give up */
+				G_interactive_fd = 0;
+				G.saved_tty_pgrp = 0;
 			}
+		}
 // TODO: track & disallow any attempts of user
-// to (inadvertently) close/redirect it
-		}
+// to (inadvertently) close/redirect G_interactive_fd
 	}
 	debug_printf("interactive_fd:%d\n", G_interactive_fd);
 	if (G_interactive_fd) {
-		pid_t shell_pgrp;
+		close_on_exec_on(G_interactive_fd);
 
-		/* We are indeed interactive shell, and we will perform
-		 * job control. Setting up for that. */
+		if (G.saved_tty_pgrp) {
+			/* If we were run as 'hush &', sleep until we are
+			 * in the foreground (tty pgrp == our pgrp).
+			 * If we get started under a job aware app (like bash),
+			 * make sure we are now in charge so we don't fight over
+			 * who gets the foreground */
+			while (1) {
+				pid_t shell_pgrp = getpgrp();
+				G.saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
+				if (G.saved_tty_pgrp == shell_pgrp)
+					break;
+				/* send TTIN to ourself (should stop us) */
+				kill(- shell_pgrp, SIGTTIN);
+			}
+		}
 
-		close_on_exec_on(G_interactive_fd);
-		/* If we were run as 'hush &', sleep until we are
-		 * in the foreground (tty pgrp == our pgrp).
-		 * If we get started under a job aware app (like bash),
-		 * make sure we are now in charge so we don't fight over
-		 * who gets the foreground */
-		while (1) {
-			shell_pgrp = getpgrp();
-			G.saved_tty_pgrp = tcgetpgrp(G_interactive_fd);
-			if (G.saved_tty_pgrp == shell_pgrp)
-				break;
-			/* send TTIN to ourself (should stop us) */
-			kill(- shell_pgrp, SIGTTIN);
-		}
 		/* Block some signals */
 		block_signals(signal_mask_is_inited);
-		/* Set other signals to restore saved_tty_pgrp */
-		set_fatal_handlers();
-		/* Put ourselves in our own process group */
-		bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
-		/* Grab control of the terminal */
-		tcsetpgrp(G_interactive_fd, getpid());
+
+		if (G.saved_tty_pgrp) {
+			/* Set other signals to restore saved_tty_pgrp */
+			set_fatal_handlers();
+			/* Put ourselves in our own process group
+			 * (bash, too, does this only if ctty is available) */
+			bb_setpgrp(); /* is the same as setpgid(our_pid, our_pid); */
+			/* Grab control of the terminal */
+			tcsetpgrp(G_interactive_fd, getpid());
+		}
 		/* -1 is special - makes xfuncs longjmp, not exit
 		 * (we reset die_sleep = 0 whereever we [v]fork) */
 		enable_restore_tty_pgrp_on_exit(); /* sets die_sleep = -1 */
@@ -6604,6 +6625,7 @@
 
 	if (!G_interactive_fd)
 		return EXIT_FAILURE;
+
 	/* If they gave us no args, assume they want the last backgrounded task */
 	if (!argv[1]) {
 		for (pi = G.job_list; pi; pi = pi->next) {
@@ -6628,7 +6650,7 @@
  found:
 	/* TODO: bash prints a string representation
 	 * of job being foregrounded (like "sleep 1 | cat") */
-	if (argv[0][0] == 'f') {
+	if (argv[0][0] == 'f' && G.saved_tty_pgrp) {
 		/* Put the job into the foreground.  */
 		tcsetpgrp(G_interactive_fd, pi->pgrp);
 	}

 ------------------------------------------------------------------------
r26216 | vda | 2009-04-26 18:25:36 -0500 (Sun, 26 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush_test/hush-z_slow/leak_var2.tests

make leak test more robust by unsetting all vars


 ------------------------------------------------------------------------

Index: shell/hush_test/hush-z_slow/leak_var2.tests
===================================================================
--- shell/hush_test/hush-z_slow/leak_var2.tests	(revision 26215)
+++ shell/hush_test/hush-z_slow/leak_var2.tests	(revision 26216)
@@ -1,7 +1,6 @@
+echo "Warm up"
 t=1
 export t
-
-echo "Warm up"
 i=1
 while test $i != X; do
     t=111111111111111111111111111111111111111111111111111111111111111111111110$i
@@ -14,10 +13,13 @@
     if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi
     if test $i = 1111111111111111111111111111111111111111111114; then i=X; fi
 done
+unset t i
 
 memleak
 
 echo "Measuring memory leak..."
+t=1
+export t
 i=1
 while test $i != X; do
     t=111111111111111111111111111111111111111111111111111111111111111111111110$i
@@ -30,6 +32,7 @@
     if test $i = 1111111111111111111111111111111111111111111113; then i=4; fi
     if test $i = 1111111111111111111111111111111111111111111114; then i=X; fi
 done
+unset t i
 
 memleak
 kb=$?

 ------------------------------------------------------------------------
r26215 | vda | 2009-04-26 18:22:40 -0500 (Sun, 26 Apr 2009) | 9 lines
Changed paths:
   M /trunk/busybox/libbb/getopt32.c
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/shell/hush_test/hush-vars/unset.right

hush: make getopt32 usable in builtins. use it in unset.
 more uses are expected in the future.

function                                             old     new   delta
getopt32                                            1356    1393     +37
builtin_export                                       256     266     +10
builtin_unset                                        418     380     -38


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26214)
+++ shell/hush.c	(revision 26215)
@@ -6451,7 +6451,11 @@
 	}
 
 #if ENABLE_HUSH_EXPORT_N
-	opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */
+	/* "!": do not abort on errors */
+	/* "+": stop at 1st non-option */
+	opt_unexport = getopt32(argv, "!+n");
+	if (opt_unexport == (unsigned)-1)
+		return EXIT_FAILURE;
 	argv += optind;
 #else
 	opt_unexport = 0;
@@ -6918,36 +6922,22 @@
 static int builtin_unset(char **argv)
 {
 	int ret;
-	char var;
-	char *arg;
+	unsigned opts;
 
-	if (!*++argv)
-		return EXIT_SUCCESS;
-
-	var = 0;
-	while ((arg = *argv) != NULL && arg[0] == '-') {
-		arg++;
-		do {
-			switch (*arg) {
-			case 'v':
-			case 'f':
-				if (var == 0 || var == *arg) {
-					var = *arg;
-					break;
-				}
-				/* else: unset -vf, which is illegal.
-				 * fall through */
-			default:
-				bb_error_msg("unset: %s: invalid option", *argv);
-				return EXIT_FAILURE;
-			}
-		} while (*++arg);
-		argv++;
+	/* "!": do not abort on errors */
+	/* "+": stop at 1st non-option */
+	opts = getopt32(argv, "!+vf");
+	if (opts == (unsigned)-1)
+		return EXIT_FAILURE;
+	if (opts == 3) {
+		bb_error_msg("unset: -v and -f are exclusive");
+		return EXIT_FAILURE;
 	}
+	argv += optind;
 
 	ret = EXIT_SUCCESS;
 	while (*argv) {
-		if (var != 'f') {
+		if (!(opts & 2)) { /* not -f */
 			if (unset_local_var(*argv)) {
 				/* unset  doesn't fail.
 				 * Error is when one tries to unset RO var.
Index: shell/hush_test/hush-vars/unset.right
===================================================================
--- shell/hush_test/hush-vars/unset.right	(revision 26214)
+++ shell/hush_test/hush-vars/unset.right	(revision 26215)
@@ -1,7 +1,6 @@
-hush: unset: -: invalid option
+0
+unset: invalid option -- m
 1
-hush: unset: -m: invalid option
-1
 0
 ___
 0 f g
Index: libbb/getopt32.c
===================================================================
--- libbb/getopt32.c	(revision 26214)
+++ libbb/getopt32.c	(revision 26215)
@@ -72,6 +72,9 @@
         env -i ls -d /
         Here we want env to process just the '-i', not the '-d'.
 
+ "!"    Report bad option, missing required options,
+        inconsistent options with all-ones return value (instead of abort).
+
 const char *applet_long_options
 
         This struct allows you to define long options:
@@ -327,6 +330,7 @@
 	unsigned flags = 0;
 	unsigned requires = 0;
 	t_complementary complementary[33]; /* last stays zero-filled */
+	char first_char;
 	int c;
 	const unsigned char *s;
 	t_complementary *on_off;
@@ -357,6 +361,11 @@
 	on_off = complementary;
 	memset(on_off, 0, sizeof(complementary));
 
+	/* skip bbox extension */
+	first_char = applet_opts[0];
+	if (first_char == '!')
+		applet_opts++;
+
 	/* skip GNU extension */
 	s = (const unsigned char *)applet_opts;
 	if (*s == '+' || *s == '-')
@@ -549,11 +558,11 @@
 			 * is always NULL (see above) */
 			if (on_off->opt_char == '\0' /* && c != '\0' */) {
 				/* c is probably '?' - "bad option" */
-				bb_show_usage();
+				goto error;
 			}
 		}
 		if (flags & on_off->incongruously)
-			bb_show_usage();
+			goto error;
 		trigger = on_off->switch_on & on_off->switch_off;
 		flags &= ~(on_off->switch_off ^ trigger);
 		flags |= on_off->switch_on ^ trigger;
@@ -577,16 +586,24 @@
 
 	/* check depending requires for given options */
 	for (on_off = complementary; on_off->opt_char; on_off++) {
-		if (on_off->requires && (flags & on_off->switch_on) &&
-					(flags & on_off->requires) == 0)
-			bb_show_usage();
+		if (on_off->requires
+		 && (flags & on_off->switch_on)
+		 && (flags & on_off->requires) == 0
+		) {
+			goto error;
+		}
 	}
 	if (requires && (flags & requires) == 0)
-		bb_show_usage();
+		goto error;
 	argc -= optind;
 	if (argc < min_arg || (max_arg >= 0 && argc > max_arg))
-		bb_show_usage();
+		goto error;
 
 	option_mask32 = flags;
 	return flags;
+
+ error:
+	if (first_char != '!')
+		bb_show_usage();
+	return (int32_t)-1;
 }

 ------------------------------------------------------------------------
r26211 | vda | 2009-04-26 15:06:14 -0500 (Sun, 26 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   A /trunk/busybox/shell/hush_test/hush-misc/func4.right
   A /trunk/busybox/shell/hush_test/hush-misc/func4.tests
   M /trunk/busybox/shell/hush_test/hush-z_slow/leak_all1.tests

hush: nommu fix for function passing


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26210)
+++ shell/hush.c	(revision 26211)
@@ -5328,9 +5328,12 @@
 		 * within double quotes by preceding it with a backslash.
 		 */
 		if (strchr("$`\"\\", next) != NULL) {
-			o_addqchr(dest, i_getch(input));
+			ch = i_getch(input);
+			o_addqchr(dest, ch);
+			nommu_addchr(as_string, ch);
 		} else {
 			o_addqchr(dest, '\\');
+			nommu_addchr(as_string, '\\');
 		}
 		goto again;
 	}
Index: shell/hush_test/hush-misc/func4.right
===================================================================
--- shell/hush_test/hush-misc/func4.right	(revision 0)
+++ shell/hush_test/hush-misc/func4.right	(revision 26211)
@@ -0,0 +1,2 @@
+24
+Done
Index: shell/hush_test/hush-misc/func4.tests
===================================================================
--- shell/hush_test/hush-misc/func4.tests	(revision 0)
+++ shell/hush_test/hush-misc/func4.tests	(revision 26211)
@@ -0,0 +1,7 @@
+func() { 
+	eval "echo \"\${val_${1}}\"" 
+}
+
+val_x=24 
+(func x)
+echo Done

Property changes on: shell/hush_test/hush-misc/func4.tests
___________________________________________________________________
Name: svn:executable
   + *

Index: shell/hush_test/hush-z_slow/leak_all1.tests
===================================================================
--- shell/hush_test/hush-z_slow/leak_all1.tests	(revision 26210)
+++ shell/hush_test/hush-z_slow/leak_all1.tests	(revision 26211)
@@ -67,6 +67,7 @@
     f >/dev/null
     : $((i++))
 done
+unset i l t
 unset -f f
 
 memleak
@@ -134,6 +135,7 @@
     f >/dev/null
     : $((i++))
 done
+unset i l t
 unset -f f
 
 

 ------------------------------------------------------------------------
r26210 | vda | 2009-04-26 06:25:19 -0500 (Sun, 26 Apr 2009) | 6 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/shell/hush_test/hush-arith/arith.right
   M /trunk/busybox/shell/hush_test/hush-vars/var_posix1.right
   M /trunk/busybox/shell/hush_test/hush-vars/var_posix1.tests
   M /trunk/busybox/shell/match.c
   M /trunk/busybox/shell/match.h

hush: fix SEGV in % expansion

function                                             old     new   delta
expand_variables                                    2203    2217     +14


 ------------------------------------------------------------------------

Index: shell/match.h
===================================================================
--- shell/match.h	(revision 26209)
+++ shell/match.h	(revision 26210)
@@ -2,12 +2,12 @@
 
 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
 
-typedef char *(*scan_t)(char *string, char *match, bool zero);
+typedef char *(*scan_t)(char *string, char *match, bool match_at_left);
 
-char *scanleft(char *string, char *match, bool zero);
-char *scanright(char *string, char *match, bool zero);
+char *scanleft(char *string, char *match, bool match_at_left);
+char *scanright(char *string, char *match, bool match_at_left);
 
-static inline scan_t pick_scan(char op1, char op2, bool *zero)
+static inline scan_t pick_scan(char op1, char op2, bool *match_at_left)
 {
 	/* #  - scanleft
 	 * ## - scanright
@@ -15,10 +15,10 @@
 	 * %% - scanleft
 	 */
 	if (op1 == '#') {
-		*zero = true;
+		*match_at_left = true;
 		return op1 == op2 ? scanright : scanleft;
 	} else {
-		*zero = false;
+		*match_at_left = false;
 		return op1 == op2 ? scanleft : scanright;
 	}
 }
Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26209)
+++ shell/hush.c	(revision 26210)
@@ -1990,12 +1990,9 @@
 	 * (expansion of right-hand side of assignment == 1-element expand.
 	 * It will also do no globbing, and thus we must not backslash-quote!) */
 
-	char first_ch, ored_ch;
-	int i;
-	const char *val;
-	char *dyn_val, *p;
+	char ored_ch;
+	char *p;
 
-	dyn_val = NULL;
 	ored_ch = 0;
 
 	debug_printf_expand("expand_vars_to_list: arg '%s'\n", arg);
@@ -2004,6 +2001,10 @@
 	debug_print_list("expand_vars_to_list[0]", output, n);
 
 	while ((p = strchr(arg, SPECIAL_VAR_SYMBOL)) != NULL) {
+		char first_ch;
+		int i;
+		char *dyn_val = NULL;
+		const char *val = NULL;
 #if ENABLE_HUSH_TICK
 		o_string subst_result = NULL_O_STRING;
 #endif
@@ -2021,7 +2022,6 @@
 		if ((first_ch & 0x7f) != '@')
 			ored_ch |= first_ch;
 
-		val = NULL;
 		switch (first_ch & 0x7f) {
 		/* Highest bit in first_ch indicates that var is double-quoted */
 		case '$': /* pid */
@@ -2194,16 +2194,16 @@
 				if (exp_op == '%' || exp_op == '#') {
 					if (val) {
 						/* we need to do a pattern match */
-						bool zero;
+						bool match_at_left;
 						char *loc;
-						scan_t scan = pick_scan(exp_op, *exp_word, &zero);
+						scan_t scan = pick_scan(exp_op, *exp_word, &match_at_left);
 						if (exp_op == *exp_word)	/* ## or %% */
 							++exp_word;
 						val = dyn_val = xstrdup(val);
-						loc = scan(dyn_val, exp_word, zero);
-						if (zero)
+						loc = scan(dyn_val, exp_word, match_at_left);
+						if (match_at_left) /* # or ## */
 							val = loc;
-						else
+						else if (loc) /* % or %% and match was found */
 							*loc = '\0';
 					}
 				} else {
@@ -2263,11 +2263,11 @@
 			}
 		} /* default: */
 		} /* switch (char after ) */
+
 		if (val) {
 			o_addQstr(output, val, strlen(val));
 		}
 		free(dyn_val);
-		dyn_val = NULL;
 		/* Do the check to avoid writing to a const string */
 		if (*p != SPECIAL_VAR_SYMBOL)
 			*p = SPECIAL_VAR_SYMBOL;
Index: shell/hush_test/hush-vars/var_posix1.right
===================================================================
--- shell/hush_test/hush-vars/var_posix1.right	(revision 26209)
+++ shell/hush_test/hush-vars/var_posix1.right	(revision 26210)
@@ -32,4 +32,5 @@
 ababcdcd
 Empty:
 ababcdcd}_tail
+ababcdcd
 end
Index: shell/hush_test/hush-vars/var_posix1.tests
===================================================================
--- shell/hush_test/hush-vars/var_posix1.tests	(revision 26209)
+++ shell/hush_test/hush-vars/var_posix1.tests	(revision 26210)
@@ -43,5 +43,6 @@
 echo Empty:${var%%*}
 echo ${var#}}_tail
 # UNFIXED BUG: echo ${var#\}}_tail
+echo ${var%\\*}
 
 echo end
Index: shell/hush_test/hush-arith/arith.right
===================================================================
--- shell/hush_test/hush-arith/arith.right	(revision 26209)
+++ shell/hush_test/hush-arith/arith.right	(revision 26210)
@@ -63,9 +63,9 @@
 40 40
 hush: error in arithmetic
 hush: divide by 0
-hush: can't exec 'let': No such file or directory
+hush: can't execute 'let': No such file or directory
 hush: error in arithmetic
-hush: can't exec 'let': No such file or directory
+hush: can't execute 'let': No such file or directory
 abc
 def
 ghi
@@ -135,4 +135,4 @@
 42
 42
 42
-hush: can't exec 'a[b[c]d]=e': No such file or directory
+hush: can't execute 'a[b[c]d]=e': No such file or directory
Index: shell/match.c
===================================================================
--- shell/match.c	(revision 26209)
+++ shell/match.c	(revision 26210)
@@ -11,8 +11,6 @@
  * Kenneth Almquist.
  *
  * Licensed under the GPL v2 or later, see the file LICENSE in this tarball.
- *
- * Original BSD copyright notice is retained at the end of this file.
  */
 #ifdef STANDALONE
 # include 
@@ -28,7 +26,7 @@
 
 #define pmatch(a, b) !fnmatch((a), (b), 0)
 
-char *scanleft(char *string, char *pattern, bool zero)
+char *scanleft(char *string, char *pattern, bool match_at_left)
 {
 	char c;
 	char *loc = string;
@@ -38,7 +36,7 @@
 		const char *s;
 
 		c = *loc;
-		if (zero) {
+		if (match_at_left) {
 			*loc = '\0';
 			s = string;
 		} else
@@ -55,7 +53,7 @@
 	return NULL;
 }
 
-char *scanright(char *string, char *pattern, bool zero)
+char *scanright(char *string, char *pattern, bool match_at_left)
 {
 	char c;
 	char *loc = string + strlen(string);
@@ -65,7 +63,7 @@
 		const char *s;
 
 		c = *loc;
-		if (zero) {
+		if (match_at_left) {
 			*loc = '\0';
 			s = string;
 		} else
@@ -88,7 +86,7 @@
 	char *string;
 	char *op;
 	char *pattern;
-	bool zero;
+	bool match_at_left;
 	char *loc;
 
 	int i;
@@ -117,15 +115,15 @@
 			continue;
 		}
 		op = string + off;
-		scan = pick_scan(op[0], op[1], &zero);
+		scan = pick_scan(op[0], op[1], &match_at_left);
 		pattern = op + 1;
 		if (op[0] == op[1])
 			op[1] = '\0', ++pattern;
 		op[0] = '\0';
 
-		loc = scan(string, pattern, zero);
+		loc = scan(string, pattern, match_at_left);
 
-		if (zero) {
+		if (match_at_left) {
 			printf("'%s'\n", loc);
 		} else {
 			*loc = '\0';

 ------------------------------------------------------------------------
r26209 | vda | 2009-04-25 20:43:36 -0500 (Sat, 25 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/ifplugd.c

ifplugd: tiny shrink


 ------------------------------------------------------------------------

Index: networking/ifplugd.c
===================================================================
--- networking/ifplugd.c	(revision 26208)
+++ networking/ifplugd.c	(revision 26209)
@@ -222,7 +222,7 @@
 static void set_ifreq_to_ifname(struct ifreq *ifreq)
 {
 	memset(ifreq, 0, sizeof(struct ifreq));
-	strncpy(ifreq->ifr_name, G.iface, IFNAMSIZ);
+	strncpy_IFNAMSIZ(ifreq->ifr_name, G.iface);
 }
 
 static const char *strstatus(int status)
@@ -389,7 +389,7 @@
 	uint8_t mac[ETH_ALEN];
 
 	memset(&iwrequest, 0, sizeof(struct iwreq));
-	strncpy(iwrequest.ifr_ifrn.ifrn_name, G.iface, IFNAMSIZ);
+	strncpy_IFNAMSIZ(iwrequest.ifr_ifrn.ifrn_name, G.iface);
 
 	if (network_ioctl(SIOCGIWAP, &iwrequest) < 0) {
 		bb_perror_msg("SIOCGIWAP failed");

 ------------------------------------------------------------------------
r26208 | vda | 2009-04-25 20:17:44 -0500 (Sat, 25 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/ifplugd.c

ifplugd: add copyright


 ------------------------------------------------------------------------

Index: networking/ifplugd.c
===================================================================
--- networking/ifplugd.c	(revision 26207)
+++ networking/ifplugd.c	(revision 26208)
@@ -2,7 +2,7 @@
 /*
  * ifplugd for busybox
  *
- * Copyright (C) 2009
+ * Copyright (C) 2009 Maksym Kryzhanovskyy 
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
@@ -19,6 +19,21 @@
 #define __user
 #include 
 
+/*
+TODO: describe compat status here.
+
+One questionable point of the design is netlink usage:
+
+We have 1 second timeout by default to poll the link status,
+it is short enough so that there are no real benefits in
+using netlink to get "instantaneous" interface creation/deletion
+notifications. We can check for interface existence by just
+doing some fast ioctl using its name.
+
+Netlink code then can be just dropped (1k or more?)
+*/
+
+
 #define IFPLUGD_ENV_PREVIOUS "IFPLUGD_PREVIOUS"
 #define IFPLUGD_ENV_CURRENT "IFPLUGD_CURRENT"
 

 ------------------------------------------------------------------------
r26207 | vda | 2009-04-25 20:08:51 -0500 (Sat, 25 Apr 2009) | 4 lines
Changed paths:
   M /trunk/busybox/include/applets.h
   M /trunk/busybox/include/usage.h
   M /trunk/busybox/networking/Config.in
   M /trunk/busybox/networking/Kbuild
   A /trunk/busybox/networking/ifplugd.c

ifplugd: new applet by Maksym Kryzhanovskyy (xmaks AT email.cz)
 +3k code and 0.5k in messages. Most of the bloat due to compat :(


 ------------------------------------------------------------------------

Index: networking/Kbuild
===================================================================
--- networking/Kbuild	(revision 26206)
+++ networking/Kbuild	(revision 26207)
@@ -18,6 +18,7 @@
 lib-$(CONFIG_HTTPD)        += httpd.o
 lib-$(CONFIG_IFCONFIG)     += ifconfig.o interface.o
 lib-$(CONFIG_IFENSLAVE)    += ifenslave.o interface.o
+lib-$(CONFIG_IFPLUGD)      += ifplugd.o
 lib-$(CONFIG_IFUPDOWN)     += ifupdown.o
 lib-$(CONFIG_INETD)        += inetd.o
 lib-$(CONFIG_IP)           += ip.o
Index: networking/ifplugd.c
===================================================================
--- networking/ifplugd.c	(revision 0)
+++ networking/ifplugd.c	(revision 26207)
@@ -0,0 +1,810 @@
+/* vi: set sw=4 ts=4: */
+/*
+ * ifplugd for busybox
+ *
+ * Copyright (C) 2009
+ *
+ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
+ */
+#include "libbb.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#define __user
+#include 
+
+#define IFPLUGD_ENV_PREVIOUS "IFPLUGD_PREVIOUS"
+#define IFPLUGD_ENV_CURRENT "IFPLUGD_CURRENT"
+
+enum {
+	FLAG_NO_AUTO			= 1 <<  0, // -a, Do not enable interface automatically
+	FLAG_NO_DAEMON			= 1 <<  1, // -n, Do not daemonize
+	FLAG_NO_SYSLOG			= 1 <<  2, // -s, Do not use syslog, use stderr instead
+	FLAG_IGNORE_FAIL		= 1 <<  3, // -f, Ignore detection failure, retry instead (failure is treated as DOWN)
+	FLAG_IGNORE_FAIL_POSITIVE	= 1 <<  4, // -F, Ignore detection failure, retry instead (failure is treated as UP)
+	FLAG_IFACE			= 1 <<  5, // -i, Specify ethernet interface
+	FLAG_RUN			= 1 <<  6, // -r, Specify program to execute
+	FLAG_IGNORE_RETVAL		= 1 <<  7, // -I, Don't exit on nonzero return value of program executed
+	FLAG_POLL_TIME			= 1 <<  8, // -t, Specify poll time in seconds
+	FLAG_DELAY_UP			= 1 <<  9, // -u, Specify delay for configuring interface
+	FLAG_DELAY_DOWN			= 1 << 10, // -d, Specify delay for deconfiguring interface
+	FLAG_API_MODE			= 1 << 11, // -m, Force API mode (mii, priv, ethtool, wlan, auto)
+	FLAG_NO_STARTUP			= 1 << 12, // -p, Don't run script on daemon startup
+	FLAG_NO_SHUTDOWN		= 1 << 13, // -q, Don't run script on daemon quit
+	FLAG_INITIAL_DOWN		= 1 << 14, // -l, Run "down" script on startup if no cable is detected
+	FLAG_EXTRA_ARG			= 1 << 15, // -x, Specify an extra argument for action script
+	FLAG_MONITOR			= 1 << 16, // -M, Use interface monitoring
+#if ENABLE_FEATURE_PIDFILE
+	FLAG_KILL			= 1 << 17, // -k, Kill a running daemon
+#endif
+};
+#if ENABLE_FEATURE_PIDFILE
+# define OPTION_STR "+ansfFi:r:It:u:d:m:pqlx:Mk"
+#else
+# 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,
+	IFSTATUS_UP = 1,
+};
+
+enum { // constant fds
+	ioctl_fd = 3,
+	netlink_fd = 4,
+};
+
+struct globals {
+	smallint iface_last_status;
+	smallint iface_exists;
+
+	/* Used in getopt32, must have sizeof == sizeof(int) */
+	unsigned poll_time;
+	unsigned delay_up;
+	unsigned delay_down;
+
+	const char *iface;
+	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 { \
+	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
+	G.iface_last_status = -1; \
+	G.iface_exists   = 1; \
+	G.poll_time      = 1; \
+	G.delay_down     = 5; \
+	G.iface          = "eth0"; \
+	G.api_mode       = "a"; \
+	G.script_name    = "/etc/ifplugd/ifplugd.action"; \
+} while (0)
+
+
+static int run_script(const char *action)
+{
+	pid_t pid;
+	int r;
+
+	bb_error_msg("executing '%s %s %s'", G.script_name, G.iface, action);
+
+#if 1
+	pid = vfork();
+	if (pid < 0) {
+		bb_perror_msg("fork");
+		return -1;
+	}
+
+	if (pid == 0) {
+		/* child */
+		execlp(G.script_name, G.script_name, G.iface, action, G.extra_arg, NULL);
+		bb_perror_msg_and_die("can't execute '%s'", G.script_name);
+	}
+
+	/* parent */
+	wait(&r);
+	r = WEXITSTATUS(r);
+
+	bb_error_msg("exit code: %u", r);
+	return (option_mask32 & FLAG_IGNORE_RETVAL) ? 0 : r;
+
+#else /* insanity */
+
+	struct fd_pair pipe_pair;
+	char buf[256];
+	int i = 0;
+
+	xpiped_pair(pipe_pair);
+
+	pid = vfork();
+	if (pid < 0) {
+		bb_perror_msg("fork");
+		return -1;
+	}
+
+	/* child */
+	if (pid == 0) {
+		xmove_fd(pipe_pair.wr, 1);
+		xdup2(1, 2);
+		if (pipe_pair.rd > 2)
+			close(pipe_pair.rd);
+
+		// umask(0022); // Set up a sane umask
+
+		execlp(G.script_name, G.script_name, G.iface, action, G.extra_arg, NULL);
+		_exit(EXIT_FAILURE);
+	}
+
+	/* parent */
+	close(pipe_pair.wr);
+
+	while (1) {
+		if (bb_got_signal && bb_got_signal != SIGCHLD) {
+			bb_error_msg("killing child");
+			kill(pid, SIGTERM);
+			bb_got_signal = 0;
+			break;
+		}
+
+		r = read(pipe_pair.rd, &buf[i], 1);
+
+		if (buf[i] == '\n' || i == sizeof(buf)-2 || r != 1) {
+			if (r == 1 && buf[i] != '\n')
+				i++;
+
+			buf[i] = '\0';
+
+			if (i > 0)
+				bb_error_msg("client: %s", buf);
+
+			i = 0;
+		} else {
+			i++;
+		}
+
+		if (r != 1)
+			break;
+	}
+
+	close(pipe_pair.rd);
+
+	wait(&r);
+
+	if (!WIFEXITED(r) || WEXITSTATUS(r) != 0) {
+		bb_error_msg("program execution failed, return value is %i",
+			WEXITSTATUS(r));
+		return option_mask32 & FLAG_IGNORE_RETVAL ? 0 : WEXITSTATUS(r);
+	}
+	bb_error_msg("program executed successfully");
+	return 0;
+#endif
+}
+
+static int network_ioctl(int request, void* data)
+{
+	return ioctl(ioctl_fd, request, data);
+}
+
+static void set_ifreq_to_ifname(struct ifreq *ifreq)
+{
+	memset(ifreq, 0, sizeof(struct ifreq));
+	strncpy(ifreq->ifr_name, G.iface, IFNAMSIZ);
+}
+
+static const char *strstatus(int status)
+{
+	if (status == IFSTATUS_ERR)
+		return "error";
+	return "down\0up" + (status * 5);
+}
+
+static void up_iface(void)
+{
+	struct ifreq ifrequest;
+
+	if (!G.iface_exists)
+		return;
+
+	set_ifreq_to_ifname(&ifrequest);
+	if (network_ioctl(SIOCGIFFLAGS, &ifrequest) < 0) {
+		bb_perror_msg("can't %cet interface flags", 'g');
+		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) < 0)
+			bb_perror_msg_and_die("can't %cet interface flags", 's');
+	}
+
+#if 0 /* why do we mess with IP addr? It's not our business */
+	if (network_ioctl(SIOCGIFADDR, &ifrequest) < 0) {
+		bb_error_msg("can't get interface address");
+	} 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;
+		if (network_ioctl(SIOCSIFADDR, &ifrequest) < 0)
+			bb_perror_msg("can't set interface address");
+	}
+	if (network_ioctl(SIOCGIFFLAGS, &ifrequest) < 0) {
+		bb_perror_msg("can't get interface flags");
+		return;
+	}
+#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) == 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) == 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;
+}
+
+static smallint detect_link_mii(void)
+{
+	struct ifreq ifreq;
+
+	set_ifreq_to_ifname(&ifreq);
+
+	if (network_ioctl(SIOCGMIIPHY, &ifreq) < 0) {
+		bb_perror_msg("SIOCGMIIPHY failed");
+		return IFSTATUS_ERR;
+	}
+
+	((unsigned short*)&ifreq.ifr_data)[1] = 1;
+
+	if (network_ioctl(SIOCGMIIREG, &ifreq) < 0) {
+		bb_perror_msg("SIOCGMIIREG failed");
+		return IFSTATUS_ERR;
+	}
+
+	return (((unsigned short*)&ifreq.ifr_data)[3] & 0x0004) ?
+		IFSTATUS_UP : IFSTATUS_DOWN;
+}
+
+static smallint detect_link_priv(void)
+{
+	struct ifreq ifreq;
+
+	set_ifreq_to_ifname(&ifreq);
+
+	if (network_ioctl(SIOCDEVPRIVATE, &ifreq) < 0) {
+		bb_perror_msg("SIOCDEVPRIVATE failed");
+		return IFSTATUS_ERR;
+	}
+
+	((unsigned short*) &ifreq.ifr_data)[1] = 1;
+
+	if (network_ioctl(SIOCDEVPRIVATE+1, &ifreq) < 0) {
+		bb_perror_msg("SIOCDEVPRIVATE+1 failed");
+		return IFSTATUS_ERR;
+	}
+
+	return (((unsigned short*)&ifreq.ifr_data)[3] & 0x0004) ?
+		IFSTATUS_UP : IFSTATUS_DOWN;
+}
+
+static smallint detect_link_ethtool(void)
+{
+	struct ifreq ifreq;
+	struct ethtool_value edata;
+
+	set_ifreq_to_ifname(&ifreq);
+
+	edata.cmd = ETHTOOL_GLINK;
+	ifreq.ifr_data = &edata;
+
+	if (network_ioctl(SIOCETHTOOL, &ifreq) < 0) {
+		bb_perror_msg("ETHTOOL_GLINK failed");
+		return IFSTATUS_ERR;
+	}
+
+	return edata.data ? IFSTATUS_UP : IFSTATUS_DOWN;
+}
+
+static smallint detect_link_iff(void)
+{
+	struct ifreq ifreq;
+
+	set_ifreq_to_ifname(&ifreq);
+
+	if (network_ioctl(SIOCGIFFLAGS, &ifreq) < 0) {
+		bb_perror_msg("SIOCGIFFLAGS failed");
+		return IFSTATUS_ERR;
+	}
+
+	return (ifreq.ifr_flags & IFF_RUNNING) ? IFSTATUS_UP : IFSTATUS_DOWN;
+}
+
+static smallint detect_link_wlan(void)
+{
+	struct iwreq iwrequest;
+	uint8_t mac[ETH_ALEN];
+
+	memset(&iwrequest, 0, sizeof(struct iwreq));
+	strncpy(iwrequest.ifr_ifrn.ifrn_name, G.iface, IFNAMSIZ);
+
+	if (network_ioctl(SIOCGIWAP, &iwrequest) < 0) {
+		bb_perror_msg("SIOCGIWAP failed");
+		return IFSTATUS_ERR;
+	}
+
+	memcpy(mac, &(iwrequest.u.ap_addr.sa_data), ETH_ALEN);
+
+	if (mac[0] == 0xFF || mac[0] == 0x44 || mac[0] == 0x00) {
+		for (int i = 1; i < ETH_ALEN; ++i) {
+			if (mac[i] != mac[0])
+				return IFSTATUS_UP;
+		}
+		return IFSTATUS_DOWN;
+	}
+
+	return IFSTATUS_UP;
+}
+
+static smallint detect_link_auto(void)
+{
+	const char *method;
+	smallint iface_status;
+	smallint sv_logmode;
+
+	if (G.cached_detect_link_func) {
+		iface_status = G.cached_detect_link_func();
+		if (iface_status != IFSTATUS_ERR)
+			return iface_status;
+	}
+
+	sv_logmode = logmode;
+	logmode = LOGMODE_NONE;
+
+	iface_status = detect_link_ethtool();
+	if (iface_status != IFSTATUS_ERR) {
+		G.cached_detect_link_func = detect_link_ethtool;
+		method = "SIOCETHTOOL";
+ found_method:
+		logmode = sv_logmode;
+		bb_error_msg("using %s detection mode", method);
+		return iface_status;
+	}
+
+	iface_status = detect_link_mii();
+	if (iface_status != IFSTATUS_ERR) {
+		G.cached_detect_link_func = detect_link_mii;
+		method = "SIOCGMIIPHY";
+		goto found_method;
+	}
+
+	iface_status = detect_link_priv();
+	if (iface_status != IFSTATUS_ERR) {
+		G.cached_detect_link_func = detect_link_priv;
+		method = "SIOCDEVPRIVATE";
+		goto found_method;
+	}
+
+	iface_status = detect_link_wlan();
+	if (iface_status != IFSTATUS_ERR) {
+		G.cached_detect_link_func = detect_link_wlan;
+		method = "wireless extension";
+		goto found_method;
+	}
+
+	iface_status = detect_link_iff();
+	if (iface_status != IFSTATUS_ERR) {
+		G.cached_detect_link_func = detect_link_iff;
+		method = "IFF_RUNNING";
+		goto found_method;
+	}
+
+	logmode = sv_logmode;
+	return iface_status; /* IFSTATUS_ERR */
+}
+
+static smallint detect_link(void)
+{
+	smallint status;
+
+	if (!G.iface_exists)
+		return (option_mask32 & FLAG_MONITOR) ? IFSTATUS_DOWN : IFSTATUS_ERR;
+
+#if 0
+/* Why? This behavior makes it hard to temporary down the iface.
+ * It makes a bit more sense to do only in maybe_up_new_iface.
+ * OTOH, maybe detect_link_wlan needs this. Then it should be done
+ * _only_ there.
+ */
+	if (!(option_mask32 & FLAG_NO_AUTO))
+		up_iface();
+#endif
+
+	status = G.detect_link_func();
+	if (status == IFSTATUS_ERR) {
+		if (option_mask32 & FLAG_IGNORE_FAIL)
+			status = IFSTATUS_DOWN;
+		if (option_mask32 & FLAG_IGNORE_FAIL_POSITIVE)
+			status = IFSTATUS_UP;
+	}
+
+	if (status == IFSTATUS_ERR
+	 && G.detect_link_func == detect_link_auto
+	) {
+		bb_error_msg("failed to detect link status");
+	}
+
+	if (status != G.iface_last_status) {
+//TODO: is it safe to repeatedly do this?
+		setenv(IFPLUGD_ENV_PREVIOUS, strstatus(G.iface_last_status), 1);
+		setenv(IFPLUGD_ENV_CURRENT, strstatus(status), 1);
+		G.iface_last_status = status;
+	}
+
+	return status;
+}
+
+static NOINLINE int check_existence_through_netlink(void)
+{
+	char replybuf[1024];
+
+	while (1) {
+		struct nlmsghdr *mhdr;
+		ssize_t bytes;
+
+		bytes = recv(netlink_fd, &replybuf, sizeof(replybuf), MSG_DONTWAIT);
+		if (bytes < 0) {
+			if (errno == EAGAIN)
+				return G.iface_exists;
+			if (errno == EINTR)
+				continue;
+
+			bb_perror_msg("netlink: recv");
+			return -1;
+		}
+
+		mhdr = (struct nlmsghdr*)replybuf;
+		while (bytes > 0) {
+			if (!NLMSG_OK(mhdr, bytes)
+			 || bytes < sizeof(struct nlmsghdr)
+			 || bytes < mhdr->nlmsg_len
+			) {
+				bb_error_msg("netlink packet too small or truncated");
+				return -1;
+			}
+
+			if (mhdr->nlmsg_type == RTM_NEWLINK || mhdr->nlmsg_type == RTM_DELLINK) {
+				struct rtattr *attr;
+				struct ifinfomsg *imsg;
+				int attr_len;
+
+				imsg = NLMSG_DATA(mhdr);
+
+				if (mhdr->nlmsg_len < NLMSG_LENGTH(sizeof(struct ifinfomsg))) {
+					bb_error_msg("netlink packet too small or truncated");
+					return -1;
+				}
+
+				attr = (struct rtattr*)((char*)imsg + NLMSG_ALIGN(sizeof(struct ifinfomsg)));
+				attr_len = NLMSG_PAYLOAD(mhdr, sizeof(struct ifinfomsg));
+
+				while (RTA_OK(attr, attr_len)) {
+					if (attr->rta_type == IFLA_IFNAME) {
+						char ifname[IFNAMSIZ + 1];
+						int len = RTA_PAYLOAD(attr);
+
+						if (len > IFNAMSIZ)
+							len = IFNAMSIZ;
+						memcpy(ifname, RTA_DATA(attr), len);
+						if (strcmp(G.iface, ifname) == 0) {
+							G.iface_exists = (mhdr->nlmsg_type == RTM_NEWLINK);
+						}
+					}
+					attr = RTA_NEXT(attr, attr_len);
+				}
+			}
+
+			mhdr = NLMSG_NEXT(mhdr, bytes);
+		}
+	}
+
+	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;
+}
+
+static NOINLINE pid_t read_pid(const char *filename)
+{
+	int len;
+	char buf[128];
+
+	len = open_read_close(filename, buf, 127);
+	if (len > 0) {
+		buf[len] = '\0';
+		/* returns ULONG_MAX on error => -1 */
+		return bb_strtoul(buf, NULL, 10);
+	}
+	return 0;
+}
+
+int ifplugd_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
+int ifplugd_main(int argc UNUSED_PARAM, char **argv)
+{
+	int iface_status;
+	int delay_time;
+	const char *iface_status_str;
+	struct pollfd netlink_pollfd[1];
+	unsigned opts;
+#if ENABLE_FEATURE_PIDFILE
+	char *pidfile_name;
+	pid_t pid_from_pidfile;
+#endif
+
+	INIT_G();
+
+	opt_complementary = "t+:u+:d+";
+	opts = getopt32(argv, OPTION_STR,
+		&G.iface, &G.script_name, &G.poll_time, &G.delay_up,
+		&G.delay_down, &G.api_mode, &G.extra_arg);
+
+	applet_name = xasprintf("ifplugd(%s)", G.iface);
+
+#if ENABLE_FEATURE_PIDFILE
+	pidfile_name = xasprintf(_PATH_VARRUN"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);
+		return EXIT_SUCCESS;
+	}
+
+	if (pid_from_pidfile > 0 && kill(pid_from_pidfile, 0) == 0)
+		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:
+		bb_error_msg_and_die("unknown API mode '%s'", G.api_mode);
+	}
+
+	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);
+	}
+
+	write_pidfile(pidfile_name);
+
+	/* this can't be moved before socket creation */
+	if (!(opts & FLAG_NO_SYSLOG)) {
+		openlog(applet_name, 0, LOG_DAEMON);
+		logmode |= LOGMODE_SYSLOG;
+	}
+
+	bb_signals(0
+		| (1 << SIGINT )
+		| (1 << SIGTERM)
+		| (1 << SIGQUIT)
+		| (1 << SIGHUP ) /* why we ignore it? */
+		/* | (1 << SIGCHLD) - run_script does not use it anymore */
+		, record_signo);
+
+	bb_error_msg("started: %s", bb_banner);
+
+	if (opts & FLAG_MONITOR) {
+		struct ifreq ifrequest;
+		set_ifreq_to_ifname(&ifrequest);
+		G.iface_exists = (network_ioctl(SIOCGIFINDEX, &ifrequest) == 0);
+	}
+
+	if (G.iface_exists)
+		maybe_up_new_iface();
+
+	iface_status = detect_link();
+	if (iface_status == IFSTATUS_ERR)
+		goto exiting;
+	iface_status_str = strstatus(iface_status);
+
+	if (opts & FLAG_MONITOR) {
+		bb_error_msg("interface %s",
+			G.iface_exists ? "exists"
+			: "doesn't exist, waiting");
+	}
+	/* else we assume it always exists, but don't mislead user
+	 * by potentially lying that it really exists */
+
+	if (G.iface_exists) {
+		bb_error_msg("link is %s", iface_status_str);
+	}
+
+	if ((!(opts & FLAG_NO_STARTUP)
+	     && iface_status == IFSTATUS_UP
+	    )
+	 || (opts & FLAG_INITIAL_DOWN)
+	) {
+		if (run_script(iface_status_str) != 0)
+			goto exiting;
+	}
+
+	/* Main loop */
+	netlink_pollfd[0].fd = netlink_fd;
+	netlink_pollfd[0].events = POLLIN;
+	delay_time = 0;
+	while (1) {
+		int iface_status_old;
+		int iface_exists_old;
+
+		switch (bb_got_signal) {
+		case SIGINT:
+		case SIGTERM:
+			bb_got_signal = 0;
+			goto cleanup;
+		case SIGQUIT:
+			bb_got_signal = 0;
+			goto exiting;
+		default:
+			bb_got_signal = 0;
+			break;
+		}
+
+		if (poll(netlink_pollfd,
+				(opts & FLAG_MONITOR) ? 1 : 0,
+				G.poll_time * 1000
+			) < 0
+		) {
+			if (errno == EINTR)
+				continue;
+			bb_perror_msg("poll");
+			goto exiting;
+		}
+
+		iface_status_old = iface_status;
+		iface_exists_old = G.iface_exists;
+
+		if ((opts & FLAG_MONITOR)
+		 && (netlink_pollfd[0].revents & POLLIN)
+		) {
+			G.iface_exists = check_existence_through_netlink();
+			if (G.iface_exists < 0) /* error */
+				goto exiting;
+			if (iface_exists_old != G.iface_exists) {
+				bb_error_msg("interface %sappeared",
+						G.iface_exists ? "" : "dis");
+				if (G.iface_exists)
+					maybe_up_new_iface();
+			}
+		}
+
+		/* note: if !G.iface_exists, returns DOWN */
+		iface_status = detect_link();
+		if (iface_status == IFSTATUS_ERR) {
+			if (!(opts & FLAG_MONITOR))
+				goto exiting;
+			iface_status = IFSTATUS_DOWN;
+		}
+		iface_status_str = strstatus(iface_status);
+
+		if (iface_status_old != iface_status) {
+			bb_error_msg("link is %s", iface_status_str);
+
+			if (delay_time) {
+				/* link restored its old status before
+				 * we run script. don't run the script: */
+				delay_time = 0;
+			} else {
+				delay_time = monotonic_sec();
+				if (iface_status == IFSTATUS_UP)
+					delay_time += G.delay_up;
+				if (iface_status == IFSTATUS_DOWN)
+					delay_time += G.delay_down;
+				if (delay_time == 0)
+					delay_time++;
+			}
+		}
+
+		if (delay_time && (int)(monotonic_sec() - delay_time) >= 0) {
+			delay_time = 0;
+			if (run_script(iface_status_str) != 0)
+				goto exiting;
+		}
+	} /* while (1) */
+
+ cleanup:
+	if (!(opts & FLAG_NO_SHUTDOWN)
+	 && (iface_status == IFSTATUS_UP
+	     || (iface_status == IFSTATUS_DOWN && delay_time)
+	    )
+	) {
+		setenv(IFPLUGD_ENV_PREVIOUS, strstatus(iface_status), 1);
+		setenv(IFPLUGD_ENV_CURRENT, strstatus(-1), 1);
+		run_script("down\0up"); /* reusing string */
+	}
+
+ exiting:
+	remove_pidfile(pidfile_name);
+	bb_error_msg_and_die("exiting");
+}
Index: networking/Config.in
===================================================================
--- networking/Config.in	(revision 26206)
+++ networking/Config.in	(revision 26207)
@@ -303,6 +303,12 @@
 	  Userspace application to bind several interfaces
 	  to a logical interface (use with kernel bonding driver).
 
+config IFPLUGD
+	bool "ifplugd"
+	default n
+	help
+	  Network interface plug detection daemon.
+
 config IFUPDOWN
 	bool "ifupdown"
 	default n
Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26206)
+++ include/usage.h	(revision 26207)
@@ -1727,22 +1727,47 @@
 /*   "\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" \
+       "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" \
+       "- 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" \
+       "- 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" \
+       "  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\n" \
+       "Options:\n" \
+     "\n	-n		Do not daemonize" \
+     "\n	-s		Do not 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		Do not up interface automatically" \
+     "\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, auto)" \
+     "\n	-k		Kill running daemon" \
+
 #define ifup_trivial_usage \
        "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
 #define ifup_full_usage "\n\n" \
@@ -4346,17 +4371,17 @@
 	"CMD: {add|del|change|replace|show}\n" \
 	"\n" \
 	"qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \
-	/* "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ \
-	"\t[ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \
-	"\tQDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\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" \
-	"\t[ [ QDISC_KIND ] [ help | OPTIONS ] ]\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" */ \
-	"\t[ root | classid CLASSID ] [ handle FILTERID ]\n" \
-	"\t[ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" \
+	"	[ root | classid CLASSID ] [ handle FILTERID ]\n" \
+	"	[ [ FILTER_TYPE ] [ help | OPTIONS ] ]\n" \
 	"filter show [ dev STRING ] [ root | parent CLASSID ]"
 
 #define tcpsvd_trivial_usage \
Index: include/applets.h
===================================================================
--- include/applets.h	(revision 26206)
+++ include/applets.h	(revision 26207)
@@ -189,6 +189,7 @@
 IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
 IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifdown))
 IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_IFPLUGD(APPLET(ifplugd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup))
 IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
 IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))

 ------------------------------------------------------------------------
r26206 | vda | 2009-04-25 08:26:10 -0500 (Sat, 25 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/libbb/update_passwd.c

shrink if FEATURE_SHADOWPASSWDS is off


 ------------------------------------------------------------------------

Index: libbb/update_passwd.c
===================================================================
--- libbb/update_passwd.c	(revision 26205)
+++ libbb/update_passwd.c	(revision 26206)
@@ -100,7 +100,7 @@
 	name = xasprintf("%s:", name);
 	user_len = strlen(name);
 
-	if (strstr(filename, "shadow"))
+	if (ENABLE_FEATURE_SHADOWPASSWDS && strstr(filename, "shadow"))
 		old_fp = fopen(filename, "r+");
 	else
 		old_fp = fopen_or_warn(filename, "r+");

 ------------------------------------------------------------------------
r26205 | vda | 2009-04-25 08:16:53 -0500 (Sat, 25 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/libbb/xconnect.c
   M /trunk/busybox/networking/Config.in
   M /trunk/busybox/networking/nc.c
   M /trunk/busybox/networking/nc_bloaty.c

add FEATURE_UNIX_LOCAL. By Ingo van Lil (inguin AT gmx.de)


 ------------------------------------------------------------------------

Index: networking/nc_bloaty.c
===================================================================
--- networking/nc_bloaty.c	(revision 26204)
+++ networking/nc_bloaty.c	(revision 26205)
@@ -377,9 +377,7 @@
 		socklen_t x = sizeof(optbuf);
 
 		rr = getsockopt(netfd, IPPROTO_IP, IP_OPTIONS, optbuf, &x);
-		if (rr < 0)
-			bb_perror_msg("getsockopt failed");
-		else if (x) {    /* we've got options, lessee em... */
+		if (rr >= 0 && x) {    /* we've got options, lessee em... */
 			bin2hex(bigbuf_net, optbuf, x);
 			bigbuf_net[2*x] = '\0';
 			fprintf(stderr, "IP options: %s\n", bigbuf_net);
@@ -603,7 +601,10 @@
 	 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(0);
+				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?)
 			} else {
 				rzleft = rr;
 				zp = bigbuf_in;
@@ -768,7 +769,12 @@
 	setsockopt_reuseaddr(netfd);
 	if (o_udpmode)
 		socket_want_pktinfo(netfd);
-	xbind(netfd, &ouraddr->u.sa, ouraddr->len);
+	if (!ENABLE_FEATURE_UNIX_LOCAL
+	 || o_listen
+	 || ouraddr->u.sa.sa_family != AF_UNIX
+	) {
+		xbind(netfd, &ouraddr->u.sa, ouraddr->len);
+	}
 #if 0
 	setsockopt(netfd, SOL_SOCKET, SO_RCVBUF, &o_rcvbuf, sizeof o_rcvbuf);
 	setsockopt(netfd, SOL_SOCKET, SO_SNDBUF, &o_sndbuf, sizeof o_sndbuf);
Index: networking/nc.c
===================================================================
--- networking/nc.c	(revision 26204)
+++ networking/nc.c	(revision 26205)
@@ -34,7 +34,6 @@
 	IF_NOT_NC_EXTRA (const) unsigned delay = 0;
 	IF_NOT_NC_EXTRA (const int execparam = 0;)
 	IF_NC_EXTRA     (char **execparam = NULL;)
-	len_and_sockaddr *lsa;
 	fd_set readfds, testfds;
 	int opt; /* must be signed (getopt returns -1) */
 
@@ -44,17 +43,17 @@
 		while ((opt = getopt(argc, argv,
 		        "" IF_NC_SERVER("lp:") IF_NC_EXTRA("w:i:f:e:") )) > 0
 		) {
-			if (ENABLE_NC_SERVER && opt=='l')
+			if (ENABLE_NC_SERVER && opt == 'l')
 				IF_NC_SERVER(do_listen++);
-			else if (ENABLE_NC_SERVER && opt=='p')
+			else if (ENABLE_NC_SERVER && opt == 'p')
 				IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
-			else if (ENABLE_NC_EXTRA && opt=='w')
+			else if (ENABLE_NC_EXTRA && opt == 'w')
 				IF_NC_EXTRA( wsecs = xatou(optarg));
-			else if (ENABLE_NC_EXTRA && opt=='i')
+			else if (ENABLE_NC_EXTRA && opt == 'i')
 				IF_NC_EXTRA( delay = xatou(optarg));
-			else if (ENABLE_NC_EXTRA && opt=='f')
+			else if (ENABLE_NC_EXTRA && opt == 'f')
 				IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
-			else if (ENABLE_NC_EXTRA && opt=='e' && optind <= argc) {
+			else if (ENABLE_NC_EXTRA && opt == 'e' && optind <= argc) {
 				/* We cannot just 'break'. We should let getopt finish.
 				** Or else we won't be able to find where
 				** 'host' and 'port' params are
@@ -80,9 +79,12 @@
 		argc -= optind;
 		// -l and -f don't mix
 		if (do_listen && cfd) bb_show_usage();
-		// Listen or file modes need zero arguments, client mode needs 2
-		if (do_listen || cfd) {
+		// File mode needs need zero arguments, listen mode needs zero or one,
+		// client mode needs one or two
+		if (cfd) {
 			if (argc) bb_show_usage();
+		} else if (do_listen) {
+			if (argc > 1) bb_show_usage();
 		} else {
 			if (!argc || argc > 2) bb_show_usage();
 		}
@@ -99,24 +101,20 @@
 
 	if (!cfd) {
 		if (do_listen) {
-			/* create_and_bind_stream_or_die(NULL, lport)
-			 * would've work wonderfully, but we need
-			 * to know lsa */
-			sfd = xsocket_stream(&lsa);
-			if (lport)
-				set_nport(lsa, htons(lport));
-			setsockopt_reuseaddr(sfd);
-			xbind(sfd, &lsa->u.sa, lsa->len);
+			sfd = create_and_bind_stream_or_die(argv[0], lport);
 			xlisten(sfd, do_listen); /* can be > 1 */
+#if 0  /* nc-1.10 does not do this (without -v) */
 			/* If we didn't specify a port number,
 			 * query and print it after listen() */
 			if (!lport) {
-				getsockname(sfd, &lsa->u.sa, &lsa->len);
-				lport = get_nport(&lsa->u.sa);
+				len_and_sockaddr lsa;
+				lsa.len = LSA_SIZEOF_SA;
+				getsockname(sfd, &lsa.u.sa, &lsa.len);
+				lport = get_nport(&lsa.u.sa);
 				fdprintf(2, "%d\n", ntohs(lport));
 			}
+#endif
 			close_on_exec_on(sfd);
-			free(lsa);
  accept_again:
 			cfd = accept(sfd, NULL, 0);
 			if (cfd < 0)
Index: networking/Config.in
===================================================================
--- networking/Config.in	(revision 26204)
+++ networking/Config.in	(revision 26205)
@@ -12,6 +12,13 @@
 	  Enable IPv6 support in busybox.
 	  This adds IPv6 support in the networking applets.
 
+config FEATURE_UNIX_LOCAL
+	bool "Enable Unix domain socket support"
+	default n
+	help
+	  Enable Unix domain socket support in all busybox networking
+	  applets.
+
 config FEATURE_PREFER_IPV4_ADDRESS
 	bool "Prefer IPv4 addresses from DNS queries"
 	default y
Index: libbb/xconnect.c
===================================================================
--- libbb/xconnect.c	(revision 26204)
+++ libbb/xconnect.c	(revision 26205)
@@ -9,6 +9,7 @@
 
 #include 
 #include 
+#include 
 #include "libbb.h"
 
 void FAST_FUNC setsockopt_reuseaddr(int fd)
@@ -160,13 +161,26 @@
 		int ai_flags)
 {
 	int rc;
-	len_and_sockaddr *r = NULL;
+	len_and_sockaddr *r;
 	struct addrinfo *result = NULL;
 	struct addrinfo *used_res;
 	const char *org_host = host; /* only for error msg */
 	const char *cp;
 	struct addrinfo hint;
 
+	if (ENABLE_FEATURE_UNIX_LOCAL && strncmp(host, "local:", 6) == 0) {
+		struct sockaddr_un *sun;
+
+		r = xzalloc(LSA_LEN_SIZE + sizeof(struct sockaddr_un));
+		r->len = sizeof(struct sockaddr_un);
+		r->u.sa.sa_family = AF_UNIX;
+		sun = (struct sockaddr_un *)&r->u.sa;
+		safe_strncpy(sun->sun_path, host + 6, sizeof(sun->sun_path));
+		return r;
+	}
+
+	r = NULL;
+
 	/* Ugly parsing of host:addr */
 	if (ENABLE_FEATURE_IPV6 && host[0] == '[') {
 		/* Even uglier parsing of [xx]:nn */
@@ -188,6 +202,7 @@
 	}
 	if (cp) { /* points to ":" or "]:" */
 		int sz = cp - host + 1;
+
 		host = safe_strncpy(alloca(sz), host, sz);
 		if (ENABLE_FEATURE_IPV6 && *cp != ':') {
 			cp++; /* skip ']' */
@@ -371,6 +386,13 @@
 	int rc;
 	socklen_t salen;
 
+	if (ENABLE_FEATURE_UNIX_LOCAL && sa->sa_family == AF_UNIX) {
+		struct sockaddr_un *sun = (struct sockaddr_un *)sa;
+		return xasprintf("local:%.*s",
+				(int) sizeof(sun->sun_path),
+				sun->sun_path);
+	}
+
 	salen = LSA_SIZEOF_SA;
 #if ENABLE_FEATURE_IPV6
 	if (sa->sa_family == AF_INET)

 ------------------------------------------------------------------------
r26204 | vda | 2009-04-25 07:19:35 -0500 (Sat, 25 Apr 2009) | 19 lines
Changed paths:
   M /trunk/busybox/archival/Config.in
   M /trunk/busybox/archival/libunarchive/decompress_unlzma.c

unlzma: speedup, by Pascal Bellard (pascal.bellard AT ads-lu.com)

LZMA_FAST off: 10% faster and:
function                                             old     new   delta
rc_is_bit_1                                            -      92     +92
rc_do_normalize                                       45      81     +36
rc_update_bit_1                                       25       -     -25
rc_update_bit_0                                       30       -     -30
rc_is_bit_0_helper                                    38       -     -38
rc_get_bit                                            60      17     -43
rc_read                                               48       -     -48
unpack_lzma_stream                                  1768    1517    -251
 ------------------------------------------------------------------------------

(add/remove: 1/4 grow/shrink: 1/2 up/down: 128/-435)         Total: -307 bytes

LZMA_FAST on: 14% faster and:
unpack_lzma_stream                                  2301    2737    +436
rc_get_bit                                           106       -    -106

 ------------------------------------------------------------------------

Index: archival/Config.in
===================================================================
--- archival/Config.in	(revision 26203)
+++ archival/Config.in	(revision 26204)
@@ -283,8 +283,8 @@
 	default n
 	depends on UNLZMA
 	help
-	  This option reduces decompression time by about 33% at the cost of
-	  a 2K bigger binary.
+	  This option reduces decompression time by about 25% at the cost of
+	  a 1K bigger binary.
 
 config UNZIP
 	bool "unzip"
Index: archival/libunarchive/decompress_unlzma.c
===================================================================
--- archival/libunarchive/decompress_unlzma.c	(revision 26203)
+++ archival/libunarchive/decompress_unlzma.c	(revision 26204)
@@ -8,14 +8,15 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
-
 #include "libbb.h"
 #include "unarchive.h"
 
 #if ENABLE_FEATURE_LZMA_FAST
 #  define speed_inline ALWAYS_INLINE
+#  define size_inline
 #else
 #  define speed_inline
+#  define size_inline ALWAYS_INLINE
 #endif
 
 
@@ -44,8 +45,8 @@
 #define RC_MODEL_TOTAL_BITS 11
 
 
-/* Called twice: once at startup and once in rc_normalize() */
-static void rc_read(rc_t *rc)
+/* Called twice: once at startup (LZMA_FAST only) and once in rc_normalize() */
+static size_inline void rc_read(rc_t *rc)
 {
 	int buffer_size = safe_read(rc->fd, RC_BUFFER, RC_BUFFER_SIZE);
 	if (buffer_size <= 0)
@@ -54,8 +55,17 @@
 	rc->buffer_end = RC_BUFFER + buffer_size;
 }
 
+/* Called twice, but one callsite is in speed_inline'd rc_is_bit_1() */
+static void rc_do_normalize(rc_t *rc)
+{
+	if (rc->ptr >= rc->buffer_end)
+		rc_read(rc);
+	rc->range <<= 8;
+	rc->code = (rc->code << 8) | *rc->ptr++;
+}
+
 /* Called once */
-static rc_t* rc_init(int fd) /*, int buffer_size) */
+static ALWAYS_INLINE rc_t* rc_init(int fd) /*, int buffer_size) */
 {
 	int i;
 	rc_t *rc;
@@ -63,17 +73,18 @@
 	rc = xmalloc(sizeof(*rc) + RC_BUFFER_SIZE);
 
 	rc->fd = fd;
-	/* rc->buffer_size = buffer_size; */
-	rc->buffer_end = RC_BUFFER + RC_BUFFER_SIZE;
 	rc->ptr = rc->buffer_end;
 
-	rc->code = 0;
-	rc->range = 0xFFFFFFFF;
 	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;
 	return rc;
 }
 
@@ -83,14 +94,6 @@
 	free(rc);
 }
 
-/* Called twice, but one callsite is in speed_inline'd rc_is_bit_0_helper() */
-static void rc_do_normalize(rc_t *rc)
-{
-	if (rc->ptr >= rc->buffer_end)
-		rc_read(rc);
-	rc->range <<= 8;
-	rc->code = (rc->code << 8) | *rc->ptr++;
-}
 static ALWAYS_INLINE void rc_normalize(rc_t *rc)
 {
 	if (rc->range < (1 << RC_TOP_BITS)) {
@@ -98,49 +101,28 @@
 	}
 }
 
-/* rc_is_bit_0 is called 9 times */
-/* Why rc_is_bit_0_helper exists?
- * Because we want to always expose (rc->code < rc->bound) to optimizer.
- * Thus rc_is_bit_0 is always inlined, and rc_is_bit_0_helper is inlined
- * only if we compile for speed.
- */
-static speed_inline uint32_t rc_is_bit_0_helper(rc_t *rc, uint16_t *p)
+/* rc_is_bit_1 is called 9 times */
+static speed_inline int rc_is_bit_1(rc_t *rc, uint16_t *p)
 {
 	rc_normalize(rc);
 	rc->bound = *p * (rc->range >> RC_MODEL_TOTAL_BITS);
-	return rc->bound;
-}
-static ALWAYS_INLINE int rc_is_bit_0(rc_t *rc, uint16_t *p)
-{
-	uint32_t t = rc_is_bit_0_helper(rc, p);
-	return rc->code < t;
-}
-
-/* Called ~10 times, but very small, thus inlined */
-static speed_inline void rc_update_bit_0(rc_t *rc, uint16_t *p)
-{
-	rc->range = rc->bound;
-	*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
-}
-static speed_inline void rc_update_bit_1(rc_t *rc, uint16_t *p)
-{
+	if (rc->code < rc->bound) {
+		rc->range = rc->bound;
+		*p += ((1 << RC_MODEL_TOTAL_BITS) - *p) >> RC_MOVE_BITS;
+		return 0;
+	}
 	rc->range -= rc->bound;
 	rc->code -= rc->bound;
 	*p -= *p >> RC_MOVE_BITS;
+	return 1;
 }
 
 /* Called 4 times in unlzma loop */
-static int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
+static speed_inline int rc_get_bit(rc_t *rc, uint16_t *p, int *symbol)
 {
-	if (rc_is_bit_0(rc, p)) {
-		rc_update_bit_0(rc, p);
-		*symbol *= 2;
-		return 0;
-	} else {
-		rc_update_bit_1(rc, p);
-		*symbol = *symbol * 2 + 1;
-		return 1;
-	}
+	int ret = rc_is_bit_1(rc, p);
+	*symbol = *symbol * 2 + ret;
+	return ret;
 }
 
 /* Called once */
@@ -266,13 +248,13 @@
 	header.dst_size = SWAP_LE64(header.dst_size);
 
 	if (header.dict_size == 0)
-		header.dict_size = 1;
+		header.dict_size++;
 
 	buffer = xmalloc(MIN(header.dst_size, header.dict_size));
 
 	num_probs = LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp));
 	p = xmalloc(num_probs * sizeof(*p));
-	num_probs = LZMA_LITERAL + (LZMA_LIT_SIZE << (lc + lp));
+	num_probs += LZMA_LITERAL - LZMA_BASE_SIZE;
 	for (i = 0; i < num_probs; i++)
 		p[i] = (1 << RC_MODEL_TOTAL_BITS) >> 1;
 
@@ -282,9 +264,8 @@
 		int pos_state = (buffer_pos + global_pos) & pos_state_mask;
 
 		prob = p + LZMA_IS_MATCH + (state << LZMA_NUM_POS_BITS_MAX) + pos_state;
-		if (rc_is_bit_0(rc, prob)) {
+		if (!rc_is_bit_1(rc, prob)) {
 			mi = 1;
-			rc_update_bit_0(rc, prob);
 			prob = (p + LZMA_LITERAL
 			        + (LZMA_LIT_SIZE * ((((buffer_pos + global_pos) & literal_pos_mask) << lc)
 			                            + (previous_byte >> (8 - lc))
@@ -340,27 +321,21 @@
 			int offset;
 			uint16_t *prob_len;
 
-			rc_update_bit_1(rc, prob);
 			prob = p + LZMA_IS_REP + state;
-			if (rc_is_bit_0(rc, prob)) {
-				rc_update_bit_0(rc, prob);
+			if (!rc_is_bit_1(rc, prob)) {
 				rep3 = rep2;
 				rep2 = rep1;
 				rep1 = rep0;
 				state = state < LZMA_NUM_LIT_STATES ? 0 : 3;
 				prob = p + LZMA_LEN_CODER;
 			} else {
-				rc_update_bit_1(rc, prob);
-				prob = p + LZMA_IS_REP_G0 + state;
-				if (rc_is_bit_0(rc, prob)) {
-					rc_update_bit_0(rc, prob);
+				prob += LZMA_IS_REP_G0 - LZMA_IS_REP;
+				if (!rc_is_bit_1(rc, prob)) {
 					prob = (p + LZMA_IS_REP_0_LONG
 					        + (state << LZMA_NUM_POS_BITS_MAX)
 					        + pos_state
 					);
-					if (rc_is_bit_0(rc, prob)) {
-						rc_update_bit_0(rc, prob);
-
+					if (!rc_is_bit_1(rc, prob)) {
 						state = state < LZMA_NUM_LIT_STATES ? 9 : 11;
 #if ENABLE_FEATURE_LZMA_FAST
 						pos = buffer_pos - rep0;
@@ -372,25 +347,16 @@
 						len = 1;
 						goto string;
 #endif
-					} else {
-						rc_update_bit_1(rc, prob);
 					}
 				} else {
 					uint32_t distance;
 
-					rc_update_bit_1(rc, prob);
-					prob = p + LZMA_IS_REP_G1 + state;
-					if (rc_is_bit_0(rc, prob)) {
-						rc_update_bit_0(rc, prob);
-						distance = rep1;
-					} else {
-						rc_update_bit_1(rc, prob);
-						prob = p + LZMA_IS_REP_G2 + state;
-						if (rc_is_bit_0(rc, prob)) {
-							rc_update_bit_0(rc, prob);
-							distance = rep2;
-						} else {
-							rc_update_bit_1(rc, prob);
+					prob += LZMA_IS_REP_G1 - LZMA_IS_REP_G0;
+					distance = rep1;
+					if (rc_is_bit_1(rc, prob)) {
+						prob += LZMA_IS_REP_G2 - LZMA_IS_REP_G1;
+						distance = rep2;
+						if (rc_is_bit_1(rc, prob)) {
 							distance = rep3;
 							rep3 = rep2;
 						}
@@ -404,24 +370,20 @@
 			}
 
 			prob_len = prob + LZMA_LEN_CHOICE;
-			if (rc_is_bit_0(rc, prob_len)) {
-				rc_update_bit_0(rc, prob_len);
-				prob_len = (prob + LZMA_LEN_LOW
-				            + (pos_state << LZMA_LEN_NUM_LOW_BITS));
+			if (!rc_is_bit_1(rc, prob_len)) {
+				prob_len += LZMA_LEN_LOW - LZMA_LEN_CHOICE
+				            + (pos_state << LZMA_LEN_NUM_LOW_BITS);
 				offset = 0;
 				num_bits = LZMA_LEN_NUM_LOW_BITS;
 			} else {
-				rc_update_bit_1(rc, prob_len);
-				prob_len = prob + LZMA_LEN_CHOICE_2;
-				if (rc_is_bit_0(rc, prob_len)) {
-					rc_update_bit_0(rc, prob_len);
-					prob_len = (prob + LZMA_LEN_MID
-					            + (pos_state << LZMA_LEN_NUM_MID_BITS));
+				prob_len += LZMA_LEN_CHOICE_2 - LZMA_LEN_CHOICE;
+				if (!rc_is_bit_1(rc, prob_len)) {
+					prob_len += LZMA_LEN_MID - LZMA_LEN_CHOICE_2
+					            + (pos_state << LZMA_LEN_NUM_MID_BITS);
 					offset = 1 << LZMA_LEN_NUM_LOW_BITS;
 					num_bits = LZMA_LEN_NUM_MID_BITS;
 				} else {
-					rc_update_bit_1(rc, prob_len);
-					prob_len = prob + LZMA_LEN_HIGH;
+					prob_len += LZMA_LEN_HIGH - LZMA_LEN_CHOICE_2;
 					offset = ((1 << LZMA_LEN_NUM_LOW_BITS)
 					          + (1 << LZMA_LEN_NUM_MID_BITS));
 					num_bits = LZMA_LEN_NUM_HIGH_BITS;
@@ -438,19 +400,20 @@
 				       ((len < LZMA_NUM_LEN_TO_POS_STATES ? len :
 				         LZMA_NUM_LEN_TO_POS_STATES - 1)
 				         << LZMA_NUM_POS_SLOT_BITS);
-				rc_bit_tree_decode(rc, prob, LZMA_NUM_POS_SLOT_BITS,
-								   &pos_slot);
+				rc_bit_tree_decode(rc, prob,
+					LZMA_NUM_POS_SLOT_BITS, &pos_slot);
+				rep0 = pos_slot;
 				if (pos_slot >= LZMA_START_POS_MODEL_INDEX) {
 					num_bits = (pos_slot >> 1) - 1;
 					rep0 = 2 | (pos_slot & 1);
+					prob = p + LZMA_ALIGN;
 					if (pos_slot < LZMA_END_POS_MODEL_INDEX) {
 						rep0 <<= num_bits;
-						prob = p + LZMA_SPEC_POS + rep0 - pos_slot - 1;
+						prob += LZMA_SPEC_POS - LZMA_ALIGN - 1 + rep0 - pos_slot;
 					} else {
 						num_bits -= LZMA_NUM_ALIGN_BITS;
 						while (num_bits--)
 							rep0 = (rep0 << 1) | rc_direct_bit(rc);
-						prob = p + LZMA_ALIGN;
 						rep0 <<= LZMA_NUM_ALIGN_BITS;
 						num_bits = LZMA_NUM_ALIGN_BITS;
 					}
@@ -461,8 +424,7 @@
 							rep0 |= i;
 						i <<= 1;
 					}
-				} else
-					rep0 = pos_slot;
+				}
 				if (++rep0 == 0)
 					break;
 			}

 ------------------------------------------------------------------------
r26203 | vapier | 2009-04-25 01:16:37 -0500 (Sat, 25 Apr 2009) | 1 line
Changed paths:
   M /trunk/busybox/miscutils/watchdog.c

we need to daemonize *before* opening the watchdog device
 ------------------------------------------------------------------------

Index: miscutils/watchdog.c
===================================================================
--- miscutils/watchdog.c	(revision 26202)
+++ miscutils/watchdog.c	(revision 26203)
@@ -45,6 +45,15 @@
 	opt_complementary = "=1"; /* must have exactly 1 argument */
 	opts = getopt32(argv, "Ft:T:", &st_arg, &ht_arg);
 
+	/* We need to daemonize *before* opening the watchdog as many drivers
+	 * will only allow one process at a time to do so.  Since daemonizing
+	 * is not perfect (child may run before parent finishes exiting), we
+	 * can't rely on parent exiting before us (let alone *cleanly* releasing
+	 * the watchdog fd -- something else that may not even be allowed).
+	 */
+	if (!(opts & OPT_FOREGROUND))
+		bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
+
 	if (opts & OPT_HTIMER)
 		htimer_duration = xatou_sfx(ht_arg, suffixes);
 	stimer_duration = htimer_duration / 2;
@@ -76,10 +85,6 @@
 		stimer_duration, htimer_duration * 1000);
 #endif
 
-	if (!(opts & OPT_FOREGROUND)) {
-		bb_daemonize_or_rexec(DAEMON_CHDIR_ROOT, argv);
-	}
-
 	while (1) {
 		/*
 		 * Make sure we clear the counter before sleeping,

 ------------------------------------------------------------------------
r26201 | vapier | 2009-04-24 01:40:30 -0500 (Fri, 24 Apr 2009) | 1 line
Changed paths:
   M /trunk/busybox/shell/hush.c

do not tell people they can enter "help" if help has actually been disabled
 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26200)
+++ shell/hush.c	(revision 26201)
@@ -6259,7 +6259,9 @@
 
 	if (!ENABLE_FEATURE_SH_EXTRA_QUIET && G_interactive_fd) {
 		printf("\n\n%s hush - the humble shell\n", bb_banner);
-		printf("Enter 'help' for a list of built-in commands.\n\n");
+		if (ENABLE_HUSH_HELP)
+			puts("Enter 'help' for a list of built-in commands.");
+		puts("");
 	}
 
 	parse_and_run_file(stdin);

 ------------------------------------------------------------------------
r26200 | vapier | 2009-04-24 01:26:18 -0500 (Fri, 24 Apr 2009) | 1 line
Changed paths:
   M /trunk/busybox/shell/hush.c

use get_local_var_value() rather than getenv() when working with PS1/PS2/HOME, respect the PS2 env var, and make sure that the prompt changes whenever PS1/PS2 changes so we dont have to re-exec the shell to get a changed prompt
 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26199)
+++ shell/hush.c	(revision 26200)
@@ -795,6 +795,13 @@
 #endif
 
 
+#if ENABLE_HUSH_INTERACTIVE
+static void cmdedit_update_prompt(void);
+#else
+# define cmdedit_update_prompt()
+#endif
+
+
 /* Utility functions
  */
 static int glob_needed(const char *s)
@@ -1332,6 +1339,8 @@
  exp:
 	if (flg_export == 1)
 		cur->flg_export = 1;
+	if (name_len == 4 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
+		cmdedit_update_prompt();
 	if (cur->flg_export) {
 		if (flg_export == -1) {
 			cur->flg_export = 0;
@@ -1365,6 +1374,8 @@
 			prev->next = cur->next;
 			debug_printf_env("%s: unsetenv '%s'\n", __func__, cur->varstr);
 			bb_unsetenv(cur->varstr);
+			if (name_len == 3 && cur->varstr[0] == 'P' && cur->varstr[1] == 'S')
+				cmdedit_update_prompt();
 			if (!cur->max_len)
 				free(cur->varstr);
 			free(cur);
@@ -1421,14 +1432,17 @@
 
 #if ENABLE_HUSH_INTERACTIVE
 
-static void cmdedit_set_initial_prompt(void)
+static void cmdedit_update_prompt(void)
 {
 	if (ENABLE_FEATURE_EDITING_FANCY_PROMPT) {
-		G.PS1 = getenv("PS1");
+		G.PS1 = get_local_var_value("PS1");
 		if (G.PS1 == NULL)
 			G.PS1 = "\\w \\$ ";
+		G.PS2 = get_local_var_value("PS2");
 	} else
 		G.PS1 = NULL;
+	if (G.PS2 == NULL)
+		G.PS2 = "> ";
 }
 
 static const char* setup_prompt_string(int promptmode)
@@ -6002,11 +6016,7 @@
 	G.global_argv = argv;
 	/* Initialize some more globals to non-zero values */
 	set_cwd();
-#if ENABLE_HUSH_INTERACTIVE
-	if (ENABLE_FEATURE_EDITING)
-		cmdedit_set_initial_prompt();
-	G.PS2 = "> ";
-#endif
+	cmdedit_update_prompt();
 
 	if (setjmp(die_jmp)) {
 		/* xfunc has failed! die die die */
@@ -6334,7 +6344,7 @@
 		 * bash says "bash: cd: HOME not set" and does nothing
 		 * (exitcode 1)
 		 */
-		newdir = getenv("HOME") ? : "/";
+		newdir = get_local_var_value("HOME") ? : "/";
 	}
 	if (chdir(newdir)) {
 		/* Mimic bash message exactly */

 ------------------------------------------------------------------------
r26188 | vda | 2009-04-22 18:25:48 -0500 (Wed, 22 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/inetd.c

inetd: constify data


 ------------------------------------------------------------------------

Index: networking/inetd.c
===================================================================
--- networking/inetd.c	(revision 26187)
+++ networking/inetd.c	(revision 26188)
@@ -658,7 +658,7 @@
 	}
 
 	{
-		static int8_t SOCK_xxx[] ALIGN1 = {
+		static const int8_t SOCK_xxx[] ALIGN1 = {
 			-1,
 			SOCK_STREAM, SOCK_DGRAM, SOCK_RDM,
 			SOCK_SEQPACKET, SOCK_RAW

 ------------------------------------------------------------------------
r26187 | vda | 2009-04-22 16:35:52 -0500 (Wed, 22 Apr 2009) | 13 lines
Changed paths:
   M /trunk/busybox/include/usage.h
   M /trunk/busybox/loginutils/Config.in
   M /trunk/busybox/loginutils/addgroup.c
   M /trunk/busybox/loginutils/adduser.c

adduser/addgroup: support specifying uid/gid, add system
 account creation mode. By Tito.

function                                             old     new   delta
adduser_main                                         650     726     +76
addgroup_main                                        341     402     +61
addgroup_longopts                                      -      16     +16
adduser_longopts                                      97     103      +6
packed_usage                                       26161   26163      +2
 ------------------------------------------------------------------------------

(add/remove: 1/0 grow/shrink: 4/0 up/down: 161/0)             Total: 161 bytes


 ------------------------------------------------------------------------

Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26186)
+++ include/usage.h	(revision 26187)
@@ -39,6 +39,7 @@
        "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_name"
@@ -52,6 +53,7 @@
      "\n	-S		Create a system user" \
      "\n	-D		Do not assign a password" \
      "\n	-H		Do not create home directory" \
+     "\n	-u UID		User id" \
 
 #define adjtimex_trivial_usage \
        "[-q] [-o offset] [-f frequency] [-p timeconstant] [-t tick]"
Index: loginutils/addgroup.c
===================================================================
--- loginutils/addgroup.c	(revision 26186)
+++ loginutils/addgroup.c	(revision 26187)
@@ -11,34 +11,50 @@
  */
 #include "libbb.h"
 
+#define OPT_GID                       (1 << 0)
+#define OPT_SYSTEM_ACCOUNT            (1 << 1)
+
+/* We assume GID_T_MAX == INT_MAX */
 static void xgroup_study(struct group *g)
 {
+	unsigned max = INT_MAX;
+
 	/* Make sure gr_name is unused */
 	if (getgrnam(g->gr_name)) {
-		goto error;
+		bb_error_msg_and_die("%s '%s' in use", "group", g->gr_name);
+		/* these format strings are reused in adduser and addgroup */
 	}
 
+	/* if a specific gid is requested, the --system switch and */
+	/* min and max values are overriden, and the range of valid */
+	/* gid values is set to [0, INT_MAX] */
+	if (!(option_mask32 & OPT_GID)) {
+		if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
+			g->gr_gid = 100; /* FIRST_SYSTEM_GID */
+			max = 999;       /* LAST_SYSTEM_GID */
+		} else {
+			g->gr_gid = 1000; /* FIRST_GID */
+			max = 64999;      /* LAST_GID */
+		}
+	}
 	/* Check if the desired gid is free
 	 * or find the first free one */
 	while (1) {
 		if (!getgrgid(g->gr_gid)) {
 			return; /* found free group: return */
 		}
-		if (option_mask32) {
+		if (option_mask32 & OPT_GID) {
 			/* -g N, cannot pick gid other than N: error */
-			g->gr_name = itoa(g->gr_gid);
-			goto error;
+			bb_error_msg_and_die("%s '%s' in use", "gid", itoa(g->gr_gid));
+			/* this format strings is reused in adduser and addgroup */
 		}
-		g->gr_gid++;
-		if (g->gr_gid <= 0) {
+		if (g->gr_gid == max) {
 			/* overflowed: error */
-			bb_error_msg_and_die("no gids left");
+			bb_error_msg_and_die("no %cids left", 'g');
+			/* this format string is reused in adduser and addgroup */
 		}
+		g->gr_gid++;
 	}
-
- error:
-	/* exit */
-	bb_error_msg_and_die("group %s already exists", g->gr_name);
 }
 
 /* append a new user to the passwd file */
@@ -53,7 +69,7 @@
 	xgroup_study(&gr);
 
 	/* add entry to group */
-	p = xasprintf("x:%u:", gr.gr_gid);
+	p = xasprintf("x:%u:", (unsigned) gr.gr_gid);
 	if (update_passwd(bb_path_group_file, group, p, NULL) < 0)
 		exit(EXIT_FAILURE);
 	if (ENABLE_FEATURE_CLEAN_UP)
@@ -64,6 +80,13 @@
 #endif
 }
 
+#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
+static const char addgroup_longopts[] ALIGN1 =
+		"gid\0"                 Required_argument "g"
+		"system\0"              No_argument       "S"
+		;
+#endif
+
 /*
  * addgroup will take a login_name as its first parameter.
  *
@@ -74,23 +97,23 @@
 int addgroup_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int addgroup_main(int argc UNUSED_PARAM, char **argv)
 {
-	char *group;
-	gid_t gid = 0;
+	unsigned opts;
+	unsigned gid = 0;
 
 	/* need to be root */
 	if (geteuid()) {
 		bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
 	}
-
+#if ENABLE_FEATURE_ADDGROUP_LONG_OPTIONS
+	applet_long_options = addgroup_longopts;
+#endif
 	/* Syntax:
 	 *  addgroup group
 	 *  addgroup -g num group
 	 *  addgroup user group
 	 * Check for min, max and missing args */
-	opt_complementary = "-1:?2";
-	if (getopt32(argv, "g:", &group)) {
-		gid = xatoul_range(group, 0, ((unsigned long)(gid_t)ULONG_MAX) >> 1);
-	}
+	opt_complementary = "-1:?2:g+";
+	opts = getopt32(argv, "g:S", &gid);
 	/* move past the commandline options */
 	argv += optind;
 	//argc -= optind;
@@ -99,7 +122,7 @@
 	if (argv[1]) {
 		struct group *gr;
 
-		if (option_mask32) {
+		if (opts & OPT_GID) {
 			/* -g was there, but "addgroup -g num user group"
 			 * is a no-no */
 			bb_show_usage();
Index: loginutils/adduser.c
===================================================================
--- loginutils/adduser.c	(revision 26186)
+++ loginutils/adduser.c	(revision 26187)
@@ -9,38 +9,55 @@
  */
 #include "libbb.h"
 
+/* #define OPT_HOME           (1 << 0) */ /* unused */
+/* #define OPT_GECOS          (1 << 1) */ /* unused */
+#define OPT_SHELL          (1 << 2)
+#define OPT_GID            (1 << 3)
 #define OPT_DONT_SET_PASS  (1 << 4)
 #define OPT_SYSTEM_ACCOUNT (1 << 5)
 #define OPT_DONT_MAKE_HOME (1 << 6)
+#define OPT_UID            (1 << 7)
 
+/* We assume UID_T_MAX == INT_MAX */
 /* remix */
 /* recoded such that the uid may be passed in *p */
 static void passwd_study(struct passwd *p)
 {
-	int max;
+	int max = UINT_MAX;
 
-	if (getpwnam(p->pw_name))
-		bb_error_msg_and_die("login '%s' is in use", p->pw_name);
+	if (getpwnam(p->pw_name)) {
+		bb_error_msg_and_die("%s '%s' in use", "user", p->pw_name);
+		/* this format string is reused in adduser and addgroup */
+	}
 
-	if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
-		p->pw_uid = 0;
-		max = 999;
-	} else {
-		p->pw_uid = 1000;
-		max = 64999;
+	if (!(option_mask32 & OPT_UID)) {
+		if (option_mask32 & OPT_SYSTEM_ACCOUNT) {
+			p->pw_uid = 100; /* FIRST_SYSTEM_UID */
+			max = 999;       /* LAST_SYSTEM_UID */
+		} else {
+			p->pw_uid = 1000; /* FIRST_UID */
+			max = 64999;      /* LAST_UID */
+		}
 	}
-
 	/* check for a free uid (and maybe gid) */
 	while (getpwuid(p->pw_uid) || (p->pw_gid == (gid_t)-1 && getgrgid(p->pw_uid))) {
+		if (option_mask32 & OPT_UID) {
+			/* -u N, cannot pick uid other than N: error */
+			bb_error_msg_and_die("%s '%s' in use", "uid", itoa(p->pw_uid));
+			/* this format string is reused in adduser and addgroup */
+		}
+		if (p->pw_uid == max) {
+			bb_error_msg_and_die("no %cids left", 'u');
+		}
 		p->pw_uid++;
-		if (p->pw_uid > max)
-			bb_error_msg_and_die("no free uids left");
 	}
 
 	if (p->pw_gid == (gid_t)-1) {
 		p->pw_gid = p->pw_uid; /* new gid = uid */
-		if (getgrnam(p->pw_name))
-			bb_error_msg_and_die("group name '%s' is in use", p->pw_name);
+		if (getgrnam(p->pw_name)) {
+			bb_error_msg_and_die("%s '%s' in use", "group", p->pw_name);
+			/* this format string is reused in adduser and addgroup */
+		}
 	}
 }
 
@@ -73,6 +90,7 @@
 		"empty-password\0"      No_argument       "D"
 		"system\0"              No_argument       "S"
 		"no-create-home\0"      No_argument       "H"
+		"uid\0"                 Required_argument "u"
 		;
 #endif
 
@@ -87,6 +105,7 @@
 	struct passwd pw;
 	const char *usegroup = NULL;
 	char *p;
+	unsigned opts;
 
 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
 	applet_long_options = adduser_longopts;
@@ -102,8 +121,17 @@
 	pw.pw_dir = NULL;
 
 	/* exactly one non-option arg */
-	opt_complementary = "=1";
-	getopt32(argv, "h:g:s:G:DSH", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup);
+	/* 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);
+	} else {
+		unsigned uid;
+		opts = getopt32(argv, "h:g:s:G:DSHu:", &pw.pw_dir, &pw.pw_gecos, &pw.pw_shell, &usegroup, &uid);
+		if (opts & OPT_UID) {
+			pw.pw_uid = uid;
+		}
+	}
 	argv += optind;
 
 	/* fill in the passwd struct */
@@ -114,12 +142,22 @@
 		pw.pw_dir = xasprintf("/home/%s", argv[0]);
 	}
 	pw.pw_passwd = (char *)"x";
+	if (opts & OPT_SYSTEM_ACCOUNT) {
+		if (!usegroup) {
+			usegroup = "nogroup";
+		}
+		if (!(opts & OPT_SHELL)) {
+			pw.pw_shell = (char *) "/bin/false";
+		}
+	}
 	pw.pw_gid = usegroup ? xgroup2gid(usegroup) : -1; /* exits on failure */
 
 	/* make sure everything is kosher and setup uid && maybe gid */
 	passwd_study(&pw);
 
-	p = xasprintf("x:%u:%u:%s:%s:%s", pw.pw_uid, pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell);
+	p = xasprintf("x:%u:%u:%s:%s:%s",
+			(unsigned) pw.pw_uid, (unsigned) pw.pw_gid,
+			pw.pw_gecos, pw.pw_dir, pw.pw_shell);
 	if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) {
 		return EXIT_FAILURE;
 	}
@@ -143,10 +181,10 @@
 	/* clear the umask for this process so it doesn't
 	 * screw up the permissions on the mkdir and chown. */
 	umask(0);
-	if (!(option_mask32 & OPT_DONT_MAKE_HOME)) {
-		/* Set the owner and group so it is owned by the new user,
-		   then fix up the permissions to 2755. Can't do it before
-		   since chown will clear the setgid bit */
+	if (!(opts & OPT_DONT_MAKE_HOME)) {
+		/* set the owner and group so it is owned by the new user,
+		 * then fix up the permissions to 2755. Can't do it before
+		 * since chown will clear the setgid bit */
 		if (mkdir(pw.pw_dir, 0755)
 		 || chown(pw.pw_dir, pw.pw_uid, pw.pw_gid)
 		 || chmod(pw.pw_dir, 02755) /* set setgid bit on homedir */
@@ -155,7 +193,7 @@
 		}
 	}
 
-	if (!(option_mask32 & OPT_DONT_SET_PASS)) {
+	if (!(opts & OPT_DONT_SET_PASS)) {
 		/* interactively set passwd */
 		passwd_wrapper(pw.pw_name);
 	}
Index: loginutils/Config.in
===================================================================
--- loginutils/Config.in	(revision 26186)
+++ loginutils/Config.in	(revision 26187)
@@ -97,6 +97,13 @@
 	help
 	  Utility for creating a new group account.
 
+config FEATURE_ADDGROUP_LONG_OPTIONS
+	bool "Enable long options"
+	default n
+	depends on ADDGROUP && GETOPT_LONG
+	help
+	  Support long options for the addgroup applet.
+
 config FEATURE_ADDUSER_TO_GROUP
 	bool "Support for adding users to groups"
 	default n

 ------------------------------------------------------------------------
r26186 | vda | 2009-04-22 09:16:59 -0500 (Wed, 22 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/httpd.c

httpd: fix small bug in parser. it crept in during cleanup


 ------------------------------------------------------------------------

Index: networking/httpd.c
===================================================================
--- networking/httpd.c	(revision 26185)
+++ networking/httpd.c	(revision 26186)
@@ -100,7 +100,6 @@
 # include 
 #endif
 
-//#define DEBUG 1
 #define DEBUG 0
 
 #define IOBUF_SIZE 8192    /* IO buffer */
@@ -698,13 +697,13 @@
 			unsigned file_len;
 
 			/* note: path is "" unless we are in SUBDIR parse,
-			 * otherwise it always starts with "/" */
+			 * otherwise it does NOT start with "/" */
 			cur = xzalloc(sizeof(*cur) /* includes space for NUL */
-				+ strlen(path)
+				+ 1 + strlen(path)
 				+ strlen_buf
 				);
 			/* form "/path/file" */
-			sprintf(cur->before_colon, "%s%.*s",
+			sprintf(cur->before_colon, "/%s%.*s",
 				path,
 				after_colon - buf - 1, /* includes "/", but not ":" */
 				buf);

 ------------------------------------------------------------------------
r26185 | vda | 2009-04-22 08:52:22 -0500 (Wed, 22 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/httpd.c

httpd: allow empty lines in conf file


 ------------------------------------------------------------------------

Index: networking/httpd.c
===================================================================
--- networking/httpd.c	(revision 26184)
+++ networking/httpd.c	(revision 26185)
@@ -546,9 +546,11 @@
 			}
 			*p = '\0';
 			strlen_buf = p - buf;
+			if (strlen_buf == 0)
+				continue;
 		}
 
-		/* empty or strange line? */
+		/* strange line? */
 		if (after_colon == NULL || *after_colon == '\0')
 			goto config_error;
 

 ------------------------------------------------------------------------
r26184 | vda | 2009-04-22 08:49:16 -0500 (Wed, 22 Apr 2009) | 14 lines
Changed paths:
   M /trunk/busybox/include/libbb.h
   M /trunk/busybox/libbb/simplify_path.c
   M /trunk/busybox/networking/httpd.c

httpd: simplify insane conf file parser

function                                             old     new   delta
bb_simplify_abs_path_inplace                           -      98     +98
parse_expr                                           824     832      +8
passwd_main                                         1025    1027      +2
evalvar                                             1374    1376      +2
parse_command                                       1463    1460      -3
bb_simplify_path                                     137      55     -82
parse_conf                                          1572    1422    -150
 ------------------------------------------------------------------------------

(add/remove: 3/2 grow/shrink: 3/3 up/down: 126/-251)         Total: -125 bytes


 ------------------------------------------------------------------------

Index: networking/httpd.c
===================================================================
--- networking/httpd.c	(revision 26183)
+++ networking/httpd.c	(revision 26184)
@@ -54,7 +54,7 @@
  * /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/
  * .au:audio/basic   # additional mime type for audio.au files
- * *.php:/path/php   # running cgi.php scripts through an interpreter
+ * *.php:/path/php   # run xxx.php through an interpreter
  *
  * A/D may be as a/d or allow/deny - only first char matters.
  * Deny/Allow IP logic:
@@ -115,8 +115,8 @@
 
 #define HEADER_READ_TIMEOUT 60
 
-static const char default_path_httpd_conf[] ALIGN1 = "/etc";
-static const char httpd_conf[] ALIGN1 = "httpd.conf";
+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";
 
 typedef struct has_next_ptr {
@@ -242,7 +242,7 @@
 	const char *bind_addr_or_port;
 
 	const char *g_query;
-	const char *configFile;
+	const char *opt_c_configFile;
 	const char *home_httpd;
 	const char *index_page;
 
@@ -289,7 +289,7 @@
 #define rmt_ip            (G.rmt_ip           )
 #define bind_addr_or_port (G.bind_addr_or_port)
 #define g_query           (G.g_query          )
-#define configFile        (G.configFile       )
+#define opt_c_configFile  (G.opt_c_configFile )
 #define home_httpd        (G.home_httpd       )
 #define index_page        (G.index_page       )
 #define found_mime_type   (G.found_mime_type  )
@@ -452,14 +452,6 @@
 /*
  * Parse configuration file into in-memory linked list.
  *
- * The first non-white character is examined to determine if the config line
- * is one of the following:
- *    .ext:mime/type   # new mime type not compiled into httpd
- *    [adAD]:from      # ip address allow/deny, * for wildcard
- *    /path:user:pass  # username/password
- *    Ennn:error.html  # error page for status nnn
- *    P:/url:[http://]hostname[:port]/new/path # reverse proxy
- *
  * Any previous IP rules are discarded.
  * If the flag argument is not SUBDIR_PARSE then all /path and mime rules
  * are also discarded.  That is, previous settings are retained if flag is
@@ -469,99 +461,136 @@
  * path   Path where to look for httpd.conf (without filename).
  * flag   Type of the parse request.
  */
-/* flag */
-#define FIRST_PARSE          0
-#define SUBDIR_PARSE         1
-#define SIGNALED_PARSE       2
-#define FIND_FROM_HTTPD_ROOT 3
+/* flag param: */
+enum {
+	FIRST_PARSE    = 0, /* path will be "/etc" */
+	SIGNALED_PARSE = 1, /* path will be "/etc" */
+	SUBDIR_PARSE   = 2, /* path will be derived from URL */
+};
 static void parse_conf(const char *path, int flag)
 {
+	/* internally used extra flag state */
+	enum { TRY_CURDIR_PARSE = 3 };
+
 	FILE *f;
-#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-	Htaccess *prev;
-#endif
-	Htaccess *cur;
-	const char *filename = configFile;
+	const char *filename;
 	char buf[160];
-	char *p, *p0;
-	char *after_colon;
-	Htaccess_IP *pip;
 
 	/* discard old rules */
 	free_Htaccess_IP_list(&ip_a_d);
 	flg_deny_all = 0;
 	/* retain previous auth and mime config only for subdir parse */
 	if (flag != SUBDIR_PARSE) {
+		free_Htaccess_list(&mime_a);
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
 		free_Htaccess_list(&g_auth);
 #endif
-		free_Htaccess_list(&mime_a);
 #if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
 		free_Htaccess_list(&script_i);
 #endif
 	}
 
+	filename = opt_c_configFile;
 	if (flag == SUBDIR_PARSE || filename == NULL) {
-		filename = alloca(strlen(path) + sizeof(httpd_conf) + 2);
-		sprintf((char *)filename, "%s/%s", path, httpd_conf);
+		filename = alloca(strlen(path) + sizeof(HTTPD_CONF) + 2);
+		sprintf((char *)filename, "%s/%s", path, HTTPD_CONF);
 	}
 
 	while ((f = fopen_for_read(filename)) == NULL) {
-		if (flag == SUBDIR_PARSE || flag == FIND_FROM_HTTPD_ROOT) {
+		if (flag >= SUBDIR_PARSE) { /* SUBDIR or TRY_CURDIR */
 			/* config file not found, no changes to config */
 			return;
 		}
-		if (configFile && flag == FIRST_PARSE) /* if -c option given */
-			bb_simple_perror_msg_and_die(filename);
-		flag = FIND_FROM_HTTPD_ROOT;
-		filename = httpd_conf;
+		if (flag == FIRST_PARSE) {
+			/* -c CONFFILE given, but CONFFILE doesn't exist? */
+			if (opt_c_configFile)
+				bb_simple_perror_msg_and_die(opt_c_configFile);
+			/* else: no -c, thus we looked at /etc/httpd.conf,
+			 * and it's not there. try ./httpd.conf: */
+		}
+		flag = TRY_CURDIR_PARSE;
+		filename = HTTPD_CONF;
 	}
 
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-	prev = g_auth;
+	/* in "/file:user:pass" lines, we prepend path in subdirs */
+	if (flag != SUBDIR_PARSE)
+		path = "";
 #endif
-	/* This could stand some work */
-	while ((p0 = fgets(buf, sizeof(buf), f)) != NULL) {
-		after_colon = NULL;
-		for (p = p0; *p0 != '\0' && *p0 != '#'; p0++) {
-			if (!isspace(*p0)) {
-				*p++ = *p0;
-				if (*p0 == ':' && after_colon == NULL)
-					after_colon = p;
+	/* The lines can be:
+	 *
+	 * I:default_index_file
+	 * H:http_home
+	 * [AD]:IP[/mask]   # allow/deny, * for wildcard
+	 * Ennn:error.html  # error page for status nnn
+	 * P:/url:[http://]hostname[:port]/new/path # reverse proxy
+	 * .ext:mime/type   # mime type
+	 * *.php:/path/php  # run xxx.php through an interpreter
+	 * /file:user:pass  # username and password
+	 */
+	while (fgets(buf, sizeof(buf), f) != NULL) {
+		unsigned strlen_buf;
+		unsigned char ch;
+		char *after_colon = NULL;
+
+		{ /* remove all whitespace, and # comments */
+			char *p, *p0;
+
+			p = p0 = buf;
+			while ((ch = *p0++) != '\0' && ch != '#') {
+				if (!isspace(ch)) {
+					*p++ = ch;
+					if (ch == ':' && after_colon == NULL)
+						after_colon = p;
+				}
 			}
+			*p = '\0';
+			strlen_buf = p - buf;
 		}
-		*p = '\0';
 
-		/* test for empty or strange line */
+		/* empty or strange line? */
 		if (after_colon == NULL || *after_colon == '\0')
+			goto config_error;
+
+		ch = (buf[0] & ~0x20); /* toupper if it's a letter */
+
+		if (ch == 'I') {
+			index_page = xstrdup(after_colon);
 			continue;
-		p0 = buf;
-		if (*p0 == 'd' || *p0 == 'a')
-			*p0 -= 0x20; /* a/d -> A/D */
-		if (*after_colon == '*') {
-			if (*p0 == 'D') {
-				/* memorize "deny all" */
-				flg_deny_all = 1;
-			}
-			/* skip assumed "A:*", it is a default anyway */
+		}
+
+		/* do not allow jumping around using H in subdir's configs */
+		if (flag == FIRST_PARSE && ch == 'H') {
+			home_httpd = xstrdup(after_colon);
+			xchdir(home_httpd);
 			continue;
 		}
 
-		if (*p0 == 'A' || *p0 == 'D') {
-			/* storing current config IP line */
-			pip = xzalloc(sizeof(Htaccess_IP));
-			if (scan_ip_mask(after_colon, &(pip->ip), &(pip->mask))) {
+		if (ch == 'A' || ch == 'D') {
+			Htaccess_IP *pip;
+
+			if (*after_colon == '*') {
+				if (ch == 'D') {
+					/* memorize "deny all" */
+					flg_deny_all = 1;
+				}
+				/* skip assumed "A:*", it is a default anyway */
+				continue;
+			}
+			/* store "allow/deny IP/mask" line */
+			pip = xzalloc(sizeof(*pip));
+			if (scan_ip_mask(after_colon, &pip->ip, &pip->mask)) {
 				/* IP{/mask} syntax error detected, protect all */
-				*p0 = 'D';
+				ch = 'D';
 				pip->mask = 0;
 			}
-			pip->allow_deny = *p0;
-			if (*p0 == 'D') {
+			pip->allow_deny = ch;
+			if (ch == 'D') {
 				/* Deny:from_IP - prepend */
 				pip->next = ip_a_d;
 				ip_a_d = pip;
 			} else {
-				/* A:from_IP - append (thus D precedes A) */
+				/* A:from_IP - append (thus all D's precedes A's) */
 				Htaccess_IP *prev_IP = ip_a_d;
 				if (prev_IP == NULL) {
 					ip_a_d = pip;
@@ -575,12 +604,12 @@
 		}
 
 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES
-		if (flag == FIRST_PARSE && *p0 == 'E') {
+		if (flag == FIRST_PARSE && ch == 'E') {
 			unsigned i;
-			int status = atoi(++p0); /* error status code */
+			int status = atoi(buf + 1); /* error status code */
+
 			if (status < HTTP_CONTINUE) {
-				bb_error_msg("config error '%s' in '%s'", buf, filename);
-				continue;
+				goto config_error;
 			}
 			/* then error page; find matching status */
 			for (i = 0; i < ARRAY_SIZE(http_response_type); i++) {
@@ -597,7 +626,7 @@
 #endif
 
 #if ENABLE_FEATURE_HTTPD_PROXY
-		if (flag == FIRST_PARSE && *p0 == 'P') {
+		if (flag == FIRST_PARSE && ch == 'P') {
 			/* P:/url:[http://]hostname[:port]/new/path */
 			char *url_from, *host_port, *url_to;
 			Htaccess_Proxy *proxy_entry;
@@ -605,23 +634,20 @@
 			url_from = after_colon;
 			host_port = strchr(after_colon, ':');
 			if (host_port == NULL) {
-				bb_error_msg("config error '%s' in '%s'", buf, filename);
-				continue;
+				goto config_error;
 			}
 			*host_port++ = '\0';
 			if (strncmp(host_port, "http://", 7) == 0)
 				host_port += 7;
 			if (*host_port == '\0') {
-				bb_error_msg("config error '%s' in '%s'", buf, filename);
-				continue;
+				goto config_error;
 			}
 			url_to = strchr(host_port, '/');
 			if (url_to == NULL) {
-				bb_error_msg("config error '%s' in '%s'", buf, filename);
-				continue;
+				goto config_error;
 			}
 			*url_to = '\0';
-			proxy_entry = xzalloc(sizeof(Htaccess_Proxy));
+			proxy_entry = xzalloc(sizeof(*proxy_entry));
 			proxy_entry->url_from = xstrdup(url_from);
 			proxy_entry->host_port = xstrdup(host_port);
 			*url_to = '/';
@@ -631,115 +657,87 @@
 			continue;
 		}
 #endif
+		/* the rest of directives are non-alphabetic,
+		 * must avoid using "toupper'ed" ch */
+		ch = buf[0];
 
-#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-		if (*p0 == '/') {
-			/* make full path from httpd root / current_path / config_line_path */
-			const char *tp = (flag == SUBDIR_PARSE ? path : "");
-			p0 = xmalloc(strlen(tp) + (after_colon - buf) + 2 + strlen(after_colon));
-			after_colon[-1] = '\0';
-			sprintf(p0, "/%s%s", tp, buf);
+		if (ch == '.' /* ".ext:mime/type" */
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+		 || (ch == '*' && buf[1] == '.') /* "*.php:/path/php" */
+#endif
+		) {
+			char *p;
+			Htaccess *cur;
 
-			/* looks like bb_simplify_path... */
-			tp = p = p0;
-			do {
-				if (*p == '/') {
-					if (*tp == '/') {    /* skip duplicate (or initial) slash */
-						continue;
-					}
-					if (*tp == '.') {
-						if (tp[1] == '/' || tp[1] == '\0') { /* remove extra '.' */
-							continue;
-						}
-						if ((tp[1] == '.') && (tp[2] == '/' || tp[2] == '\0')) {
-							++tp;
-							if (p > p0) {
-								while (*--p != '/') /* omit previous dir */
-									continue;
-							}
-							continue;
-						}
-					}
-				}
-				*++p = *tp;
-			} while (*++tp);
-
-			if ((p == p0) || (*p != '/')) { /* not a trailing slash */
-				++p;                    /* so keep last character */
+			cur = xzalloc(sizeof(*cur) /* includes space for NUL */ + strlen_buf);
+			strcpy(cur->before_colon, buf);
+			p = cur->before_colon + (after_colon - buf);
+			p[-1] = '\0';
+			cur->after_colon = p;
+			if (ch == '.') {
+				/* .mime line: prepend to mime_a list */
+				cur->next = mime_a;
+				mime_a = cur;
 			}
-			*p = ':';
-			strcpy(p + 1, after_colon);
-		}
+#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
+			else {
+				/* script interpreter line: prepend to script_i list */
+				cur->next = script_i;
+				script_i = cur;
+			}
 #endif
-		if (*p0 == 'I') {
-			index_page = xstrdup(after_colon);
 			continue;
 		}
 
-		/* Do not allow jumping around using H in subdir's configs */
-		if (flag == FIRST_PARSE && *p0 == 'H') {
-			home_httpd = xstrdup(after_colon);
-			xchdir(home_httpd);
-			continue;
-		}
-
-		/* storing current config line */
-		cur = xzalloc(sizeof(Htaccess) + strlen(p0));
-		strcpy(cur->before_colon, p0);
 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-		if (*p0 == '/') /* was malloced - see above */
-			free(p0);
-#endif
-		cur->after_colon = strchr(cur->before_colon, ':');
-		*cur->after_colon++ = '\0';
-		if (cur->before_colon[0] == '.') {
-			/* .mime line: prepend to mime_a list */
-			cur->next = mime_a;
-			mime_a = cur;
-			continue;
-		}
-#if ENABLE_FEATURE_HTTPD_CONFIG_WITH_SCRIPT_INTERPR
-		if (cur->before_colon[0] == '*' && cur->before_colon[1] == '.') {
-			/* script interpreter line: prepend to script_i list */
-			cur->next = script_i;
-			script_i = cur;
-			continue;
-		}
-#endif
-#if ENABLE_FEATURE_HTTPD_BASIC_AUTH
-//TODO: we do not test for leading "/"??
-//also, do we leak cur if BASIC_AUTH is off?
-		if (prev == NULL) {
-			/* first line */
-			g_auth = prev = cur;
-		} else {
-			/* sort path, if current length eq or bigger then move up */
-			Htaccess *prev_hti = g_auth;
-			size_t l = strlen(cur->before_colon);
-			Htaccess *hti;
+		if (ch == '/') { /* "/file:user:pass" */
+			char *p;
+			Htaccess *cur;
+			unsigned file_len;
 
-			for (hti = prev_hti; hti; hti = hti->next) {
-				if (l >= strlen(hti->before_colon)) {
-					/* insert before hti */
-					cur->next = hti;
-					if (prev_hti != hti) {
-						prev_hti->next = cur;
-					} else {
-						/* insert as top */
-						g_auth = cur;
+			/* note: path is "" unless we are in SUBDIR parse,
+			 * otherwise it always starts with "/" */
+			cur = xzalloc(sizeof(*cur) /* includes space for NUL */
+				+ strlen(path)
+				+ strlen_buf
+				);
+			/* form "/path/file" */
+			sprintf(cur->before_colon, "%s%.*s",
+				path,
+				after_colon - buf - 1, /* includes "/", but not ":" */
+				buf);
+			/* canonicalize it */
+			p = bb_simplify_abs_path_inplace(cur->before_colon);
+			file_len = p - cur->before_colon;
+			/* add "user:pass" after NUL */
+			strcpy(++p, after_colon);
+			cur->after_colon = p;
+
+			/* insert cur into g_auth */
+			/* g_auth is sorted by decreased filename length */
+			{
+				Htaccess *auth, **authp;
+
+				authp = &g_auth;
+				while ((auth = *authp) != NULL) {
+					if (file_len >= strlen(auth->before_colon)) {
+						/* insert cur before auth */
+						cur->next = auth;
+						break;
 					}
-					break;
+					authp = &auth->next;
 				}
-				if (prev_hti != hti)
-					prev_hti = prev_hti->next;
+				*authp = cur;
 			}
-			if (!hti) {       /* not inserted, add to bottom */
-				prev->next = cur;
-				prev = cur;
-			}
+			continue;
 		}
 #endif /* BASIC_AUTH */
+
+		/* the line is not recognized */
+ config_error:
+		bb_error_msg("config error '%s' in '%s'", buf, filename);
 	 } /* while (fgets) */
+
 	 fclose(f);
 }
 
@@ -2031,8 +2029,8 @@
 	/* We are done reading headers, disable peer timeout */
 	alarm(0);
 
-	if (strcmp(bb_basename(urlcopy), httpd_conf) == 0 || !ip_allowed) {
-		/* protect listing [/path]/httpd_conf or IP deny */
+	if (strcmp(bb_basename(urlcopy), HTTPD_CONF) == 0 || !ip_allowed) {
+		/* protect listing [/path]/httpd.conf or IP deny */
 		send_headers_and_exit(HTTP_FORBIDDEN);
 	}
 
@@ -2245,7 +2243,7 @@
 
 static void sighup_handler(int sig UNUSED_PARAM)
 {
-	parse_conf(default_path_httpd_conf, SIGNALED_PARSE);
+	parse_conf(DEFAULT_PATH_HTTPD_CONF, SIGNALED_PARSE);
 }
 
 enum {
@@ -2304,7 +2302,7 @@
 			IF_FEATURE_HTTPD_AUTH_MD5("m:")
 			IF_FEATURE_HTTPD_SETUID("u:")
 			"p:ifv",
-			&configFile, &url_for_decode, &home_httpd
+			&opt_c_configFile, &url_for_decode, &home_httpd
 			IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
 			IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
 			IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
@@ -2375,7 +2373,7 @@
 	}
 #endif
 
-	parse_conf(default_path_httpd_conf, FIRST_PARSE);
+	parse_conf(DEFAULT_PATH_HTTPD_CONF, FIRST_PARSE);
 	if (!(opt & OPT_INETD))
 		signal(SIGHUP, sighup_handler);
 
Index: libbb/simplify_path.c
===================================================================
--- libbb/simplify_path.c	(revision 26183)
+++ libbb/simplify_path.c	(revision 26184)
@@ -6,22 +6,13 @@
  *
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
-
 #include "libbb.h"
 
-char* FAST_FUNC bb_simplify_path(const char *path)
+char* FAST_FUNC bb_simplify_abs_path_inplace(char *start)
 {
-	char *s, *start, *p;
+	char *s, *p;
 
-	if (path[0] == '/')
-		start = xstrdup(path);
-	else {
-		s = xrealloc_getcwd_or_warn(NULL);
-		start = concat_path_file(s, path);
-		free(s);
-	}
 	p = s = start;
-
 	do {
 		if (*p == '/') {
 			if (*s == '/') {	/* skip duplicate (or initial) slash */
@@ -47,7 +38,22 @@
 	if ((p == start) || (*p != '/')) {	/* not a trailing slash */
 		++p;					/* so keep last character */
 	}
-	*p = 0;
+	*p = '\0';
+	return p;
+}
 
-	return start;
+char* FAST_FUNC bb_simplify_path(const char *path)
+{
+	char *s, *p;
+
+	if (path[0] == '/')
+		s = xstrdup(path);
+	else {
+		p = xrealloc_getcwd_or_warn(NULL);
+		s = concat_path_file(p, path);
+		free(p);
+	}
+
+	bb_simplify_abs_path_inplace(s);
+	return s;
 }
Index: include/libbb.h
===================================================================
--- include/libbb.h	(revision 26183)
+++ include/libbb.h	(revision 26184)
@@ -1093,6 +1093,8 @@
 void print_signames(void) FAST_FUNC;
 
 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
 extern void bb_do_delay(int seconds) FAST_FUNC;

 ------------------------------------------------------------------------
r26181 | vda | 2009-04-21 21:53:02 -0500 (Tue, 21 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/sysklogd/syslogd.c

syslogd: added comment, no code changes


 ------------------------------------------------------------------------

Index: sysklogd/syslogd.c
===================================================================
--- sysklogd/syslogd.c	(revision 26180)
+++ sysklogd/syslogd.c	(revision 26181)
@@ -423,6 +423,8 @@
 	char *timestamp;
 	time_t now;
 
+	/* Jan 18 00:11:22 msg... */
+	/* 01234567890123456 */
 	if (len < 16 || msg[3] != ' ' || msg[6] != ' '
 	 || msg[9] != ':' || msg[12] != ':' || msg[15] != ' '
 	) {

 ------------------------------------------------------------------------
r26180 | vda | 2009-04-21 19:26:39 -0500 (Tue, 21 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/include/usage.h

httpd: improve help text


 ------------------------------------------------------------------------

Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26179)
+++ include/usage.h	(revision 26180)
@@ -1631,29 +1631,28 @@
        "sage\n"
 
 #define httpd_trivial_usage \
-       "[-c conffile]" \
-       " [-p [ip:]port]" \
-       " [-i] [-f] [-v[v]]" \
-	IF_FEATURE_HTTPD_SETUID(" [-u user[:grp]]") \
-	IF_FEATURE_HTTPD_BASIC_AUTH(" [-r realm]") \
-	IF_FEATURE_HTTPD_AUTH_MD5(" [-m pass]") \
-       " [-h home]" \
-       " [-d/-e string]"
+       "[-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	-c FILE		Configuration file (default httpd.conf)" \
-     "\n	-p [IP:]PORT	Bind to ip:port (default *:80)" \
      "\n	-i		Inetd mode" \
      "\n	-f		Do not daemonize" \
      "\n	-v[v]		Verbose" \
+     "\n	-c FILE		Configuration file (default httpd.conf)" \
+     "\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") \
-	IF_FEATURE_HTTPD_AUTH_MD5( \
-     "\n	-m PASS		Crypt PASS with md5 algorithm") \
      "\n	-h HOME		Home directory (default .)" \
+	IF_FEATURE_HTTPD_AUTH_MD5( \
+     "\n	-m STRING	MD5 crypt STRING") \
      "\n	-e STRING	HTML encode STRING" \
      "\n	-d STRING	URL decode STRING" \
 

 ------------------------------------------------------------------------
r26179 | vda | 2009-04-21 18:51:43 -0500 (Tue, 21 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/nc.c

nc: free lsa in server mode, we might be up for a long time


 ------------------------------------------------------------------------

Index: networking/nc.c
===================================================================
--- networking/nc.c	(revision 26178)
+++ networking/nc.c	(revision 26179)
@@ -111,12 +111,12 @@
 			/* If we didn't specify a port number,
 			 * query and print it after listen() */
 			if (!lport) {
-				socklen_t addrlen = lsa->len;
-				getsockname(sfd, &lsa->u.sa, &addrlen);
+				getsockname(sfd, &lsa->u.sa, &lsa->len);
 				lport = get_nport(&lsa->u.sa);
 				fdprintf(2, "%d\n", ntohs(lport));
 			}
 			close_on_exec_on(sfd);
+			free(lsa);
  accept_again:
 			cfd = accept(sfd, NULL, 0);
 			if (cfd < 0)

 ------------------------------------------------------------------------
r26178 | vda | 2009-04-21 18:48:38 -0500 (Tue, 21 Apr 2009) | 11 lines
Changed paths:
   M /trunk/busybox/libbb/xconnect.c
   M /trunk/busybox/networking/arping.c
   M /trunk/busybox/networking/libiproute/iplink.c
   M /trunk/busybox/networking/libiproute/libnetlink.c
   M /trunk/busybox/networking/libiproute/libnetlink.h
   M /trunk/busybox/networking/nc_bloaty.c

*: remove check for errors on getsockaddr in cases we know they can't happen
libbb: make get_sock_lsa use only one getsockaddr syscall, not two

function                                             old     new   delta
get_sock_lsa                                          72     101     +29
do_iplink                                           1151    1137     -14
arping_main                                         1585    1569     -16
dolisten                                             789     755     -34
xrtnl_open                                           161      94     -67


 ------------------------------------------------------------------------

Index: networking/nc_bloaty.c
===================================================================
--- networking/nc_bloaty.c	(revision 26177)
+++ networking/nc_bloaty.c	(revision 26178)
@@ -278,9 +278,9 @@
 	 random unknown port is probably not very useful without "netstat". */
 	if (o_verbose) {
 		char *addr;
-		rr = getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
-		if (rr < 0)
-			bb_perror_msg_and_die("getsockname after bind");
+		getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
+		//if (rr < 0)
+		//	bb_perror_msg_and_die("getsockname after bind");
 		addr = xmalloc_sockaddr2dotted(&ouraddr->u.sa);
 		fprintf(stderr, "listening on %s ...\n", addr);
 		free(addr);
@@ -359,9 +359,9 @@
 		 doing a listen-on-any on a multihomed machine.  This allows one to
 		 offer different services via different alias addresses, such as the
 		 "virtual web site" hack. */
-		rr = getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
-		if (rr < 0)
-			bb_perror_msg_and_die("getsockname after accept");
+		getsockname(netfd, &ouraddr->u.sa, &ouraddr->len);
+		//if (rr < 0)
+		//	bb_perror_msg_and_die("getsockname after accept");
 	}
 
 	if (o_verbose) {
Index: networking/libiproute/libnetlink.h
===================================================================
--- networking/libiproute/libnetlink.h	(revision 26177)
+++ networking/libiproute/libnetlink.h	(revision 26178)
@@ -10,8 +10,7 @@
 
 PUSH_AND_SET_FUNCTION_VISIBILITY_TO_HIDDEN
 
-struct rtnl_handle
-{
+struct rtnl_handle {
 	int			fd;
 	struct sockaddr_nl	local;
 	struct sockaddr_nl	peer;
Index: networking/libiproute/iplink.c
===================================================================
--- networking/libiproute/iplink.c	(revision 26177)
+++ networking/libiproute/iplink.c	(revision 26178)
@@ -112,11 +112,11 @@
 	me.sll_ifindex = ifr.ifr_ifindex;
 	me.sll_protocol = htons(ETH_P_LOOP);
 	xbind(s, (struct sockaddr*)&me, sizeof(me));
-
 	alen = sizeof(me);
-	if (getsockname(s, (struct sockaddr*)&me, &alen) == -1) {
-		bb_perror_msg_and_die("getsockname");
-	}
+	getsockname(s, (struct sockaddr*)&me, &alen);
+	//never happens:
+	//if (getsockname(s, (struct sockaddr*)&me, &alen) == -1)
+	//	bb_perror_msg_and_die("getsockname");
 	close(s);
 	*htype = me.sll_hatype;
 	return me.sll_halen;
Index: networking/libiproute/libnetlink.c
===================================================================
--- networking/libiproute/libnetlink.c	(revision 26177)
+++ networking/libiproute/libnetlink.c	(revision 26178)
@@ -26,22 +26,23 @@
 {
 	socklen_t addr_len;
 
-	memset(rth, 0, sizeof(rth));
-
+	memset(rth, 0, sizeof(*rth));
 	rth->fd = xsocket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
-
-	memset(&rth->local, 0, sizeof(rth->local));
 	rth->local.nl_family = AF_NETLINK;
 	/*rth->local.nl_groups = subscriptions;*/
 
 	xbind(rth->fd, (struct sockaddr*)&rth->local, sizeof(rth->local));
 	addr_len = sizeof(rth->local);
+	getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len);
+
+/* too much paranoia
 	if (getsockname(rth->fd, (struct sockaddr*)&rth->local, &addr_len) < 0)
 		bb_perror_msg_and_die("getsockname");
 	if (addr_len != sizeof(rth->local))
 		bb_error_msg_and_die("wrong address length %d", addr_len);
 	if (rth->local.nl_family != AF_NETLINK)
 		bb_error_msg_and_die("wrong address family %d", rth->local.nl_family);
+*/
 	rth->seq = time(NULL);
 	return 0;
 }
Index: networking/arping.c
===================================================================
--- networking/arping.c	(revision 26177)
+++ networking/arping.c	(revision 26178)
@@ -348,9 +348,10 @@
 			if (setsockopt(probe_fd, SOL_SOCKET, SO_DONTROUTE, &const_int_1, sizeof(const_int_1)) == -1)
 				bb_perror_msg("setsockopt(SO_DONTROUTE)");
 			xconnect(probe_fd, (struct sockaddr *) &saddr, sizeof(saddr));
-			if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1) {
-				bb_perror_msg_and_die("getsockname");
-			}
+			getsockname(probe_fd, (struct sockaddr *) &saddr, &alen);
+			//never happens:
+			//if (getsockname(probe_fd, (struct sockaddr *) &saddr, &alen) == -1)
+			//	bb_perror_msg_and_die("getsockname");
 			if (saddr.sin_family != AF_INET)
 				bb_error_msg_and_die("no IP address configured");
 			src = saddr.sin_addr;
@@ -365,10 +366,10 @@
 
 	{
 		socklen_t alen = sizeof(me);
-
-		if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1) {
-			bb_perror_msg_and_die("getsockname");
-		}
+		getsockname(sock_fd, (struct sockaddr *) &me, &alen);
+		//never happens:
+		//if (getsockname(sock_fd, (struct sockaddr *) &me, &alen) == -1)
+		//	bb_perror_msg_and_die("getsockname");
 	}
 	if (me.sll_halen == 0) {
 		bb_error_msg(err_str, "is not ARPable (no ll address)");
Index: libbb/xconnect.c
===================================================================
--- libbb/xconnect.c	(revision 26177)
+++ libbb/xconnect.c	(revision 26178)
@@ -37,16 +37,21 @@
 
 len_and_sockaddr* FAST_FUNC get_sock_lsa(int fd)
 {
-	len_and_sockaddr *lsa;
-	socklen_t len = 0;
+	len_and_sockaddr lsa;
+	len_and_sockaddr *lsa_ptr;
 
-	/* Can be optimized to do only one getsockname() */
-	if (getsockname(fd, NULL, &len) != 0)
+	lsa.len = LSA_SIZEOF_SA;
+	if (getsockname(fd, &lsa.u.sa, &lsa.len) != 0)
 		return NULL;
-	lsa = xzalloc(LSA_LEN_SIZE + len);
-	lsa->len = len;
-	getsockname(fd, &lsa->u.sa, &lsa->len);
-	return lsa;
+
+	lsa_ptr = xzalloc(LSA_LEN_SIZE + lsa.len);
+	if (lsa.len > LSA_SIZEOF_SA) { /* rarely (if ever) happens */
+		lsa_ptr->len = lsa.len;
+		getsockname(fd, &lsa_ptr->u.sa, &lsa_ptr->len);
+	} else {
+		memcpy(lsa_ptr, &lsa, LSA_LEN_SIZE + lsa.len);
+	}
+	return lsa_ptr;
 }
 
 void FAST_FUNC xconnect(int s, const struct sockaddr *s_addr, socklen_t addrlen)

 ------------------------------------------------------------------------
r26177 | vda | 2009-04-21 15:52:58 -0500 (Tue, 21 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/switch_root.c

switch_root: move misplaced comment


 ------------------------------------------------------------------------

Index: util-linux/switch_root.c
===================================================================
--- util-linux/switch_root.c	(revision 26176)
+++ util-linux/switch_root.c	(revision 26177)
@@ -103,8 +103,8 @@
 		// For example, fails when newroot is not a mountpoint
 		bb_perror_msg_and_die("error moving root");
 	}
+	xchroot(".");
 	// The chdir is needed to recalculate "." and ".." links
-	xchroot(".");
 	xchdir("/");
 
 	// If a new console specified, redirect stdin/stdout/stderr to it

 ------------------------------------------------------------------------
r26176 | vda | 2009-04-21 15:40:51 -0500 (Tue, 21 Apr 2009) | 4 lines
Changed paths:
   M /trunk/busybox/archival/libunarchive/open_transformer.c
   M /trunk/busybox/archival/tar.c
   M /trunk/busybox/coreutils/chroot.c
   M /trunk/busybox/debianutils/run_parts.c
   M /trunk/busybox/include/usage.h
   M /trunk/busybox/loginutils/adduser.c
   M /trunk/busybox/selinux/runcon.c
   M /trunk/busybox/shell/cttyhack.c
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/util-linux/switch_root.c

switch_root: improve behavior on error; improve help text
*: make "can't execute '%s'" message uniform


 ------------------------------------------------------------------------

Index: archival/tar.c
===================================================================
--- archival/tar.c	(revision 26175)
+++ archival/tar.c	(revision 26176)
@@ -577,7 +577,7 @@
 #endif
 	if (vfork_exec_errno) {
 		errno = vfork_exec_errno;
-		bb_perror_msg_and_die("cannot exec %s", zip_exec);
+		bb_perror_msg_and_die("can't execute '%s'", zip_exec);
 	}
 }
 #endif /* ENABLE_FEATURE_SEAMLESS_GZ || ENABLE_FEATURE_SEAMLESS_BZ2 */
Index: archival/libunarchive/open_transformer.c
===================================================================
--- archival/libunarchive/open_transformer.c	(revision 26175)
+++ archival/libunarchive/open_transformer.c	(revision 26176)
@@ -52,7 +52,7 @@
 			argv[2] = (char*)"-";
 			argv[3] = NULL;
 			BB_EXECVP(transform_prog, argv);
-			bb_perror_msg_and_die("can't exec %s", transform_prog);
+			bb_perror_msg_and_die("can't execute '%s'", transform_prog);
 		}
 #endif
 		/* notreached */
Index: debianutils/run_parts.c
===================================================================
--- debianutils/run_parts.c	(revision 26175)
+++ debianutils/run_parts.c	(revision 26176)
@@ -164,7 +164,7 @@
 			continue;
 		n = 1;
 		if (ret < 0)
-			bb_perror_msg("can't exec %s", name);
+			bb_perror_msg("can't execute '%s'", name);
 		else /* ret > 0 */
 			bb_error_msg("%s exited with code %d", name, ret);
 	}
Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26175)
+++ shell/hush.c	(revision 26176)
@@ -3048,7 +3048,7 @@
 	debug_printf_exec("execing '%s'\n", argv[0]);
 	sigprocmask(SIG_SETMASK, &G.inherited_set, NULL);
 	execvp(argv[0], argv);
-	bb_perror_msg("can't exec '%s'", argv[0]);
+	bb_perror_msg("can't execute '%s'", argv[0]);
 	_exit(EXIT_FAILURE);
 }
 
Index: shell/cttyhack.c
===================================================================
--- shell/cttyhack.c	(revision 26175)
+++ shell/cttyhack.c	(revision 26176)
@@ -73,5 +73,5 @@
 	}
 
 	BB_EXECVP(argv[0], argv);
-	bb_perror_msg_and_die("cannot exec '%s'", argv[0]);
+	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
 }
Index: coreutils/chroot.c
===================================================================
--- coreutils/chroot.c	(revision 26175)
+++ coreutils/chroot.c	(revision 26176)
@@ -33,5 +33,5 @@
 	}
 
 	BB_EXECVP(*argv, argv);
-	bb_perror_msg_and_die("cannot execute %s", *argv);
+	bb_perror_msg_and_die("can't execute '%s'", *argv);
 }
Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26175)
+++ include/usage.h	(revision 26176)
@@ -4125,12 +4125,13 @@
 	) \
 
 #define switch_root_trivial_usage \
-       "[-c /dev/console] NEW_ROOT NEW_INIT [ARGUMENTS_TO_INIT]"
+       "[-c /dev/console] NEW_ROOT NEW_INIT [ARG...]"
 #define switch_root_full_usage "\n\n" \
-       "Use from PID 1 under initramfs to free initramfs, chroot to NEW_ROOT,\n" \
-       "and exec NEW_INIT\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	Redirect console to device on new root" \
+     "\n	-c DEV	Reopen stdio to DEV after switch" \
 
 #define sync_trivial_usage \
        ""
@@ -4142,7 +4143,7 @@
 #define sysctl_full_usage "\n\n" \
        "Configure kernel parameters at runtime\n" \
      "\nOptions:" \
-     "\n	-n	Disable printing of key names" \
+     "\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)" \
Index: selinux/runcon.c
===================================================================
--- selinux/runcon.c	(revision 26175)
+++ selinux/runcon.c	(revision 26176)
@@ -129,10 +129,10 @@
 				     context_str(con));
 
 	if (setexeccon(context_str(con)))
-		bb_error_msg_and_die("cannot set up security context '%s'",
+		bb_error_msg_and_die("can't set up security context '%s'",
 				     context_str(con));
 
 	execvp(argv[0], argv);
 
-	bb_perror_msg_and_die("cannot execute '%s'", argv[0]);
+	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
 }
Index: loginutils/adduser.c
===================================================================
--- loginutils/adduser.c	(revision 26175)
+++ loginutils/adduser.c	(revision 26176)
@@ -60,7 +60,7 @@
 	static const char prog[] ALIGN1 = "passwd";
 
 	BB_EXECLP(prog, prog, login, NULL);
-	bb_error_msg_and_die("cannot execute %s, you must set password manually", prog);
+	bb_error_msg_and_die("can't execute %s, you must set password manually", prog);
 }
 
 #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS
Index: util-linux/switch_root.c
===================================================================
--- util-linux/switch_root.c	(revision 26175)
+++ util-linux/switch_root.c	(revision 26176)
@@ -5,11 +5,10 @@
  *
  * Licensed under GPL version 2, see file LICENSE in this tarball for details.
  */
-
 #include "libbb.h"
 #include 
 
-// Make up for header deficiencies.
+// Make up for header deficiencies
 #ifndef RAMFS_MAGIC
 #define RAMFS_MAGIC ((unsigned)0x858458f6)
 #endif
@@ -22,7 +21,7 @@
 #define MS_MOVE     8192
 #endif
 
-// Recursively delete contents of rootfs.
+// Recursively delete contents of rootfs
 static void delete_contents(const char *directory, dev_t rootdev)
 {
 	DIR *dir;
@@ -33,7 +32,7 @@
 	if (lstat(directory, &st) || st.st_dev != rootdev)
 		return;
 
-	// Recursively delete the contents of directories.
+	// Recursively delete the contents of directories
 	if (S_ISDIR(st.st_mode)) {
 		dir = opendir(directory);
 		if (dir) {
@@ -51,42 +50,47 @@
 			}
 			closedir(dir);
 
-			// Directory should now be empty.  Zap it.
+			// Directory should now be empty, zap it
 			rmdir(directory);
 		}
-
-	// It wasn't a directory.  Zap it.
-	} else unlink(directory);
+	} else {
+		// It wasn't a directory, zap it
+		unlink(directory);
+	}
 }
 
 int switch_root_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int switch_root_main(int argc UNUSED_PARAM, char **argv)
 {
 	char *newroot, *console = NULL;
-	struct stat st1, st2;
+	struct stat st;
 	struct statfs stfs;
 	dev_t rootdev;
 
 	// Parse args (-c console)
 	opt_complementary = "-2"; // minimum 2 params
-	getopt32(argv, "+c:", &console); // '+': stop parsing at first non-option
+	getopt32(argv, "+c:", &console); // '+': stop at first non-option
 	argv += optind;
-
-	// Change to new root directory and verify it's a different fs.
 	newroot = *argv++;
 
+	// Change to new root directory and verify it's a different fs
 	xchdir(newroot);
-	if (lstat(".", &st1) || lstat("/", &st2) || st1.st_dev == st2.st_dev) {
-		bb_error_msg_and_die("bad newroot %s", newroot);
+	xstat("/", &st);
+	rootdev = st.st_dev;
+	xstat(".", &st);
+	if (st.st_dev == rootdev || getpid() != 1) {
+		// Show usage, it says new root must be a mountpoint
+		// and we must be PID 1
+		bb_show_usage();
 	}
-	rootdev = st2.st_dev;
 
-	// Additional sanity checks: we're about to rm -rf /,  so be REALLY SURE
-	// we mean it.  (I could make this a CONFIG option, but I would get email
-	// from all the people who WILL eat their filesystems.)
-	if (lstat("/init", &st1) || !S_ISREG(st1.st_mode) || statfs("/", &stfs)
-	 || (((unsigned)stfs.f_type != RAMFS_MAGIC) && ((unsigned)stfs.f_type != TMPFS_MAGIC))
-	 || (getpid() != 1)
+	// Additional sanity checks: we're about to rm -rf /, so be REALLY SURE
+	// we mean it. I could make this a CONFIG option, but I would get email
+	// from all the people who WILL destroy their filesystems.
+	statfs("/", &stfs); // this never fails
+	if (lstat("/init", &st) != 0 || !S_ISREG(st.st_mode)
+	 || ((unsigned)stfs.f_type != RAMFS_MAGIC
+	     && (unsigned)stfs.f_type != TMPFS_MAGIC)
 	) {
 		bb_error_msg_and_die("not rootfs");
 	}
@@ -94,14 +98,16 @@
 	// Zap everything out of rootdev
 	delete_contents("/", rootdev);
 
-	// Overmount / with newdir and chroot into it.  The chdir is needed to
-	// recalculate "." and ".." links.
-	if (mount(".", "/", NULL, MS_MOVE, NULL))
+	// Overmount / with newdir and chroot into it
+	if (mount(".", "/", NULL, MS_MOVE, NULL)) {
+		// For example, fails when newroot is not a mountpoint
 		bb_perror_msg_and_die("error moving root");
+	}
+	// The chdir is needed to recalculate "." and ".." links
 	xchroot(".");
 	xchdir("/");
 
-	// If a new console specified, redirect stdin/stdout/stderr to that.
+	// If a new console specified, redirect stdin/stdout/stderr to it
 	if (console) {
 		close(0);
 		xopen(console, O_RDWR);
@@ -109,7 +115,7 @@
 		xdup2(0, 2);
 	}
 
-	// Exec real init.  (This is why we must be pid 1.)
+	// Exec real init
 	execv(argv[0], argv);
-	bb_perror_msg_and_die("bad init %s", argv[0]);
+	bb_perror_msg_and_die("can't execute '%s'", argv[0]);
 }

 ------------------------------------------------------------------------
r26174 | vda | 2009-04-21 06:23:56 -0500 (Tue, 21 Apr 2009) | 6 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: speed up set_local_var

function                                             old     new   delta
set_local_var                                        265     290     +25


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26173)
+++ shell/hush.c	(revision 26174)
@@ -1266,16 +1266,16 @@
 static int set_local_var(char *str, int flg_export, int flg_read_only)
 {
 	struct variable *cur;
-	char *value;
+	char *eq_sign;
 	int name_len;
 
-	value = strchr(str, '=');
-	if (!value) { /* not expected to ever happen? */
+	eq_sign = strchr(str, '=');
+	if (!eq_sign) { /* not expected to ever happen? */
 		free(str);
 		return -1;
 	}
 
-	name_len = value - str + 1; /* including '=' */
+	name_len = eq_sign - str + 1; /* including '=' */
 	cur = G.top_var; /* cannot be NULL (we have HUSH_VERSION and it's RO) */
 	while (1) {
 		if (strncmp(cur->varstr, str, name_len) != 0) {
@@ -1288,7 +1288,6 @@
 			continue;
 		}
 		/* We found an existing var with this name */
-		*value = '\0';
 		if (cur->flg_read_only) {
 #if !BB_MMU
 			if (!flg_read_only)
@@ -1297,11 +1296,13 @@
 			free(str);
 			return -1;
 		}
-//TODO: optimize out redundant unsetenv/putenv's?
-		debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
-		unsetenv(str); /* just in case */
-		*value = '=';
-		if (strcmp(cur->varstr, str) == 0) {
+		if (flg_export == -1) {
+			debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
+			*eq_sign = '\0';
+			unsetenv(str);
+			*eq_sign = '=';
+		}
+		if (strcmp(cur->varstr + name_len, eq_sign + 1) == 0) {
  free_and_exp:
 			free(str);
 			goto exp;

 ------------------------------------------------------------------------
r26173 | vda | 2009-04-21 06:09:40 -0500 (Tue, 21 Apr 2009) | 5 lines
Changed paths:
   M /trunk/busybox/archival/bbunzip.c
   M /trunk/busybox/archival/bzip2.c
   M /trunk/busybox/archival/cpio.c
   M /trunk/busybox/archival/gzip.c
   M /trunk/busybox/archival/libunarchive/decompress_bunzip2.c
   M /trunk/busybox/archival/libunarchive/decompress_uncompress.c
   M /trunk/busybox/archival/libunarchive/decompress_unlzma.c
   M /trunk/busybox/archival/libunarchive/decompress_unzip.c
   M /trunk/busybox/archival/libunarchive/get_header_tar.c
   M /trunk/busybox/archival/libunarchive/open_transformer.c
   M /trunk/busybox/archival/rpm.c
   M /trunk/busybox/archival/tar.c
   M /trunk/busybox/coreutils/chmod.c
   M /trunk/busybox/coreutils/chown.c
   M /trunk/busybox/coreutils/date.c
   M /trunk/busybox/coreutils/df.c
   M /trunk/busybox/coreutils/du.c
   M /trunk/busybox/coreutils/expand.c
   M /trunk/busybox/coreutils/id.c
   M /trunk/busybox/coreutils/install.c
   M /trunk/busybox/coreutils/libcoreutils/getopt_mk_fifo_nod.c
   M /trunk/busybox/coreutils/ls.c
   M /trunk/busybox/coreutils/mkdir.c
   M /trunk/busybox/coreutils/readlink.c
   M /trunk/busybox/coreutils/stat.c
   M /trunk/busybox/coreutils/tail.c
   M /trunk/busybox/coreutils/touch.c
   M /trunk/busybox/coreutils/tty.c
   M /trunk/busybox/coreutils/uname.c
   M /trunk/busybox/debianutils/run_parts.c
   M /trunk/busybox/debianutils/start_stop_daemon.c
   M /trunk/busybox/debianutils/which.c
   M /trunk/busybox/docs/autodocifier.pl
   M /trunk/busybox/docs/new-applet-HOWTO.txt
   M /trunk/busybox/editors/cmp.c
   M /trunk/busybox/editors/diff.c
   M /trunk/busybox/editors/vi.c
   M /trunk/busybox/findutils/find.c
   M /trunk/busybox/findutils/grep.c
   M /trunk/busybox/findutils/xargs.c
   M /trunk/busybox/include/applets.h
   M /trunk/busybox/include/libbb.h
   M /trunk/busybox/include/unarchive.h
   M /trunk/busybox/include/usage.h
   M /trunk/busybox/libbb/appletlib.c
   M /trunk/busybox/libbb/lineedit.c
   M /trunk/busybox/libbb/mtab_file.c
   M /trunk/busybox/libbb/procps.c
   M /trunk/busybox/libbb/read.c
   M /trunk/busybox/libbb/xconnect.c
   M /trunk/busybox/libbb/xfuncs_printf.c
   M /trunk/busybox/loginutils/chpasswd.c
   M /trunk/busybox/loginutils/login.c
   M /trunk/busybox/loginutils/su.c
   M /trunk/busybox/loginutils/sulogin.c
   M /trunk/busybox/mailutils/mime.c
   M /trunk/busybox/mailutils/popmaildir.c
   M /trunk/busybox/miscutils/crond.c
   M /trunk/busybox/miscutils/eject.c
   M /trunk/busybox/miscutils/hdparm.c
   M /trunk/busybox/miscutils/less.c
   M /trunk/busybox/modutils/insmod.c
   M /trunk/busybox/modutils/modprobe-small.c
   M /trunk/busybox/modutils/modprobe.c
   M /trunk/busybox/modutils/modutils.h
   M /trunk/busybox/networking/brctl.c
   M /trunk/busybox/networking/ftpd.c
   M /trunk/busybox/networking/httpd.c
   M /trunk/busybox/networking/ifconfig.c
   M /trunk/busybox/networking/ifupdown.c
   M /trunk/busybox/networking/ip.c
   M /trunk/busybox/networking/ipcalc.c
   M /trunk/busybox/networking/libiproute/iproute.c
   M /trunk/busybox/networking/nc.c
   M /trunk/busybox/networking/nc_bloaty.c
   M /trunk/busybox/networking/netstat.c
   M /trunk/busybox/networking/ping.c
   M /trunk/busybox/networking/telnetd.c
   M /trunk/busybox/networking/telnetd.ctrlSQ.patch
   M /trunk/busybox/networking/tftp.c
   M /trunk/busybox/networking/tunctl.c
   M /trunk/busybox/networking/udhcp/dhcpc.c
   M /trunk/busybox/networking/udhcp/dhcpc.h
   M /trunk/busybox/networking/udhcp/dhcpd.c
   M /trunk/busybox/networking/udhcp/files.c
   M /trunk/busybox/networking/wget.c
   M /trunk/busybox/procps/pidof.c
   M /trunk/busybox/procps/ps.c
   M /trunk/busybox/procps/top.c
   M /trunk/busybox/runit/chpst.c
   M /trunk/busybox/scripts/basic/fixdep.c
   M /trunk/busybox/scripts/kconfig/confdata.c
   M /trunk/busybox/selinux/setfiles.c
   M /trunk/busybox/shell/ash.c
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/sysklogd/syslogd.c
   M /trunk/busybox/testsuite/all_sourcecode.tests
   M /trunk/busybox/util-linux/acpid.c
   M /trunk/busybox/util-linux/fdisk.c
   M /trunk/busybox/util-linux/fsck_minix.c
   M /trunk/busybox/util-linux/hexdump.c
   M /trunk/busybox/util-linux/mount.c

*: mass renaming of USE_XXXX to IF_XXXX
and SKIP_XXXX to IF_NOT_XXXX - the second one was especially
badly named. It was not skipping anything!


 ------------------------------------------------------------------------

Index: networking/wget.c
===================================================================
--- networking/wget.c	(revision 26172)
+++ networking/wget.c	(revision 26173)
@@ -497,14 +497,14 @@
 	applet_long_options = wget_longopts;
 #endif
 	/* server.allocated = target.allocated = NULL; */
-	opt_complementary = "-1" USE_FEATURE_WGET_LONG_OPTIONS(":\xfe::");
+	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 */
-				USE_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
-				USE_FEATURE_WGET_LONG_OPTIONS(, &post_data)
+				IF_FEATURE_WGET_LONG_OPTIONS(, &headers_llist)
+				IF_FEATURE_WGET_LONG_OPTIONS(, &post_data)
 				);
 	if (strcmp(proxy_flag, "off") == 0) {
 		/* Use the proxy if necessary */
Index: networking/ip.c
===================================================================
--- networking/ip.c	(revision 26172)
+++ networking/ip.c	(revision 26173)
@@ -76,18 +76,18 @@
 int ip_main(int argc UNUSED_PARAM, char **argv)
 {
 	static const char keywords[] ALIGN1 =
-		USE_FEATURE_IP_ADDRESS("address\0")
-		USE_FEATURE_IP_ROUTE("route\0")
-		USE_FEATURE_IP_LINK("link\0")
-		USE_FEATURE_IP_TUNNEL("tunnel\0" "tunl\0")
-		USE_FEATURE_IP_RULE("rule\0")
+		IF_FEATURE_IP_ADDRESS("address\0")
+		IF_FEATURE_IP_ROUTE("route\0")
+		IF_FEATURE_IP_LINK("link\0")
+		IF_FEATURE_IP_TUNNEL("tunnel\0" "tunl\0")
+		IF_FEATURE_IP_RULE("rule\0")
 		;
 	enum {
-		USE_FEATURE_IP_ADDRESS(IP_addr,)
-		USE_FEATURE_IP_ROUTE(IP_route,)
-		USE_FEATURE_IP_LINK(IP_link,)
-		USE_FEATURE_IP_TUNNEL(IP_tunnel, IP_tunl,)
-		USE_FEATURE_IP_RULE(IP_rule,)
+		IF_FEATURE_IP_ADDRESS(IP_addr,)
+		IF_FEATURE_IP_ROUTE(IP_route,)
+		IF_FEATURE_IP_LINK(IP_link,)
+		IF_FEATURE_IP_TUNNEL(IP_tunnel, IP_tunl,)
+		IF_FEATURE_IP_RULE(IP_rule,)
 		IP_none
 	};
 	int (*ip_func)(char**) = ip_print_help;
Index: networking/nc_bloaty.c
===================================================================
--- networking/nc_bloaty.c	(revision 26172)
+++ networking/nc_bloaty.c	(revision 26173)
@@ -675,7 +675,7 @@
 int nc_main(int argc, char **argv)
 {
 	char *str_p, *str_s;
-	USE_NC_EXTRA(char *str_i, *str_o;)
+	IF_NC_EXTRA(char *str_i, *str_o;)
 	char *themdotted = themdotted; /* gcc */
 	char **proggie;
 	int x;
@@ -711,10 +711,10 @@
 
 	// -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:" USE_NC_SERVER("l")
-			USE_NC_EXTRA("i:o:z"),
+	getopt32(argv, "hnp:s:uvw:" IF_NC_SERVER("l")
+			IF_NC_EXTRA("i:o:z"),
 			&str_p, &str_s, &o_wait
-			USE_NC_EXTRA(, &str_i, &str_o, &o_verbose));
+			IF_NC_EXTRA(, &str_i, &str_o, &o_verbose));
 	argv += optind;
 #if ENABLE_NC_EXTRA
 	if (option_mask32 & OPT_i) /* line-interval time */
Index: networking/tftp.c
===================================================================
--- networking/tftp.c	(revision 26172)
+++ networking/tftp.c	(revision 26173)
@@ -64,15 +64,15 @@
 };
 
 #if ENABLE_FEATURE_TFTP_GET && !ENABLE_FEATURE_TFTP_PUT
-#define USE_GETPUT(...)
+#define IF_GETPUT(...)
 #define CMD_GET(cmd) 1
 #define CMD_PUT(cmd) 0
 #elif !ENABLE_FEATURE_TFTP_GET && ENABLE_FEATURE_TFTP_PUT
-#define USE_GETPUT(...)
+#define IF_GETPUT(...)
 #define CMD_GET(cmd) 0
 #define CMD_PUT(cmd) 1
 #else
-#define USE_GETPUT(...) __VA_ARGS__
+#define IF_GETPUT(...) __VA_ARGS__
 #define CMD_GET(cmd) ((cmd) & TFTP_OPT_GET)
 #define CMD_PUT(cmd) ((cmd) & TFTP_OPT_PUT)
 #endif
@@ -160,9 +160,9 @@
 		len_and_sockaddr *our_lsa,
 		len_and_sockaddr *peer_lsa,
 		const char *local_file
-		USE_TFTP(, const char *remote_file)
-		USE_FEATURE_TFTP_BLOCKSIZE(USE_TFTPD(, void *tsize))
-		USE_FEATURE_TFTP_BLOCKSIZE(, int blksize))
+		IF_TFTP(, const char *remote_file)
+		IF_FEATURE_TFTP_BLOCKSIZE(IF_TFTPD(, void *tsize))
+		IF_FEATURE_TFTP_BLOCKSIZE(, int blksize))
 {
 #if !ENABLE_TFTP
 #define remote_file NULL
@@ -178,7 +178,7 @@
 #define socket_fd (pfd[0].fd)
 	int len;
 	int send_len;
-	USE_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
+	IF_FEATURE_TFTP_BLOCKSIZE(smallint want_option_ack = 0;)
 	smallint finished = 0;
 	uint16_t opcode;
 	uint16_t block_nr;
@@ -564,19 +564,19 @@
 #endif
 	int result;
 	int port;
-	USE_GETPUT(int opt;)
+	IF_GETPUT(int opt;)
 
 	INIT_G();
 
 	/* -p or -g is mandatory, and they are mutually exclusive */
-	opt_complementary = "" USE_FEATURE_TFTP_GET("g:") USE_FEATURE_TFTP_PUT("p:")
-			USE_GETPUT("g--p:p--g:");
+	opt_complementary = "" IF_FEATURE_TFTP_GET("g:") IF_FEATURE_TFTP_PUT("p:")
+			IF_GETPUT("g--p:p--g:");
 
-	USE_GETPUT(opt =) getopt32(argv,
-			USE_FEATURE_TFTP_GET("g") USE_FEATURE_TFTP_PUT("p")
-				"l:r:" USE_FEATURE_TFTP_BLOCKSIZE("b:"),
+	IF_GETPUT(opt =) getopt32(argv,
+			IF_FEATURE_TFTP_GET("g") IF_FEATURE_TFTP_PUT("p")
+				"l:r:" IF_FEATURE_TFTP_BLOCKSIZE("b:"),
 			&local_file, &remote_file
-			USE_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
+			IF_FEATURE_TFTP_BLOCKSIZE(, &blksize_str));
 	argv += optind;
 
 #if ENABLE_FEATURE_TFTP_BLOCKSIZE
@@ -614,8 +614,8 @@
 	result = tftp_protocol(
 		NULL /*our_lsa*/, peer_lsa,
 		local_file, remote_file
-		USE_FEATURE_TFTP_BLOCKSIZE(USE_TFTPD(, NULL /*tsize*/))
-		USE_FEATURE_TFTP_BLOCKSIZE(, blksize)
+		IF_FEATURE_TFTP_BLOCKSIZE(IF_TFTPD(, NULL /*tsize*/))
+		IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
 	);
 
 	if (result != EXIT_SUCCESS && NOT_LONE_DASH(local_file) && CMD_GET(opt)) {
@@ -635,8 +635,8 @@
 	char *local_file, *mode;
 	const char *error_msg;
 	int opt, result, opcode;
-	USE_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
-	USE_FEATURE_TFTP_BLOCKSIZE(char *tsize = NULL;)
+	IF_FEATURE_TFTP_BLOCKSIZE(int blksize = TFTP_BLKSIZE_DEFAULT;)
+	IF_FEATURE_TFTP_BLOCKSIZE(char *tsize = NULL;)
 
 	INIT_G();
 
@@ -667,9 +667,9 @@
 	opcode = ntohs(*(uint16_t*)block_buf);
 	if (result < 4 || result >= sizeof(block_buf)
 	 || block_buf[result-1] != '\0'
-	 || (USE_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
-	     USE_GETPUT(&&)
-	     USE_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
+	 || (IF_FEATURE_TFTP_PUT(opcode != TFTP_RRQ) /* not download */
+	     IF_GETPUT(&&)
+	     IF_FEATURE_TFTP_GET(opcode != TFTP_WRQ) /* not upload */
 	    )
 	) {
 		goto err;
@@ -711,9 +711,9 @@
 			error_msg = bb_msg_write_error;
 			goto err;
 		}
-		USE_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
+		IF_GETPUT(option_mask32 |= TFTP_OPT_GET;) /* will receive file's data */
 	} else {
-		USE_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
+		IF_GETPUT(option_mask32 |= TFTP_OPT_PUT;) /* will send file's data */
 	}
 
 	/* NB: if error_pkt_str or error_pkt_reason is set up,
@@ -724,9 +724,9 @@
 	/* tftp_protocol() will create new one, bound to particular local IP */
 	result = tftp_protocol(
 		our_lsa, peer_lsa,
-		local_file USE_TFTP(, NULL /*remote_file*/)
-		USE_FEATURE_TFTP_BLOCKSIZE(, tsize)
-		USE_FEATURE_TFTP_BLOCKSIZE(, blksize)
+		local_file IF_TFTP(, NULL /*remote_file*/)
+		IF_FEATURE_TFTP_BLOCKSIZE(, tsize)
+		IF_FEATURE_TFTP_BLOCKSIZE(, blksize)
 	);
 
 	return result;
Index: networking/telnetd.ctrlSQ.patch
===================================================================
--- networking/telnetd.ctrlSQ.patch	(revision 26172)
+++ networking/telnetd.ctrlSQ.patch	(revision 26173)
@@ -104,7 +104,7 @@
 +#endif
  	/* Even if !STANDALONE, we accept (and ignore) -i, thus people
  	 * don't need to guess whether it's ok to pass -i to us */
- 	opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
+ 	opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
 @@ -475,7 +495,7 @@
  				FD_SET(ts->sockfd_read, &rdfdset);
  			if (ts->size2 > 0)       /* can write to socket */
Index: networking/ifupdown.c
===================================================================
--- networking/ifupdown.c	(revision 26172)
+++ networking/ifupdown.c	(revision 26173)
@@ -87,7 +87,7 @@
 	struct mapping_defn_t *mappings;
 };
 
-#define OPTION_STR "anvf" USE_FEATURE_IFUPDOWN_MAPPING("m") "i:"
+#define OPTION_STR "anvf" IF_FEATURE_IFUPDOWN_MAPPING("m") "i:"
 enum {
 	OPT_do_all = 0x1,
 	OPT_no_act = 0x2,
Index: networking/libiproute/iproute.c
===================================================================
--- networking/libiproute/iproute.c	(revision 26172)
+++ networking/libiproute/iproute.c	(revision 26173)
@@ -287,14 +287,14 @@
 static int iproute_modify(int cmd, unsigned flags, char **argv)
 {
 	static const char keywords[] ALIGN1 =
-		"src\0""via\0""mtu\0""lock\0""protocol\0"USE_FEATURE_IP_RULE("table\0")
+		"src\0""via\0""mtu\0""lock\0""protocol\0"IF_FEATURE_IP_RULE("table\0")
 		"dev\0""oif\0""to\0""metric\0";
 	enum {
 		ARG_src,
 		ARG_via,
 		ARG_mtu, PARM_lock,
 		ARG_protocol,
-USE_FEATURE_IP_RULE(ARG_table,)
+IF_FEATURE_IP_RULE(ARG_table,)
 		ARG_dev,
 		ARG_oif,
 		ARG_to,
Index: networking/telnetd.c
===================================================================
--- networking/telnetd.c	(revision 26172)
+++ networking/telnetd.c	(revision 26173)
@@ -201,8 +201,8 @@
 
 static struct tsession *
 make_new_session(
-		USE_FEATURE_TELNETD_STANDALONE(int sock)
-		SKIP_FEATURE_TELNETD_STANDALONE(void)
+		IF_FEATURE_TELNETD_STANDALONE(int sock)
+		IF_NOT_FEATURE_TELNETD_STANDALONE(void)
 ) {
 	const char *login_argv[2];
 	struct termios termbuf;
@@ -437,9 +437,9 @@
 #endif
 	/* Even if !STANDALONE, we accept (and ignore) -i, thus people
 	 * don't need to guess whether it's ok to pass -i to us */
-	opt = getopt32(argv, "f:l:Ki" USE_FEATURE_TELNETD_STANDALONE("p:b:F"),
+	opt = getopt32(argv, "f:l:Ki" IF_FEATURE_TELNETD_STANDALONE("p:b:F"),
 			&issuefile, &loginpath
-			USE_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
+			IF_FEATURE_TELNETD_STANDALONE(, &opt_portnbr, &opt_bindaddr));
 	if (!IS_INETD /*&& !re_execed*/) {
 		/* inform that we start in standalone mode?
 		 * May be useful when people forget to give -i */
@@ -455,7 +455,7 @@
 		openlog(applet_name, LOG_PID, LOG_DAEMON);
 		logmode = LOGMODE_SYSLOG;
 	}
-	USE_FEATURE_TELNETD_STANDALONE(
+	IF_FEATURE_TELNETD_STANDALONE(
 		if (opt & OPT_PORT)
 			portnbr = xatou16(opt_portnbr);
 	);
Index: networking/nc.c
===================================================================
--- networking/nc.c	(revision 26172)
+++ networking/nc.c	(revision 26173)
@@ -29,11 +29,11 @@
 	int sfd = sfd; /* for gcc */
 	int cfd = 0;
 	unsigned lport = 0;
-	SKIP_NC_SERVER(const) unsigned do_listen = 0;
-	SKIP_NC_EXTRA (const) unsigned wsecs = 0;
-	SKIP_NC_EXTRA (const) unsigned delay = 0;
-	SKIP_NC_EXTRA (const int execparam = 0;)
-	USE_NC_EXTRA  (char **execparam = NULL;)
+	IF_NOT_NC_SERVER(const) unsigned do_listen = 0;
+	IF_NOT_NC_EXTRA (const) unsigned wsecs = 0;
+	IF_NOT_NC_EXTRA (const) unsigned delay = 0;
+	IF_NOT_NC_EXTRA (const int execparam = 0;)
+	IF_NC_EXTRA     (char **execparam = NULL;)
 	len_and_sockaddr *lsa;
 	fd_set readfds, testfds;
 	int opt; /* must be signed (getopt returns -1) */
@@ -42,24 +42,24 @@
 		/* getopt32 is _almost_ usable:
 		** it cannot handle "... -e prog -prog-opt" */
 		while ((opt = getopt(argc, argv,
-		        "" USE_NC_SERVER("lp:") USE_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')
-				USE_NC_SERVER(do_listen++);
+				IF_NC_SERVER(do_listen++);
 			else if (ENABLE_NC_SERVER && opt=='p')
-				USE_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
+				IF_NC_SERVER(lport = bb_lookup_port(optarg, "tcp", 0));
 			else if (ENABLE_NC_EXTRA && opt=='w')
-				USE_NC_EXTRA( wsecs = xatou(optarg));
+				IF_NC_EXTRA( wsecs = xatou(optarg));
 			else if (ENABLE_NC_EXTRA && opt=='i')
-				USE_NC_EXTRA( delay = xatou(optarg));
+				IF_NC_EXTRA( delay = xatou(optarg));
 			else if (ENABLE_NC_EXTRA && opt=='f')
-				USE_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
+				IF_NC_EXTRA( cfd = xopen(optarg, O_RDWR));
 			else if (ENABLE_NC_EXTRA && opt=='e' && optind <= argc) {
 				/* We cannot just 'break'. We should let getopt finish.
 				** Or else we won't be able to find where
 				** 'host' and 'port' params are
 				** (think "nc -w 60 host port -e prog"). */
-				USE_NC_EXTRA(
+				IF_NC_EXTRA(
 					char **p;
 					// +2: one for progname (optarg) and one for NULL
 					execparam = xzalloc(sizeof(char*) * (argc - optind + 2));
@@ -154,7 +154,7 @@
 		xmove_fd(cfd, 0);
 		xdup2(0, 1);
 		xdup2(0, 2);
-		USE_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
+		IF_NC_EXTRA(BB_EXECVP(execparam[0], execparam);)
 		/* Don't print stuff or it will go over the wire.... */
 		_exit(127);
 	}
Index: networking/brctl.c
===================================================================
--- networking/brctl.c	(revision 26172)
+++ networking/brctl.c	(revision 26173)
@@ -99,20 +99,20 @@
 {
 	static const char keywords[] ALIGN1 =
 		"addbr\0" "delbr\0" "addif\0" "delif\0"
-	USE_FEATURE_BRCTL_FANCY(
+	IF_FEATURE_BRCTL_FANCY(
 		"stp\0"
 		"setageing\0" "setfd\0" "sethello\0" "setmaxage\0"
 		"setpathcost\0" "setportprio\0" "setbridgeprio\0"
 	)
-	USE_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
+	IF_FEATURE_BRCTL_SHOW("showmacs\0" "show\0");
 
 	enum { ARG_addbr = 0, ARG_delbr, ARG_addif, ARG_delif
-		USE_FEATURE_BRCTL_FANCY(,
+		IF_FEATURE_BRCTL_FANCY(,
 		   ARG_stp,
 		   ARG_setageing, ARG_setfd, ARG_sethello, ARG_setmaxage,
 		   ARG_setpathcost, ARG_setportprio, ARG_setbridgeprio
 		)
-		USE_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show)
+		IF_FEATURE_BRCTL_SHOW(, ARG_showmacs, ARG_show)
 	};
 
 	int fd;
Index: networking/tunctl.c
===================================================================
--- networking/tunctl.c	(revision 26172)
+++ networking/tunctl.c	(revision 26173)
@@ -48,9 +48,9 @@
 	};
 
 	opt_complementary = "=0:t--d:d--t"; // no arguments; t ^ d
-	opts = getopt32(argv, "f:t:d:" USE_FEATURE_TUNCTL_UG("u:g:b"),
+	opts = getopt32(argv, "f:t:d:" IF_FEATURE_TUNCTL_UG("u:g:b"),
 			&opt_device, &opt_name, &opt_name
-			USE_FEATURE_TUNCTL_UG(, &opt_user, &opt_group));
+			IF_FEATURE_TUNCTL_UG(, &opt_user, &opt_group));
 
 	// select device
 	memset(&ifr, 0, sizeof(ifr));
Index: networking/netstat.c
===================================================================
--- networking/netstat.c	(revision 26172)
+++ networking/netstat.c	(revision 26173)
@@ -18,15 +18,15 @@
 #include "inet_common.h"
 
 #define NETSTAT_OPTS "laentuwx" \
-	USE_ROUTE(               "r") \
-	USE_FEATURE_NETSTAT_WIDE("W") \
-	USE_FEATURE_NETSTAT_PRG( "p")
+	IF_ROUTE(               "r") \
+	IF_FEATURE_NETSTAT_WIDE("W") \
+	IF_FEATURE_NETSTAT_PRG( "p")
 
 enum {
 	OPTBIT_KEEP_OLD = 7,
-	USE_ROUTE(               OPTBIT_ROUTE,)
-	USE_FEATURE_NETSTAT_WIDE(OPTBIT_WIDE ,)
-	USE_FEATURE_NETSTAT_PRG( OPTBIT_PRG  ,)
+	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,9 +35,9 @@
 	OPT_sock_udp    = 1 << 5, // u
 	OPT_sock_raw    = 1 << 6, // w
 	OPT_sock_unix   = 1 << 7, // x
-	OPT_route       = USE_ROUTE(               (1 << OPTBIT_ROUTE)) + 0, // r
-	OPT_wide        = USE_FEATURE_NETSTAT_WIDE((1 << OPTBIT_WIDE )) + 0, // W
-	OPT_prg         = USE_FEATURE_NETSTAT_PRG( (1 << OPTBIT_PRG  )) + 0, // p
+	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
 };
 
 #define NETSTAT_CONNECTED 0x01
Index: networking/udhcp/files.c
===================================================================
--- networking/udhcp/files.c	(revision 26172)
+++ networking/udhcp/files.c	(revision 26173)
@@ -394,7 +394,7 @@
 	struct dhcpOfferedAddr lease;
 	int64_t written_at, time_passed;
 	int fd;
-	USE_UDHCP_DEBUG(unsigned i;)
+	IF_UDHCP_DEBUG(unsigned i;)
 
 	fd = open_or_warn(file, O_RDONLY);
 	if (fd < 0)
@@ -410,7 +410,7 @@
 	if ((uint64_t)time_passed > 12 * 60 * 60)
 		goto ret;
 
-	USE_UDHCP_DEBUG(i = 0;)
+	IF_UDHCP_DEBUG(i = 0;)
 	while (full_read(fd, &lease, sizeof(lease)) == sizeof(lease)) {
 		/* ADDME: what if it matches some static lease? */
 		uint32_t y = ntohl(lease.yiaddr);
@@ -424,7 +424,7 @@
 				bb_error_msg("too many leases while loading %s", file);
 				break;
 			}
-			USE_UDHCP_DEBUG(i++;)
+			IF_UDHCP_DEBUG(i++;)
 		}
 	}
 	DEBUG("Read %d leases", i);
Index: networking/udhcp/dhcpc.c
===================================================================
--- networking/udhcp/dhcpc.c	(revision 26172)
+++ networking/udhcp/dhcpc.c	(revision 26173)
@@ -133,7 +133,7 @@
 {
 	uint8_t *temp, *message;
 	char *str_c, *str_V, *str_h, *str_F, *str_r;
-	USE_FEATURE_UDHCP_PORT(char *str_P;)
+	IF_FEATURE_UDHCP_PORT(char *str_P;)
 	llist_t *list_O = NULL;
 	int tryagain_timeout = 20;
 	int discover_timeout = 3;
@@ -175,8 +175,8 @@
 		"no-default-options\0" No_argument   "o"
 		"foreground\0"     No_argument       "f"
 		"background\0"     No_argument       "b"
-		USE_FEATURE_UDHCPC_ARPING("arping\0"	No_argument       "a")
-		USE_FEATURE_UDHCP_PORT("client-port\0"	Required_argument "P")
+		IF_FEATURE_UDHCPC_ARPING("arping\0"	No_argument       "a")
+		IF_FEATURE_UDHCP_PORT("client-port\0"	Required_argument "P")
 		;
 #endif
 	enum {
@@ -204,33 +204,33 @@
 /* The rest has variable bit positions, need to be clever */
 		OPTBIT_f = 20,
 		USE_FOR_MMU(              OPTBIT_b,)
-		USE_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
-		USE_FEATURE_UDHCP_PORT(   OPTBIT_P,)
+		IF_FEATURE_UDHCPC_ARPING(OPTBIT_a,)
+		IF_FEATURE_UDHCP_PORT(   OPTBIT_P,)
 		USE_FOR_MMU(              OPT_b = 1 << OPTBIT_b,)
-		USE_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
-		USE_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
+		IF_FEATURE_UDHCPC_ARPING(OPT_a = 1 << OPTBIT_a,)
+		IF_FEATURE_UDHCP_PORT(   OPT_P = 1 << OPTBIT_P,)
 	};
 
 	/* Default options. */
-	USE_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
-	USE_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
+	IF_FEATURE_UDHCP_PORT(SERVER_PORT = 67;)
+	IF_FEATURE_UDHCP_PORT(CLIENT_PORT = 68;)
 	client_config.interface = "eth0";
 	client_config.script = DEFAULT_SCRIPT;
 
 	/* Parse command line */
 	/* Cc: mutually exclusive; O: list; -T,-t,-A take numeric param */
 	opt_complementary = "c--C:C--c:O::T+:t+:A+";
-	USE_GETOPT_LONG(applet_long_options = udhcpc_longopts;)
+	IF_GETOPT_LONG(applet_long_options = udhcpc_longopts;)
 	opt = getopt32(argv, "c:CV:H:h:F:i:np:qRr:s:T:t:vSA:O:of"
 		USE_FOR_MMU("b")
-		USE_FEATURE_UDHCPC_ARPING("a")
-		USE_FEATURE_UDHCP_PORT("P:")
+		IF_FEATURE_UDHCPC_ARPING("a")
+		IF_FEATURE_UDHCP_PORT("P:")
 		, &str_c, &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
-		USE_FEATURE_UDHCP_PORT(, &str_P)
+		IF_FEATURE_UDHCP_PORT(, &str_P)
 		);
 	if (opt & OPT_c)
 		client_config.clientid = alloc_dhcp_option(DHCP_CLIENT_ID, str_c, 0);
Index: networking/udhcp/dhcpd.c
===================================================================
--- networking/udhcp/dhcpd.c	(revision 26172)
+++ networking/udhcp/dhcpd.c	(revision 26173)
@@ -37,14 +37,14 @@
 	unsigned opt;
 	struct option_set *option;
 	struct dhcpOfferedAddr *lease, static_lease;
-	USE_FEATURE_UDHCP_PORT(char *str_P;)
+	IF_FEATURE_UDHCP_PORT(char *str_P;)
 
 #if ENABLE_FEATURE_UDHCP_PORT
 	SERVER_PORT = 67;
 	CLIENT_PORT = 68;
 #endif
 
-	opt = getopt32(argv, "fS" USE_FEATURE_UDHCP_PORT("P:", &str_P));
+	opt = getopt32(argv, "fS" IF_FEATURE_UDHCP_PORT("P:", &str_P));
 	argv += optind;
 	if (!(opt & 1)) { /* no -f */
 		bb_daemonize_or_rexec(0, argv);
Index: networking/udhcp/dhcpc.h
===================================================================
--- networking/udhcp/dhcpc.h	(revision 26172)
+++ networking/udhcp/dhcpc.h	(revision 26173)
@@ -10,7 +10,7 @@
 	/* TODO: combine flag fields into single "unsigned opt" */
 	/* (can be set directly to the result of getopt32) */
 	char no_default_options;        /* Do not include default optins in request */
-	USE_FEATURE_UDHCP_PORT(uint16_t port;)
+	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) */
 	const char *interface;          /* The name of the interface to use */
Index: networking/httpd.c
===================================================================
--- networking/httpd.c	(revision 26172)
+++ networking/httpd.c	(revision 26173)
@@ -250,13 +250,13 @@
 	const char *found_moved_temporarily;
 	Htaccess_IP *ip_a_d;    /* config allow/deny lines */
 
-	USE_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
-	USE_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
-	USE_FEATURE_HTTPD_CGI(char *referer;)
-	USE_FEATURE_HTTPD_CGI(char *user_agent;)
-	USE_FEATURE_HTTPD_CGI(char *host;)
-	USE_FEATURE_HTTPD_CGI(char *http_accept;)
-	USE_FEATURE_HTTPD_CGI(char *http_accept_language;)
+	IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
+	IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
+	IF_FEATURE_HTTPD_CGI(char *referer;)
+	IF_FEATURE_HTTPD_CGI(char *user_agent;)
+	IF_FEATURE_HTTPD_CGI(char *host;)
+	IF_FEATURE_HTTPD_CGI(char *http_accept;)
+	IF_FEATURE_HTTPD_CGI(char *http_accept_language;)
 
 	off_t file_size;        /* -1 - unknown */
 #if ENABLE_FEATURE_HTTPD_RANGES
@@ -326,7 +326,7 @@
 #define proxy             (G.proxy            )
 #define INIT_G() do { \
 	SET_PTR_TO_GLOBALS(xzalloc(sizeof(G))); \
-	USE_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
+	IF_FEATURE_HTTPD_BASIC_AUTH(g_realm = "Web Server Authentication";) \
 	bind_addr_or_port = "80"; \
 	index_page = "index.html"; \
 	file_size = -1; \
@@ -1587,14 +1587,14 @@
 		while (1) {
 			/* sz is rounded down to 64k */
 			ssize_t sz = MAXINT(ssize_t) - 0xffff;
-			USE_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;)
+			IF_FEATURE_HTTPD_RANGES(if (sz > range_len) sz = range_len;)
 			count = sendfile(STDOUT_FILENO, fd, &offset, sz);
 			if (count < 0) {
 				if (offset == range_start)
 					break; /* fall back to read/write loop */
 				goto fin;
 			}
-			USE_FEATURE_HTTPD_RANGES(range_len -= sz;)
+			IF_FEATURE_HTTPD_RANGES(range_len -= sz;)
 			if (count == 0 || range_len == 0)
 				log_and_exit();
 		}
@@ -1602,16 +1602,16 @@
 #endif
 	while ((count = safe_read(fd, iobuf, IOBUF_SIZE)) > 0) {
 		ssize_t n;
-		USE_FEATURE_HTTPD_RANGES(if (count > range_len) count = range_len;)
+		IF_FEATURE_HTTPD_RANGES(if (count > range_len) count = range_len;)
 		n = full_write(STDOUT_FILENO, iobuf, count);
 		if (count != n)
 			break;
-		USE_FEATURE_HTTPD_RANGES(range_len -= count;)
+		IF_FEATURE_HTTPD_RANGES(range_len -= count;)
 		if (range_len == 0)
 			break;
 	}
 	if (count < 0) {
- USE_FEATURE_HTTPD_USE_SENDFILE(fin:)
+ IF_FEATURE_HTTPD_USE_SENDFILE(fin:)
 		if (verbose > 1)
 			bb_perror_msg("error");
 	}
@@ -1839,12 +1839,12 @@
 
 	/* Find end of URL and parse HTTP version, if any */
 	http_major_version = '0';
-	USE_FEATURE_HTTPD_PROXY(http_minor_version = '0';)
+	IF_FEATURE_HTTPD_PROXY(http_minor_version = '0';)
 	tptr = strchrnul(urlp, ' ');
 	/* Is it " HTTP/"? */
 	if (tptr[0] && strncmp(tptr + 1, HTTP_200, 5) == 0) {
 		http_major_version = tptr[6];
-		USE_FEATURE_HTTPD_PROXY(http_minor_version = tptr[8];)
+		IF_FEATURE_HTTPD_PROXY(http_minor_version = tptr[8];)
 	}
 	*tptr = '\0';
 
@@ -2252,10 +2252,10 @@
 	c_opt_config_file = 0,
 	d_opt_decode_url,
 	h_opt_home_httpd,
-	USE_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
-	USE_FEATURE_HTTPD_BASIC_AUTH(    r_opt_realm     ,)
-	USE_FEATURE_HTTPD_AUTH_MD5(      m_opt_md5       ,)
-	USE_FEATURE_HTTPD_SETUID(        u_opt_setuid    ,)
+	IF_FEATURE_HTTPD_ENCODE_URL_STR(e_opt_encode_url,)
+	IF_FEATURE_HTTPD_BASIC_AUTH(    r_opt_realm     ,)
+	IF_FEATURE_HTTPD_AUTH_MD5(      m_opt_md5       ,)
+	IF_FEATURE_HTTPD_SETUID(        u_opt_setuid    ,)
 	p_opt_port      ,
 	p_opt_inetd     ,
 	p_opt_foreground,
@@ -2263,10 +2263,10 @@
 	OPT_CONFIG_FILE = 1 << c_opt_config_file,
 	OPT_DECODE_URL  = 1 << d_opt_decode_url,
 	OPT_HOME_HTTPD  = 1 << h_opt_home_httpd,
-	OPT_ENCODE_URL  = USE_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
-	OPT_REALM       = USE_FEATURE_HTTPD_BASIC_AUTH(    (1 << r_opt_realm     )) + 0,
-	OPT_MD5         = USE_FEATURE_HTTPD_AUTH_MD5(      (1 << m_opt_md5       )) + 0,
-	OPT_SETUID      = USE_FEATURE_HTTPD_SETUID(        (1 << u_opt_setuid    )) + 0,
+	OPT_ENCODE_URL  = IF_FEATURE_HTTPD_ENCODE_URL_STR((1 << e_opt_encode_url)) + 0,
+	OPT_REALM       = IF_FEATURE_HTTPD_BASIC_AUTH(    (1 << r_opt_realm     )) + 0,
+	OPT_MD5         = IF_FEATURE_HTTPD_AUTH_MD5(      (1 << m_opt_md5       )) + 0,
+	OPT_SETUID      = IF_FEATURE_HTTPD_SETUID(        (1 << u_opt_setuid    )) + 0,
 	OPT_PORT        = 1 << p_opt_port,
 	OPT_INETD       = 1 << p_opt_inetd,
 	OPT_FOREGROUND  = 1 << p_opt_foreground,
@@ -2280,10 +2280,10 @@
 	int server_socket = server_socket; /* for gcc */
 	unsigned opt;
 	char *url_for_decode;
-	USE_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
-	USE_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
-	USE_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
-	USE_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
+	IF_FEATURE_HTTPD_ENCODE_URL_STR(const char *url_for_encode;)
+	IF_FEATURE_HTTPD_SETUID(const char *s_ugid = NULL;)
+	IF_FEATURE_HTTPD_SETUID(struct bb_uidgid_t ugid;)
+	IF_FEATURE_HTTPD_AUTH_MD5(const char *pass;)
 
 	INIT_G();
 
@@ -2299,16 +2299,16 @@
 	 * If user gives relative path in -h,
 	 * $SCRIPT_FILENAME will not be set. */
 	opt = getopt32(argv, "c:d:h:"
-			USE_FEATURE_HTTPD_ENCODE_URL_STR("e:")
-			USE_FEATURE_HTTPD_BASIC_AUTH("r:")
-			USE_FEATURE_HTTPD_AUTH_MD5("m:")
-			USE_FEATURE_HTTPD_SETUID("u:")
+			IF_FEATURE_HTTPD_ENCODE_URL_STR("e:")
+			IF_FEATURE_HTTPD_BASIC_AUTH("r:")
+			IF_FEATURE_HTTPD_AUTH_MD5("m:")
+			IF_FEATURE_HTTPD_SETUID("u:")
 			"p:ifv",
 			&configFile, &url_for_decode, &home_httpd
-			USE_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
-			USE_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
-			USE_FEATURE_HTTPD_AUTH_MD5(, &pass)
-			USE_FEATURE_HTTPD_SETUID(, &s_ugid)
+			IF_FEATURE_HTTPD_ENCODE_URL_STR(, &url_for_encode)
+			IF_FEATURE_HTTPD_BASIC_AUTH(, &g_realm)
+			IF_FEATURE_HTTPD_AUTH_MD5(, &pass)
+			IF_FEATURE_HTTPD_SETUID(, &s_ugid)
 			, &bind_addr_or_port
 			, &verbose
 		);
Index: networking/ifconfig.c
===================================================================
--- networking/ifconfig.c	(revision 26172)
+++ networking/ifconfig.c	(revision 26173)
@@ -424,7 +424,7 @@
 					} else {	/* A_CAST_HOST_COPY_IN_ETHER */
 						/* This is the "hw" arg case. */
 						smalluint hw_class= index_in_substrings("ether\0"
-								USE_FEATURE_HWIB("infiniband\0"), *argv) + 1;
+								IF_FEATURE_HWIB("infiniband\0"), *argv) + 1;
 						if (!hw_class || !*++argv)
 							bb_show_usage();
 						/*safe_strncpy(host, *argv, sizeof(host));*/
Index: networking/ipcalc.c
===================================================================
--- networking/ipcalc.c	(revision 26172)
+++ networking/ipcalc.c	(revision 26173)
@@ -86,7 +86,7 @@
 #if ENABLE_FEATURE_IPCALC_LONG_OPTIONS
 	applet_long_options = ipcalc_longopts;
 #endif
-	opt = getopt32(argv, "mbn" USE_FEATURE_IPCALC_FANCY("phs"));
+	opt = getopt32(argv, "mbn" IF_FEATURE_IPCALC_FANCY("phs"));
 	argc -= optind;
 	argv += optind;
 	if (opt & (BROADCAST | NETWORK | NETPREFIX)) {
Index: networking/ping.c
===================================================================
--- networking/ping.c	(revision 26172)
+++ networking/ping.c	(revision 26173)
@@ -224,7 +224,7 @@
 
 /* full(er) version */
 
-#define OPT_STRING ("qvc:s:w:W:I:4" USE_PING6("6"))
+#define OPT_STRING ("qvc:s:w:W:I:4" IF_PING6("6"))
 enum {
 	OPT_QUIET = 1 << 0,
 	OPT_VERBOSE = 1 << 1,
Index: networking/ftpd.c
===================================================================
--- networking/ftpd.c	(revision 26172)
+++ networking/ftpd.c	(revision 26173)
@@ -1103,9 +1103,9 @@
 	G.timeout = 2 * 60;
 	opt_complementary = "t+:T+:vv";
 #if BB_MMU
-	opts = getopt32(argv,   "vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
+	opts = getopt32(argv,   "vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
 #else
-	opts = getopt32(argv, "l1vS" USE_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
+	opts = getopt32(argv, "l1vS" IF_FEATURE_FTP_WRITE("w") "t:T:", &G.timeout, &abs_timeout, &G.verbose);
 	if (opts & (OPT_l|OPT_1)) {
 		/* Our secret backdoor to ls */
 /* TODO: pass -n too? */
Index: scripts/kconfig/confdata.c
===================================================================
--- scripts/kconfig/confdata.c	(revision 26172)
+++ scripts/kconfig/confdata.c	(revision 26173)
@@ -458,8 +458,8 @@
 						fprintf(out_h, "#undef CONFIG_%s\n", sym->name);
 						/* bbox */
 						fprintf(out_h, "#define ENABLE_%s 0\n", sym->name);
-						fprintf(out_h, "#define USE_%s(...)\n", sym->name);
-						fprintf(out_h, "#define SKIP_%s(...) __VA_ARGS__\n", sym->name);
+						fprintf(out_h, "#define IF_%s(...)\n", sym->name);
+						fprintf(out_h, "#define IF_NOT_%s(...) __VA_ARGS__\n", sym->name);
 					}
 					break;
 				case mod:
@@ -473,8 +473,8 @@
 						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 USE_%s(...) __VA_ARGS__\n", sym->name);
-						fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
+						fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name);
+						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 					}
 					break;
 				}
@@ -505,8 +505,8 @@
 					fputs("\"\n", out_h);
 					/* bbox */
 					fprintf(out_h, "#define ENABLE_%s 1\n", sym->name);
-					fprintf(out_h, "#define USE_%s(...) __VA_ARGS__\n", sym->name);
-					fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
+					fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name);
+					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 				}
 				break;
 			case S_HEX:
@@ -517,8 +517,8 @@
 						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 USE_%s(...) __VA_ARGS__\n", sym->name);
-						fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
+						fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name);
+						fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 					}
 					break;
 				}
@@ -531,8 +531,8 @@
 					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 USE_%s(...) __VA_ARGS__\n", sym->name);
-					fprintf(out_h, "#define SKIP_%s(...)\n", sym->name);
+					fprintf(out_h, "#define IF_%s(...) __VA_ARGS__\n", sym->name);
+					fprintf(out_h, "#define IF_NOT_%s(...)\n", sym->name);
 				}
 				break;
 			}
Index: scripts/basic/fixdep.c
===================================================================
--- scripts/basic/fixdep.c	(revision 26172)
+++ scripts/basic/fixdep.c	(revision 26173)
@@ -225,32 +225,36 @@
 void parse_config_file(char *map, size_t len)
 {
 	/* modified for bbox */
-	char *end_4 = map + len - 4; /* 4 == length of "USE_" */
+	char *end_3 = map + len - 3; /* 3 == length of "IF_" */
 	char *end_7 = map + len - 7;
 	char *p = map;
 	char *q;
 	int off;
 
-	for (; p < end_4; p++) {
+	for (; p <= end_3; p++) {
+		/* Find next identifier's beginning */
+		if (!(isalnum(*p) || *p == '_'))
+			continue;
+
+		/* Check it */
 		if (p < end_7 && p[6] == '_') {
 			if (!memcmp(p, "CONFIG", 6)) goto conf7;
 			if (!memcmp(p, "ENABLE", 6)) goto conf7;
+			if (!memcmp(p, "IF_NOT", 6)) goto conf7;
 		}
-		/* We have at least 5 chars: for() has
-		 * "p < end-4", not "p <= end-4"
-		 * therefore we don't need to check p <= end-5 here */
-		if (p[4] == '_')
-			if (!memcmp(p, "SKIP", 4)) goto conf5;
-		/* Ehhh, gcc is too stupid to just compare it as 32bit int */
-		if (p[0] == 'U')
-			if (!memcmp(p, "USE_", 4)) goto conf4;
+		/* we have at least 3 chars because of p <= end_3 */
+		/*if (!memcmp(p, "IF_", 3)) goto conf3;*/
+		if (p[0] == 'I' && p[1] == 'F' && p[2] == '_') goto conf3;
+
+		/* This identifier is not interesting, skip it */
+		while (p <= end_3 && (isalnum(*p) || *p == '_'))
+			p++;
 		continue;
 
-	conf4:	off = 4;
-	conf5:	off = 5;
+	conf3:	off = 3;
 	conf7:	off = 7;
 		p += off;
-		for (q = p; q < end_4+4; q++) {
+		for (q = p; q < end_3+3; q++) {
 			if (!(isalnum(*q) || *q == '_'))
 				break;
 		}
Index: docs/autodocifier.pl
===================================================================
--- docs/autodocifier.pl	(revision 26172)
+++ docs/autodocifier.pl	(revision 26173)
@@ -24,8 +24,8 @@
 	my $text = shift;
 	for (;;) {
 		my $text2 = $text;
-		$text =~ s/SKIP_\w+\(.*?"\s*\)//sxg;
-		$text =~ s/USE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
+		$text =~ s/IF_NOT_\w+\(.*?"\s*\)//sxg;
+		$text =~ s/IF_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
 		$text =~ s/USAGE_\w+\(\s*?(.*?)"\s*\)/$1"/sxg;
 		last if ( $text2 eq $text );
 	}
Index: docs/new-applet-HOWTO.txt
===================================================================
--- docs/new-applet-HOWTO.txt	(revision 26172)
+++ docs/new-applet-HOWTO.txt	(revision 26173)
@@ -162,7 +162,7 @@
 Be sure to read the top of applets.h before adding your applet.
 
 	/* all programs above here are alphabetically "less than" 'mu' */
-	USE_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+	IF_MU(APPLET(mu, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 	/* all programs below here are alphabetically "greater than" 'mu' */
 
 
Index: archival/rpm.c
===================================================================
--- archival/rpm.c	(revision 26172)
+++ archival/rpm.c	(revision 26173)
@@ -190,7 +190,7 @@
 	archive_handle_t *archive_handle;
 	unsigned char magic[2];
 #if BB_MMU
-	USE_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
+	IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
 	enum { xformer_prog = 0 };
 #else
 	enum { xformer = 0 };
@@ -224,7 +224,7 @@
 		 || magic[0] != 'B' || magic[1] != 'Z'
 		) {
 			bb_error_msg_and_die("no gzip"
-				USE_FEATURE_SEAMLESS_BZ2("/bzip2")
+				IF_FEATURE_SEAMLESS_BZ2("/bzip2")
 				" magic");
 		}
 #if BB_MMU
Index: archival/bbunzip.c
===================================================================
--- archival/bbunzip.c	(revision 26172)
+++ archival/bbunzip.c	(revision 26173)
@@ -30,11 +30,11 @@
 
 int FAST_FUNC bbunpack(char **argv,
 	char* (*make_new_name)(char *filename),
-	USE_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)
+	IF_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)
 )
 {
 	struct stat stat_buf;
-	USE_DESKTOP(long long) int status;
+	IF_DESKTOP(long long) int status;
 	char *filename, *new_name;
 	smallint exitcode = 0;
 	unpack_info_t info;
@@ -175,7 +175,7 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM)
+IF_DESKTOP(long long) int unpack_bunzip2(unpack_info_t *info UNUSED_PARAM)
 {
 	return unpack_bz2_stream_prime(STDIN_FILENO, STDOUT_FILENO);
 }
@@ -251,9 +251,9 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info)
+IF_DESKTOP(long long) int unpack_gunzip(unpack_info_t *info)
 {
-	USE_DESKTOP(long long) int status = -1;
+	IF_DESKTOP(long long) int status = -1;
 
 	/* do the decompression, and cleanup */
 	if (xread_char(STDIN_FILENO) == 0x1f) {
@@ -325,7 +325,7 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM)
+IF_DESKTOP(long long) int unpack_unlzma(unpack_info_t *info UNUSED_PARAM)
 {
 	return unpack_lzma_stream(STDIN_FILENO, STDOUT_FILENO);
 }
@@ -360,9 +360,9 @@
 }
 
 static
-USE_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM)
+IF_DESKTOP(long long) int unpack_uncompress(unpack_info_t *info UNUSED_PARAM)
 {
-	USE_DESKTOP(long long) int status = -1;
+	IF_DESKTOP(long long) int status = -1;
 
 	if ((xread_char(STDIN_FILENO) != 0x1f) || (xread_char(STDIN_FILENO) != 0x9d)) {
 		bb_error_msg("invalid magic");
Index: archival/gzip.c
===================================================================
--- archival/gzip.c	(revision 26172)
+++ archival/gzip.c	(revision 26173)
@@ -2015,7 +2015,7 @@
 }
 
 static
-USE_DESKTOP(long long) int pack_gzip(unpack_info_t *info UNUSED_PARAM)
+IF_DESKTOP(long long) int pack_gzip(unpack_info_t *info UNUSED_PARAM)
 {
 	struct stat s;
 
@@ -2050,7 +2050,7 @@
 	unsigned opt;
 
 	/* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
-	opt = getopt32(argv, "cfv" USE_GUNZIP("dt") "q123456789n");
+	opt = getopt32(argv, "cfv" IF_GUNZIP("dt") "q123456789n");
 #if ENABLE_GUNZIP /* gunzip_main may not be visible... */
 	if (opt & 0x18) // -d and/or -t
 		return gunzip_main(argc, argv);
Index: archival/tar.c
===================================================================
--- archival/tar.c	(revision 26172)
+++ archival/tar.c	(revision 26173)
@@ -728,14 +728,14 @@
 
 enum {
 	OPTBIT_KEEP_OLD = 7,
-	USE_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
-	USE_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
-	USE_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
-	USE_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
-	USE_FEATURE_TAR_FROM(     OPTBIT_INCLUDE_FROM,)
-	USE_FEATURE_TAR_FROM(     OPTBIT_EXCLUDE_FROM,)
-	USE_FEATURE_SEAMLESS_GZ(  OPTBIT_GZIP        ,)
-	USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
+	IF_FEATURE_TAR_CREATE(   OPTBIT_CREATE      ,)
+	IF_FEATURE_TAR_CREATE(   OPTBIT_DEREFERENCE ,)
+	IF_FEATURE_SEAMLESS_BZ2( OPTBIT_BZIP2       ,)
+	IF_FEATURE_SEAMLESS_LZMA(OPTBIT_LZMA        ,)
+	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    ,)
 	OPTBIT_NOPRESERVE_OWN,
 	OPTBIT_NOPRESERVE_PERM,
 	OPTBIT_NUMERIC_OWNER,
@@ -747,14 +747,14 @@
 	OPT_P            = 1 << 5, // p
 	OPT_VERBOSE      = 1 << 6, // v
 	OPT_KEEP_OLD     = 1 << 7, // k
-	OPT_CREATE       = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
-	OPT_DEREFERENCE  = USE_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
-	OPT_BZIP2        = USE_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
-	OPT_LZMA         = USE_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
-	OPT_INCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_INCLUDE_FROM)) + 0, // T
-	OPT_EXCLUDE_FROM = USE_FEATURE_TAR_FROM(     (1 << OPTBIT_EXCLUDE_FROM)) + 0, // X
-	OPT_GZIP         = USE_FEATURE_SEAMLESS_GZ(  (1 << OPTBIT_GZIP        )) + 0, // z
-	OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
+	OPT_CREATE       = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_CREATE      )) + 0, // c
+	OPT_DEREFERENCE  = IF_FEATURE_TAR_CREATE(   (1 << OPTBIT_DEREFERENCE )) + 0, // h
+	OPT_BZIP2        = IF_FEATURE_SEAMLESS_BZ2( (1 << OPTBIT_BZIP2       )) + 0, // j
+	OPT_LZMA         = IF_FEATURE_SEAMLESS_LZMA((1 << OPTBIT_LZMA        )) + 0, // a
+	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_COMPRESS     = IF_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
 	OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
 	OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
 	OPT_NUMERIC_OWNER = 1 << OPTBIT_NUMERIC_OWNER,
@@ -832,24 +832,24 @@
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 		"\xff::" // cumulative lists for --exclude
 #endif
-		USE_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
-		USE_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
-		SKIP_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
+		IF_FEATURE_TAR_CREATE("c:") "t:x:" // at least one of these is reqd
+		IF_FEATURE_TAR_CREATE("c--tx:t--cx:x--ct") // mutually exclusive
+		IF_NOT_FEATURE_TAR_CREATE("t--x:x--t"); // mutually exclusive
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
 	applet_long_options = tar_longopts;
 #endif
 	opt = getopt32(argv,
 		"txC:f:Opvk"
-		USE_FEATURE_TAR_CREATE(   "ch"  )
-		USE_FEATURE_SEAMLESS_BZ2( "j"   )
-		USE_FEATURE_SEAMLESS_LZMA("a"   )
-		USE_FEATURE_TAR_FROM(     "T:X:")
-		USE_FEATURE_SEAMLESS_GZ(  "z"   )
-		USE_FEATURE_SEAMLESS_Z(   "Z"   )
+		IF_FEATURE_TAR_CREATE(   "ch"  )
+		IF_FEATURE_SEAMLESS_BZ2( "j"   )
+		IF_FEATURE_SEAMLESS_LZMA("a"   )
+		IF_FEATURE_TAR_FROM(     "T:X:")
+		IF_FEATURE_SEAMLESS_GZ(  "z"   )
+		IF_FEATURE_SEAMLESS_Z(   "Z"   )
 		, &base_dir // -C dir
 		, &tar_filename // -f filename
-		USE_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
-		USE_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
+		IF_FEATURE_TAR_FROM(, &(tar_handle->accept)) // T
+		IF_FEATURE_TAR_FROM(, &(tar_handle->reject)) // X
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS && ENABLE_FEATURE_TAR_FROM
 		, &excludes // --exclude
 #endif
Index: archival/bzip2.c
===================================================================
--- archival/bzip2.c	(revision 26172)
+++ archival/bzip2.c	(revision 26173)
@@ -64,7 +64,7 @@
  * total written bytes so far otherwise
  */
 static
-USE_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
+IF_DESKTOP(long long) int bz_write(bz_stream *strm, void* rbuf, ssize_t rlen, void *wbuf)
 {
 	int n, n2, ret;
 
@@ -98,13 +98,13 @@
 		if (rlen && strm->avail_in == 0)
 			break;
 	}
-	return 0 USE_DESKTOP( + strm->total_out );
+	return 0 IF_DESKTOP( + strm->total_out );
 }
 
 static
-USE_DESKTOP(long long) int compressStream(unpack_info_t *info UNUSED_PARAM)
+IF_DESKTOP(long long) int compressStream(unpack_info_t *info UNUSED_PARAM)
 {
-	USE_DESKTOP(long long) int total;
+	IF_DESKTOP(long long) int total;
 	ssize_t count;
 	bz_stream bzs; /* it's small */
 #define strm (&bzs)
@@ -163,7 +163,7 @@
 
 	opt_complementary = "s2"; /* -s means -2 (compatibility) */
 	/* Must match bbunzip's constants OPT_STDOUT, OPT_FORCE! */
-	opt = getopt32(argv, "cfv" USE_BUNZIP2("dt") "123456789qzs");
+	opt = getopt32(argv, "cfv" IF_BUNZIP2("dt") "123456789qzs");
 #if ENABLE_BUNZIP2 /* bunzip2_main may not be visible... */
 	if (opt & 0x18) // -d and/or -t
 		return bunzip2_main(argc, argv);
Index: archival/libunarchive/decompress_bunzip2.c
===================================================================
--- archival/libunarchive/decompress_bunzip2.c	(revision 26172)
+++ archival/libunarchive/decompress_bunzip2.c	(revision 26173)
@@ -648,10 +648,10 @@
 
 
 /* Decompress src_fd to dst_fd.  Stops at end of bzip data, not end of file. */
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_bz2_stream(int src_fd, int dst_fd)
 {
-	USE_DESKTOP(long long total_written = 0;)
+	IF_DESKTOP(long long total_written = 0;)
 	char *outbuf;
 	bunzip_data *bd;
 	int i;
@@ -666,7 +666,7 @@
 				i = RETVAL_SHORT_WRITE;
 				break;
 			}
-			USE_DESKTOP(total_written += i;)
+			IF_DESKTOP(total_written += i;)
 		}
 	}
 
@@ -686,10 +686,10 @@
 	dealloc_bunzip(bd);
 	free(outbuf);
 
-	return i ? i : USE_DESKTOP(total_written) + 0;
+	return i ? i : IF_DESKTOP(total_written) + 0;
 }
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_bz2_stream_prime(int src_fd, int dst_fd)
 {
 	unsigned char magic[2];
Index: archival/libunarchive/decompress_uncompress.c
===================================================================
--- archival/libunarchive/decompress_uncompress.c	(revision 26172)
+++ archival/libunarchive/decompress_uncompress.c	(revision 26173)
@@ -72,11 +72,11 @@
  * be stored in the compressed file.
  */
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_Z_stream(int fd_in, int fd_out)
 {
-	USE_DESKTOP(long long total_written = 0;)
-	USE_DESKTOP(long long) int retval = -1;
+	IF_DESKTOP(long long total_written = 0;)
+	IF_DESKTOP(long long) int retval = -1;
 	unsigned char *stackp;
 	long code;
 	int finchar;
@@ -265,7 +265,7 @@
 						if (outpos >= OBUFSIZ) {
 							full_write(fd_out, outbuf, outpos);
 //error check??
-							USE_DESKTOP(total_written += outpos;)
+							IF_DESKTOP(total_written += outpos;)
 							outpos = 0;
 						}
 						stackp += i;
@@ -294,10 +294,10 @@
 	if (outpos > 0) {
 		full_write(fd_out, outbuf, outpos);
 //error check??
-		USE_DESKTOP(total_written += outpos;)
+		IF_DESKTOP(total_written += outpos;)
 	}
 
-	retval = USE_DESKTOP(total_written) + 0;
+	retval = IF_DESKTOP(total_written) + 0;
  err:
 	free(inbuf);
 	free(outbuf);
Index: archival/libunarchive/open_transformer.c
===================================================================
--- archival/libunarchive/open_transformer.c	(revision 26172)
+++ archival/libunarchive/open_transformer.c	(revision 26173)
@@ -12,7 +12,7 @@
  * in include/unarchive.h. On NOMMU, transformer is removed.
  */
 void FAST_FUNC open_transformer(int fd,
-	USE_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd),
+	IF_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd),
 	const char *transform_prog)
 {
 	struct fd_pair fd_pipe;
Index: archival/libunarchive/decompress_unzip.c
===================================================================
--- archival/libunarchive/decompress_unzip.c	(revision 26172)
+++ archival/libunarchive/decompress_unzip.c	(revision 26173)
@@ -970,10 +970,10 @@
 
 
 /* Called from unpack_gz_stream() and inflate_unzip() */
-static USE_DESKTOP(long long) int
+static IF_DESKTOP(long long) int
 inflate_unzip_internal(STATE_PARAM int in, int out)
 {
-	USE_DESKTOP(long long) int n = 0;
+	IF_DESKTOP(long long) int n = 0;
 	ssize_t nwrote;
 
 	/* Allocate all global buffers (for DYN_ALLOC option) */
@@ -1008,7 +1008,7 @@
 			n = -1;
 			goto ret;
 		}
-		USE_DESKTOP(n += nwrote;)
+		IF_DESKTOP(n += nwrote;)
 		if (r == 0) break;
 	}
 
@@ -1033,10 +1033,10 @@
 
 /* For unzip */
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 inflate_unzip(inflate_unzip_result *res, off_t compr_size, int in, int out)
 {
-	USE_DESKTOP(long long) int n;
+	IF_DESKTOP(long long) int n;
 	DECLARE_STATE;
 
 	ALLOC_STATE;
@@ -1181,11 +1181,11 @@
 	return 1;
 }
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_gz_stream_with_info(int in, int out, unpack_info_t *info)
 {
 	uint32_t v32;
-	USE_DESKTOP(long long) int n;
+	IF_DESKTOP(long long) int n;
 	DECLARE_STATE;
 
 	n = 0;
@@ -1245,7 +1245,7 @@
 	return n;
 }
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_gz_stream(int in, int out)
 {
 	return unpack_gz_stream_with_info(in, out, NULL);
Index: archival/libunarchive/decompress_unlzma.c
===================================================================
--- archival/libunarchive/decompress_unlzma.c	(revision 26172)
+++ archival/libunarchive/decompress_unlzma.c	(revision 26173)
@@ -228,10 +228,10 @@
 };
 
 
-USE_DESKTOP(long long) int FAST_FUNC
+IF_DESKTOP(long long) int FAST_FUNC
 unpack_lzma_stream(int src_fd, int dst_fd)
 {
-	USE_DESKTOP(long long total_written = 0;)
+	IF_DESKTOP(long long total_written = 0;)
 	lzma_header_t header;
 	int lc, pb, lp;
 	uint32_t pos_state_mask;
@@ -330,7 +330,7 @@
 				global_pos += header.dict_size;
 				if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
 					goto bad;
-				USE_DESKTOP(total_written += header.dict_size;)
+				IF_DESKTOP(total_written += header.dict_size;)
 			}
 #else
 			len = 1;
@@ -468,20 +468,20 @@
 			}
 
 			len += LZMA_MATCH_MIN_LEN;
- SKIP_FEATURE_LZMA_FAST(string:)
+ IF_NOT_FEATURE_LZMA_FAST(string:)
 			do {
 				pos = buffer_pos - rep0;
 				while (pos >= header.dict_size)
 					pos += header.dict_size;
 				previous_byte = buffer[pos];
- SKIP_FEATURE_LZMA_FAST(one_byte2:)
+ IF_NOT_FEATURE_LZMA_FAST(one_byte2:)
 				buffer[buffer_pos++] = previous_byte;
 				if (buffer_pos == header.dict_size) {
 					buffer_pos = 0;
 					global_pos += header.dict_size;
 					if (full_write(dst_fd, buffer, header.dict_size) != (ssize_t)header.dict_size)
 						goto bad;
-					USE_DESKTOP(total_written += header.dict_size;)
+					IF_DESKTOP(total_written += header.dict_size;)
 				}
 				len--;
 			} while (len != 0 && buffer_pos < header.dst_size);
@@ -489,8 +489,8 @@
 	}
 
 	{
-		SKIP_DESKTOP(int total_written = 0; /* success */)
-		USE_DESKTOP(total_written += buffer_pos;)
+		IF_NOT_DESKTOP(int total_written = 0; /* success */)
+		IF_DESKTOP(total_written += buffer_pos;)
 		if (full_write(dst_fd, buffer, buffer_pos) != (ssize_t)buffer_pos) {
  bad:
 			total_written = -1; /* failure */
Index: archival/libunarchive/get_header_tar.c
===================================================================
--- archival/libunarchive/get_header_tar.c	(revision 26172)
+++ archival/libunarchive/get_header_tar.c	(revision 26173)
@@ -144,8 +144,8 @@
 //	if (!archive_handle->ah_priv_inited) {
 //		archive_handle->ah_priv_inited = 1;
 //		p_end = 0;
-//		USE_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)
-//		USE_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)
+//		IF_FEATURE_TAR_GNU_EXTENSIONS(p_longname = NULL;)
+//		IF_FEATURE_TAR_GNU_EXTENSIONS(p_linkname = NULL;)
 //	}
 
 	if (sizeof(tar) != 512)
@@ -176,7 +176,7 @@
 		bb_error_msg_and_die("short read");
 	}
 	if (i != 512) {
-		USE_FEATURE_TAR_AUTODETECT(goto autodetect;)
+		IF_FEATURE_TAR_AUTODETECT(goto autodetect;)
 		goto short_read;
 	}
 
@@ -265,14 +265,14 @@
 #if ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
 	sum = strtoul(tar.chksum, &cp, 8);
 	if ((*cp && *cp != ' ')
-	 || (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
+	 || (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum))
 	) {
 		bb_error_msg_and_die("invalid tar header checksum");
 	}
 #else
 	/* This field does not need special treatment (getOctal) */
 	sum = xstrtoul(tar.chksum, 8);
-	if (sum_u != sum USE_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
+	if (sum_u != sum IF_FEATURE_TAR_OLDSUN_COMPATIBILITY(&& sum_s != sum)) {
 		bb_error_msg_and_die("invalid tar header checksum");
 	}
 #endif
@@ -356,7 +356,7 @@
 		file_header->mode |= S_IFBLK;
 		goto size0;
 	case '5':
- USE_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
+ IF_FEATURE_TAR_OLDGNU_COMPATIBILITY(set_dir:)
 		file_header->mode |= S_IFDIR;
 		goto size0;
 	case '6':
Index: archival/cpio.c
===================================================================
--- archival/cpio.c	(revision 26172)
+++ archival/cpio.c	(revision 26173)
@@ -270,7 +270,7 @@
 {
 	archive_handle_t *archive_handle;
 	char *cpio_filename;
-	USE_FEATURE_CPIO_O(const char *cpio_fmt = "";)
+	IF_FEATURE_CPIO_O(const char *cpio_fmt = "";)
 	unsigned opt;
 
 #if ENABLE_GETOPT_LONG
@@ -295,7 +295,7 @@
 #if !ENABLE_FEATURE_CPIO_O
 	opt = getopt32(argv, OPTION_STR, &cpio_filename);
 #else
-	opt = getopt32(argv, OPTION_STR "oH:" USE_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
+	opt = getopt32(argv, OPTION_STR "oH:" IF_FEATURE_CPIO_P("p"), &cpio_filename, &cpio_fmt);
 	if (opt & CPIO_OPT_PASSTHROUGH) {
 		pid_t pid;
 		struct fd_pair pp;
Index: sysklogd/syslogd.c
===================================================================
--- sysklogd/syslogd.c	(revision 26172)
+++ sysklogd/syslogd.c	(revision 26173)
@@ -66,7 +66,7 @@
 	/*int markInterval;*/                   \
 	/* level of messages to be logged */    \
 	int logLevel;                           \
-USE_FEATURE_ROTATE_LOGFILE( \
+IF_FEATURE_ROTATE_LOGFILE( \
 	/* max size of file before rotation */  \
 	unsigned logFileSize;                   \
 	/* number of rotated message files */   \
@@ -74,12 +74,12 @@
 	unsigned curFileSize;                   \
 	smallint isRegular;                     \
 ) \
-USE_FEATURE_REMOTE_LOG( \
+IF_FEATURE_REMOTE_LOG( \
 	/* udp socket for remote logging */     \
 	int remoteFD;                           \
 	len_and_sockaddr* remoteAddr;           \
 ) \
-USE_FEATURE_IPC_SYSLOG( \
+IF_FEATURE_IPC_SYSLOG( \
 	int shmid; /* ipc shared memory id */   \
 	int s_semid; /* ipc semaphore id */     \
 	int shm_size;                           \
@@ -153,41 +153,41 @@
 	OPTBIT_outfile, // -O
 	OPTBIT_loglevel, // -l
 	OPTBIT_small, // -S
-	USE_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize   ,)	// -s
-	USE_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt  ,)	// -b
-	USE_FEATURE_REMOTE_LOG(    OPTBIT_remotelog  ,)	// -R
-	USE_FEATURE_REMOTE_LOG(    OPTBIT_locallog   ,)	// -L
-	USE_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)	// -C
-	USE_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)	// -D
+	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_filesize   ,)	// -s
+	IF_FEATURE_ROTATE_LOGFILE(OPTBIT_rotatecnt  ,)	// -b
+	IF_FEATURE_REMOTE_LOG(    OPTBIT_remotelog  ,)	// -R
+	IF_FEATURE_REMOTE_LOG(    OPTBIT_locallog   ,)	// -L
+	IF_FEATURE_IPC_SYSLOG(    OPTBIT_circularlog,)	// -C
+	IF_FEATURE_SYSLOGD_DUP(   OPTBIT_dup        ,)	// -D
 
 	OPT_mark        = 1 << OPTBIT_mark    ,
 	OPT_nofork      = 1 << OPTBIT_nofork  ,
 	OPT_outfile     = 1 << OPTBIT_outfile ,
 	OPT_loglevel    = 1 << OPTBIT_loglevel,
 	OPT_small       = 1 << OPTBIT_small   ,
-	OPT_filesize    = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize   )) + 0,
-	OPT_rotatecnt   = USE_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt  )) + 0,
-	OPT_remotelog   = USE_FEATURE_REMOTE_LOG(    (1 << OPTBIT_remotelog  )) + 0,
-	OPT_locallog    = USE_FEATURE_REMOTE_LOG(    (1 << OPTBIT_locallog   )) + 0,
-	OPT_circularlog = USE_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
-	OPT_dup         = USE_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
+	OPT_filesize    = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_filesize   )) + 0,
+	OPT_rotatecnt   = IF_FEATURE_ROTATE_LOGFILE((1 << OPTBIT_rotatecnt  )) + 0,
+	OPT_remotelog   = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_remotelog  )) + 0,
+	OPT_locallog    = IF_FEATURE_REMOTE_LOG(    (1 << OPTBIT_locallog   )) + 0,
+	OPT_circularlog = IF_FEATURE_IPC_SYSLOG(    (1 << OPTBIT_circularlog)) + 0,
+	OPT_dup         = IF_FEATURE_SYSLOGD_DUP(   (1 << OPTBIT_dup        )) + 0,
 };
 #define OPTION_STR "m:nO:l:S" \
-	USE_FEATURE_ROTATE_LOGFILE("s:" ) \
-	USE_FEATURE_ROTATE_LOGFILE("b:" ) \
-	USE_FEATURE_REMOTE_LOG(    "R:" ) \
-	USE_FEATURE_REMOTE_LOG(    "L"  ) \
-	USE_FEATURE_IPC_SYSLOG(    "C::") \
-	USE_FEATURE_SYSLOGD_DUP(   "D"  )
+	IF_FEATURE_ROTATE_LOGFILE("s:" ) \
+	IF_FEATURE_ROTATE_LOGFILE("b:" ) \
+	IF_FEATURE_REMOTE_LOG(    "R:" ) \
+	IF_FEATURE_REMOTE_LOG(    "L"  ) \
+	IF_FEATURE_IPC_SYSLOG(    "C::") \
+	IF_FEATURE_SYSLOGD_DUP(   "D"  )
 #define OPTION_DECL *opt_m, *opt_l \
-	USE_FEATURE_ROTATE_LOGFILE(,*opt_s) \
-	USE_FEATURE_ROTATE_LOGFILE(,*opt_b) \
-	USE_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL)
+	IF_FEATURE_ROTATE_LOGFILE(,*opt_s) \
+	IF_FEATURE_ROTATE_LOGFILE(,*opt_b) \
+	IF_FEATURE_IPC_SYSLOG(    ,*opt_C = NULL)
 #define OPTION_PARAM &opt_m, &G.logFilePath, &opt_l \
-	USE_FEATURE_ROTATE_LOGFILE(,&opt_s) \
-	USE_FEATURE_ROTATE_LOGFILE(,&opt_b) \
-	USE_FEATURE_REMOTE_LOG(    ,&G.remoteAddrStr) \
-	USE_FEATURE_IPC_SYSLOG(    ,&opt_C)
+	IF_FEATURE_ROTATE_LOGFILE(,&opt_s) \
+	IF_FEATURE_ROTATE_LOGFILE(,&opt_b) \
+	IF_FEATURE_REMOTE_LOG(    ,&G.remoteAddrStr) \
+	IF_FEATURE_IPC_SYSLOG(    ,&opt_C)
 
 
 /* circular buffer variables/structures */
Index: modutils/modutils.h
===================================================================
--- modutils/modutils.h	(revision 26172)
+++ modutils/modutils.h	(revision 26173)
@@ -26,10 +26,10 @@
 
 #define INSMOD_OPTS \
 	"vq" \
-	USE_FEATURE_2_4_MODULES("sLo:fkx") \
-	USE_FEATURE_INSMOD_LOAD_MAP("m")
+	IF_FEATURE_2_4_MODULES("sLo:fkx") \
+	IF_FEATURE_INSMOD_LOAD_MAP("m")
 
-#define INSMOD_ARGS USE_FEATURE_2_4_MODULES(, NULL)
+#define INSMOD_ARGS IF_FEATURE_2_4_MODULES(, NULL)
 
 enum {
 	INSMOD_OPT_VERBOSE	= 0x0001,
Index: modutils/modprobe.c
===================================================================
--- modutils/modprobe.c	(revision 26172)
+++ modutils/modprobe.c	(revision 26173)
@@ -33,7 +33,7 @@
 	llist_t *deps; /* strings. modules we depend on */
 };
 
-#define MODPROBE_OPTS  "acdlnrt:VC:" USE_FEATURE_MODPROBE_BLACKLIST("b")
+#define MODPROBE_OPTS  "acdlnrt:VC:" IF_FEATURE_MODPROBE_BLACKLIST("b")
 enum {
 	MODPROBE_OPT_INSERT_ALL	= (INSMOD_OPT_UNUSED << 0), /* a */
 	MODPROBE_OPT_DUMP_ONLY	= (INSMOD_OPT_UNUSED << 1), /* c */
Index: modutils/insmod.c
===================================================================
--- modutils/insmod.c	(revision 26172)
+++ modutils/insmod.c	(revision 26173)
@@ -24,7 +24,7 @@
 	 * or in $MODPATH.
 	 */
 
-	USE_FEATURE_2_4_MODULES(
+	IF_FEATURE_2_4_MODULES(
 		getopt32(argv, INSMOD_OPTS INSMOD_ARGS);
 		argv += optind - 1;
 	);
Index: modutils/modprobe-small.c
===================================================================
--- modutils/modprobe-small.c	(revision 26172)
+++ modutils/modprobe-small.c	(revision 26173)
@@ -679,7 +679,7 @@
 {
 	struct utsname uts;
 	char applet0 = applet_name[0];
-	USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
+	IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(char *options;)
 
 	/* are we lsmod? -> just dump /proc/modules */
 	if ('l' == applet0) {
@@ -773,8 +773,8 @@
 		len = MAXINT(ssize_t);
 		map = xmalloc_xopen_read_close(*argv, &len);
 		if (init_module(map, len,
-			USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
-			SKIP_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
+			IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "")
+			IF_NOT_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("")
 				) != 0)
 			bb_error_msg_and_die("can't insert '%s': %s",
 					*argv, moderror(errno));
@@ -791,7 +791,7 @@
 	} while (*argv);
 
 	if (ENABLE_FEATURE_CLEAN_UP) {
-		USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
+		IF_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(free(options);)
 	}
 	return EXIT_SUCCESS;
 }
Index: debianutils/which.c
===================================================================
--- debianutils/which.c	(revision 26172)
+++ debianutils/which.c	(revision 26173)
@@ -15,13 +15,13 @@
 int which_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int which_main(int argc UNUSED_PARAM, char **argv)
 {
-	USE_DESKTOP(int opt;)
+	IF_DESKTOP(int opt;)
 	int status = EXIT_SUCCESS;
 	char *path;
 	char *p;
 
 	opt_complementary = "-1"; /* at least one argument */
-	USE_DESKTOP(opt =) getopt32(argv, "a");
+	IF_DESKTOP(opt =) getopt32(argv, "a");
 	argv += optind;
 
 	/* This matches what is seen on e.g. ubuntu.
Index: debianutils/start_stop_daemon.c
===================================================================
--- debianutils/start_stop_daemon.c	(revision 26172)
+++ debianutils/start_stop_daemon.c	(revision 26173)
@@ -347,13 +347,13 @@
 	/* -xa (at least one) is required if -S is given */
 	/* -q turns off -v */
 	opt_complementary = "K:S:K--S:S--K:m?p:K?xpun:S?xa"
-		USE_FEATURE_START_STOP_DAEMON_FANCY("q-v");
+		IF_FEATURE_START_STOP_DAEMON_FANCY("q-v");
 	opt = getopt32(argv, "KSbqtma:n:s:u:c:x:p:"
-		USE_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
+		IF_FEATURE_START_STOP_DAEMON_FANCY("ovN:R:"),
 		&startas, &cmdname, &signame, &userspec, &chuid, &execname, &pidfile
-		USE_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
+		IF_FEATURE_START_STOP_DAEMON_FANCY(,&opt_N)
 		/* We accept and ignore -R  / --retry  */
-		USE_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
+		IF_FEATURE_START_STOP_DAEMON_FANCY(,NULL)
 	);
 
 	if (opt & OPT_s) {
@@ -366,7 +366,7 @@
 	if (!execname) /* in case -a is given and -x is not */
 		execname = startas;
 
-//	USE_FEATURE_START_STOP_DAEMON_FANCY(
+//	IF_FEATURE_START_STOP_DAEMON_FANCY(
 //		if (retry_arg)
 //			retries = xatoi_u(retry_arg);
 //	)
Index: debianutils/run_parts.c
===================================================================
--- debianutils/run_parts.c	(revision 26172)
+++ debianutils/run_parts.c	(revision 26173)
@@ -124,7 +124,7 @@
 	/* We require exactly one argument: the directory name */
 	/* We require exactly one argument: the directory name */
 	opt_complementary = "=1:a::";
-	getopt32(argv, "ra:u:t"USE_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
+	getopt32(argv, "ra:u:t"IF_FEATURE_RUN_PARTS_FANCY("l"), &arg_list, &umask_p);
 
 	umask(xstrtou_range(umask_p, 8, 0, 07777));
 
Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26172)
+++ shell/hush.c	(revision 26173)
@@ -97,11 +97,11 @@
 /* STANDALONE does not make sense, and won't compile */
 # undef CONFIG_FEATURE_SH_STANDALONE
 # undef ENABLE_FEATURE_SH_STANDALONE
-# undef USE_FEATURE_SH_STANDALONE
-# define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
+# undef IF_FEATURE_SH_STANDALONE
+# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 # define ENABLE_FEATURE_SH_STANDALONE 0
-# define USE_FEATURE_SH_STANDALONE(...)
-# define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
+# define IF_FEATURE_SH_STANDALONE(...)
+# define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 #endif
 
 #if !ENABLE_HUSH_INTERACTIVE
@@ -2443,11 +2443,11 @@
 		goto do_exec;
 	}
 
-	sprintf(param_buf, "-$%x:%x:%x" USE_HUSH_LOOPS(":%x")
+	sprintf(param_buf, "-$%x:%x:%x" IF_HUSH_LOOPS(":%x")
 			, (unsigned) G.root_pid
 			, (unsigned) G.last_bg_pid
 			, (unsigned) G.last_exitcode
-			USE_HUSH_LOOPS(, G.depth_of_loop)
+			IF_HUSH_LOOPS(, G.depth_of_loop)
 			);
 	/* 1:hush 2:-$:::  
 	 * 3:-c 4: 5:  6:NULL
@@ -3386,7 +3386,7 @@
 	debug_printf_exec("run_pipe start: members:%d\n", pi->num_cmds);
 	debug_enter();
 
-	USE_HUSH_JOB(pi->pgrp = -1;)
+	IF_HUSH_JOB(pi->pgrp = -1;)
 	pi->stopped_cmds = 0;
 	command = &(pi->cmds[0]);
 	argv_expanded = NULL;
@@ -3821,7 +3821,7 @@
 	rcode = G.last_exitcode;
 
 	/* Go through list of pipes, (maybe) executing them. */
-	for (; pi; pi = USE_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
+	for (; pi; pi = IF_HUSH_LOOPS(rword == RES_DONE ? loop_top : ) pi->next) {
 		if (G.flag_SIGINT)
 			break;
 
@@ -4773,7 +4773,7 @@
 		close(channel[0]); /* NB: close _first_, then move fd! */
 		xmove_fd(channel[1], 1);
 		/* Prevent it from trying to handle ctrl-z etc */
-		USE_HUSH_JOB(G.run_list_level = 1;)
+		IF_HUSH_JOB(G.run_list_level = 1;)
 #if BB_MMU
 		reset_traps_to_defaults();
 		parse_and_run_string(s);
@@ -5441,7 +5441,7 @@
 		nommu_addchr(&ctx.as_string, ch);
 		is_ifs = strchr(G.ifs, ch);
 		is_special = strchr("<>;&|(){}#'" /* special outside of "str" */
-				"\\$\"" USE_HUSH_TICK("`") /* always special */
+				"\\$\"" IF_HUSH_TICK("`") /* always special */
 				, ch);
 
 		if (!is_special && !is_ifs) { /* ordinary char */
@@ -5832,7 +5832,7 @@
 		}
 		/* Discard cached input, force prompt */
 		input->p = NULL;
-		USE_HUSH_INTERACTIVE(input->promptme = 1;)
+		IF_HUSH_INTERACTIVE(input->promptme = 1;)
 		goto reset;
 	}
 }
Index: shell/ash.c
===================================================================
--- shell/ash.c	(revision 26172)
+++ shell/ash.c	(revision 26173)
@@ -56,11 +56,11 @@
 /* STANDALONE does not make sense, and won't compile */
 #undef CONFIG_FEATURE_SH_STANDALONE
 #undef ENABLE_FEATURE_SH_STANDALONE
-#undef USE_FEATURE_SH_STANDALONE
-#undef SKIP_FEATURE_SH_STANDALONE(...)
+#undef IF_FEATURE_SH_STANDALONE
+#undef IF_NOT_FEATURE_SH_STANDALONE(...)
 #define ENABLE_FEATURE_SH_STANDALONE 0
-#define USE_FEATURE_SH_STANDALONE(...)
-#define SKIP_FEATURE_SH_STANDALONE(...) __VA_ARGS__
+#define IF_FEATURE_SH_STANDALONE(...)
+#define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__
 #endif
 
 #ifndef PIPE_BUF
@@ -349,7 +349,7 @@
 } while (0)
 #endif
 
-static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
+static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 int_on(void)
 {
 	xbarrier();
@@ -358,7 +358,7 @@
 	}
 }
 #define INT_ON int_on()
-static USE_ASH_OPTIMIZE_FOR_SIZE(inline) void
+static IF_ASH_OPTIMIZE_FOR_SIZE(inline) void
 force_int_on(void)
 {
 	xbarrier();
@@ -4219,7 +4219,7 @@
 	static const char vstype[VSTYPE + 1][3] = {
 		"", "}", "-", "+", "?", "=",
 		"%", "%%", "#", "##"
-		USE_ASH_BASH_COMPAT(, ":", "/", "//")
+		IF_ASH_BASH_COMPAT(, ":", "/", "//")
 	};
 
 	const char *p, *str;
@@ -6069,9 +6069,9 @@
 	char *startp;
 	char *loc;
 	char *rmesc, *rmescend;
-	USE_ASH_BASH_COMPAT(char *repl = NULL;)
-	USE_ASH_BASH_COMPAT(char null = '\0';)
-	USE_ASH_BASH_COMPAT(int pos, len, orig_len;)
+	IF_ASH_BASH_COMPAT(char *repl = NULL;)
+	IF_ASH_BASH_COMPAT(char null = '\0';)
+	IF_ASH_BASH_COMPAT(int pos, len, orig_len;)
 	int saveherefd = herefd;
 	int amount, workloc, resetloc;
 	int zero;
@@ -6157,7 +6157,7 @@
 	 * stack will need rebasing, and we'll need to remove our work
 	 * areas each time
 	 */
- USE_ASH_BASH_COMPAT(restart:)
+ IF_ASH_BASH_COMPAT(restart:)
 
 	amount = expdest - ((char *)stackblock() + resetloc);
 	STADJUST(-amount, expdest);
@@ -7083,7 +7083,7 @@
 
 
 static void
-tryexec(USE_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
+tryexec(IF_FEATURE_SH_STANDALONE(int applet_no,) char *cmd, char **argv, char **envp)
 {
 	int repeated = 0;
 
@@ -7155,13 +7155,13 @@
 	 || (applet_no = find_applet_by_name(argv[0])) >= 0
 #endif
 	) {
-		tryexec(USE_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
+		tryexec(IF_FEATURE_SH_STANDALONE(applet_no,) argv[0], argv, envp);
 		e = errno;
 	} else {
 		e = ENOENT;
 		while ((cmdname = padvance(&path, argv[0])) != NULL) {
 			if (--idx < 0 && pathopt == NULL) {
-				tryexec(USE_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
+				tryexec(IF_FEATURE_SH_STANDALONE(-1,) cmdname, argv, envp);
 				if (errno != ENOENT && errno != ENOTDIR)
 					e = errno;
 			}
@@ -10789,7 +10789,7 @@
 	int parenlevel;      /* levels of parens in arithmetic */
 	int dqvarnest;       /* levels of variables expansion within double quotes */
 
-	USE_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
+	IF_ASH_BASH_COMPAT(smallint bash_dollar_squote = 0;)
 
 #if __GNUC__
 	/* Avoid longjmp clobbering */
@@ -10895,7 +10895,7 @@
 				dblquote = 1;
 				goto quotemark;
 			case CENDQUOTE:
-				USE_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
+				IF_ASH_BASH_COMPAT(bash_dollar_squote = 0;)
 				if (eofmark != NULL && arinest == 0
 				 && varnest == 0
 				) {
@@ -10994,7 +10994,7 @@
 	len = out - (char *)stackblock();
 	out = stackblock();
 	if (eofmark == NULL) {
-		if ((c == '>' || c == '<' USE_ASH_BASH_COMPAT( || c == 0x100 + '>'))
+		if ((c == '>' || c == '<' IF_ASH_BASH_COMPAT( || c == 0x100 + '>'))
 		 && quotef == 0
 		) {
 			if (isdigit_str9(out)) {
@@ -11488,7 +11488,7 @@
 	startlinno = g_parsefile->linno;
 	for (;;) {                      /* until token or start of word found */
 		c = pgetc_fast();
-		if (c == ' ' || c == '\t' USE_ASH_ALIAS( || c == PEOA))
+		if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA))
 			continue;
 
 		if (c == '#') {
@@ -12454,8 +12454,8 @@
 	rflag = 0;
 	prompt = NULL;
 	while ((i = nextopt("p:u:r"
-		USE_ASH_READ_TIMEOUT("t:")
-		USE_ASH_READ_NCHARS("n:s")
+		IF_ASH_READ_TIMEOUT("t:")
+		IF_ASH_READ_NCHARS("n:s")
 	)) != '\0') {
 		switch (i) {
 		case 'p':
Index: coreutils/uname.c
===================================================================
--- coreutils/uname.c	(revision 26172)
+++ coreutils/uname.c	(revision 26173)
@@ -97,7 +97,7 @@
 	const unsigned short *delta;
 	unsigned toprint;
 
-	USE_GETOPT_LONG(applet_long_options = longopts);
+	IF_GETOPT_LONG(applet_long_options = longopts);
 	toprint = getopt32(argv, options);
 
 	if (argv[optind]) { /* coreutils-6.9 compat */
Index: coreutils/libcoreutils/getopt_mk_fifo_nod.c
===================================================================
--- coreutils/libcoreutils/getopt_mk_fifo_nod.c	(revision 26172)
+++ coreutils/libcoreutils/getopt_mk_fifo_nod.c	(revision 26173)
@@ -31,7 +31,7 @@
 	security_context_t scontext;
 #endif
 	int opt;
-	opt = getopt32(argv, "m:" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+	opt = getopt32(argv, "m:" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
 	if (opt & 1) {
 		if (bb_parse_mode(smode, &mode))
 			umask(0);
Index: coreutils/df.c
===================================================================
--- coreutils/df.c	(revision 26172)
+++ coreutils/df.c	(revision 26173)
@@ -64,9 +64,9 @@
 	opt_complementary = "k-m:m-k";
 #endif
 	opt = getopt32(argv, "kP"
-			USE_FEATURE_DF_FANCY("aiB:")
-			USE_FEATURE_HUMAN_READABLE("hm")
-			USE_FEATURE_DF_FANCY(, &chp));
+			IF_FEATURE_DF_FANCY("aiB:")
+			IF_FEATURE_HUMAN_READABLE("hm")
+			IF_FEATURE_DF_FANCY(, &chp));
 	if (opt & OPT_MEGA)
 		df_disp_hr = 1024*1024;
 
Index: coreutils/date.c
===================================================================
--- coreutils/date.c	(revision 26172)
+++ coreutils/date.c	(revision 26173)
@@ -52,11 +52,11 @@
 	char *isofmt_arg = NULL;
 
 	opt_complementary = "d--s:s--d"
-		USE_FEATURE_DATE_ISOFMT(":R--I:I--R");
+		IF_FEATURE_DATE_ISOFMT(":R--I:I--R");
 	opt = getopt32(argv, "Rs:ud:r:"
-			USE_FEATURE_DATE_ISOFMT("I::D:"),
+			IF_FEATURE_DATE_ISOFMT("I::D:"),
 			&date_str, &date_str, &filename
-			USE_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
+			IF_FEATURE_DATE_ISOFMT(, &isofmt_arg, &fmt_str2dt));
 	argv += optind;
 	maybe_set_utc(opt);
 
Index: coreutils/readlink.c
===================================================================
--- coreutils/readlink.c	(revision 26172)
+++ coreutils/readlink.c	(revision 26173)
@@ -16,14 +16,14 @@
 	char *fname;
 	char pathbuf[PATH_MAX];
 
-	USE_FEATURE_READLINK_FOLLOW(
+	IF_FEATURE_READLINK_FOLLOW(
 		unsigned opt;
 		/* We need exactly one non-option argument.  */
 		opt_complementary = "=1";
 		opt = getopt32(argv, "f");
 		fname = argv[optind];
 	)
-	SKIP_FEATURE_READLINK_FOLLOW(
+	IF_NOT_FEATURE_READLINK_FOLLOW(
 		const unsigned opt = 0;
 		if (argc != 2) bb_show_usage();
 		fname = argv[1];
Index: coreutils/chmod.c
===================================================================
--- coreutils/chmod.c	(revision 26172)
+++ coreutils/chmod.c	(revision 26173)
@@ -20,10 +20,10 @@
 
 
 #define OPT_RECURSE (option_mask32 & 1)
-#define OPT_VERBOSE (USE_DESKTOP(option_mask32 & 2) SKIP_DESKTOP(0))
-#define OPT_CHANGED (USE_DESKTOP(option_mask32 & 4) SKIP_DESKTOP(0))
-#define OPT_QUIET   (USE_DESKTOP(option_mask32 & 8) SKIP_DESKTOP(0))
-#define OPT_STR     "R" USE_DESKTOP("vcf")
+#define OPT_VERBOSE (IF_DESKTOP(option_mask32 & 2) IF_NOT_DESKTOP(0))
+#define OPT_CHANGED (IF_DESKTOP(option_mask32 & 4) IF_NOT_DESKTOP(0))
+#define OPT_QUIET   (IF_DESKTOP(option_mask32 & 8) IF_NOT_DESKTOP(0))
+#define OPT_STR     "R" IF_DESKTOP("vcf")
 
 /* coreutils:
  * chmod never changes the permissions of symbolic links; the chmod
Index: coreutils/install.c
===================================================================
--- coreutils/install.c	(revision 26172)
+++ coreutils/install.c	(revision 26173)
@@ -101,12 +101,12 @@
 #if ENABLE_FEATURE_INSTALL_LONG_OPTIONS
 	applet_long_options = install_longopts;
 #endif
-	opt_complementary = "s--d:d--s" USE_SELINUX(":Z--\xff:\xff--Z");
+	opt_complementary = "s--d:d--s" IF_SELINUX(":Z--\xff:\xff--Z");
 	/* -c exists for backwards compatibility, it's needed */
 	/* -v is ignored ("print name of each created directory") */
 	/* -b is ignored ("make a backup of each existing destination file") */
-	opts = getopt32(argv, "cvb" "Ddpsg:m:o:" USE_SELINUX("Z:"),
-			&gid_str, &mode_str, &uid_str USE_SELINUX(, &scontext));
+	opts = getopt32(argv, "cvb" "Ddpsg:m:o:" IF_SELINUX("Z:"),
+			&gid_str, &mode_str, &uid_str IF_SELINUX(, &scontext));
 	argc -= optind;
 	argv += optind;
 
Index: coreutils/stat.c
===================================================================
--- coreutils/stat.c	(revision 26172)
+++ coreutils/stat.c	(revision 26173)
@@ -156,7 +156,7 @@
 /* print statfs info */
 static void print_statfs(char *pformat, const char m,
 		const char *const filename, const void *data
-		USE_SELINUX(, security_context_t scontext))
+		IF_SELINUX(, security_context_t scontext))
 {
 	const struct statfs *statfsbuf = data;
 	if (m == 'n') {
@@ -203,7 +203,7 @@
 /* print stat info */
 static void print_stat(char *pformat, const char m,
 		const char *const filename, const void *data
-		USE_SELINUX(, security_context_t scontext))
+		IF_SELINUX(, security_context_t scontext))
 {
 #define TYPE_SIGNED(t) (! ((t) 0 < (t) -1))
 	struct stat *statbuf = (struct stat *) data;
@@ -306,9 +306,9 @@
 }
 
 static void print_it(const char *masterformat, const char *filename,
-		void (*print_func) (char*, char, const char*, const void* USE_SELINUX(, security_context_t scontext)),
+		void (*print_func) (char*, char, const char*, const void* IF_SELINUX(, security_context_t scontext)),
 		const void *data
-		USE_SELINUX(, security_context_t scontext) )
+		IF_SELINUX(, security_context_t scontext) )
 {
 	/* Create a working copy of the format string */
 	char *format = xstrdup(masterformat);
@@ -347,7 +347,7 @@
 			break;
 		default:
 			/* Completes "%" with specifier and printfs */
-			print_func(dest, *p, filename, data USE_SELINUX(,scontext));
+			print_func(dest, *p, filename, data IF_SELINUX(,scontext));
 			break;
 		}
 	}
@@ -416,7 +416,7 @@
 			);
 #endif /* SELINUX */
 	}
-	print_it(format, filename, print_statfs, &statfsbuf USE_SELINUX(, scontext));
+	print_it(format, filename, print_statfs, &statfsbuf IF_SELINUX(, scontext));
 #else /* FEATURE_STAT_FORMAT */
 	format = (option_mask32 & OPT_TERSE
 		? "%s %llx %lu "
@@ -560,11 +560,11 @@
 		}
 #endif
 	}
-	print_it(format, filename, print_stat, &statbuf USE_SELINUX(, scontext));
+	print_it(format, filename, print_stat, &statbuf IF_SELINUX(, scontext));
 #else	/* FEATURE_STAT_FORMAT */
 	if (option_mask32 & OPT_TERSE) {
 		printf("%s %ju %ju %lx %lu %lu %jx %ju %lu %lx %lx %lu %lu %lu %lu"
-		       SKIP_SELINUX("\n"),
+		       IF_NOT_SELINUX("\n"),
 		       filename,
 		       (uintmax_t) (statbuf.st_size),
 		       (uintmax_t) statbuf.st_blocks,
@@ -642,14 +642,14 @@
 int stat_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int stat_main(int argc, char **argv)
 {
-	USE_FEATURE_STAT_FORMAT(char *format = NULL;)
+	IF_FEATURE_STAT_FORMAT(char *format = NULL;)
 	int i;
 	int ok = 1;
 	statfunc_ptr statfunc = do_stat;
 
 	getopt32(argv, "ftL"
-		USE_SELINUX("Z")
-		USE_FEATURE_STAT_FORMAT("c:", &format)
+		IF_SELINUX("Z")
+		IF_FEATURE_STAT_FORMAT("c:", &format)
 	);
 
 	if (option_mask32 & OPT_FILESYS) /* -f */
@@ -663,7 +663,7 @@
 	}
 #endif	/* ENABLE_SELINUX */
 	for (i = optind; i < argc; ++i)
-		ok &= statfunc(argv[i] USE_FEATURE_STAT_FORMAT(, format));
+		ok &= statfunc(argv[i] IF_FEATURE_STAT_FORMAT(, format));
 
 	return (ok ? EXIT_SUCCESS : EXIT_FAILURE);
 }
Index: coreutils/chown.c
===================================================================
--- coreutils/chown.c	(revision 26172)
+++ coreutils/chown.c	(revision 26173)
@@ -16,13 +16,13 @@
 /* This is a NOEXEC applet. Be very careful! */
 
 
-#define OPT_STR     ("Rh" USE_DESKTOP("vcfLHP"))
+#define OPT_STR     ("Rh" IF_DESKTOP("vcfLHP"))
 #define BIT_RECURSE 1
 #define OPT_RECURSE (opt & 1)
 #define OPT_NODEREF (opt & 2)
-#define OPT_VERBOSE (USE_DESKTOP(opt & 0x04) SKIP_DESKTOP(0))
-#define OPT_CHANGED (USE_DESKTOP(opt & 0x08) SKIP_DESKTOP(0))
-#define OPT_QUIET   (USE_DESKTOP(opt & 0x10) SKIP_DESKTOP(0))
+#define OPT_VERBOSE (IF_DESKTOP(opt & 0x04) IF_NOT_DESKTOP(0))
+#define OPT_CHANGED (IF_DESKTOP(opt & 0x08) IF_NOT_DESKTOP(0))
+#define OPT_QUIET   (IF_DESKTOP(opt & 0x10) IF_NOT_DESKTOP(0))
 /* POSIX options
  * -L traverse every symbolic link to a directory encountered
  * -H if a command line argument is a symbolic link to a directory, traverse it
@@ -32,10 +32,10 @@
  * The last option specified shall determine the behavior of the utility." */
 /* -L */
 #define BIT_TRAVERSE 0x20
-#define OPT_TRAVERSE (USE_DESKTOP(opt & BIT_TRAVERSE) SKIP_DESKTOP(0))
+#define OPT_TRAVERSE (IF_DESKTOP(opt & BIT_TRAVERSE) IF_NOT_DESKTOP(0))
 /* -H or -L */
 #define BIT_TRAVERSE_TOP (0x20|0x40)
-#define OPT_TRAVERSE_TOP (USE_DESKTOP(opt & BIT_TRAVERSE_TOP) SKIP_DESKTOP(0))
+#define OPT_TRAVERSE_TOP (IF_DESKTOP(opt & BIT_TRAVERSE_TOP) IF_NOT_DESKTOP(0))
 
 typedef int (*chown_fptr)(const char *, uid_t, gid_t);
 
@@ -85,7 +85,7 @@
 	/* This matches coreutils behavior (almost - see below) */
 	if (OPT_NODEREF
 	    /* || (OPT_RECURSE && !OPT_TRAVERSE_TOP): */
-	    USE_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
+	    IF_DESKTOP( || (opt & (BIT_RECURSE|BIT_TRAVERSE_TOP)) == BIT_RECURSE)
 	) {
 		param.chown_func = lchown;
 	}
Index: coreutils/tail.c
===================================================================
--- coreutils/tail.c	(revision 26172)
+++ coreutils/tail.c	(revision 26173)
@@ -110,9 +110,9 @@
 	}
 #endif
 
-	USE_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
-	opt = getopt32(argv, "fc:n:" USE_FEATURE_FANCY_TAIL("qs:v"),
-			&str_c, &str_n USE_FEATURE_FANCY_TAIL(,&sleep_period));
+	IF_FEATURE_FANCY_TAIL(opt_complementary = "s+";) /* -s N */
+	opt = getopt32(argv, "fc:n:" IF_FEATURE_FANCY_TAIL("qs:v"),
+			&str_c, &str_n IF_FEATURE_FANCY_TAIL(,&sleep_period));
 #define FOLLOW (opt & 0x1)
 #define COUNT_BYTES (opt & 0x2)
 	//if (opt & 0x1) // -f
Index: coreutils/mkdir.c
===================================================================
--- coreutils/mkdir.c	(revision 26172)
+++ coreutils/mkdir.c	(revision 26173)
@@ -48,7 +48,7 @@
 #if ENABLE_FEATURE_MKDIR_LONG_OPTIONS
 	applet_long_options = mkdir_longopts;
 #endif
-	opt = getopt32(argv, "m:p" USE_SELINUX("Z:"), &smode USE_SELINUX(,&scontext));
+	opt = getopt32(argv, "m:p" IF_SELINUX("Z:"), &smode IF_SELINUX(,&scontext));
 	if (opt & 1) {
 		mode = 0777;
 		if (!bb_parse_mode(smode, &mode)) {
Index: coreutils/du.c
===================================================================
--- coreutils/du.c	(revision 26172)
+++ coreutils/du.c	(revision 26173)
@@ -155,13 +155,13 @@
 	unsigned opt;
 
 #if ENABLE_FEATURE_HUMAN_READABLE
-	USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
-	SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
+	IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 1024;)
+	IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_hr = 512;)
 	if (getenv("POSIXLY_CORRECT"))  /* TODO - a new libbb function? */
 		G.disp_hr = 512;
 #else
-	USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
-	/* SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */
+	IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 1;)
+	/* IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(G.disp_k = 0;) - G is pre-zeroed */
 #endif
 	G.max_print_depth = INT_MAX;
 
Index: coreutils/ls.c
===================================================================
--- coreutils/ls.c	(revision 26172)
+++ coreutils/ls.c	(revision 26173)
@@ -46,12 +46,12 @@
  */
 # undef CONFIG_FEATURE_LS_TIMESTAMPS
 # undef ENABLE_FEATURE_LS_TIMESTAMPS
-# undef USE_FEATURE_LS_TIMESTAMPS
-# undef SKIP_FEATURE_LS_TIMESTAMPS
+# undef IF_FEATURE_LS_TIMESTAMPS
+# undef IF_NOT_FEATURE_LS_TIMESTAMPS
 # define CONFIG_FEATURE_LS_TIMESTAMPS 1
 # define ENABLE_FEATURE_LS_TIMESTAMPS 1
-# define USE_FEATURE_LS_TIMESTAMPS(...) __VA_ARGS__
-# define SKIP_FEATURE_LS_TIMESTAMPS(...)
+# define IF_FEATURE_LS_TIMESTAMPS(...) __VA_ARGS__
+# define IF_NOT_FEATURE_LS_TIMESTAMPS(...)
 #endif
 
 
@@ -138,15 +138,15 @@
 /* "[-]e", I think we made this one up */
 static const char ls_options[] ALIGN1 =
 	"Cadil1gnsxQAk" /* 13 opts, total 13 */
-	USE_FEATURE_LS_TIMESTAMPS("cetu") /* 4, 17 */
-	USE_FEATURE_LS_SORTFILES("SXrv")  /* 4, 21 */
-	USE_FEATURE_LS_FILETYPES("Fp")    /* 2, 23 */
-	USE_FEATURE_LS_FOLLOWLINKS("L")   /* 1, 24 */
-	USE_FEATURE_LS_RECURSIVE("R")     /* 1, 25 */
-	USE_FEATURE_HUMAN_READABLE("h")   /* 1, 26 */
-	USE_SELINUX("K") /* 1, 27 */
-	USE_SELINUX("Z") /* 1, 28 */
-	USE_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */
+	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("K") /* 1, 27 */
+	IF_SELINUX("Z") /* 1, 28 */
+	IF_FEATURE_AUTOWIDTH("T:w:") /* 2, 30 */
 	;
 enum {
 	//OPT_C = (1 << 0),
@@ -232,7 +232,7 @@
 	const char *fullname;         /* the dir entry name */
 	int   allocated;
 	struct stat dstat;      /* the file stat info */
-	USE_SELINUX(security_context_t sid;)
+	IF_SELINUX(security_context_t sid;)
 	struct dnode *next;     /* point at the next node */
 };
 
@@ -277,9 +277,9 @@
 /* memset: we have to zero it out because of NOEXEC */
 #define INIT_G() do { \
 	memset(&G, 0, sizeof(G)); \
-	USE_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \
-	USE_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \
-	USE_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \
+	IF_FEATURE_AUTOWIDTH(tabstops = COLUMN_GAP;) \
+	IF_FEATURE_AUTOWIDTH(terminal_width = TERMINAL_WIDTH;) \
+	IF_FEATURE_LS_TIMESTAMPS(time(¤t_time_t);) \
 } while (0)
 
 
@@ -302,7 +302,7 @@
 {
 	struct stat dstat;
 	struct dnode *cur;
-	USE_SELINUX(security_context_t sid = NULL;)
+	IF_SELINUX(security_context_t sid = NULL;)
 
 	if ((all_fmt & FOLLOW_LINKS) || force_follow) {
 #if ENABLE_SELINUX
@@ -332,7 +332,7 @@
 	cur->fullname = fullname;
 	cur->name = name;
 	cur->dstat = dstat;
-	USE_SELINUX(cur->sid = sid;)
+	IF_SELINUX(cur->sid = sid;)
 	return cur;
 }
 
@@ -570,7 +570,7 @@
 				column_width = len;
 		}
 		column_width += tabstops +
-			USE_SELINUX( ((all_fmt & LIST_CONTEXT) ? 33 : 0) + )
+			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);
@@ -912,7 +912,7 @@
 	int dndirs;
 	int i;
 	/* need to initialize since --color has _an optional_ argument */
-	USE_FEATURE_LS_COLOR(const char *color_opt = "always";)
+	IF_FEATURE_LS_COLOR(const char *color_opt = "always";)
 
 	INIT_G();
 
@@ -927,13 +927,13 @@
 #endif
 
 	/* process options */
-	USE_FEATURE_LS_COLOR(applet_long_options = ls_color_opt;)
+	IF_FEATURE_LS_COLOR(applet_long_options = ls_color_opt;)
 #if ENABLE_FEATURE_AUTOWIDTH
 	opt_complementary = "T+:w+"; /* -T N, -w N */
 	opt = getopt32(argv, ls_options, &tabstops, &terminal_width
-				USE_FEATURE_LS_COLOR(, &color_opt));
+				IF_FEATURE_LS_COLOR(, &color_opt));
 #else
-	opt = getopt32(argv, ls_options USE_FEATURE_LS_COLOR(, &color_opt));
+	opt = getopt32(argv, ls_options IF_FEATURE_LS_COLOR(, &color_opt));
 #endif
 	for (i = 0; opt_flags[i] != (1U<<31); i++) {
 		if (opt & (1 << i)) {
Index: coreutils/expand.c
===================================================================
--- coreutils/expand.c	(revision 26172)
+++ coreutils/expand.c	(revision 26173)
@@ -132,10 +132,10 @@
 #endif
 
 	if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e')) {
-		USE_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
+		IF_FEATURE_EXPAND_LONG_OPTIONS(applet_long_options = expand_longopts);
 		opt = getopt32(argv, "it:", &opt_t);
 	} else {
-		USE_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
+		IF_FEATURE_UNEXPAND_LONG_OPTIONS(applet_long_options = unexpand_longopts);
 		/* -t NUM sets also -a */
 		opt_complementary = "ta";
 		opt = getopt32(argv, "ft:a", &opt_t);
@@ -157,9 +157,9 @@
 		}
 
 		if (ENABLE_EXPAND && (!ENABLE_UNEXPAND || applet_name[0] == 'e'))
-			USE_EXPAND(expand(file, tab_size, opt));
+			IF_EXPAND(expand(file, tab_size, opt));
 		else
-			USE_UNEXPAND(unexpand(file, tab_size, opt));
+			IF_UNEXPAND(unexpand(file, tab_size, opt));
 
 		/* Check and close the file */
 		if (fclose_if_not_stdin(file)) {
Index: coreutils/tty.c
===================================================================
--- coreutils/tty.c	(revision 26172)
+++ coreutils/tty.c	(revision 26173)
@@ -13,17 +13,17 @@
 #include "libbb.h"
 
 int tty_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
-int tty_main(int argc, char **argv SKIP_INCLUDE_SUSv2(UNUSED_PARAM))
+int tty_main(int argc, char **argv IF_NOT_INCLUDE_SUSv2(UNUSED_PARAM))
 {
 	const char *s;
-	USE_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. */
 
-	USE_INCLUDE_SUSv2(silent = getopt32(argv, "s");)
-	USE_INCLUDE_SUSv2(argc -= optind;)
-	SKIP_INCLUDE_SUSv2(argc -= 1;)
+	IF_INCLUDE_SUSv2(silent = getopt32(argv, "s");)
+	IF_INCLUDE_SUSv2(argc -= optind;)
+	IF_NOT_INCLUDE_SUSv2(argc -= 1;)
 
 	/* gnu tty outputs a warning that it is ignoring all args. */
 	bb_warn_ignoring_args(argc);
@@ -37,8 +37,8 @@
 		s = "not a tty";
 		retval = 1;
 	}
-	USE_INCLUDE_SUSv2(if (!silent) puts(s);)
-	SKIP_INCLUDE_SUSv2(puts(s);)
+	IF_INCLUDE_SUSv2(if (!silent) puts(s);)
+	IF_NOT_INCLUDE_SUSv2(puts(s);)
 
 	fflush_stdout_and_exit(retval);
 }
Index: coreutils/touch.c
===================================================================
--- coreutils/touch.c	(revision 26172)
+++ coreutils/touch.c	(revision 26173)
@@ -63,9 +63,9 @@
 	applet_long_options = longopts;
 #endif
 #endif
-	opts = getopt32(argv, "c" USE_DESKTOP("r:")
+	opts = getopt32(argv, "c" IF_DESKTOP("r:")
 				/*ignored:*/ "fma"
-				USE_DESKTOP(, &reference_file));
+				IF_DESKTOP(, &reference_file));
 
 	opts &= 1; /* only -c bit is left */
 	argv += optind;
Index: coreutils/id.c
===================================================================
--- coreutils/id.c	(revision 26172)
+++ coreutils/id.c	(revision 26173)
@@ -119,8 +119,8 @@
 	/* Don't allow -n -r -nr -ug -rug -nug -rnug -uZ -gZ -GZ*/
 	/* Don't allow more than one username */
 	opt_complementary = "?1:u--g:g--u:G--u:u--G:g--G:G--g:r?ugG:n?ugG"
-			 USE_SELINUX(":u--Z:Z--u:g--Z:Z--g:G--Z:Z--G");
-	opt = getopt32(argv, "rnugG" USE_SELINUX("Z"));
+			 IF_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) {
Index: libbb/procps.c
===================================================================
--- libbb/procps.c	(revision 26172)
+++ libbb/procps.c	(revision 26173)
@@ -111,7 +111,7 @@
 {
 	closedir(sp->dir);
 	free(sp->argv0);
-	USE_SELINUX(free(sp->context);)
+	IF_SELINUX(free(sp->context);)
 	free(sp);
 }
 
Index: libbb/read.c
===================================================================
--- libbb/read.c	(revision 26172)
+++ libbb/read.c	(revision 26173)
@@ -315,7 +315,7 @@
 	char *sfx;
 	int fd;
 #if BB_MMU
-	USE_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
+	IF_DESKTOP(long long) int FAST_FUNC (*xformer)(int src_fd, int dst_fd);
 	enum { xformer_prog = 0 };
 #else
 	enum { xformer = 0 };
@@ -352,7 +352,7 @@
 				 || magic[0] != 'B' || magic[1] != 'Z'
 				) {
 					bb_error_msg_and_die("no gzip"
-						USE_FEATURE_SEAMLESS_BZ2("/bzip2")
+						IF_FEATURE_SEAMLESS_BZ2("/bzip2")
 						" magic");
 				}
 #if BB_MMU
Index: libbb/xfuncs_printf.c
===================================================================
--- libbb/xfuncs_printf.c	(revision 26172)
+++ libbb/xfuncs_printf.c	(revision 26173)
@@ -420,7 +420,7 @@
 		const char *s = "INET";
 		if (domain == AF_PACKET) s = "PACKET";
 		if (domain == AF_NETLINK) s = "NETLINK";
-USE_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
+IF_FEATURE_IPV6(if (domain == AF_INET6) s = "INET6";)
 		bb_perror_msg_and_die("socket(AF_%s)", s);
 #else
 		bb_perror_msg_and_die("socket");
Index: libbb/lineedit.c
===================================================================
--- libbb/lineedit.c	(revision 26172)
+++ libbb/lineedit.c	(revision 26173)
@@ -62,10 +62,10 @@
 
 #define ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR \
 	(ENABLE_FEATURE_USERNAME_COMPLETION || ENABLE_FEATURE_EDITING_FANCY_PROMPT)
-#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...)
+#define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...)
 #if ENABLE_FEATURE_GETUSERNAME_AND_HOMEDIR
-#undef USE_FEATURE_GETUSERNAME_AND_HOMEDIR
-#define USE_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__
+#undef IF_FEATURE_GETUSERNAME_AND_HOMEDIR
+#define IF_FEATURE_GETUSERNAME_AND_HOMEDIR(...) __VA_ARGS__
 #endif
 
 enum {
@@ -152,8 +152,8 @@
 	(*(struct lineedit_statics**)&lineedit_ptr_to_statics) = xzalloc(sizeof(S)); \
 	barrier(); \
 	cmdedit_termw = 80; \
-	USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
-	USE_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \
+	IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines = 1;) \
+	IF_FEATURE_GETUSERNAME_AND_HOMEDIR(home_pwd_buf = (char*)null_str;) \
 } while (0)
 static void deinit_S(void)
 {
@@ -1160,7 +1160,7 @@
 	if ((state->flags & SAVE_HISTORY) && state->hist_file)
 		save_history(str);
 #endif
-	USE_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
+	IF_FEATURE_EDITING_FANCY_PROMPT(num_ok_lines++;)
 }
 
 #else /* MAX_HISTORY == 0 */
@@ -1442,7 +1442,7 @@
 
 /* leave out the "vi-mode"-only case labels if vi editing isn't
  * configured. */
-#define vi_case(caselabel) USE_FEATURE_EDITING(case caselabel)
+#define vi_case(caselabel) IF_FEATURE_EDITING(case caselabel)
 
 /* convert uppercase ascii to equivalent control char, for readability */
 #undef CTRL
Index: libbb/xconnect.c
===================================================================
--- libbb/xconnect.c	(revision 26172)
+++ libbb/xconnect.c	(revision 26173)
@@ -151,7 +151,7 @@
  * port: if neither of above specifies port # */
 static len_and_sockaddr* str2sockaddr(
 		const char *host, int port,
-USE_FEATURE_IPV6(sa_family_t af,)
+IF_FEATURE_IPV6(sa_family_t af,)
 		int ai_flags)
 {
 	int rc;
@@ -269,9 +269,9 @@
 }
 
 #undef xsocket_type
-int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, USE_FEATURE_IPV6(int family,) int sock_type)
+int FAST_FUNC xsocket_type(len_and_sockaddr **lsap, IF_FEATURE_IPV6(int family,) int sock_type)
 {
-	SKIP_FEATURE_IPV6(enum { family = AF_INET };)
+	IF_NOT_FEATURE_IPV6(enum { family = AF_INET };)
 	len_and_sockaddr *lsa;
 	int fd;
 	int len;
@@ -303,7 +303,7 @@
 
 int FAST_FUNC xsocket_stream(len_and_sockaddr **lsap)
 {
-	return xsocket_type(lsap, USE_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
+	return xsocket_type(lsap, IF_FEATURE_IPV6(AF_UNSPEC,) SOCK_STREAM);
 }
 
 static int create_and_bind_or_die(const char *bindaddr, int port, int sock_type)
@@ -316,7 +316,7 @@
 		/* user specified bind addr dictates family */
 		fd = xsocket(lsa->u.sa.sa_family, sock_type, 0);
 	} else {
-		fd = xsocket_type(&lsa, USE_FEATURE_IPV6(AF_UNSPEC,) sock_type);
+		fd = xsocket_type(&lsa, IF_FEATURE_IPV6(AF_UNSPEC,) sock_type);
 		set_nport(lsa, htons(port));
 	}
 	setsockopt_reuseaddr(fd);
Index: libbb/mtab_file.c
===================================================================
--- libbb/mtab_file.c	(revision 26172)
+++ libbb/mtab_file.c	(revision 26173)
@@ -12,4 +12,4 @@
 /* Busybox mount uses either /proc/mounts or /etc/mtab to
  * get the list of currently mounted filesystems */
 const char bb_path_mtab_file[] ALIGN1 =
-USE_FEATURE_MTAB_SUPPORT("/etc/mtab")SKIP_FEATURE_MTAB_SUPPORT("/proc/mounts");
+IF_FEATURE_MTAB_SUPPORT("/etc/mtab")IF_NOT_FEATURE_MTAB_SUPPORT("/proc/mounts");
Index: libbb/appletlib.c
===================================================================
--- libbb/appletlib.c	(revision 26172)
+++ libbb/appletlib.c	(revision 26173)
@@ -55,8 +55,8 @@
 #ifdef SINGLE_APPLET_MAIN
 #undef ENABLE_FEATURE_INDIVIDUAL
 #define ENABLE_FEATURE_INDIVIDUAL 1
-#undef USE_FEATURE_INDIVIDUAL
-#define USE_FEATURE_INDIVIDUAL(...) __VA_ARGS__
+#undef IF_FEATURE_INDIVIDUAL
+#define IF_FEATURE_INDIVIDUAL(...) __VA_ARGS__
 #endif
 
 
@@ -179,10 +179,10 @@
 
 
 void lbb_prepare(const char *applet
-		USE_FEATURE_INDIVIDUAL(, char **argv))
+		IF_FEATURE_INDIVIDUAL(, char **argv))
 				MAIN_EXTERNALLY_VISIBLE;
 void lbb_prepare(const char *applet
-		USE_FEATURE_INDIVIDUAL(, char **argv))
+		IF_FEATURE_INDIVIDUAL(, char **argv))
 {
 #ifdef __GLIBC__
 	(*(int **)&bb_errno) = __errno_location();
@@ -224,7 +224,7 @@
 /* If not built as a single-applet executable... */
 #if !defined(SINGLE_APPLET_MAIN)
 
-USE_FEATURE_SUID(static uid_t ruid;)  /* real uid */
+IF_FEATURE_SUID(static uid_t ruid;)  /* real uid */
 
 #if ENABLE_FEATURE_SUID_CONFIG
 
@@ -500,7 +500,7 @@
 #else
 static inline void parse_config_file(void)
 {
-	USE_FEATURE_SUID(ruid = getuid();)
+	IF_FEATURE_SUID(ruid = getuid();)
 }
 #endif /* FEATURE_SUID_CONFIG */
 
@@ -754,10 +754,10 @@
 #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 USE_FEATURE_INDIVIDUAL(, argv));
+	lbb_prepare(applet_names IF_FEATURE_INDIVIDUAL(, argv));
 	return SINGLE_APPLET_MAIN(argc, argv);
 #else
-	lbb_prepare("busybox" USE_FEATURE_INDIVIDUAL(, argv));
+	lbb_prepare("busybox" IF_FEATURE_INDIVIDUAL(, argv));
 
 #if !BB_MMU
 	/* NOMMU re-exec trick sets high-order bit in first byte of name */
Index: miscutils/hdparm.c
===================================================================
--- miscutils/hdparm.c	(revision 26172)
+++ miscutils/hdparm.c	(revision 26173)
@@ -293,15 +293,15 @@
 	unsigned long doorlock;
 	unsigned long apmmode;
 #endif
-	USE_FEATURE_HDPARM_GET_IDENTITY(        smallint get_IDentity;)
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint set_busstate, get_busstate;)
-	USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(    smallint perform_reset;)
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint perform_tristate;)
-	USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
-	USE_FEATURE_HDPARM_HDIO_SCAN_HWIF(      smallint scan_hwif;)
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long busstate;)
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long tristate;)
-	USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
+	IF_FEATURE_HDPARM_GET_IDENTITY(        smallint get_IDentity;)
+	IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint set_busstate, get_busstate;)
+	IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(    smallint perform_reset;)
+	IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  smallint perform_tristate;)
+	IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(smallint unregister_hwif;)
+	IF_FEATURE_HDPARM_HDIO_SCAN_HWIF(      smallint scan_hwif;)
+	IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long busstate;)
+	IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(  unsigned long tristate;)
+	IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(unsigned long hwif;)
 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
 	unsigned long hwif_data;
 	unsigned long hwif_ctrl;
@@ -1960,12 +1960,12 @@
 /*------- getopt short options --------*/
 static const char hdparm_options[] ALIGN1 =
 	"gfu::n::p:r::m::c::k::a::B:tT"
-	USE_FEATURE_HDPARM_GET_IDENTITY("iI")
-	USE_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
+	IF_FEATURE_HDPARM_GET_IDENTITY("iI")
+	IF_FEATURE_HDPARM_HDIO_GETSET_DMA("d::")
 #ifdef HDIO_DRIVE_CMD
 	"S:D:P:X:K:A:L:W:CyYzZ"
 #endif
-	USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
+	IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF("U:")
 #ifdef HDIO_GET_QDMA
 #ifdef HDIO_SET_QDMA
 	"Q:"
@@ -1973,9 +1973,9 @@
 	"Q"
 #endif
 #endif
-	USE_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
-	USE_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
+	IF_FEATURE_HDPARM_HDIO_DRIVE_RESET("w")
+	IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF("x::b:")
+	IF_FEATURE_HDPARM_HDIO_SCAN_HWIF("R:");
 /*-------------------------------------*/
 
 /* our main() routine: */
@@ -1987,12 +1987,12 @@
 
 	while ((c = getopt(argc, argv, hdparm_options)) >= 0) {
 		flagcount++;
-		USE_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
-		USE_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
+		IF_FEATURE_HDPARM_GET_IDENTITY(get_IDentity |= (c == 'I'));
+		IF_FEATURE_HDPARM_GET_IDENTITY(get_identity |= (c == 'i'));
 		get_geom |= (c == 'g');
 		do_flush |= (c == 'f');
 		if (c == 'u') parse_opts(&get_unmask, &set_unmask, &unmask, 0, 1);
-		USE_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
+		IF_FEATURE_HDPARM_HDIO_GETSET_DMA(if (c == 'd') parse_opts(&get_dma, &set_dma, &dma, 0, 9));
 		if (c == 'n') parse_opts(&get_nowerr, &set_nowerr, &nowerr, 0, 1);
 		parse_xfermode((c == 'p'), &noisy_piomode, &set_piomode, &piomode);
 		if (c == 'r') parse_opts(&get_readonly, &set_readonly, &readonly, 0, 1);
@@ -2018,7 +2018,7 @@
 		reread_partn |= (c == 'z');
 		get_seagate = set_seagate |= (c == 'Z');
 #endif
-		USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
+		IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF(if (c == 'U') parse_opts(NULL, &unregister_hwif, &hwif, 0, INT_MAX));
 #ifdef HDIO_GET_QDMA
 		if (c == 'Q') {
 #ifdef HDIO_SET_QDMA
@@ -2028,9 +2028,9 @@
 #endif
 		}
 #endif
-		USE_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
-		USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
-		USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
+		IF_FEATURE_HDPARM_HDIO_DRIVE_RESET(perform_reset = (c == 'r'));
+		IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'x') parse_opts(NULL, &perform_tristate, &tristate, 0, 1));
+		IF_FEATURE_HDPARM_HDIO_TRISTATE_HWIF(if (c == 'b') parse_opts(&get_busstate, &set_busstate, &busstate, 0, 2));
 #if ENABLE_FEATURE_HDPARM_HDIO_SCAN_HWIF
 		if (c == 'R') {
 			parse_opts(NULL, &scan_hwif, &hwif_data, 0, INT_MAX);
@@ -2045,7 +2045,7 @@
 	/* When no flags are given (flagcount = 0), -acdgkmnru is assumed. */
 	if (!flagcount) {
 		get_mult = get_io32bit = get_unmask = get_keep = get_readonly = get_readahead = get_geom = 1;
-		USE_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
+		IF_FEATURE_HDPARM_HDIO_GETSET_DMA(get_dma = 1);
 	}
 	argv += optind;
 
Index: miscutils/crond.c
===================================================================
--- miscutils/crond.c	(revision 26172)
+++ miscutils/crond.c	(revision 26173)
@@ -162,11 +162,11 @@
 	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" USE_FEATURE_CROND_D(":d-l")
+	opt_complementary = "f-b:b-f:S-L:L-S" IF_FEATURE_CROND_D(":d-l")
 			":l+:d+"; /* -l and -d have numeric param */
-	opt = getopt32(argv, "l:L:fbSc:" USE_FEATURE_CROND_D("d:"),
+	opt = getopt32(argv, "l:L:fbSc:" IF_FEATURE_CROND_D("d:"),
 			&LogLevel, &LogFile, &CDir
-			USE_FEATURE_CROND_D(,&LogLevel));
+			IF_FEATURE_CROND_D(,&LogLevel));
 	/* both -d N and -l N set the same variable: LogLevel */
 
 	if (!(opt & OPT_f)) {
Index: miscutils/less.c
===================================================================
--- miscutils/less.c	(revision 26172)
+++ miscutils/less.c	(revision 26173)
@@ -145,7 +145,7 @@
 	current_file = 1; \
 	eof_error = 1; \
 	terminated = 1; \
-	USE_FEATURE_LESS_REGEXP(wanted_match = -1;) \
+	IF_FEATURE_LESS_REGEXP(wanted_match = -1;) \
 } while (0)
 
 /* flines[] are lines read from stdin, each in malloc'ed buffer.
@@ -326,7 +326,7 @@
 	if (option_mask32 & FLAG_N)
 		w -= 8;
 
- USE_FEATURE_LESS_REGEXP(again0:)
+ IF_FEATURE_LESS_REGEXP(again0:)
 
 	p = current_line = ((char*)xmalloc(w + 4)) + 4;
 	max_fline += last_terminated;
@@ -1509,7 +1509,7 @@
 	/* TODO: -x: do not interpret backspace, -xx: tab also */
 	/* -xxx: newline also */
 	/* -w N: assume width N (-xxx -w 32: hex viewer of sorts) */
-	getopt32(argv, "EMmN~I" USE_FEATURE_LESS_DASHCMD("S"));
+	getopt32(argv, "EMmN~I" IF_FEATURE_LESS_DASHCMD("S"));
 	argc -= optind;
 	argv += optind;
 	num_files = argc;
Index: miscutils/eject.c
===================================================================
--- miscutils/eject.c	(revision 26172)
+++ miscutils/eject.c	(revision 26173)
@@ -89,7 +89,7 @@
 	const char *device;
 
 	opt_complementary = "?1:t--T:T--t";
-	flags = getopt32(argv, "tT" USE_FEATURE_EJECT_SCSI("s"));
+	flags = getopt32(argv, "tT" IF_FEATURE_EJECT_SCSI("s"));
 	device = argv[optind] ? argv[optind] : "/dev/cdrom";
 
 	/* We used to do "umount " here, but it was buggy
Index: include/libbb.h
===================================================================
--- include/libbb.h	(revision 26172)
+++ include/libbb.h	(revision 26173)
@@ -260,7 +260,7 @@
 	FILEUTILS_SET_SECURITY_CONTEXT = 0x200
 #endif
 };
-#define FILEUTILS_CP_OPTSTR "pdRfilsL" USE_SELINUX("c")
+#define FILEUTILS_CP_OPTSTR "pdRfilsL" IF_SELINUX("c")
 extern int remove_file(const char *path, int flags) FAST_FUNC;
 /* NB: without FILEUTILS_RECUR in flags, it will basically "cat"
  * the source, not copy (unless "source" is a directory).
@@ -916,15 +916,15 @@
 /* Applets which are useful from another applets */
 int bb_cat(char** argv);
 /* If shell needs them, they exist even if not enabled as applets */
-int echo_main(int argc, char** argv) USE_ECHO(MAIN_EXTERNALLY_VISIBLE);
-int printf_main(int argc, char **argv) USE_PRINTF(MAIN_EXTERNALLY_VISIBLE);
-int test_main(int argc, char **argv) USE_TEST(MAIN_EXTERNALLY_VISIBLE);
-int kill_main(int argc, char **argv) USE_KILL(MAIN_EXTERNALLY_VISIBLE);
+int echo_main(int argc, char** argv) IF_ECHO(MAIN_EXTERNALLY_VISIBLE);
+int printf_main(int argc, char **argv) IF_PRINTF(MAIN_EXTERNALLY_VISIBLE);
+int test_main(int argc, char **argv) IF_TEST(MAIN_EXTERNALLY_VISIBLE);
+int kill_main(int argc, char **argv) IF_KILL(MAIN_EXTERNALLY_VISIBLE);
 /* Similar, but used by chgrp, not shell */
-int chown_main(int argc, char **argv) USE_CHOWN(MAIN_EXTERNALLY_VISIBLE);
+int chown_main(int argc, char **argv) IF_CHOWN(MAIN_EXTERNALLY_VISIBLE);
 /* Used by ftpd */
-int ls_main(int argc, char **argv) USE_LS(MAIN_EXTERNALLY_VISIBLE);
-/* Don't need USE_xxx() guard for these */
+int ls_main(int argc, char **argv) IF_LS(MAIN_EXTERNALLY_VISIBLE);
+/* Don't need IF_xxx() guard for these */
 int gunzip_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int bunzip2_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 
@@ -1253,7 +1253,7 @@
 /* Fields are set to 0/NULL if failed to determine (or not requested) */
 	uint16_t argv_len;
 	char *argv0;
-	USE_SELINUX(char *context;)
+	IF_SELINUX(char *context;)
 	/* 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 */
@@ -1309,7 +1309,7 @@
 				|| ENABLE_PIDOF
 				|| ENABLE_SESTATUS
 				),
-	USE_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
+	IF_SELINUX(PSSCAN_CONTEXT = 1 << 17,)
 	PSSCAN_START_TIME = 1 << 18,
 	PSSCAN_CPU      = 1 << 19,
 	/* These are all retrieved from proc/NN/stat in one go: */
Index: include/unarchive.h
===================================================================
--- include/unarchive.h	(revision 26172)
+++ include/unarchive.h	(revision 26173)
@@ -125,24 +125,24 @@
 	uint32_t crc;
 } inflate_unzip_result;
 
-USE_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC;
+IF_DESKTOP(long long) int inflate_unzip(inflate_unzip_result *res, off_t compr_size, int src_fd, int dst_fd) FAST_FUNC;
 /* lzma unpacker takes .lzma stream from offset 0 */
-USE_DESKTOP(long long) int unpack_lzma_stream(int src_fd, int dst_fd) FAST_FUNC;
+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 */
-USE_DESKTOP(long long) int unpack_bz2_stream(int src_fd, int dst_fd) FAST_FUNC;
-USE_DESKTOP(long long) int unpack_gz_stream(int src_fd, int dst_fd) FAST_FUNC;
-USE_DESKTOP(long long) int unpack_gz_stream_with_info(int src_fd, int dst_fd, unpack_info_t *info) FAST_FUNC;
-USE_DESKTOP(long long) int unpack_Z_stream(int fd_in, int fd_out) FAST_FUNC;
+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 fd_in, int fd_out) FAST_FUNC;
 /* wrapper which checks first two bytes to be "BZ" */
-USE_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC;
+IF_DESKTOP(long long) int unpack_bz2_stream_prime(int src_fd, int dst_fd) FAST_FUNC;
 
 int bbunpack(char **argv,
 	     char* (*make_new_name)(char *filename),
-	     USE_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)) FAST_FUNC;
+	     IF_DESKTOP(long long) int (*unpacker)(unpack_info_t *info)) FAST_FUNC;
 
 #if BB_MMU
 void open_transformer(int fd,
-	USE_DESKTOP(long long) int FAST_FUNC (*transformer)(int src_fd, int dst_fd)) FAST_FUNC;
+	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;
Index: include/usage.h
===================================================================
--- include/usage.h	(revision 26172)
+++ include/usage.h	(revision 26173)
@@ -25,7 +25,7 @@
      "\n	-c DIR	Config directory [/etc/acpi]" \
      "\n	-e FILE	/proc event file [/proc/acpi/event]" \
      "\n	-l FILE	Log file [/var/log/acpid]" \
-	USE_FEATURE_ACPID_COMPAT( \
+	IF_FEATURE_ACPID_COMPAT( \
      "\n\nAccept and ignore compatibility options -g -m -s -S -v" \
 	)
 
@@ -34,9 +34,9 @@
        "# acpid -d /dev/input/event*\n"
 
 #define addgroup_trivial_usage \
-       "[-g GID] " USE_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name"
+       "[-g GID] " IF_FEATURE_ADDUSER_TO_GROUP("[user_name] ") "group_name"
 #define addgroup_full_usage "\n\n" \
-       "Add a group " USE_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \
+       "Add a group " IF_FEATURE_ADDUSER_TO_GROUP("or add a user to a group") "\n" \
      "\nOptions:" \
      "\n	-g GID	Group id" \
 
@@ -160,14 +160,14 @@
 #define brctl_full_usage "\n\n" \
        "Manage ethernet bridges.\n" \
      "\nCommands:" \
-	USE_FEATURE_BRCTL_SHOW( \
+	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" \
-	USE_FEATURE_BRCTL_FANCY( \
+	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" \
@@ -281,12 +281,12 @@
 #define chcon_trivial_usage \
        "[OPTIONS] CONTEXT FILE..." \
        "\n	chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." \
-	USE_FEATURE_CHCON_LONG_OPTIONS( \
+	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" \
-	USE_FEATURE_CHCON_LONG_OPTIONS( \
+	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" \
@@ -298,7 +298,7 @@
      "\n	-l,--range=RANGE" \
      "\n	-R,--recursive		Recurse subdirectories" \
 	) \
-	SKIP_FEATURE_CHCON_LONG_OPTIONS( \
+	IF_NOT_FEATURE_CHCON_LONG_OPTIONS( \
      "\n	-v	Verbose" \
      "\n	-c	Report changes made" \
      "\n	-h	Affect symlinks instead of their targets" \
@@ -311,13 +311,13 @@
 	)
 
 #define chmod_trivial_usage \
-       "[-R"USE_DESKTOP("cvf")"] MODE[,MODE]... FILE..."
+       "[-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 directories" \
-	USE_DESKTOP( \
+	IF_DESKTOP( \
      "\n	-c	List changed files" \
      "\n	-v	List all files" \
      "\n	-f	Hide errors" \
@@ -333,7 +333,7 @@
        "-r--r--r--    1 root     root            0 Apr 12 18:25 /tmp/foo\n"
 
 #define chgrp_trivial_usage \
-       "[-RhLHP"USE_DESKTOP("cvf")"]... GROUP FILE..."
+       "[-RhLHP"IF_DESKTOP("cvf")"]... GROUP FILE..."
 #define chgrp_full_usage "\n\n" \
        "Change the group membership of each FILE to GROUP\n" \
      "\nOptions:" \
@@ -342,7 +342,7 @@
      "\n	-L	Traverse all symlinks to directories" \
      "\n	-H	Traverse symlinks on command line only" \
      "\n	-P	Do not traverse symlinks (default)" \
-	USE_DESKTOP( \
+	IF_DESKTOP( \
      "\n	-c	List changed files" \
      "\n	-v	Verbose" \
      "\n	-f	Hide errors" \
@@ -355,7 +355,7 @@
        "-r--r--r--    1 andersen root            0 Apr 12 18:25 /tmp/foo\n"
 
 #define chown_trivial_usage \
-       "[-RhLHP"USE_DESKTOP("cvf")"]... OWNER[<.|:>[GROUP]] FILE..."
+       "[-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:" \
@@ -364,7 +364,7 @@
      "\n	-L	Traverse all symlinks to directories" \
      "\n	-H	Traverse symlinks on command line only" \
      "\n	-P	Do not traverse symlinks (default)" \
-	USE_DESKTOP( \
+	IF_DESKTOP( \
      "\n	-c	List changed files" \
      "\n	-v	List all files" \
      "\n	-f	Hide errors" \
@@ -468,7 +468,7 @@
        "Clear screen"
 
 #define cmp_trivial_usage \
-       "[-l] [-s] FILE1 [FILE2" USE_DESKTOP(" [SKIP1 [SKIP2]") "]]"
+       "[-l] [-s] FILE1 [FILE2" IF_DESKTOP(" [SKIP1 [SKIP2]") "]]"
 #define cmp_full_usage "\n\n" \
        "Compares FILE1 vs stdin if FILE2 is not specified\n" \
      "\nOptions:" \
@@ -518,7 +518,7 @@
        "Copy SOURCE to DEST, or multiple SOURCE(s) to DIRECTORY\n" \
      "\nOptions:" \
      "\n	-a	Same as -dpR" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-c	Preserve security context" \
 	) \
      "\n	-d,-P	Preserve links" \
@@ -530,18 +530,18 @@
      "\n	-l,-s	Create (sym)links" \
 
 #define cpio_trivial_usage \
-       "-[ti" USE_FEATURE_CPIO_O("o") USE_FEATURE_CPIO_P("p") "dmvu] [-F FILE]" \
-       USE_FEATURE_CPIO_O( " [-H newc]" )
+       "-[ti" IF_FEATURE_CPIO_O("o") IF_FEATURE_CPIO_P("p") "dmvu] [-F FILE]" \
+       IF_FEATURE_CPIO_O( " [-H newc]" )
 #define cpio_full_usage "\n\n" \
        "Extract or list files from a cpio archive" \
-	USE_FEATURE_CPIO_O( ", or create a cpio archive" ) \
+	IF_FEATURE_CPIO_O( ", or create a cpio archive" ) \
      "\nMain operation mode:" \
      "\n	-t	List" \
      "\n	-i	Extract" \
-	USE_FEATURE_CPIO_O( \
+	IF_FEATURE_CPIO_O( \
      "\n	-o	Create" \
 	) \
-	USE_FEATURE_CPIO_P( \
+	IF_FEATURE_CPIO_P( \
      "\n	-p	Passthrough" \
 	) \
      "\nOptions:" \
@@ -550,18 +550,18 @@
      "\n	-v	Verbose" \
      "\n	-u	Overwrite" \
      "\n	-F	Input file" \
-	USE_FEATURE_CPIO_O( \
+	IF_FEATURE_CPIO_O( \
      "\n	-H	Define format" \
 	) \
 
 #define crond_trivial_usage \
-       "-fbS -l N " USE_FEATURE_CROND_D("-d N ") "-L LOGFILE -c DIR"
+       "-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" \
-	USE_FEATURE_CROND_D( \
+	IF_FEATURE_CROND_D( \
      "\n	-d	Set log level, log to stderr" \
 	) \
      "\n	-L	Log to file" \
@@ -583,13 +583,13 @@
 #define cryptpw_full_usage "\n\n" \
        "Crypt the PASSWORD using crypt(3)\n" \
      "\nOptions:" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\n	-P,--password-fd=NUM	Read password from fd NUM" \
 /*   "\n	-s,--stdin		Use stdin; like -P0" */ \
      "\n	-m,--method=TYPE	Encryption method TYPE" \
      "\n	-S,--salt=SALT" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\n	-P NUM	Read password from fd NUM" \
 /*   "\n	-s	Use stdin; like -P0" */ \
      "\n	-m TYPE	Encryption method TYPE" \
@@ -604,13 +604,13 @@
 #define mkpasswd_full_usage "\n\n" \
        "Crypt the PASSWORD using crypt(3)\n" \
      "\nOptions:" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\n	-P,--password-fd=NUM	Read password from fd NUM" \
 /*   "\n	-s,--stdin		Use stdin; like -P0" */ \
      "\n	-m,--method=TYPE	Encryption method TYPE" \
      "\n	-S,--salt=SALT" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\n	-P NUM	Read password from fd NUM" \
 /*   "\n	-s	Use stdin; like -P0" */ \
      "\n	-m TYPE	Encryption method TYPE" \
@@ -645,7 +645,7 @@
      "\nOptions:" \
      "\n	-u		Work in UTC (don't convert to local time)" \
      "\n	-R		Output RFC-822 compliant date string" \
-	USE_FEATURE_DATE_ISOFMT( \
+	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" \
@@ -654,7 +654,7 @@
      "\n	-d TIME		Display TIME, not 'now'" \
      "\n	-r FILE		Display last modification time of FILE" \
      "\n	[-s] TIME	Set time to TIME" \
-	USE_FEATURE_DATE_ISOFMT( \
+	IF_FEATURE_DATE_ISOFMT( \
      "\n	-D FMT		Use FMT for str->date conversion" \
 	) \
      "\n" \
@@ -691,24 +691,24 @@
        "64\n"
 
 #define dd_trivial_usage \
-       "[if=FILE] [of=FILE] " USE_FEATURE_DD_IBS_OBS("[ibs=N] [obs=N] ") "[bs=N] [count=N] [skip=N]\n" \
-       "	[seek=N]" USE_FEATURE_DD_IBS_OBS(" [conv=notrunc|noerror|sync|fsync]")
+       "[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" \
-	USE_FEATURE_DD_IBS_OBS( \
+	IF_FEATURE_DD_IBS_OBS( \
      "\n	ibs=N		Read N bytes at a time" \
 	) \
-	USE_FEATURE_DD_IBS_OBS( \
+	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" \
-	USE_FEATURE_DD_IBS_OBS( \
+	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" \
@@ -729,10 +729,10 @@
        "Deallocate unused virtual terminal /dev/ttyN"
 
 #define delgroup_trivial_usage \
-	USE_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
+	IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
 #define delgroup_full_usage "\n\n" \
        "Delete group GROUP from the system" \
-	USE_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")
+	IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")
 
 #define deluser_trivial_usage \
        "USER"
@@ -752,14 +752,14 @@
      "\n	VALUE	Data to be written" \
 
 #define devfsd_trivial_usage \
-       "mntpnt [-v]" USE_DEVFSD_FG_NP("[-fg][-np]")
+       "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" \
-	USE_DEVFSD_FG_NP( \
+	IF_DEVFSD_FG_NP( \
      "\n	-fg	Run in foreground" \
      "\n	-np	Exit after parsing the configuration file" \
      "\n		and processing synthetic REGISTER events," \
@@ -768,19 +768,19 @@
 
 #define df_trivial_usage \
 	"[-Pk" \
-	USE_FEATURE_HUMAN_READABLE("mh") \
-	USE_FEATURE_DF_FANCY("ai] [-B SIZE") \
+	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)" \
-	USE_FEATURE_HUMAN_READABLE( \
+	IF_FEATURE_HUMAN_READABLE( \
      "\n	-m	1M-byte blocks" \
      "\n	-h	Human readable (e.g. 1K 243M 2G)" \
 	) \
-	USE_FEATURE_DF_FANCY( \
+	IF_FEATURE_DF_FANCY( \
      "\n	-a	Show all filesystems" \
      "\n	-i	Inodes" \
      "\n	-B SIZE	Blocksize" \
@@ -894,12 +894,12 @@
        "$ dpkg-deb -X ./busybox_0.48-1_i386.deb /tmp\n"
 
 #define du_trivial_usage \
-       "[-aHLdclsx" USE_FEATURE_HUMAN_READABLE("hm") "k] [FILE]..."
+       "[-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 " \
-	USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") \
-	SKIP_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") \
+	IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("1024") \
+	IF_NOT_FEATURE_DU_DEFAULT_BLOCKSIZE_1K("512") \
        " bytes.\n" \
      "\nOptions:" \
      "\n	-a	Show file sizes too" \
@@ -910,12 +910,12 @@
      "\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" \
-	USE_FEATURE_HUMAN_READABLE( \
+	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" \
-			USE_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") \
+			IF_FEATURE_DU_DEFAULT_BLOCKSIZE_1K(" (default)") \
 
 #define du_example_usage \
        "$ du\n" \
@@ -942,12 +942,12 @@
 #define dumpleases_full_usage "\n\n" \
        "Display DHCP leases granted by udhcpd\n" \
      "\nOptions:" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\n	-f,--file=FILE	Leases file to load" \
      "\n	-r,--remaining	Interpret lease times as time remaining" \
      "\n	-a,--absolute	Interpret lease times as expire time" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\n	-f FILE	Leases file to load" \
      "\n	-r	Interpret lease times as time remaining" \
      "\n	-a	Interpret lease times as expire time" \
@@ -974,10 +974,10 @@
      "\n	-L file		Set badblocks list" \
 
 #define echo_trivial_usage \
-	USE_FEATURE_FANCY_ECHO("[-neE] ") "[ARG...]"
+	IF_FEATURE_FANCY_ECHO("[-neE] ") "[ARG...]"
 #define echo_full_usage "\n\n" \
        "Print the specified ARGs to stdout" \
-	USE_FEATURE_FANCY_ECHO( "\n" \
+	IF_FEATURE_FANCY_ECHO( "\n" \
      "\nOptions:" \
      "\n	-n	Suppress trailing newline" \
      "\n	-e	Interpret backslash-escaped characters (i.e., \\t=tab)" \
@@ -986,7 +986,7 @@
 #define echo_example_usage \
        "$ echo \"Erik is cool\"\n" \
        "Erik is cool\n" \
-	USE_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" \
+	IF_FEATURE_FANCY_ECHO("$ echo -e \"Erik\\nis\\ncool\"\n" \
        "Erik\n" \
        "is\n" \
        "cool\n" \
@@ -998,7 +998,7 @@
 #define eject_full_usage "\n\n" \
        "Eject specified DEVICE (or default /dev/cdrom)\n" \
      "\nOptions:" \
-	USE_FEATURE_EJECT_SCSI( \
+	IF_FEATURE_EJECT_SCSI( \
      "\n	-s	SCSI device" \
 	) \
      "\n	-t	Close tray" \
@@ -1032,11 +1032,11 @@
 #define expand_full_usage "\n\n" \
        "Convert tabs to spaces, writing to standard output.\n" \
      "\nOptions:" \
-	USE_FEATURE_EXPAND_LONG_OPTIONS( \
+	IF_FEATURE_EXPAND_LONG_OPTIONS( \
      "\n	-i,--initial	Do not convert tabs after non blanks" \
      "\n	-t,--tabs=N	Tabstops every N chars" \
 	) \
-	SKIP_FEATURE_EXPAND_LONG_OPTIONS( \
+	IF_NOT_FEATURE_EXPAND_LONG_OPTIONS( \
      "\n	-i	Do not convert tabs after non blanks" \
      "\n	-t	Tabstops every N chars" \
 	)
@@ -1127,18 +1127,18 @@
 /* Looks like someone forgot to add this to config system */
 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
-# define USE_FEATURE_FDISK_BLKSIZE(a)
+# define IF_FEATURE_FDISK_BLKSIZE(a)
 #endif
 
 #define fdisk_trivial_usage \
-       "[-ul" USE_FEATURE_FDISK_BLKSIZE("s") "] " \
+       "[-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" \
-	USE_FEATURE_FDISK_BLKSIZE( \
+	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" \
@@ -1165,56 +1165,56 @@
        "default EXPRESSION is '-print'\n" \
      "\nEXPRESSION may consist of:" \
      "\n	-follow		Dereference symlinks" \
-	USE_FEATURE_FIND_XDEV( \
+	IF_FEATURE_FIND_XDEV( \
      "\n	-xdev		Don't descend directories on other filesystems") \
-	USE_FEATURE_FIND_MAXDEPTH( \
+	IF_FEATURE_FIND_MAXDEPTH( \
      "\n	-maxdepth N	Descend at most N levels. -maxdepth 0 applies" \
      "\n			tests/actions to command line arguments only") \
      "\n	-mindepth N	Do not act on first N levels" \
      "\n	-name PATTERN	File name (w/o directory name) matches PATTERN" \
      "\n	-iname PATTERN	Case insensitive -name" \
-	USE_FEATURE_FIND_PATH( \
+	IF_FEATURE_FIND_PATH( \
      "\n	-path PATTERN	Path matches PATTERN") \
-	USE_FEATURE_FIND_REGEX( \
+	IF_FEATURE_FIND_REGEX( \
      "\n	-regex PATTERN	Path matches regex PATTERN") \
-	USE_FEATURE_FIND_TYPE( \
+	IF_FEATURE_FIND_TYPE( \
      "\n	-type X		File type is X (X is one of: f,d,l,b,c,...)") \
-	USE_FEATURE_FIND_PERM( \
+	IF_FEATURE_FIND_PERM( \
      "\n	-perm NNN	Permissions match any of (+NNN), all of (-NNN)," \
      "\n			or exactly (NNN)") \
-	USE_FEATURE_FIND_MTIME( \
+	IF_FEATURE_FIND_MTIME( \
      "\n	-mtime DAYS	Modified time is greater than (+N), less than (-N)," \
      "\n			or exactly (N) days") \
-	USE_FEATURE_FIND_MMIN( \
+	IF_FEATURE_FIND_MMIN( \
      "\n	-mmin MINS	Modified time is greater than (+N), less than (-N)," \
      "\n			or exactly (N) minutes") \
-	USE_FEATURE_FIND_NEWER( \
+	IF_FEATURE_FIND_NEWER( \
      "\n	-newer FILE	Modified time is more recent than FILE's") \
-	USE_FEATURE_FIND_INUM( \
+	IF_FEATURE_FIND_INUM( \
      "\n	-inum N		File has inode number N") \
-	USE_FEATURE_FIND_USER( \
+	IF_FEATURE_FIND_USER( \
      "\n	-user NAME	File is owned by user NAME (numeric user ID allowed)") \
-	USE_FEATURE_FIND_GROUP( \
+	IF_FEATURE_FIND_GROUP( \
      "\n	-group NAME	File belongs to group NAME (numeric group ID allowed)") \
-	USE_FEATURE_FIND_DEPTH( \
+	IF_FEATURE_FIND_DEPTH( \
      "\n	-depth		Process directory name after traversing it") \
-	USE_FEATURE_FIND_SIZE( \
+	IF_FEATURE_FIND_SIZE( \
      "\n	-size N[bck]	File size is N (c:bytes,k:kbytes,b:512 bytes(def.))." \
      "\n			+/-N: file size is bigger/smaller than N") \
      "\n	-print		Print (default and assumed)" \
-	USE_FEATURE_FIND_PRINT0( \
+	IF_FEATURE_FIND_PRINT0( \
      "\n	-print0		Delimit output with null characters rather than" \
      "\n			newlines") \
-	USE_FEATURE_FIND_CONTEXT ( \
+	IF_FEATURE_FIND_CONTEXT ( \
      "\n	-context	File has specified security context") \
-	USE_FEATURE_FIND_EXEC( \
+	IF_FEATURE_FIND_EXEC( \
      "\n	-exec CMD ARG ;	Execute CMD with all instances of {} replaced by the" \
      "\n			matching files") \
-	USE_FEATURE_FIND_PRUNE( \
+	IF_FEATURE_FIND_PRUNE( \
      "\n	-prune		Stop traversing current subtree") \
-	USE_FEATURE_FIND_DELETE( \
+	IF_FEATURE_FIND_DELETE( \
      "\n	-delete		Delete files, turns on -depth option") \
-	USE_FEATURE_FIND_PAREN( \
+	IF_FEATURE_FIND_PAREN( \
      "\n	(EXPR)		Group an expression") \
 
 #define find_example_usage \
@@ -1306,14 +1306,14 @@
 #define ftpget_full_usage "\n\n" \
        "Retrieve a remote file via FTP\n" \
      "\nOptions:" \
-	USE_FEATURE_FTPGETPUT_LONG_OPTIONS( \
+	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" \
 	) \
-	SKIP_FEATURE_FTPGETPUT_LONG_OPTIONS( \
+	IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \
      "\n	-c	Continue previous transfer" \
      "\n	-v	Verbose" \
      "\n	-u	Username" \
@@ -1326,13 +1326,13 @@
 #define ftpput_full_usage "\n\n" \
        "Store a local file on a remote machine via FTP\n" \
      "\nOptions:" \
-	USE_FEATURE_FTPGETPUT_LONG_OPTIONS( \
+	IF_FEATURE_FTPGETPUT_LONG_OPTIONS( \
      "\n	-v,--verbose	Verbose" \
      "\n	-u,--username	Username" \
      "\n	-p,--password	Password" \
      "\n	-P,--port	Port number" \
 	) \
-	SKIP_FEATURE_FTPGETPUT_LONG_OPTIONS( \
+	IF_NOT_FEATURE_FTPGETPUT_LONG_OPTIONS( \
      "\n	-v	Verbose" \
      "\n	-u	Username" \
      "\n	-p	Password" \
@@ -1358,7 +1358,7 @@
        "[OPTIONS]..."
 #define getopt_full_usage "\n\n" \
        "Parse command options\n" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\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" \
@@ -1369,7 +1369,7 @@
      "\n	-T,--test			Test for getopt(1) version" \
      "\n	-u,--unquoted			Don't quote the output" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\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" \
@@ -1425,11 +1425,11 @@
 
 #define grep_trivial_usage \
        "[-HhrilLnqvso" \
-	USE_DESKTOP("w") \
+	IF_DESKTOP("w") \
        "eF" \
-	USE_FEATURE_GREP_EGREP_ALIAS("E") \
-	USE_FEATURE_GREP_CONTEXT("ABC") \
-	USE_EXTRA_COMPAT("z") \
+	IF_FEATURE_GREP_EGREP_ALIAS("E") \
+	IF_FEATURE_GREP_CONTEXT("ABC") \
+	IF_EXTRA_COMPAT("z") \
        "] PATTERN [FILEs...]"
 #define grep_full_usage "\n\n" \
        "Search for PATTERN in each FILE or standard input\n" \
@@ -1447,18 +1447,18 @@
      "\n	-c	Only print count of matching lines" \
      "\n	-o	Show only the part of a line that matches PATTERN" \
      "\n	-m MAX	Match up to MAX times per file" \
-	USE_DESKTOP( \
+	IF_DESKTOP( \
      "\n	-w	Match whole words only") \
      "\n	-F	PATTERN is a set of newline-separated strings" \
-	USE_FEATURE_GREP_EGREP_ALIAS( \
+	IF_FEATURE_GREP_EGREP_ALIAS( \
      "\n	-E	PATTERN is an extended regular expression") \
      "\n	-e PTRN	Pattern to match" \
      "\n	-f FILE	Read pattern from file" \
-	USE_FEATURE_GREP_CONTEXT( \
+	IF_FEATURE_GREP_CONTEXT( \
      "\n	-A	Print NUM lines of trailing context" \
      "\n	-B	Print NUM lines of leading context" \
      "\n	-C	Print NUM lines of output context") \
-	USE_EXTRA_COMPAT( \
+	IF_EXTRA_COMPAT( \
      "\n	-z	Input is NUL terminated") \
 
 #define grep_example_usage \
@@ -1506,14 +1506,14 @@
        "-rw-rw-r--    1 andersen andersen   554058 Apr 14 17:49 /tmp/busybox.tar.gz\n"
 
 #define halt_trivial_usage \
-       "[-d delay] [-n] [-f]" USE_FEATURE_WTMP(" [-w]")
+       "[-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)" \
-	USE_FEATURE_WTMP( \
+	IF_FEATURE_WTMP( \
      "\n	-w	Only write a wtmp record" \
 	)
 
@@ -1527,15 +1527,15 @@
      "\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" \
-	USE_FEATURE_HDPARM_HDIO_GETSET_DMA( \
+	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" \
-	USE_FEATURE_HDPARM_GET_IDENTITY( \
+	IF_FEATURE_HDPARM_GET_IDENTITY( \
      "\n	-i	Display drive identification") \
-	USE_FEATURE_HDPARM_GET_IDENTITY( \
+	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)" \
@@ -1547,20 +1547,20 @@
 /*   "\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)" \
-	USE_FEATURE_HDPARM_HDIO_SCAN_HWIF( \
+	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)" \
-	USE_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( \
+	IF_FEATURE_HDPARM_HDIO_UNREGISTER_HWIF( \
      "\n	-U	Un-register an IDE interface (DANGEROUS)") \
      "\n	-v	Defaults; same as -mcudkrag for IDE drives" \
      "\n	-V	Display program version and exit immediately" \
-	USE_FEATURE_HDPARM_HDIO_DRIVE_RESET( \
+	IF_FEATURE_HDPARM_HDIO_DRIVE_RESET( \
      "\n	-w	Perform device reset (DANGEROUS)") \
      "\n	-W	Set drive write-caching flag (0/1) (DANGEROUS)" \
-	USE_FEATURE_HDPARM_HDIO_TRISTATE_HWIF( \
+	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" \
@@ -1576,7 +1576,7 @@
        "file name. With no FILE, or when FILE is -, read standard input.\n" \
      "\nOptions:" \
      "\n	-n NUM	Print first NUM lines instead of first 10" \
-	USE_FEATURE_FANCY_HEAD( \
+	IF_FEATURE_FANCY_HEAD( \
      "\n	-c NUM	Output the first NUM bytes" \
      "\n	-q	Never output headers giving file names" \
      "\n	-v	Always output headers giving file names") \
@@ -1587,7 +1587,7 @@
        "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n"
 
 #define hexdump_trivial_usage \
-       "[-bcCdefnosvx" USE_FEATURE_HEXDUMP_REVERSE("R") "] FILE..."
+       "[-bcCdefnosvx" IF_FEATURE_HEXDUMP_REVERSE("R") "] FILE..."
 #define hexdump_full_usage "\n\n" \
        "Display file(s) or standard input in a user specified format\n" \
      "\nOptions:" \
@@ -1602,7 +1602,7 @@
      "\n	-s OFFSET	Skip OFFSET bytes" \
      "\n	-v		Display all input data" \
      "\n	-x		Two-byte hexadecimal display" \
-	USE_FEATURE_HEXDUMP_REVERSE( \
+	IF_FEATURE_HEXDUMP_REVERSE( \
      "\n	-R		Reverse of 'hexdump -Cv'") \
 
 #define hd_trivial_usage \
@@ -1634,9 +1634,9 @@
        "[-c conffile]" \
        " [-p [ip:]port]" \
        " [-i] [-f] [-v[v]]" \
-	USE_FEATURE_HTTPD_SETUID(" [-u user[:grp]]") \
-	USE_FEATURE_HTTPD_BASIC_AUTH(" [-r realm]") \
-	USE_FEATURE_HTTPD_AUTH_MD5(" [-m pass]") \
+	IF_FEATURE_HTTPD_SETUID(" [-u user[:grp]]") \
+	IF_FEATURE_HTTPD_BASIC_AUTH(" [-r realm]") \
+	IF_FEATURE_HTTPD_AUTH_MD5(" [-m pass]") \
        " [-h home]" \
        " [-d/-e string]"
 #define httpd_full_usage "\n\n" \
@@ -1647,23 +1647,23 @@
      "\n	-i		Inetd mode" \
      "\n	-f		Do not daemonize" \
      "\n	-v[v]		Verbose" \
-	USE_FEATURE_HTTPD_SETUID( \
+	IF_FEATURE_HTTPD_SETUID( \
      "\n	-u USER[:GRP]	Set uid/gid after binding to port") \
-	USE_FEATURE_HTTPD_BASIC_AUTH( \
+	IF_FEATURE_HTTPD_BASIC_AUTH( \
      "\n	-r REALM	Authentication Realm for Basic Authentication") \
-	USE_FEATURE_HTTPD_AUTH_MD5( \
+	IF_FEATURE_HTTPD_AUTH_MD5( \
      "\n	-m PASS		Crypt PASS with md5 algorithm") \
      "\n	-h HOME		Home directory (default .)" \
      "\n	-e STRING	HTML encode STRING" \
      "\n	-d STRING	URL decode STRING" \
 
 #define hwclock_trivial_usage \
-	USE_FEATURE_HWCLOCK_LONG_OPTIONS( \
+	IF_FEATURE_HWCLOCK_LONG_OPTIONS( \
        "[-r|--show] [-s|--hctosys] [-w|--systohc]" \
        " [-l|--localtime] [-u|--utc]" \
        " [-f FILE]" \
 	) \
-	SKIP_FEATURE_HWCLOCK_LONG_OPTIONS( \
+	IF_NOT_FEATURE_HWCLOCK_LONG_OPTIONS( \
        "[-r] [-s] [-w] [-l] [-u] [-f FILE]" \
 	)
 #define hwclock_full_usage "\n\n" \
@@ -1681,7 +1681,7 @@
 #define id_full_usage "\n\n" \
        "Print information about USER or the current user\n" \
      "\nOptions:" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Print the security context" \
 	) \
      "\n	-u	Print user ID" \
@@ -1695,23 +1695,23 @@
        "uid=1000(andersen) gid=1000(andersen)\n"
 
 #define ifconfig_trivial_usage \
-	USE_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]"
+	IF_FEATURE_IFCONFIG_STATUS("[-a]") " interface [address]"
 #define ifconfig_full_usage "\n\n" \
        "Configure a network interface\n" \
      "\nOptions:" \
      "\n" \
-	USE_FEATURE_IPV6( \
+	IF_FEATURE_IPV6( \
        "	[add ADDRESS[/PREFIXLEN]]\n") \
-	USE_FEATURE_IPV6( \
+	IF_FEATURE_IPV6( \
        "	[del ADDRESS[/PREFIXLEN]]\n") \
        "	[[-]broadcast [ADDRESS]] [[-]pointopoint [ADDRESS]]\n" \
        "	[netmask ADDRESS] [dstaddr ADDRESS]\n" \
-	USE_FEATURE_IFCONFIG_SLIP( \
+	IF_FEATURE_IFCONFIG_SLIP( \
        "	[outfill NN] [keepalive NN]\n") \
-       "	" USE_FEATURE_IFCONFIG_HW("[hw ether" USE_FEATURE_HWIB("|infiniband")" ADDRESS] ") "[metric NN] [mtu 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" \
-	USE_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( \
+	IF_FEATURE_IFCONFIG_MEMSTART_IOADDR_IRQ( \
        "	[mem_start NN] [io_addr NN] [irq NN]\n") \
        "	[up|down] ..."
 
@@ -1743,13 +1743,13 @@
        "   # ifenslave -c bond0 eth0\n" \
 
 #define ifup_trivial_usage \
-       "[-ain"USE_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
+       "[-ain"IF_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
 #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" \
-	USE_FEATURE_IFUPDOWN_MAPPING( \
+	IF_FEATURE_IFUPDOWN_MAPPING( \
      "\n		(note: doesn't disable mappings)" \
      "\n	-m	Don't run any mappings" \
 	) \
@@ -1757,13 +1757,13 @@
      "\n	-f	Force de/configuration" \
 
 #define ifdown_trivial_usage \
-       "[-ain"USE_FEATURE_IFUPDOWN_MAPPING("m")"vf] ifaces..."
+       "[-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" \
-	USE_FEATURE_IFUPDOWN_MAPPING( \
+	IF_FEATURE_IFUPDOWN_MAPPING( \
      "\n		(note: doesn't disable mappings)" \
      "\n	-m	Don't run any mappings" \
 	) \
@@ -1943,19 +1943,19 @@
 /* 2.6 style insmod has no options and required filename
  * (not module name - .ko can't be omitted) */
 #define insmod_trivial_usage \
-	USE_FEATURE_2_4_MODULES("[OPTION]... MODULE ") \
-	SKIP_FEATURE_2_4_MODULES("FILE ") \
+	IF_FEATURE_2_4_MODULES("[OPTION]... MODULE ") \
+	IF_NOT_FEATURE_2_4_MODULES("FILE ") \
 	"[symbol=value]..."
 #define insmod_full_usage "\n\n" \
        "Load the specified kernel modules into the kernel" \
-	USE_FEATURE_2_4_MODULES( "\n" \
+	IF_FEATURE_2_4_MODULES( "\n" \
      "\nOptions:" \
      "\n	-f	Force module to load into the wrong kernel version" \
      "\n	-k	Make module autoclean-able" \
      "\n	-v	Verbose" \
      "\n	-q	Quiet" \
      "\n	-L	Lock to prevent simultaneous loads of a module" \
-	USE_FEATURE_INSMOD_LOAD_MAP( \
+	IF_FEATURE_INSMOD_LOAD_MAP( \
      "\n	-m	Output load map to stdout" \
 	) \
      "\n	-o NAME	Set internal module name to NAME" \
@@ -1976,7 +1976,7 @@
      "\n	-o USER	Set ownership" \
      "\n	-g GRP	Set group ownership" \
      "\n	-m MODE	Set permissions" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Set security context" \
 	)
 
@@ -1991,20 +1991,20 @@
 /* would need to make the " | " optional depending on more than one selected: */
 #define ip_trivial_usage \
        "[OPTIONS] {" \
-	USE_FEATURE_IP_ADDRESS("address | ") \
-	USE_FEATURE_IP_ROUTE("route | ") \
-	USE_FEATURE_IP_LINK("link | ") \
-	USE_FEATURE_IP_TUNNEL("tunnel | ") \
-	USE_FEATURE_IP_RULE("rule") \
+	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 := {" \
-	USE_FEATURE_IP_ADDRESS("address | ") \
-	USE_FEATURE_IP_ROUTE("route | ") \
-	USE_FEATURE_IP_LINK("link | ") \
-	USE_FEATURE_IP_TUNNEL("tunnel | ") \
-	USE_FEATURE_IP_RULE("rule") \
+	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] }" \
 
@@ -2025,21 +2025,21 @@
 #define ipcalc_full_usage "\n\n" \
        "Calculate IP network settings from a IP address\n" \
      "\nOptions:" \
-	USE_FEATURE_IPCALC_LONG_OPTIONS( \
+	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" \
-	USE_FEATURE_IPCALC_FANCY( \
+	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" \
 	) \
 	) \
-	SKIP_FEATURE_IPCALC_LONG_OPTIONS( \
+	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" \
-	USE_FEATURE_IPCALC_FANCY( \
+	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" \
@@ -2332,14 +2332,14 @@
      "\n	-V	Verbose" \
 
 #define ls_trivial_usage \
-       "[-1Aa" USE_FEATURE_LS_TIMESTAMPS("c") "Cd" \
-	USE_FEATURE_LS_TIMESTAMPS("e") USE_FEATURE_LS_FILETYPES("F") "iln" \
-	USE_FEATURE_LS_FILETYPES("p") USE_FEATURE_LS_FOLLOWLINKS("L") \
-	USE_FEATURE_LS_RECURSIVE("R") USE_FEATURE_LS_SORTFILES("rS") "s" \
-	USE_FEATURE_AUTOWIDTH("T") USE_FEATURE_LS_TIMESTAMPS("tu") \
-	USE_FEATURE_LS_SORTFILES("v") USE_FEATURE_AUTOWIDTH("w") "x" \
-	USE_FEATURE_LS_SORTFILES("X") USE_FEATURE_HUMAN_READABLE("h") "k" \
-	USE_SELINUX("K") "] [filenames...]"
+       "[-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") "] [filenames...]"
 #define ls_full_usage "\n\n" \
        "List directory contents\n" \
      "\nOptions:" \
@@ -2347,49 +2347,49 @@
      "\n	-A	Don't list . and .." \
      "\n	-a	Don't hide entries starting with ." \
      "\n	-C	List by columns" \
-	USE_FEATURE_LS_TIMESTAMPS( \
+	IF_FEATURE_LS_TIMESTAMPS( \
      "\n	-c	With -l: sort by ctime") \
-	USE_FEATURE_LS_COLOR( \
+	IF_FEATURE_LS_COLOR( \
      "\n	--color[={always,never,auto}]	Control coloring") \
      "\n	-d	List directory entries instead of contents" \
-	USE_FEATURE_LS_TIMESTAMPS( \
+	IF_FEATURE_LS_TIMESTAMPS( \
      "\n	-e	List full date and time") \
-	USE_FEATURE_LS_FILETYPES( \
+	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" \
-	USE_FEATURE_LS_FILETYPES( \
+	IF_FEATURE_LS_FILETYPES( \
      "\n	-p	Append indicator (one of /=@|) to entries") \
-	USE_FEATURE_LS_FOLLOWLINKS( \
+	IF_FEATURE_LS_FOLLOWLINKS( \
      "\n	-L	List entries pointed to by symlinks") \
-	USE_FEATURE_LS_RECURSIVE( \
+	IF_FEATURE_LS_RECURSIVE( \
      "\n	-R	List subdirectories recursively") \
-	USE_FEATURE_LS_SORTFILES( \
+	IF_FEATURE_LS_SORTFILES( \
      "\n	-r	Sort in reverse order") \
-	USE_FEATURE_LS_SORTFILES( \
+	IF_FEATURE_LS_SORTFILES( \
      "\n	-S	Sort by file size") \
      "\n	-s	List the size of each file, in blocks" \
-	USE_FEATURE_AUTOWIDTH( \
+	IF_FEATURE_AUTOWIDTH( \
      "\n	-T NUM	Assume tabstop every NUM columns") \
-	USE_FEATURE_LS_TIMESTAMPS( \
+	IF_FEATURE_LS_TIMESTAMPS( \
      "\n	-t	With -l: sort by modification time") \
-	USE_FEATURE_LS_TIMESTAMPS( \
+	IF_FEATURE_LS_TIMESTAMPS( \
      "\n	-u	With -l: sort by access time") \
-	USE_FEATURE_LS_SORTFILES( \
+	IF_FEATURE_LS_SORTFILES( \
      "\n	-v	Sort by version") \
-	USE_FEATURE_AUTOWIDTH( \
+	IF_FEATURE_AUTOWIDTH( \
      "\n	-w NUM	Assume the terminal is NUM columns wide") \
      "\n	-x	List by lines" \
-	USE_FEATURE_LS_SORTFILES( \
+	IF_FEATURE_LS_SORTFILES( \
      "\n	-X	Sort by extension") \
-	USE_FEATURE_HUMAN_READABLE( \
+	IF_FEATURE_HUMAN_READABLE( \
      "\n	-h	List sizes in human readable format (1K 243M 2G)") \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-k	List security context") \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-K	List security context in long format") \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	List security context and permission") \
 
 #define lsattr_trivial_usage \
@@ -2495,10 +2495,10 @@
 
 #define md5sum_trivial_usage \
        "[OPTION] [FILEs...]" \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: md5sum [OPTION] -c [FILE]")
+	IF_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: md5sum [OPTION] -c [FILE]")
 #define md5sum_full_usage "\n\n" \
-       "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " MD5 checksums" \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK( "\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" \
@@ -2517,10 +2517,10 @@
 
 #define sha1sum_trivial_usage \
        "[OPTION] [FILEs...]" \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha1sum [OPTION] -c [FILE]")
+	IF_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha1sum [OPTION] -c [FILE]")
 #define sha1sum_full_usage "\n\n" \
-       "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK( "\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" \
@@ -2529,10 +2529,10 @@
 
 #define sha256sum_trivial_usage \
        "[OPTION] [FILEs...]" \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha256sum [OPTION] -c [FILE]")
+	IF_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha256sum [OPTION] -c [FILE]")
 #define sha256sum_full_usage "\n\n" \
-       "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK( "\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" \
@@ -2541,10 +2541,10 @@
 
 #define sha512sum_trivial_usage \
        "[OPTION] [FILEs...]" \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha512sum [OPTION] -c [FILE]")
+	IF_FEATURE_MD5_SHA1_SUM_CHECK("\n   or: sha512sum [OPTION] -c [FILE]")
 #define sha512sum_full_usage "\n\n" \
-       "Print" USE_FEATURE_MD5_SHA1_SUM_CHECK(" or check") " SHA1 checksums." \
-	USE_FEATURE_MD5_SHA1_SUM_CHECK( "\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" \
@@ -2558,19 +2558,19 @@
        "\n" \
        "It can be run by kernel as a hotplug helper. To activate it:\n" \
        " echo /bin/mdev >/proc/sys/kernel/hotplug\n" \
-	USE_FEATURE_MDEV_CONF( \
+	IF_FEATURE_MDEV_CONF( \
        "It uses /etc/mdev.conf with lines\n" \
        "[-]DEVNAME UID:GID PERM" \
-			USE_FEATURE_MDEV_RENAME(" [>|=PATH]") \
-			USE_FEATURE_MDEV_EXEC(" [@|$|*COMMAND]") \
+			IF_FEATURE_MDEV_RENAME(" [>|=PATH]") \
+			IF_FEATURE_MDEV_EXEC(" [@|$|*COMMAND]") \
 	) \
 
 #define mdev_notes_usage "" \
-	USE_FEATURE_MDEV_CONFIG( \
+	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" \
-	USE_FEATURE_MDEV_EXEC( \
+	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" \
@@ -2610,7 +2610,7 @@
      "\nOptions:" \
      "\n	-m	Set permission mode (as in chmod), not rwxrwxrwx - umask" \
      "\n	-p	No error if existing, make parent directories as needed" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Set security context" \
 	)
 
@@ -2659,7 +2659,7 @@
        "Create named pipe (identical to 'mknod name p')\n" \
      "\nOptions:" \
      "\n	-m MODE	Mode (default a=rw)" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Set security context" \
 	)
 
@@ -2700,7 +2700,7 @@
      "\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)" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Set security context" \
 	)
 
@@ -2745,7 +2745,7 @@
        "[-knqrsv] MODULE [symbol=value...]"
 #define modprobe_full_usage "\n\n" \
        "Options:" \
-	USE_FEATURE_2_4_MODULES( \
+	IF_FEATURE_2_4_MODULES( \
      "\n	-k	Make module autoclean-able" \
 	) \
      "\n	-n	Dry run" \
@@ -2753,7 +2753,7 @@
      "\n	-r	Remove module (stacks) or do autoclean" \
      "\n	-s	Report via syslog instead of stderr" \
      "\n	-v	Verbose" \
-	USE_FEATURE_MODPROBE_BLACKLIST( \
+	IF_FEATURE_MODPROBE_BLACKLIST( \
      "\n	-b	Apply blacklist to module names too" \
         )
 
@@ -2831,15 +2831,15 @@
        "Mount a filesystem. Filesystem autodetection requires /proc be mounted.\n" \
      "\nOptions:" \
      "\n	-a		Mount all filesystems in fstab" \
-	USE_FEATURE_MOUNT_FAKE( \
-	USE_FEATURE_MTAB_SUPPORT( \
+	IF_FEATURE_MOUNT_FAKE( \
+	IF_FEATURE_MTAB_SUPPORT( \
      "\n	-f		Update /etc/mtab, but don't mount" \
 	) \
-	SKIP_FEATURE_MTAB_SUPPORT( \
+	IF_NOT_FEATURE_MTAB_SUPPORT( \
      "\n	-f		Dry run" \
 	) \
 	) \
-	USE_FEATURE_MTAB_SUPPORT( \
+	IF_FEATURE_MTAB_SUPPORT( \
      "\n	-n		Don't update /etc/mtab" \
 	) \
      "\n	-r		Read-only mount" \
@@ -2847,10 +2847,10 @@
      "\n	-t FSTYPE	Filesystem type" \
      "\n	-O OPT		Mount only filesystems with option OPT (-a only)" \
      "\n-o OPT:" \
-	USE_FEATURE_MOUNT_LOOP( \
+	IF_FEATURE_MOUNT_LOOP( \
      "\n	loop		Ignored (loop devices are autodetected)" \
 	) \
-	USE_FEATURE_MOUNT_FLAGS( \
+	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" \
@@ -2945,26 +2945,26 @@
 #endif
 
 #define nc_trivial_usage \
-	USE_NC_EXTRA("[-iN] [-wN] ")USE_NC_SERVER("[-l] [-p PORT] ") \
-       "["USE_NC_EXTRA("-f FILENAME|")"IPADDR PORTNUM]"USE_NC_EXTRA(" [-e COMMAND]")
+	IF_NC_EXTRA("[-iN] [-wN] ")IF_NC_SERVER("[-l] [-p PORT] ") \
+       "["IF_NC_EXTRA("-f FILENAME|")"IPADDR PORTNUM]"IF_NC_EXTRA(" [-e COMMAND]")
 #define nc_full_usage "\n\n" \
-       "Open a pipe to IP:port" USE_NC_EXTRA(" or file") \
+       "Open a pipe to IP:port" IF_NC_EXTRA(" or file") \
 	NC_OPTIONS_STR \
-	USE_NC_EXTRA( \
+	IF_NC_EXTRA( \
      "\n	-e	Exec rest of command line after connect" \
      "\n	-i SECS	Delay interval for lines sent" \
      "\n	-w SECS	Timeout for connect" \
      "\n	-f FILE	Use file (ala /dev/ttyS0) instead of network" \
 	) \
-	USE_NC_SERVER( \
+	IF_NC_SERVER( \
      "\n	-l	Listen mode, for inbound connects" \
-	USE_NC_EXTRA( \
+	IF_NC_EXTRA( \
      "\n		(use -l twice with -e for persistent server)") \
      "\n	-p PORT	Local port number" \
 	)
 
 #define nc_notes_usage "" \
-	USE_NC_EXTRA( \
+	IF_NC_EXTRA( \
        "To use netcat as a terminal emulator on a serial port:\n\n" \
        "$ stty 115200 -F /dev/ttyS0\n" \
        "$ stty raw -echo -ctlecho && nc -f /dev/ttyS0\n" \
@@ -2984,12 +2984,12 @@
 
 #define nc_trivial_usage \
        "[-options] hostname port  - connect" \
-	USE_NC_SERVER("\n" \
+	IF_NC_SERVER("\n" \
        "nc [-options] -l -p port [hostname] [port]  - listen")
 #define nc_full_usage "\n\n" \
        "Options:" \
      "\n	-e prog [args]	Program to exec after connect (must be last)" \
-	USE_NC_SERVER( \
+	IF_NC_SERVER( \
      "\n	-l		Listen mode, for inbound connects" \
 	) \
      "\n	-n		Don't do DNS resolution" \
@@ -2998,7 +2998,7 @@
      "\n	-u		UDP mode" \
      "\n	-v		Verbose (cumulative: -vv)" \
      "\n	-w secs		Timeout for connects and final net reads" \
-	USE_NC_EXTRA( \
+	IF_NC_EXTRA( \
      "\n	-i sec		Delay interval for lines sent" /* ", ports scanned" */ \
      "\n	-o file		Hex dump of traffic" \
      "\n	-z		Zero-I/O mode (scanning)" \
@@ -3011,7 +3011,7 @@
 #endif
 
 #define netstat_trivial_usage \
-       "[-laentuwxr"USE_FEATURE_NETSTAT_WIDE("W")USE_FEATURE_NETSTAT_PRG("p")"]"
+       "[-laentuwxr"IF_FEATURE_NETSTAT_WIDE("W")IF_FEATURE_NETSTAT_PRG("p")"]"
 #define netstat_full_usage "\n\n" \
        "Display networking information\n" \
      "\nOptions:" \
@@ -3024,10 +3024,10 @@
      "\n	-w	Raw sockets" \
      "\n	-x	Unix sockets" \
      "\n	-r	Display routing table" \
-	USE_FEATURE_NETSTAT_WIDE( \
+	IF_FEATURE_NETSTAT_WIDE( \
      "\n	-W	Display with no column truncation" \
 	) \
-	USE_FEATURE_NETSTAT_PRG( \
+	IF_FEATURE_NETSTAT_PRG( \
      "\n	-p	Display PID/Program name for sockets" \
 	)
 
@@ -3084,7 +3084,7 @@
        "Address:    127.0.0.1\n"
 
 #define od_trivial_usage \
-       "[-aBbcDdeFfHhIiLlOovXx] " USE_DESKTOP("[-t TYPE] ") "[FILE]"
+       "[-aBbcDdeFfHhIiLlOovXx] " IF_DESKTOP("[-t TYPE] ") "[FILE]"
 #define od_full_usage "\n\n" \
        "Write an unambiguous representation, octal bytes by default, of FILE\n" \
        "to standard output. With no FILE or when FILE is -, read standard input."
@@ -3119,16 +3119,16 @@
      "\n	-u	Unlock (re-enable) account" \
 
 #define chpasswd_trivial_usage \
-	USE_GETOPT_LONG("[--md5|--encrypted]") SKIP_GETOPT_LONG("[-m|-e]")
+	IF_GETOPT_LONG("[--md5|--encrypted]") IF_NOT_GETOPT_LONG("[-m|-e]")
 #define chpasswd_full_usage "\n\n" \
        "Read user:password information from stdin " \
        "and update /etc/passwd accordingly.\n" \
      "\nOptions:" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\n	-e,--encrypted	Supplied passwords are in encrypted form" \
      "\n	-m,--md5	Use MD5 encryption instead of DES" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\n	-e	Supplied passwords are in encrypted form" \
      "\n	-m	Use MD5 encryption instead of DES" \
 	)
@@ -3168,18 +3168,18 @@
 #define pidof_full_usage "\n\n" \
        "List PIDs of all processes with names that match NAMEs" \
 	USAGE_PIDOF \
-	USE_FEATURE_PIDOF_SINGLE( \
+	IF_FEATURE_PIDOF_SINGLE( \
      "\n	-s	Show only one PID") \
-	USE_FEATURE_PIDOF_OMIT( \
+	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" \
-	USE_FEATURE_PIDOF_OMIT( \
+	IF_FEATURE_PIDOF_OMIT( \
        "$ pidof /bin/sh\n20351 5973 5950\n") \
-	USE_FEATURE_PIDOF_OMIT( \
+	IF_FEATURE_PIDOF_OMIT( \
        "$ pidof /bin/sh -o %PPID\n20351 5950")
 
 #if !ENABLE_FEATURE_FANCY_PING
@@ -3273,7 +3273,7 @@
      "\n	-T		Get messages with TOP instead with RETR" \
      "\n	-k		Keep retrieved messages on the server" \
      "\n	-t timeout	Set network timeout" \
-     USE_FEATURE_POPMAILDIR_DELIVERY( \
+     IF_FEATURE_POPMAILDIR_DELIVERY( \
      "\n	-F \"program arg1 arg2 ...\"	Filter by program. May be multiple" \
      "\n	-M \"program arg1 arg2 ...\"	Deliver by program" \
      ) \
@@ -3332,10 +3332,10 @@
 #define ps_full_usage "\n\n" \
        "Report process status\n" \
 	USAGE_PS \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Show SE Linux context" \
 	) \
-	USE_FEATURE_PS_WIDE( \
+	IF_FEATURE_PS_WIDE( \
      "\n	w	Wide output" \
 	)
 
@@ -3404,10 +3404,10 @@
        "files do not block on disk I/O"
 
 #define readlink_trivial_usage \
-	USE_FEATURE_READLINK_FOLLOW("[-f] ") "FILE"
+	IF_FEATURE_READLINK_FOLLOW("[-f] ") "FILE"
 #define readlink_full_usage "\n\n" \
        "Display the value of a symlink" \
-	USE_FEATURE_READLINK_FOLLOW( "\n" \
+	IF_FEATURE_READLINK_FOLLOW( "\n" \
      "\nOptions:" \
      "\n	-f	Canonicalize by following all symlinks") \
 
@@ -3505,11 +3505,11 @@
 #define rmdir_full_usage "\n\n" \
        "Remove the DIRECTORY, if it is empty.\n" \
      "\nOptions:" \
-     USE_FEATURE_RMDIR_LONG_OPTIONS( \
+     IF_FEATURE_RMDIR_LONG_OPTIONS( \
      "\n	-p|--parents	Include parents" \
      "\n	-ignore-fail-on-non-empty" \
      ) \
-     SKIP_FEATURE_RMDIR_LONG_OPTIONS( \
+     IF_NOT_FEATURE_RMDIR_LONG_OPTIONS( \
      "\n	-p	Include parents" \
      )
 
@@ -3535,7 +3535,7 @@
      "\nOptions:" \
      "\n	-n	Don't resolve names" \
      "\n	-e	Display other/more information" \
-     "\n	-A inet" USE_FEATURE_IPV6("{6}") "	Select address family" \
+     "\n	-A inet" IF_FEATURE_IPV6("{6}") "	Select address family" \
 
 #define rpm_trivial_usage \
        "-i -q[ildc]p package.rpm"
@@ -3559,7 +3559,7 @@
        "[-a | -l | -u] [-d DEV] [-m MODE] [-s SEC | -t TIME]"
 #define rtcwake_full_usage "\n\n" \
        "Enter a system sleep state until specified wakeup time\n" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
      "\n	-a,--auto	Read clock mode from adjtime" \
      "\n	-l,--local	Clock is set to local time" \
      "\n	-u,--utc	Clock is set to UTC time" \
@@ -3568,7 +3568,7 @@
      "\n	-s,--seconds=SEC Set the timeout in SEC seconds from now" \
      "\n	-t,--time=TIME	Set the timeout to TIME seconds from epoch" \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
      "\n	-a	Read clock mode from adjtime" \
      "\n	-l	Clock is set to local time" \
      "\n	-u	Clock is set to UTC time" \
@@ -3584,14 +3584,14 @@
 #define runcon_full_usage "\n\n" \
        "Run a program in a different security context\n" \
      "\n	CONTEXT		Complete security context\n" \
-	USE_FEATURE_RUNCON_LONG_OPTIONS( \
+	IF_FEATURE_RUNCON_LONG_OPTIONS( \
      "\n	-c,--compute	Compute process transition context before modifying" \
      "\n	-t,--type=TYPE	Type (for same role as parent)" \
      "\n	-u,--user=USER	User identity" \
      "\n	-r,--role=ROLE	Role" \
      "\n	-l,--range=RNG	Levelrange" \
 	) \
-	SKIP_FEATURE_RUNCON_LONG_OPTIONS( \
+	IF_NOT_FEATURE_RUNCON_LONG_OPTIONS( \
      "\n	-c	Compute process transition context before modifying" \
      "\n	-t TYPE	Type (for same role as parent)" \
      "\n	-u USER	User identity" \
@@ -3600,14 +3600,14 @@
 	)
 
 #define run_parts_trivial_usage \
-       "[-t] "USE_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY"
+       "[-t] "IF_FEATURE_RUN_PARTS_FANCY("[-l] ")"[-a ARG] [-u MASK] DIRECTORY"
 #define run_parts_full_usage "\n\n" \
        "Run a bunch of scripts in a directory\n" \
      "\nOptions:" \
      "\n	-t	Print what would be run, but don't actually run anything" \
      "\n	-a ARG	Pass ARG as argument for every program" \
      "\n	-u MASK	Set the umask to MASK before running every program" \
-	USE_FEATURE_RUN_PARTS_FANCY( \
+	IF_FEATURE_RUN_PARTS_FANCY( \
      "\n	-l	Print names of all matching files even if they are not executable" \
 	)
 
@@ -3728,7 +3728,7 @@
      "\n	-b	Display current state of booleans" \
 
 #define setconsole_trivial_usage \
-       "[-r" USE_FEATURE_SETCONSOLE_LONG_OPTIONS("|--reset") "] [DEVICE]"
+       "[-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:" \
@@ -3740,13 +3740,13 @@
 
 #define setfiles_trivial_usage \
        "[-dnpqsvW] [-e dir]... [-o file] [-r alt_root_path]" \
-	USE_FEATURE_SETFILES_CHECK_OPTION( \
+	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" \
-	USE_FEATURE_SETFILES_CHECK_OPTION( \
+	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" \
@@ -3809,10 +3809,10 @@
        "lash is deprecated, please use hush"
 
 #define last_trivial_usage \
-       ""USE_FEATURE_LAST_FANCY("[-HW] [-f file]")
+       ""IF_FEATURE_LAST_FANCY("[-HW] [-f file]")
 #define last_full_usage "\n\n" \
        "Show listing of the last users that logged into the system" \
-	USE_FEATURE_LAST_FANCY( "\n" \
+	IF_FEATURE_LAST_FANCY( "\n" \
      "\nOptions:" \
 /*   "\n	-H	Show header line" */ \
      "\n	-W	Display with no host column truncation" \
@@ -3843,27 +3843,27 @@
      "\n	-F	Disable RTS/CTS flow control" \
 
 #define sleep_trivial_usage \
-	USE_FEATURE_FANCY_SLEEP("[") "N" USE_FEATURE_FANCY_SLEEP("]...")
+	IF_FEATURE_FANCY_SLEEP("[") "N" IF_FEATURE_FANCY_SLEEP("]...")
 #define sleep_full_usage "\n\n" \
-	SKIP_FEATURE_FANCY_SLEEP("Pause for N seconds") \
-	USE_FEATURE_FANCY_SLEEP( \
+	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" \
-	USE_FEATURE_FANCY_SLEEP( \
+	IF_FEATURE_FANCY_SLEEP( \
        "$ sleep 1d 3h 22m 8s\n" \
        "[98528 second delay results]\n")
 
 #define sort_trivial_usage \
        "[-nru" \
-	USE_FEATURE_SORT_BIG("gMcszbdfimSTokt] [-o FILE] [-k start[.offset][opts][,end[.offset][opts]] [-t CHAR") \
+	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:" \
-	USE_FEATURE_SORT_BIG( \
+	IF_FEATURE_SORT_BIG( \
      "\n	-b	Ignore leading blanks" \
      "\n	-c	Check whether input is sorted" \
      "\n	-d	Dictionary order (blank or alphanumeric only)" \
@@ -3874,17 +3874,17 @@
      "\n	-M	Sort month" \
 	) \
      "\n	-n	Sort numbers" \
-	USE_FEATURE_SORT_BIG( \
+	IF_FEATURE_SORT_BIG( \
      "\n	-o	Output to file" \
      "\n	-k	Sort by key" \
      "\n	-t CHAR	Key separator" \
 	) \
      "\n	-r	Reverse sort order" \
-	USE_FEATURE_SORT_BIG( \
+	IF_FEATURE_SORT_BIG( \
      "\n	-s	Stable (don't sort ties alphabetically)" \
 	) \
      "\n	-u	Suppress duplicate lines" \
-	USE_FEATURE_SORT_BIG( \
+	IF_FEATURE_SORT_BIG( \
      "\n	-z	Lines are terminated by NUL, not newline" \
      "\n	-mST	Ignored for GNU compatibility") \
 
@@ -3896,7 +3896,7 @@
        "d\n" \
        "e\n" \
        "f\n" \
-	USE_FEATURE_SORT_BIG( \
+	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" \
@@ -3922,7 +3922,7 @@
        "Search for matching processes, and then\n" \
        "-K: stop all matching processes.\n" \
        "-S: start a process unless a matching process is found.\n" \
-	USE_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \
+	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" \
@@ -3935,7 +3935,7 @@
      "\n	-x,--exec EXECUTABLE	Program to run" \
      "\n	-a,--startas NAME	Zeroth argument" \
      "\n	-b,--background		Background" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+	IF_FEATURE_START_STOP_DAEMON_FANCY( \
      "\n	-N,--nicelevel N	Change nice level" \
 	) \
      "\n	-c,--chuid USER[:[GRP]]	Change to user/group" \
@@ -3944,13 +3944,13 @@
      "\n	-s,--signal SIG		Signal to send" \
      "\n	-t,--test		Match only, exit with 0 if a process is found" \
      "\nOther:" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+	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" \
 	) \
-	SKIP_FEATURE_START_STOP_DAEMON_LONG_OPTIONS( \
+	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" \
@@ -3963,7 +3963,7 @@
      "\n	-x EXECUTABLE	Program to run" \
      "\n	-a NAME		Zeroth argument" \
      "\n	-b		Background" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+	IF_FEATURE_START_STOP_DAEMON_FANCY( \
      "\n	-N N		Change nice level" \
 	) \
      "\n	-c USER[:[GRP]]	Change to user/group" \
@@ -3972,7 +3972,7 @@
      "\n	-s SIG		Signal to send" \
      "\n	-t		Match only, exit with 0 if a process is found" \
      "\nOther:" \
-	USE_FEATURE_START_STOP_DAEMON_FANCY( \
+	IF_FEATURE_START_STOP_DAEMON_FANCY( \
      "\n	-o		Exit with status 0 if nothing is done" \
      "\n	-v		Verbose" \
 	) \
@@ -3984,16 +3984,16 @@
 #define stat_full_usage "\n\n" \
        "Display file (default) or filesystem status\n" \
      "\nOptions:" \
-	USE_FEATURE_STAT_FORMAT( \
+	IF_FEATURE_STAT_FORMAT( \
      "\n	-c fmt	Use the specified format" \
 	) \
      "\n	-f	Display filesystem status" \
      "\n	-L	Dereference links" \
      "\n	-t	Display info in terse form" \
-	USE_SELINUX( \
+	IF_SELINUX( \
      "\n	-Z	Print security context" \
 	) \
-	USE_FEATURE_STAT_FORMAT( \
+	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" \
@@ -4027,7 +4027,7 @@
        " %c	Total file nodes in file system\n" \
        " %d	Free file nodes in file system\n" \
        " %f	Free blocks in file system\n" \
-	USE_SELINUX( \
+	IF_SELINUX( \
        " %C	Security context in SELinux\n" \
 	) \
        " %i	File System ID in hex\n" \
@@ -4115,12 +4115,12 @@
      "\n	-a	Stop swapping on all swap devices" \
 
 #define swapon_trivial_usage \
-       "[-a]" USE_FEATURE_SWAPON_PRI(" [-p pri]") " [DEVICE]"
+       "[-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" \
-	USE_FEATURE_SWAPON_PRI( \
+	IF_FEATURE_SWAPON_PRI( \
      "\n	-p pri	Set swap device priority" \
 	) \
 
@@ -4166,15 +4166,15 @@
      "\n	-O FILE		Log to given file (default=/var/log/messages)" \
      "\n	-l n		Set local log level" \
      "\n	-S		Smaller logging output" \
-	USE_FEATURE_ROTATE_LOGFILE( \
+	IF_FEATURE_ROTATE_LOGFILE( \
      "\n	-s SIZE		Max size (KB) before rotate (default=200KB, 0=off)" \
      "\n	-b NUM		Number of rotated logs to keep (default=1, max=99, 0=purge)") \
-	USE_FEATURE_REMOTE_LOG( \
+	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)") \
-	USE_FEATURE_SYSLOGD_DUP( \
+	IF_FEATURE_SYSLOGD_DUP( \
      "\n	-D		Drop duplicates") \
-	USE_FEATURE_IPC_SYSLOG( \
+	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)" */
@@ -4195,11 +4195,11 @@
        "With more than one FILE, precede each with a header giving the\n" \
        "file name. With no FILE, or when FILE is -, read standard input.\n" \
      "\nOptions:" \
-	USE_FEATURE_FANCY_TAIL( \
+	IF_FEATURE_FANCY_TAIL( \
      "\n	-c N[kbm]	Output the last N bytes") \
      "\n	-n N[kbm]	Print last N lines instead of last 10" \
      "\n	-f		Output data as the file grows" \
-	USE_FEATURE_FANCY_TAIL( \
+	IF_FEATURE_FANCY_TAIL( \
      "\n	-q		Never output headers giving file names" \
      "\n	-s SEC		Wait SEC seconds between reads with -f" \
      "\n	-v		Always output headers giving file names" \
@@ -4213,35 +4213,35 @@
        "nameserver 10.0.0.1\n"
 
 #define tar_trivial_usage \
-       "-[" USE_FEATURE_TAR_CREATE("c") USE_FEATURE_SEAMLESS_GZ("z") \
-	USE_FEATURE_SEAMLESS_BZ2("j") USE_FEATURE_SEAMLESS_LZMA("a") \
-	USE_FEATURE_SEAMLESS_Z("Z") "xtvO] " \
-	USE_FEATURE_TAR_FROM("[-X FILE] ") \
+       "-[" IF_FEATURE_TAR_CREATE("c") IF_FEATURE_SEAMLESS_GZ("z") \
+	IF_FEATURE_SEAMLESS_BZ2("j") IF_FEATURE_SEAMLESS_LZMA("a") \
+	IF_FEATURE_SEAMLESS_Z("Z") "xtvO] " \
+	IF_FEATURE_TAR_FROM("[-X FILE] ") \
        "[-f TARFILE] [-C DIR] [FILE(s)]..."
 #define tar_full_usage "\n\n" \
        "Create, extract, or list files from a tar file\n" \
      "\nOptions:" \
-	USE_FEATURE_TAR_CREATE( \
+	IF_FEATURE_TAR_CREATE( \
      "\n	c	Create") \
      "\n	x	Extract" \
      "\n	t	List" \
      "\nArchive format selection:" \
-	USE_FEATURE_SEAMLESS_GZ( \
+	IF_FEATURE_SEAMLESS_GZ( \
      "\n	z	Filter the archive through gzip" \
 	) \
-	USE_FEATURE_SEAMLESS_BZ2( \
+	IF_FEATURE_SEAMLESS_BZ2( \
      "\n	j	Filter the archive through bzip2" \
 	) \
-	USE_FEATURE_SEAMLESS_LZMA( \
+	IF_FEATURE_SEAMLESS_LZMA( \
      "\n	a	Filter the archive through lzma" \
 	) \
-	USE_FEATURE_SEAMLESS_Z( \
+	IF_FEATURE_SEAMLESS_Z( \
      "\n	Z	Filter the archive through compress" \
 	) \
      "\nFile selection:" \
      "\n	f	Name of TARFILE or \"-\" for stdin" \
      "\n	O	Extract to stdout" \
-	USE_FEATURE_TAR_FROM( \
+	IF_FEATURE_TAR_FROM( \
      "\n	exclude	File to exclude" \
      "\n	X	File with names to exclude" \
 	) \
@@ -4303,13 +4303,13 @@
        "[OPTION]"
 #define telnetd_full_usage "\n\n" \
        "Handle incoming telnet connections" \
-	SKIP_FEATURE_TELNETD_STANDALONE(" via inetd") "\n" \
+	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)" \
-	USE_FEATURE_TELNETD_STANDALONE( \
+	IF_FEATURE_TELNETD_STANDALONE( \
      "\n	-p PORT		Port to listen on" \
      "\n	-b ADDR		Address to bind to" \
      "\n	-F		Run in foreground" \
@@ -4343,11 +4343,11 @@
 	"OBJECT: {qdisc|class|filter}\n" \
 	"CMD: {add|del|change|replace|show}\n" \
 	"\n" \
-	"qdisc [ handle QHANDLE ] [ root |"USE_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \
+	"qdisc [ handle QHANDLE ] [ root |"IF_FEATURE_TC_INGRESS(" ingress |")" parent CLASSID ]\n" \
 	/* "\t[ estimator INTERVAL TIME_CONSTANT ]\n" */ \
 	"\t[ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \
 	"\tQDISC_KIND := { [p|b]fifo | tbf | prio | cbq | red | etc. }\n" \
-	"qdisc show [ dev STRING ]"USE_FEATURE_TC_INGRESS(" [ingress]")"\n" \
+	"qdisc show [ dev STRING ]"IF_FEATURE_TC_INGRESS(" [ingress]")"\n" \
 	"class [ classid CLASSID ] [ root | parent CLASSID ]\n" \
 	"\t[ [ QDISC_KIND ] [ help | OPTIONS ] ]\n" \
 	"class show [ dev STRING ] [ root | parent CLASSID ]\n" \
@@ -4401,13 +4401,13 @@
      "\nOptions:" \
      "\n	-l FILE	Local FILE" \
      "\n	-r FILE	Remote FILE" \
-	USE_FEATURE_TFTP_GET( \
+	IF_FEATURE_TFTP_GET( \
      "\n	-g	Get file" \
 	) \
-	USE_FEATURE_TFTP_PUT( \
+	IF_FEATURE_TFTP_PUT( \
      "\n	-p	Put file" \
 	) \
-	USE_FEATURE_TFTP_BLOCKSIZE( \
+	IF_FEATURE_TFTP_BLOCKSIZE( \
      "\n	-b SIZE	Transfer blocks of SIZE octets" \
 	)
 
@@ -4512,7 +4512,7 @@
        ""
 #define tty_full_usage "\n\n" \
        "Print file name of standard input's terminal" \
-	USE_INCLUDE_SUSv2( "\n" \
+	IF_INCLUDE_SUSv2( "\n" \
      "\nOptions:" \
      "\n	-s	Print nothing, only return exit status" \
 	)
@@ -4526,14 +4526,14 @@
        "Print dimension(s) of standard input's terminal, on error return 80x25"
 
 #define tunctl_trivial_usage \
-       "[-f device] ([-t name] | -d name)" USE_FEATURE_TUNCTL_UG(" [-u owner] [-g group] [-b]")
+       "[-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" \
      "\nOptions:" \
      "\n	-f name		tun device (/dev/net/tun)" \
      "\n	-t name		Create iface 'name'" \
      "\n	-d name		Delete iface 'name'" \
-USE_FEATURE_TUNCTL_UG( \
+IF_FEATURE_TUNCTL_UG( \
      "\n	-u owner	Set iface owner" \
      "\n	-g group	Set iface group" \
      "\n	-b		Brief output" \
@@ -4554,9 +4554,9 @@
 
 #define udhcpc_trivial_usage \
        "[-Cfbnqtvo] [-c CID] [-V VCLS] [-H HOSTNAME] [-i INTERFACE]\n" \
-       "	[-p pidfile] [-r IP] [-s script] [-O dhcp-option]..." USE_FEATURE_UDHCP_PORT(" [-P N]")
+       "	[-p pidfile] [-r IP] [-s script] [-O dhcp-option]..." IF_FEATURE_UDHCP_PORT(" [-P N]")
 #define udhcpc_full_usage "\n\n" \
-	USE_GETOPT_LONG( \
+	IF_GETOPT_LONG( \
        "	-V,--vendorclass=CLASSID	Vendor class identifier" \
      "\n	-i,--interface=INTERFACE	Interface to use (default eth0)" \
      "\n	-H,-h,--hostname=HOSTNAME	Client hostname" \
@@ -4578,14 +4578,14 @@
      "\n	-n,--now	Exit with failure if lease is not immediately obtained" \
      "\n	-q,--quit	Quit after obtaining lease" \
      "\n	-R,--release	Release IP on quit" \
-	USE_FEATURE_UDHCP_PORT( \
+	IF_FEATURE_UDHCP_PORT( \
      "\n	-P,--client-port N  Use port N instead of default 68" \
 	) \
-	USE_FEATURE_UDHCPC_ARPING( \
+	IF_FEATURE_UDHCPC_ARPING( \
      "\n	-a,--arping	Use arping to validate offered address" \
 	) \
 	) \
-	SKIP_GETOPT_LONG( \
+	IF_NOT_GETOPT_LONG( \
        "	-V CLASSID	Vendor class identifier" \
      "\n	-i INTERFACE	Interface to use (default: eth0)" \
      "\n	-H,-h HOSTNAME	Client hostname" \
@@ -4607,22 +4607,22 @@
      "\n	-n		Exit with failure if lease is not immediately obtained" \
      "\n	-q		Quit after obtaining lease" \
      "\n	-R		Release IP on quit" \
-	USE_FEATURE_UDHCP_PORT( \
+	IF_FEATURE_UDHCP_PORT( \
      "\n	-P N		Use port N instead of default 68" \
 	) \
-	USE_FEATURE_UDHCPC_ARPING( \
+	IF_FEATURE_UDHCPC_ARPING( \
      "\n	-a		Use arping to validate offered address" \
 	) \
 	)
 
 #define udhcpd_trivial_usage \
-       "[-fS]" USE_FEATURE_UDHCP_PORT(" [-P N]") " [configfile]" \
+       "[-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" \
-	USE_FEATURE_UDHCP_PORT( \
+	IF_FEATURE_UDHCP_PORT( \
      "\n	-P N	Use port N instead of default 67" \
 	)
 
@@ -4631,16 +4631,16 @@
 #define umount_full_usage "\n\n" \
        "Unmount file systems\n" \
      "\nOptions:" \
-	USE_FEATURE_UMOUNT_ALL( \
-     "\n	-a	Unmount all file systems" USE_FEATURE_MTAB_SUPPORT(" in /etc/mtab") \
+	IF_FEATURE_UMOUNT_ALL( \
+     "\n	-a	Unmount all file systems" IF_FEATURE_MTAB_SUPPORT(" in /etc/mtab") \
 	) \
-	USE_FEATURE_MTAB_SUPPORT( \
+	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)" \
-	USE_FEATURE_MOUNT_LOOP( \
+	IF_FEATURE_MOUNT_LOOP( \
      "\n	-d	Free loop device if it has been used" \
 	)
 
@@ -4677,12 +4677,12 @@
 #define unexpand_full_usage "\n\n" \
        "Convert spaces to tabs, writing to standard output.\n" \
      "\nOptions:" \
-	USE_FEATURE_UNEXPAND_LONG_OPTIONS( \
+	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" \
 	) \
-	SKIP_FEATURE_UNEXPAND_LONG_OPTIONS( \
+	IF_NOT_FEATURE_UNEXPAND_LONG_OPTIONS( \
      "\n	-a	Convert all blanks" \
      "\n	-f	Convert only leading blanks" \
      "\n	-t N	Tabstops every N chars" \
@@ -4788,9 +4788,9 @@
 #define vi_full_usage "\n\n" \
        "Edit FILE\n" \
      "\nOptions:" \
-	USE_FEATURE_VI_COLON( \
+	IF_FEATURE_VI_COLON( \
      "\n	-c	Initial command to run ($EXINIT also available)") \
-	USE_FEATURE_VI_READONLY( \
+	IF_FEATURE_VI_READONLY( \
      "\n	-R	Read-only - do not write to the file") \
      "\n	-H	Short help regarding available features" \
 
@@ -4842,12 +4842,12 @@
        "     31      46    1365 /etc/passwd\n"
 
 #define wget_trivial_usage \
-	USE_FEATURE_WGET_LONG_OPTIONS( \
+	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" \
        "	[-U|--user-agent agent] url" \
 	) \
-	SKIP_FEATURE_WGET_LONG_OPTIONS( \
+	IF_NOT_FEATURE_WGET_LONG_OPTIONS( \
        "[-csq] [-O file] [-Y on/off] [-P DIR] [-U agent] url" \
 	)
 #define wget_full_usage "\n\n" \
@@ -4886,16 +4886,16 @@
 #define xargs_full_usage "\n\n" \
        "Execute COMMAND on every item given by standard input\n" \
      "\nOptions:" \
-	USE_FEATURE_XARGS_SUPPORT_CONFIRMATION( \
+	IF_FEATURE_XARGS_SUPPORT_CONFIRMATION( \
      "\n	-p	Ask user whether to run each command") \
      "\n	-r	Do not run command if input is empty" \
-	USE_FEATURE_XARGS_SUPPORT_ZERO_TERM( \
+	IF_FEATURE_XARGS_SUPPORT_ZERO_TERM( \
      "\n	-0	Input is separated by NUL characters") \
      "\n	-t	Print the command on stderr before execution" \
      "\n	-e[STR]	STR stops input processing" \
      "\n	-n N	Pass no more than N args to COMMAND" \
      "\n	-s N	Pass command line of no more than N bytes" \
-	USE_FEATURE_XARGS_SUPPORT_TERMOPT( \
+	IF_FEATURE_XARGS_SUPPORT_TERMOPT( \
      "\n	-x	Exit if size is exceeded") \
 
 #define xargs_example_usage \
Index: include/applets.h
===================================================================
--- include/applets.h	(revision 26172)
+++ include/applets.h	(revision 26173)
@@ -67,358 +67,358 @@
 #endif
 
 
-USE_TEST(APPLET_NOFORK([,  test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
-USE_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
-USE_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER, awk))
-USE_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_NEVER, basename))
-USE_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_NEVER))
-//USE_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER, bzcat))
-USE_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CAT(APPLET_NOFORK(cat, cat, _BB_DIR_BIN, _BB_SUID_NEVER, cat))
-USE_CATV(APPLET(catv, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_CHAT(APPLET(chat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CHATTR(APPLET(chattr, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_CHCON(APPLET(chcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CHGRP(APPLET_NOEXEC(chgrp, chgrp, _BB_DIR_BIN, _BB_SUID_NEVER, chgrp))
-USE_CHMOD(APPLET_NOEXEC(chmod, chmod, _BB_DIR_BIN, _BB_SUID_NEVER, chmod))
-USE_CHOWN(APPLET_NOEXEC(chown, chown, _BB_DIR_BIN, _BB_SUID_NEVER, chown))
-USE_CHPASSWD(APPLET(chpasswd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CKSUM(APPLET(cksum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_NEVER, cp))
-USE_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
-USE_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_NEVER, cut))
-USE_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_NEVER, dd))
-USE_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
-USE_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
-USE_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dirname))
-USE_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_ALWAYS))
-USE_DOS2UNIX(APPLET(dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb))
-USE_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_APP_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-//USE_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
-//USE_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, e2label))
-USE_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER, echo))
-USE_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, egrep))
-USE_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_ENV(APPLET_NOEXEC(env, env, _BB_DIR_USR_BIN, _BB_SUID_NEVER, env))
-USE_ENVDIR(APPLET_ODDNAME(envdir, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envdir))
-USE_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envuidgid))
-USE_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ether_wake))
-USE_EXPAND(APPLET(expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_EXPR(APPLET(expr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_FAKEIDENTD(APPLET(fakeidentd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_FALSE(APPLET_NOFORK(false, false, _BB_DIR_BIN, _BB_SUID_NEVER, false))
-USE_FBSET(APPLET(fbset, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush))
-USE_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep))
-USE_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find))
-USE_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE))
-//USE_FLASH_ERASEALL(APPLET_ODDNAME(flash_eraseall, flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER, flash_eraseall))
-USE_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
-//USE_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext2))
-//USE_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext3))
-USE_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix))
-USE_FTPD(APPLET(ftpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpget))
-USE_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpput))
-USE_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hd))
-USE_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hexdump))
-USE_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hostid))
-USE_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifdown))
-USE_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup))
-USE_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
-USE_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_TEST(APPLET_NOFORK([,  test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+IF_TEST(APPLET_NOFORK([[, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+IF_ACPID(APPLET(acpid, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_ADDGROUP(APPLET(addgroup, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_ADDUSER(APPLET(adduser, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_ADJTIMEX(APPLET(adjtimex, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_AR(APPLET(ar, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_ARP(APPLET(arp, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_ARPING(APPLET(arping, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_ASH(APPLET(ash, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_AWK(APPLET_NOEXEC(awk, awk, _BB_DIR_USR_BIN, _BB_SUID_NEVER, awk))
+IF_BASENAME(APPLET_NOFORK(basename, basename, _BB_DIR_USR_BIN, _BB_SUID_NEVER, basename))
+IF_BBCONFIG(APPLET(bbconfig, _BB_DIR_BIN, _BB_SUID_NEVER))
+//IF_BBSH(APPLET(bbsh, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_BLKID(APPLET(blkid, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_BRCTL(APPLET(brctl, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_BUNZIP2(APPLET(bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_BUNZIP2(APPLET_ODDNAME(bzcat, bunzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER, bzcat))
+IF_BZIP2(APPLET(bzip2, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CAL(APPLET(cal, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CAT(APPLET_NOFORK(cat, cat, _BB_DIR_BIN, _BB_SUID_NEVER, cat))
+IF_CATV(APPLET(catv, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_CHAT(APPLET(chat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CHATTR(APPLET(chattr, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_CHCON(APPLET(chcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CHGRP(APPLET_NOEXEC(chgrp, chgrp, _BB_DIR_BIN, _BB_SUID_NEVER, chgrp))
+IF_CHMOD(APPLET_NOEXEC(chmod, chmod, _BB_DIR_BIN, _BB_SUID_NEVER, chmod))
+IF_CHOWN(APPLET_NOEXEC(chown, chown, _BB_DIR_BIN, _BB_SUID_NEVER, chown))
+IF_CHPASSWD(APPLET(chpasswd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_CHPST(APPLET(chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CHROOT(APPLET(chroot, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_CHRT(APPLET(chrt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CHVT(APPLET(chvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CKSUM(APPLET(cksum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CLEAR(APPLET(clear, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CMP(APPLET(cmp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_COMM(APPLET(comm, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CP(APPLET_NOEXEC(cp, cp, _BB_DIR_BIN, _BB_SUID_NEVER, cp))
+IF_CPIO(APPLET(cpio, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_CROND(APPLET(crond, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_CRONTAB(APPLET(crontab, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+IF_CRYPTPW(APPLET(cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_CTTYHACK(APPLET(cttyhack, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_CUT(APPLET_NOEXEC(cut, cut, _BB_DIR_USR_BIN, _BB_SUID_NEVER, cut))
+IF_DATE(APPLET(date, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_DC(APPLET(dc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DD(APPLET_NOEXEC(dd, dd, _BB_DIR_BIN, _BB_SUID_NEVER, dd))
+IF_DEALLOCVT(APPLET(deallocvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, _BB_DIR_BIN, _BB_SUID_NEVER, delgroup))
+IF_DELUSER(APPLET(deluser, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_DEPMOD(APPLET(depmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MODPROBE_SMALL(APPLET_ODDNAME(depmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+IF_DEVFSD(APPLET(devfsd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_DEVMEM(APPLET(devmem, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_DF(APPLET(df, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_APP_DHCPRELAY(APPLET(dhcprelay, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_DIFF(APPLET(diff, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DIRNAME(APPLET_NOFORK(dirname, dirname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dirname))
+IF_DMESG(APPLET(dmesg, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_DNSD(APPLET(dnsd, _BB_DIR_USR_SBIN, _BB_SUID_ALWAYS))
+IF_DOS2UNIX(APPLET(dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DPKG(APPLET(dpkg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DPKG_DEB(APPLET_ODDNAME(dpkg-deb, dpkg_deb, _BB_DIR_USR_BIN, _BB_SUID_NEVER, dpkg_deb))
+IF_DU(APPLET(du, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_DUMPKMAP(APPLET(dumpkmap, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_APP_DUMPLEASES(APPLET(dumpleases, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//IF_E2FSCK(APPLET(e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
+//IF_E2LABEL(APPLET_ODDNAME(e2label, tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, e2label))
+IF_ECHO(APPLET_NOFORK(echo, echo, _BB_DIR_BIN, _BB_SUID_NEVER, echo))
+IF_ED(APPLET(ed, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_FEATURE_GREP_EGREP_ALIAS(APPLET_ODDNAME(egrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, egrep))
+IF_EJECT(APPLET(eject, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_ENV(APPLET_NOEXEC(env, env, _BB_DIR_USR_BIN, _BB_SUID_NEVER, env))
+IF_ENVDIR(APPLET_ODDNAME(envdir, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envdir))
+IF_ENVUIDGID(APPLET_ODDNAME(envuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, envuidgid))
+IF_ETHER_WAKE(APPLET_ODDNAME(ether-wake, ether_wake, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ether_wake))
+IF_EXPAND(APPLET(expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_EXPR(APPLET(expr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_FAKEIDENTD(APPLET(fakeidentd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_FALSE(APPLET_NOFORK(false, false, _BB_DIR_BIN, _BB_SUID_NEVER, false))
+IF_FBSET(APPLET(fbset, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_FBSPLASH(APPLET(fbsplash, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_FDFLUSH(APPLET_ODDNAME(fdflush, freeramdisk, _BB_DIR_BIN, _BB_SUID_NEVER, fdflush))
+IF_FDFORMAT(APPLET(fdformat, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_FDISK(APPLET(fdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_FEATURE_GREP_FGREP_ALIAS(APPLET_ODDNAME(fgrep, grep, _BB_DIR_BIN, _BB_SUID_NEVER, fgrep))
+IF_FIND(APPLET_NOEXEC(find, find, _BB_DIR_USR_BIN, _BB_SUID_NEVER, find))
+IF_FINDFS(APPLET(findfs, _BB_DIR_SBIN, _BB_SUID_MAYBE))
+//IF_FLASH_ERASEALL(APPLET_ODDNAME(flash_eraseall, flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER, flash_eraseall))
+IF_FLASH_ERASEALL(APPLET(flash_eraseall, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_FOLD(APPLET(fold, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_FREE(APPLET(free, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_FREERAMDISK(APPLET(freeramdisk, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_FSCK(APPLET(fsck, _BB_DIR_SBIN, _BB_SUID_NEVER))
+//IF_E2FSCK(APPLET_ODDNAME(fsck.ext2, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext2))
+//IF_E2FSCK(APPLET_ODDNAME(fsck.ext3, e2fsck, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_ext3))
+IF_FSCK_MINIX(APPLET_ODDNAME(fsck.minix, fsck_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, fsck_minix))
+IF_FTPD(APPLET(ftpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_FTPGET(APPLET_ODDNAME(ftpget, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpget))
+IF_FTPPUT(APPLET_ODDNAME(ftpput, ftpgetput, _BB_DIR_USR_BIN, _BB_SUID_NEVER, ftpput))
+IF_FUSER(APPLET(fuser, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_GETENFORCE(APPLET(getenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_GETOPT(APPLET(getopt, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_GETSEBOOL(APPLET(getsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_GETTY(APPLET(getty, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_GREP(APPLET(grep, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_GUNZIP(APPLET(gunzip, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_GZIP(APPLET(gzip, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_HALT(APPLET(halt, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_HD(APPLET_NOEXEC(hd, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hd))
+IF_HDPARM(APPLET(hdparm, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_HEAD(APPLET(head, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_HEXDUMP(APPLET_NOEXEC(hexdump, hexdump, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hexdump))
+IF_HOSTID(APPLET_NOFORK(hostid, hostid, _BB_DIR_USR_BIN, _BB_SUID_NEVER, hostid))
+IF_HOSTNAME(APPLET(hostname, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_HTTPD(APPLET(httpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_HUSH(APPLET(hush, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_HWCLOCK(APPLET(hwclock, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_ID(APPLET(id, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_IFCONFIG(APPLET(ifconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_IFUPDOWN(APPLET_ODDNAME(ifdown, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifdown))
+IF_IFENSLAVE(APPLET(ifenslave, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_IFUPDOWN(APPLET_ODDNAME(ifup, ifupdown, _BB_DIR_SBIN, _BB_SUID_NEVER, ifup))
+IF_INETD(APPLET(inetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_INIT(APPLET(init, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_INOTIFYD(APPLET(inotifyd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_INSMOD(APPLET(insmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MODPROBE_SMALL(APPLET_ODDNAME(insmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+IF_INSTALL(APPLET(install, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_IONICE(APPLET(ionice, _BB_DIR_BIN, _BB_SUID_NEVER))
 #if ENABLE_FEATURE_IP_ADDRESS \
  || ENABLE_FEATURE_IP_ROUTE \
  || ENABLE_FEATURE_IP_LINK \
  || ENABLE_FEATURE_IP_TUNNEL \
  || ENABLE_FEATURE_IP_RULE
-USE_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IP(APPLET(ip, _BB_DIR_BIN, _BB_SUID_NEVER))
 #endif
-USE_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
-USE_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
-USE_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_KBD_MODE(APPLET(kbd_mode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall))
-USE_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall5))
-USE_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_NEVER, length))
-USE_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux32))
-USE_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux64))
-USE_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_NEVER, linuxrc))
-USE_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_NEVER, ln))
-USE_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_ALWAYS))
-USE_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, logname))
-USE_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_LPD(APPLET(lpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpq))
-USE_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpr))
-USE_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls))
-USE_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
-USE_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
-USE_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum))
-USE_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_NEVER, mkdir))
-USE_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat))
-//USE_MKE2FS(APPLET(mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-//USE_MKE2FS(APPLET_ODDNAME(mkfs.ext2, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext2))
-//USE_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext3))
-USE_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_minix))
-USE_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat))
-USE_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER, mkpasswd))
-USE_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MOUNT(APPLET(mount, _BB_DIR_BIN, USE_DESKTOP(_BB_SUID_MAYBE) SKIP_DESKTOP(_BB_SUID_NEVER)))
-USE_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-//USE_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
-USE_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
-USE_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill))
-USE_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff))
-USE_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf))
-USE_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_NEVER, pwd))
-USE_RAIDAUTORUN(APPLET(raidautorun, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_RDATE(APPLET(rdate, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_RDEV(APPLET(rdev, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot))
-USE_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER, restorecon))
-USE_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
-USE_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
-USE_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
-USE_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_NEVER, run_parts))
-USE_RUNCON(APPLET(runcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq))
-USE_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SETFONT(APPLET(setfont, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, setuidgid))
-USE_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
-USE_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
-USE_FEATURE_SH_IS_MSH(APPLET_ODDNAME(sh, msh, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
-USE_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha1sum))
-USE_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha256sum))
-USE_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha512sum))
-USE_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_NEVER, sleep))
-USE_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, softlimit))
-USE_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sort))
-USE_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon))
-USE_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
-USE_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
-USE_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
-USE_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_NEVER, sync))
-USE_BB_SYSCTL(APPLET(sysctl, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tac))
-USE_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-/* USE_TC(APPLET(tc, _BB_DIR_SBIN, _BB_SUID_NEVER)) */
-USE_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tcpsvd))
-USE_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_TEST(APPLET_NOFORK(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
+IF_IPADDR(APPLET(ipaddr, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IPCALC(APPLET(ipcalc, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IPCRM(APPLET(ipcrm, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+IF_IPCS(APPLET(ipcs, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+IF_IPLINK(APPLET(iplink, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IPROUTE(APPLET(iproute, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IPRULE(APPLET(iprule, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_IPTUNNEL(APPLET(iptunnel, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_KBD_MODE(APPLET(kbd_mode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_KILL(APPLET(kill, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_KILLALL(APPLET_ODDNAME(killall, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall))
+IF_KILLALL5(APPLET_ODDNAME(killall5, kill, _BB_DIR_USR_BIN, _BB_SUID_NEVER, killall5))
+IF_KLOGD(APPLET(klogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_LASH(APPLET(lash, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_LAST(APPLET(last, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_LENGTH(APPLET_NOFORK(length, length, _BB_DIR_USR_BIN, _BB_SUID_NEVER, length))
+IF_LESS(APPLET(less, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SETARCH(APPLET_ODDNAME(linux32, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux32))
+IF_SETARCH(APPLET_ODDNAME(linux64, setarch, _BB_DIR_BIN, _BB_SUID_NEVER, linux64))
+IF_FEATURE_INITRD(APPLET_ODDNAME(linuxrc, init, _BB_DIR_ROOT, _BB_SUID_NEVER, linuxrc))
+IF_LN(APPLET_NOEXEC(ln, ln, _BB_DIR_BIN, _BB_SUID_NEVER, ln))
+IF_LOAD_POLICY(APPLET(load_policy, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_LOADFONT(APPLET(loadfont, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_LOADKMAP(APPLET(loadkmap, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_LOGGER(APPLET(logger, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_LOGIN(APPLET(login, _BB_DIR_BIN, _BB_SUID_ALWAYS))
+IF_LOGNAME(APPLET_NOFORK(logname, logname, _BB_DIR_USR_BIN, _BB_SUID_NEVER, logname))
+IF_LOGREAD(APPLET(logread, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_LOSETUP(APPLET(losetup, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_LPD(APPLET(lpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_LPQ(APPLET_ODDNAME(lpq, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpq))
+IF_LPR(APPLET_ODDNAME(lpr, lpqr, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lpr))
+IF_LS(APPLET_NOEXEC(ls, ls, _BB_DIR_BIN, _BB_SUID_NEVER, ls))
+IF_LSATTR(APPLET(lsattr, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_LSMOD(APPLET(lsmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MODPROBE_SMALL(APPLET_ODDNAME(lsmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+IF_UNLZMA(APPLET_ODDNAME(lzmacat, unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER, lzmacat))
+IF_MAKEDEVS(APPLET(makedevs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MAKEMIME(APPLET(makemime, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MAN(APPLET(man, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MATCHPATHCON(APPLET(matchpathcon, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_MD5SUM(APPLET_ODDNAME(md5sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, md5sum))
+IF_MDEV(APPLET(mdev, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MESG(APPLET(mesg, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_MICROCOM(APPLET(microcom, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_MKDIR(APPLET_NOFORK(mkdir, mkdir, _BB_DIR_BIN, _BB_SUID_NEVER, mkdir))
+IF_MKFS_VFAT(APPLET_ODDNAME(mkdosfs, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat))
+//IF_MKE2FS(APPLET(mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MKFIFO(APPLET(mkfifo, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext2, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext2))
+//IF_MKE2FS(APPLET_ODDNAME(mkfs.ext3, mke2fs, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_ext3))
+IF_MKFS_MINIX(APPLET_ODDNAME(mkfs.minix, mkfs_minix, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_minix))
+IF_MKFS_VFAT(APPLET_ODDNAME(mkfs.vfat, mkfs_vfat, _BB_DIR_SBIN, _BB_SUID_NEVER, mkfs_vfat))
+IF_MKNOD(APPLET(mknod, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_CRYPTPW(APPLET_ODDNAME(mkpasswd, cryptpw, _BB_DIR_USR_BIN, _BB_SUID_NEVER, mkpasswd))
+IF_MKSWAP(APPLET(mkswap, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MKTEMP(APPLET(mktemp, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MODPROBE(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MODPROBE_SMALL(APPLET(modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MORE(APPLET(more, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MOUNT(APPLET(mount, _BB_DIR_BIN, IF_DESKTOP(_BB_SUID_MAYBE) IF_NOT_DESKTOP(_BB_SUID_NEVER)))
+IF_MOUNTPOINT(APPLET(mountpoint, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MSH(APPLET(msh, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MT(APPLET(mt, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_MV(APPLET(mv, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_NAMEIF(APPLET(nameif, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_NC(APPLET(nc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_NETSTAT(APPLET(netstat, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_NICE(APPLET(nice, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_NMETER(APPLET(nmeter, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_NOHUP(APPLET(nohup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_NSLOOKUP(APPLET(nslookup, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_OD(APPLET(od, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_OPENVT(APPLET(openvt, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+//IF_PARSE(APPLET(parse, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_PASSWD(APPLET(passwd, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+IF_PATCH(APPLET(patch, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_PGREP(APPLET(pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_PIDOF(APPLET(pidof, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_PING(APPLET(ping, _BB_DIR_BIN, _BB_SUID_MAYBE))
+IF_PING6(APPLET(ping6, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_PIPE_PROGRESS(APPLET(pipe_progress, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_PIVOT_ROOT(APPLET(pivot_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_PKILL(APPLET_ODDNAME(pkill, pgrep, _BB_DIR_USR_BIN, _BB_SUID_NEVER, pkill))
+IF_POPMAILDIR(APPLET(popmaildir, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_HALT(APPLET_ODDNAME(poweroff, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, poweroff))
+IF_PRINTENV(APPLET(printenv, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_PRINTF(APPLET_NOFORK(printf, printf, _BB_DIR_USR_BIN, _BB_SUID_NEVER, printf))
+IF_PS(APPLET(ps, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_PSCAN(APPLET(pscan, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_PWD(APPLET_NOFORK(pwd, pwd, _BB_DIR_BIN, _BB_SUID_NEVER, pwd))
+IF_RAIDAUTORUN(APPLET(raidautorun, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_RDATE(APPLET(rdate, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_RDEV(APPLET(rdev, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_READAHEAD(APPLET(readahead, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_READLINK(APPLET(readlink, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_READPROFILE(APPLET(readprofile, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_REALPATH(APPLET(realpath, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_HALT(APPLET_ODDNAME(reboot, halt, _BB_DIR_SBIN, _BB_SUID_NEVER, reboot))
+IF_REFORMIME(APPLET(reformime, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_RENICE(APPLET(renice, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RESET(APPLET(reset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RESIZE(APPLET(resize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RESTORECON(APPLET_ODDNAME(restorecon, setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER, restorecon))
+IF_RM(APPLET_NOFORK(rm, rm, _BB_DIR_BIN, _BB_SUID_NEVER, rm))
+IF_RMDIR(APPLET_NOFORK(rmdir, rmdir, _BB_DIR_BIN, _BB_SUID_NEVER, rmdir))
+IF_RMMOD(APPLET(rmmod, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_MODPROBE_SMALL(APPLET_ODDNAME(rmmod, modprobe, _BB_DIR_SBIN, _BB_SUID_NEVER, modprobe))
+IF_ROUTE(APPLET(route, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_RPM(APPLET(rpm, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_RPM2CPIO(APPLET(rpm2cpio, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RTCWAKE(APPLET(rtcwake, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RUN_PARTS(APPLET_ODDNAME(run-parts, run_parts, _BB_DIR_BIN, _BB_SUID_NEVER, run_parts))
+IF_RUNCON(APPLET(runcon, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RUNLEVEL(APPLET(runlevel, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_RUNSV(APPLET(runsv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RUNSVDIR(APPLET(runsvdir, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_RX(APPLET(rx, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SCRIPT(APPLET(script, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SED(APPLET(sed, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_SELINUXENABLED(APPLET(selinuxenabled, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SENDMAIL(APPLET(sendmail, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SEQ(APPLET_NOFORK(seq, seq, _BB_DIR_USR_BIN, _BB_SUID_NEVER, seq))
+IF_SESTATUS(APPLET(sestatus, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SETARCH(APPLET(setarch, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_SETCONSOLE(APPLET(setconsole, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SETENFORCE(APPLET(setenforce, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SETFILES(APPLET(setfiles, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SETFONT(APPLET(setfont, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SETKEYCODES(APPLET(setkeycodes, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SETLOGCONS(APPLET(setlogcons, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SETSEBOOL(APPLET(setsebool, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SETSID(APPLET(setsid, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SETUIDGID(APPLET_ODDNAME(setuidgid, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, setuidgid))
+IF_FEATURE_SH_IS_ASH(APPLET_ODDNAME(sh, ash, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+IF_FEATURE_SH_IS_HUSH(APPLET_ODDNAME(sh, hush, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+IF_FEATURE_SH_IS_MSH(APPLET_ODDNAME(sh, msh, _BB_DIR_BIN, _BB_SUID_NEVER, sh))
+IF_SHA1SUM(APPLET_ODDNAME(sha1sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha1sum))
+IF_SHA256SUM(APPLET_ODDNAME(sha256sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha256sum))
+IF_SHA512SUM(APPLET_ODDNAME(sha512sum, md5_sha1_sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sha512sum))
+IF_SHOWKEY(APPLET(showkey, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SLATTACH(APPLET(slattach, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SLEEP(APPLET_NOFORK(sleep, sleep, _BB_DIR_BIN, _BB_SUID_NEVER, sleep))
+IF_SOFTLIMIT(APPLET_ODDNAME(softlimit, chpst, _BB_DIR_USR_BIN, _BB_SUID_NEVER, softlimit))
+IF_SORT(APPLET_NOEXEC(sort, sort, _BB_DIR_USR_BIN, _BB_SUID_NEVER, sort))
+IF_SPLIT(APPLET(split, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_START_STOP_DAEMON(APPLET_ODDNAME(start-stop-daemon, start_stop_daemon, _BB_DIR_SBIN, _BB_SUID_NEVER, start_stop_daemon))
+IF_STAT(APPLET(stat, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_STRINGS(APPLET(strings, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_STTY(APPLET(stty, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_SU(APPLET(su, _BB_DIR_BIN, _BB_SUID_ALWAYS))
+IF_SULOGIN(APPLET(sulogin, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SUM(APPLET(sum, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SV(APPLET(sv, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_SVLOGD(APPLET(svlogd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_SWAPONOFF(APPLET_ODDNAME(swapoff, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER,swapoff))
+IF_SWAPONOFF(APPLET_ODDNAME(swapon, swap_on_off, _BB_DIR_SBIN, _BB_SUID_NEVER, swapon))
+IF_SWITCH_ROOT(APPLET(switch_root, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SYNC(APPLET_NOFORK(sync, sync, _BB_DIR_BIN, _BB_SUID_NEVER, sync))
+IF_BB_SYSCTL(APPLET(sysctl, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_SYSLOGD(APPLET(syslogd, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_TAC(APPLET_NOEXEC(tac, tac, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tac))
+IF_TAIL(APPLET(tail, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TAR(APPLET(tar, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_TASKSET(APPLET(taskset, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+/* IF_TC(APPLET(tc, _BB_DIR_SBIN, _BB_SUID_NEVER)) */
+IF_TCPSVD(APPLET_ODDNAME(tcpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, tcpsvd))
+IF_TEE(APPLET(tee, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TELNET(APPLET(telnet, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TELNETD(APPLET(telnetd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_TEST(APPLET_NOFORK(test, test, _BB_DIR_USR_BIN, _BB_SUID_NEVER, test))
 #if ENABLE_FEATURE_TFTP_GET || ENABLE_FEATURE_TFTP_PUT
-USE_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TFTP(APPLET(tftp, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TFTPD(APPLET(tftpd, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
 #endif
-USE_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_NEVER, touch))
-USE_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
-USE_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_NEVER, true))
-USE_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_NEVER))
-//USE_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
-USE_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, udpsvd))
-USE_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unexpand))
-USE_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos))
-USE_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep))
-USE_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
-USE_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_NEVER))
-USE_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_NEVER))
-USE_WC(APPLET(wc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_WGET(APPLET(wget, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
-USE_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_NEVER, whoami))
-USE_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_NEVER, xargs))
-USE_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_NEVER, yes))
-USE_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_NEVER, zcat))
-USE_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_TIME(APPLET(time, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TIMEOUT(APPLET(timeout, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TOP(APPLET(top, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TOUCH(APPLET_NOFORK(touch, touch, _BB_DIR_BIN, _BB_SUID_NEVER, touch))
+IF_TR(APPLET(tr, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TRACEROUTE(APPLET(traceroute, _BB_DIR_USR_BIN, _BB_SUID_MAYBE))
+IF_TRUE(APPLET_NOFORK(true, true, _BB_DIR_BIN, _BB_SUID_NEVER, true))
+IF_TTY(APPLET(tty, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TTYSIZE(APPLET(ttysize, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_TUNCTL(APPLET(tunctl, _BB_DIR_SBIN, _BB_SUID_NEVER))
+//IF_TUNE2FS(APPLET(tune2fs, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_APP_UDHCPC(APPLET(udhcpc, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_APP_UDHCPD(APPLET(udhcpd, _BB_DIR_USR_SBIN, _BB_SUID_NEVER))
+IF_UDPSVD(APPLET_ODDNAME(udpsvd, tcpudpsvd, _BB_DIR_USR_BIN, _BB_SUID_NEVER, udpsvd))
+IF_UMOUNT(APPLET(umount, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_UNAME(APPLET(uname, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_UNCOMPRESS(APPLET(uncompress, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_UNEXPAND(APPLET_ODDNAME(unexpand, expand, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unexpand))
+IF_UNIQ(APPLET(uniq, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_UNIX2DOS(APPLET_ODDNAME(unix2dos, dos2unix, _BB_DIR_USR_BIN, _BB_SUID_NEVER, unix2dos))
+IF_UNLZMA(APPLET(unlzma, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_UNZIP(APPLET(unzip, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_UPTIME(APPLET(uptime, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_USLEEP(APPLET_NOFORK(usleep, usleep, _BB_DIR_BIN, _BB_SUID_NEVER, usleep))
+IF_UUDECODE(APPLET(uudecode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_UUENCODE(APPLET(uuencode, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_VCONFIG(APPLET(vconfig, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_VI(APPLET(vi, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_VLOCK(APPLET(vlock, _BB_DIR_USR_BIN, _BB_SUID_ALWAYS))
+IF_WATCH(APPLET(watch, _BB_DIR_BIN, _BB_SUID_NEVER))
+IF_WATCHDOG(APPLET(watchdog, _BB_DIR_SBIN, _BB_SUID_NEVER))
+IF_WC(APPLET(wc, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_WGET(APPLET(wget, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_WHICH(APPLET(which, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_WHO(APPLET(who, _BB_DIR_USR_BIN, _BB_SUID_NEVER))
+IF_WHOAMI(APPLET_NOFORK(whoami, whoami, _BB_DIR_USR_BIN, _BB_SUID_NEVER, whoami))
+IF_XARGS(APPLET_NOEXEC(xargs, xargs, _BB_DIR_USR_BIN, _BB_SUID_NEVER, xargs))
+IF_YES(APPLET_NOFORK(yes, yes, _BB_DIR_USR_BIN, _BB_SUID_NEVER, yes))
+IF_GUNZIP(APPLET_ODDNAME(zcat, gunzip, _BB_DIR_BIN, _BB_SUID_NEVER, zcat))
+IF_ZCIP(APPLET(zcip, _BB_DIR_SBIN, _BB_SUID_NEVER))
 
 #if !defined(PROTOTYPES) && !defined(NAME_MAIN_CNAME) && !defined(MAKE_USAGE)
 };
Index: selinux/setfiles.c
===================================================================
--- selinux/setfiles.c	(revision 26172)
+++ selinux/setfiles.c	(revision 26173)
@@ -544,9 +544,9 @@
 			&exclude_dir, &input_filename, &out_filename, &verbose);
 	} else { /* setfiles */
 		flags = getopt32(argv, "de:f:ilnpqr:svo:FW"
-				USE_FEATURE_SETFILES_CHECK_OPTION("c:"),
+				IF_FEATURE_SETFILES_CHECK_OPTION("c:"),
 			&exclude_dir, &input_filename, &rootpath, &out_filename,
-				 USE_FEATURE_SETFILES_CHECK_OPTION(&policyfile,)
+				 IF_FEATURE_SETFILES_CHECK_OPTION(&policyfile,)
 			&verbose);
 	}
 
Index: testsuite/all_sourcecode.tests
===================================================================
--- testsuite/all_sourcecode.tests	(revision 26172)
+++ testsuite/all_sourcecode.tests	(revision 26173)
@@ -33,7 +33,7 @@
 # verify the applet order is correct in applets.h, otherwise
 # applets won't be called properly.
 #
-sed -n -e '/^USE_[A-Z]*(APPLET/{s:,.*::;s:.*(::;s:"::g;p}' \
+sed -n -e '/^IF_[A-Z]*(APPLET/{s:,.*::;s:.*(::;s:"::g;p}' \
 	$srcdir/../include/applets.h > applet.order.current
 LC_ALL=C sort applet.order.current > applet.order.correct
 testing "Applet order" "diff -u applet.order.current applet.order.correct" "" "" ""
Index: loginutils/sulogin.c
===================================================================
--- loginutils/sulogin.c	(revision 26172)
+++ loginutils/sulogin.c	(revision 26173)
@@ -99,7 +99,7 @@
 
 	bb_info_msg("System Maintenance Mode");
 
-	USE_SELINUX(renew_current_security_context());
+	IF_SELINUX(renew_current_security_context());
 
 	shell = getenv("SUSHELL");
 	if (!shell)
Index: loginutils/su.c
===================================================================
--- loginutils/su.c	(revision 26172)
+++ loginutils/su.c	(revision 26173)
@@ -43,7 +43,7 @@
 		the user, especially if someone su's from a su-shell.
 		But getlogin can fail -- usually due to lack of utmp entry.
 		in this case resort to getpwuid.  */
-		old_user = xstrdup(USE_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : "");
+		old_user = xstrdup(IF_FEATURE_UTMP(getlogin() ? : ) (pw = getpwuid(cur_uid)) ? pw->pw_name : "");
 		tty = xmalloc_ttyname(2) ? : "none";
 		openlog(applet_name, 0, LOG_AUTH);
 	}
@@ -91,7 +91,7 @@
 	change_identity(pw);
 	/* setup_environment params: shell, clear_env, change_env, pw */
 	setup_environment(opt_shell, flags & SU_OPT_l, !(flags & SU_OPT_mp), pw);
-	USE_SELINUX(set_current_security_context(NULL);)
+	IF_SELINUX(set_current_security_context(NULL);)
 
 	/* Never returns */
 	run_shell(opt_shell, flags & SU_OPT_l, opt_command, (const char**)argv);
Index: loginutils/login.c
===================================================================
--- loginutils/login.c	(revision 26172)
+++ loginutils/login.c	(revision 26173)
@@ -285,8 +285,8 @@
 	char *opt_host = opt_host; /* for compiler */
 	char *opt_user = opt_user; /* for compiler */
 	char *full_tty;
-	USE_SELINUX(security_context_t user_sid = NULL;)
-	USE_FEATURE_UTMP(struct utmp utent;)
+	IF_SELINUX(security_context_t user_sid = NULL;)
+	IF_FEATURE_UTMP(struct utmp utent;)
 #if ENABLE_PAM
 	int pamret;
 	pam_handle_t *pamh;
@@ -333,7 +333,7 @@
 	read_or_build_utent(&utent, run_by_root);
 
 	if (opt & LOGIN_OPT_h) {
-		USE_FEATURE_UTMP(safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));)
+		IF_FEATURE_UTMP(safe_strncpy(utent.ut_host, opt_host, sizeof(utent.ut_host));)
 		fromhost = xasprintf(" on '%s' from '%s'", short_tty, opt_host);
 	} else {
 		fromhost = xasprintf(" on '%s'", short_tty);
@@ -457,7 +457,7 @@
 
 	write_utent(&utent, username);
 
-	USE_SELINUX(initselinux(username, full_tty, &user_sid));
+	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); */
@@ -482,7 +482,7 @@
 
 	/* well, a simple setexeccon() here would do the job as well,
 	 * but let's play the game for now */
-	USE_SELINUX(set_current_security_context(user_sid);)
+	IF_SELINUX(set_current_security_context(user_sid);)
 
 	// util-linux login also does:
 	// /* start new session */
Index: loginutils/chpasswd.c
===================================================================
--- loginutils/chpasswd.c	(revision 26172)
+++ loginutils/chpasswd.c	(revision 26173)
@@ -29,7 +29,7 @@
 		bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
 
 	opt_complementary = "m--e:e--m";
-	USE_GETOPT_LONG(applet_long_options = chpasswd_longopts;)
+	IF_GETOPT_LONG(applet_long_options = chpasswd_longopts;)
 	opt = getopt32(argv, "em");
 
 	while ((name = xmalloc_fgetline(stdin)) != NULL) {
Index: runit/chpst.c
===================================================================
--- runit/chpst.c	(revision 26172)
+++ runit/chpst.c	(revision 26173)
@@ -200,11 +200,11 @@
 		// if yes -> getopt converts strings to numbers for us
 		opt_complementary = "-1:a+:c+:d+:f+:l+:m+:o+:p+:r+:s+:t+";
 		opt = getopt32(argv, "+a:c:d:f:l:m:o:p:r:s:t:u:U:e:"
-			USE_CHPST("/:n:vP012"),
+			IF_CHPST("/:n:vP012"),
 			&limita, &limitc, &limitd, &limitf, &limitl,
 			&limitm, &limito, &limitp, &limitr, &limits, &limitt,
 			&set_user, &env_user, &env_dir
-			USE_CHPST(, &root, &nicestr));
+			IF_CHPST(, &root, &nicestr));
 		argv += optind;
 		if (opt & OPT_m) { // -m means -asld
 			limita = limits = limitl = limitd = limitm;
Index: findutils/find.c
===================================================================
--- findutils/find.c	(revision 26172)
+++ findutils/find.c	(revision 26173)
@@ -62,8 +62,8 @@
 /* This is a NOEXEC applet. Be very careful! */
 
 
-USE_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
-USE_FEATURE_FIND_XDEV(static int xdev_count;)
+IF_FEATURE_FIND_XDEV(static dev_t *xdev_dev;)
+IF_FEATURE_FIND_XDEV(static int xdev_count;)
 
 typedef int (*action_fp)(const char *fileName, struct stat *statbuf, void *);
 
@@ -79,23 +79,23 @@
                                                   action_##name* ap UNUSED_PARAM)
                          ACTS(print)
                          ACTS(name,  const char *pattern; bool iname;)
-USE_FEATURE_FIND_PATH(   ACTS(path,  const char *pattern;))
-USE_FEATURE_FIND_REGEX(  ACTS(regex, regex_t compiled_pattern;))
-USE_FEATURE_FIND_PRINT0( ACTS(print0))
-USE_FEATURE_FIND_TYPE(   ACTS(type,  int type_mask;))
-USE_FEATURE_FIND_PERM(   ACTS(perm,  char perm_char; mode_t perm_mask;))
-USE_FEATURE_FIND_MTIME(  ACTS(mtime, char mtime_char; unsigned mtime_days;))
-USE_FEATURE_FIND_MMIN(   ACTS(mmin,  char mmin_char; unsigned mmin_mins;))
-USE_FEATURE_FIND_NEWER(  ACTS(newer, time_t newer_mtime;))
-USE_FEATURE_FIND_INUM(   ACTS(inum,  ino_t inode_num;))
-USE_FEATURE_FIND_USER(   ACTS(user,  uid_t uid;))
-USE_FEATURE_FIND_SIZE(   ACTS(size,  char size_char; off_t size;))
-USE_FEATURE_FIND_CONTEXT(ACTS(context, security_context_t context;))
-USE_FEATURE_FIND_PAREN(  ACTS(paren, action ***subexpr;))
-USE_FEATURE_FIND_PRUNE(  ACTS(prune))
-USE_FEATURE_FIND_DELETE( ACTS(delete))
-USE_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
-USE_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
+IF_FEATURE_FIND_PATH(   ACTS(path,  const char *pattern;))
+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;))
+IF_FEATURE_FIND_PERM(   ACTS(perm,  char perm_char; mode_t perm_mask;))
+IF_FEATURE_FIND_MTIME(  ACTS(mtime, char mtime_char; unsigned mtime_days;))
+IF_FEATURE_FIND_MMIN(   ACTS(mmin,  char mmin_char; unsigned mmin_mins;))
+IF_FEATURE_FIND_NEWER(  ACTS(newer, time_t newer_mtime;))
+IF_FEATURE_FIND_INUM(   ACTS(inum,  ino_t inode_num;))
+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_PAREN(  ACTS(paren, action ***subexpr;))
+IF_FEATURE_FIND_PRUNE(  ACTS(prune))
+IF_FEATURE_FIND_DELETE( ACTS(delete))
+IF_FEATURE_FIND_EXEC(   ACTS(exec,  char **exec_argv; unsigned *subst_count; int exec_argc;))
+IF_FEATURE_FIND_GROUP(  ACTS(group, gid_t gid;))
 
 static action ***actions;
 static bool need_print = 1;
@@ -376,8 +376,8 @@
 
 static int FAST_FUNC fileAction(const char *fileName,
 		struct stat *statbuf,
-		void *userData SKIP_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM),
-		int depth SKIP_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
+		void *userData IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM),
+		int depth IF_NOT_FEATURE_FIND_MAXDEPTH(UNUSED_PARAM))
 {
 	int i;
 #if ENABLE_FEATURE_FIND_MAXDEPTH
@@ -451,73 +451,73 @@
 	enum {
 	                         PARM_a         ,
 	                         PARM_o         ,
-	USE_FEATURE_FIND_NOT(	 PARM_char_not  ,)
+	IF_FEATURE_FIND_NOT(	 PARM_char_not  ,)
 #if ENABLE_DESKTOP
 	                         PARM_and       ,
 	                         PARM_or        ,
-	USE_FEATURE_FIND_NOT(    PARM_not       ,)
+	IF_FEATURE_FIND_NOT(    PARM_not       ,)
 #endif
 	                         PARM_print     ,
-	USE_FEATURE_FIND_PRINT0( PARM_print0    ,)
-	USE_FEATURE_FIND_DEPTH(  PARM_depth     ,)
-	USE_FEATURE_FIND_PRUNE(  PARM_prune     ,)
-	USE_FEATURE_FIND_DELETE( PARM_delete    ,)
-	USE_FEATURE_FIND_EXEC(   PARM_exec      ,)
-	USE_FEATURE_FIND_PAREN(  PARM_char_brace,)
+	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 */
 	                         PARM_name      ,
 	                         PARM_iname     ,
-	USE_FEATURE_FIND_PATH(   PARM_path      ,)
-	USE_FEATURE_FIND_REGEX(  PARM_regex     ,)
-	USE_FEATURE_FIND_TYPE(   PARM_type      ,)
-	USE_FEATURE_FIND_PERM(   PARM_perm      ,)
-	USE_FEATURE_FIND_MTIME(  PARM_mtime     ,)
-	USE_FEATURE_FIND_MMIN(   PARM_mmin      ,)
-	USE_FEATURE_FIND_NEWER(  PARM_newer     ,)
-	USE_FEATURE_FIND_INUM(   PARM_inum      ,)
-	USE_FEATURE_FIND_USER(   PARM_user      ,)
-	USE_FEATURE_FIND_GROUP(  PARM_group     ,)
-	USE_FEATURE_FIND_SIZE(   PARM_size      ,)
-	USE_FEATURE_FIND_CONTEXT(PARM_context   ,)
+	IF_FEATURE_FIND_PATH(   PARM_path      ,)
+	IF_FEATURE_FIND_REGEX(  PARM_regex     ,)
+	IF_FEATURE_FIND_TYPE(   PARM_type      ,)
+	IF_FEATURE_FIND_PERM(   PARM_perm      ,)
+	IF_FEATURE_FIND_MTIME(  PARM_mtime     ,)
+	IF_FEATURE_FIND_MMIN(   PARM_mmin      ,)
+	IF_FEATURE_FIND_NEWER(  PARM_newer     ,)
+	IF_FEATURE_FIND_INUM(   PARM_inum      ,)
+	IF_FEATURE_FIND_USER(   PARM_user      ,)
+	IF_FEATURE_FIND_GROUP(  PARM_group     ,)
+	IF_FEATURE_FIND_SIZE(   PARM_size      ,)
+	IF_FEATURE_FIND_CONTEXT(PARM_context   ,)
 	};
 
 	static const char params[] ALIGN1 =
 	                         "-a\0"
 	                         "-o\0"
-	USE_FEATURE_FIND_NOT(    "!\0"       )
+	IF_FEATURE_FIND_NOT(    "!\0"       )
 #if ENABLE_DESKTOP
 	                         "-and\0"
 	                         "-or\0"
-	USE_FEATURE_FIND_NOT(	 "-not\0"    )
+	IF_FEATURE_FIND_NOT(	 "-not\0"    )
 #endif
 	                         "-print\0"
-	USE_FEATURE_FIND_PRINT0( "-print0\0" )
-	USE_FEATURE_FIND_DEPTH(  "-depth\0"  )
-	USE_FEATURE_FIND_PRUNE(  "-prune\0"  )
-	USE_FEATURE_FIND_DELETE( "-delete\0" )
-	USE_FEATURE_FIND_EXEC(   "-exec\0"   )
-	USE_FEATURE_FIND_PAREN(  "(\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"
-	USE_FEATURE_FIND_PATH(   "-path\0"   )
-	USE_FEATURE_FIND_REGEX(  "-regex\0"  )
-	USE_FEATURE_FIND_TYPE(   "-type\0"   )
-	USE_FEATURE_FIND_PERM(   "-perm\0"   )
-	USE_FEATURE_FIND_MTIME(  "-mtime\0"  )
-	USE_FEATURE_FIND_MMIN(   "-mmin\0"   )
-	USE_FEATURE_FIND_NEWER(  "-newer\0"  )
-	USE_FEATURE_FIND_INUM(   "-inum\0"   )
-	USE_FEATURE_FIND_USER(   "-user\0"   )
-	USE_FEATURE_FIND_GROUP(  "-group\0"  )
-	USE_FEATURE_FIND_SIZE(   "-size\0"   )
-	USE_FEATURE_FIND_CONTEXT("-context\0")
+	IF_FEATURE_FIND_PATH(   "-path\0"   )
+	IF_FEATURE_FIND_REGEX(  "-regex\0"  )
+	IF_FEATURE_FIND_TYPE(   "-type\0"   )
+	IF_FEATURE_FIND_PERM(   "-perm\0"   )
+	IF_FEATURE_FIND_MTIME(  "-mtime\0"  )
+	IF_FEATURE_FIND_MMIN(   "-mmin\0"   )
+	IF_FEATURE_FIND_NEWER(  "-newer\0"  )
+	IF_FEATURE_FIND_INUM(   "-inum\0"   )
+	IF_FEATURE_FIND_USER(   "-user\0"   )
+	IF_FEATURE_FIND_GROUP(  "-group\0"  )
+	IF_FEATURE_FIND_SIZE(   "-size\0"   )
+	IF_FEATURE_FIND_CONTEXT("-context\0")
 	                         ;
 
 	action*** appp;
 	unsigned cur_group = 0;
 	unsigned cur_action = 0;
-	USE_FEATURE_FIND_NOT( bool invert_flag = 0; )
+	IF_FEATURE_FIND_NOT( bool invert_flag = 0; )
 
 	/* This is the only place in busybox where we use nested function.
 	 * So far more standard alternatives were bigger. */
@@ -530,8 +530,8 @@
 		appp[cur_group][cur_action++] = ap = xmalloc(sizeof_struct);
 		appp[cur_group][cur_action] = NULL;
 		ap->f = f;
-		USE_FEATURE_FIND_NOT( ap->invert = invert_flag; )
-		USE_FEATURE_FIND_NOT( invert_flag = 0; )
+		IF_FEATURE_FIND_NOT( ap->invert = invert_flag; )
+		IF_FEATURE_FIND_NOT( invert_flag = 0; )
 		return ap;
 	}
 
@@ -569,10 +569,10 @@
 		 * it doesn't give smaller code. Other arches? */
 
 	/* --- Operators --- */
-		if (parm == PARM_a USE_DESKTOP(|| parm == PARM_and)) {
+		if (parm == PARM_a IF_DESKTOP(|| parm == PARM_and)) {
 			/* no further special handling required */
 		}
-		else if (parm == PARM_o USE_DESKTOP(|| parm == PARM_or)) {
+		else if (parm == PARM_o IF_DESKTOP(|| parm == PARM_or)) {
 			/* start new OR group */
 			cur_group++;
 			appp = xrealloc(appp, (cur_group+2) * sizeof(*appp));
@@ -581,7 +581,7 @@
 			cur_action = 0;
 		}
 #if ENABLE_FEATURE_FIND_NOT
-		else if (parm == PARM_char_not USE_DESKTOP(|| parm == PARM_not)) {
+		else if (parm == PARM_char_not IF_DESKTOP(|| parm == PARM_not)) {
 			/* also handles "find ! ! -name 'foo*'" */
 			invert_flag ^= 1;
 		}
@@ -591,13 +591,13 @@
 		else if (parm == PARM_print) {
 			need_print = 0;
 			/* GNU find ignores '!' here: "find ! -print" */
-			USE_FEATURE_FIND_NOT( invert_flag = 0; )
+			IF_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(print);
 		}
 #if ENABLE_FEATURE_FIND_PRINT0
 		else if (parm == PARM_print0) {
 			need_print = 0;
-			USE_FEATURE_FIND_NOT( invert_flag = 0; )
+			IF_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(print0);
 		}
 #endif
@@ -608,7 +608,7 @@
 #endif
 #if ENABLE_FEATURE_FIND_PRUNE
 		else if (parm == PARM_prune) {
-			USE_FEATURE_FIND_NOT( invert_flag = 0; )
+			IF_FEATURE_FIND_NOT( invert_flag = 0; )
 			(void) ALLOC_ACTION(prune);
 		}
 #endif
@@ -624,7 +624,7 @@
 			int i;
 			action_exec *ap;
 			need_print = 0;
-			USE_FEATURE_FIND_NOT( invert_flag = 0; )
+			IF_FEATURE_FIND_NOT( invert_flag = 0; )
 			ap = ALLOC_ACTION(exec);
 			ap->exec_argv = ++argv; /* first arg after -exec */
 			ap->exec_argc = 0;
@@ -813,13 +813,13 @@
 {
 	static const char options[] ALIGN1 =
 	                  "-follow\0"
-USE_FEATURE_FIND_XDEV(    "-xdev\0"    )
-USE_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
+IF_FEATURE_FIND_XDEV(    "-xdev\0"    )
+IF_FEATURE_FIND_MAXDEPTH("-mindepth\0""-maxdepth\0")
 	                  ;
 	enum {
 	                  OPT_FOLLOW,
-USE_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
-USE_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
+IF_FEATURE_FIND_XDEV(    OPT_XDEV    ,)
+IF_FEATURE_FIND_MAXDEPTH(OPT_MINDEPTH,)
 	};
 
 	char *arg;
Index: findutils/xargs.c
===================================================================
--- findutils/xargs.c	(revision 26172)
+++ findutils/xargs.c	(revision 26173)
@@ -356,9 +356,9 @@
 	OPTBIT_UPTO_SIZE,
 	OPTBIT_EOF_STRING,
 	OPTBIT_EOF_STRING1,
-	USE_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
-	USE_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
-	USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
+	IF_FEATURE_XARGS_SUPPORT_CONFIRMATION(OPTBIT_INTERACTIVE,)
+	IF_FEATURE_XARGS_SUPPORT_TERMOPT(     OPTBIT_TERMINATE  ,)
+	IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   OPTBIT_ZEROTERM   ,)
 
 	OPT_VERBOSE     = 1 << OPTBIT_VERBOSE    ,
 	OPT_NO_EMPTY    = 1 << OPTBIT_NO_EMPTY   ,
@@ -366,14 +366,14 @@
 	OPT_UPTO_SIZE   = 1 << OPTBIT_UPTO_SIZE  ,
 	OPT_EOF_STRING  = 1 << OPTBIT_EOF_STRING , /* GNU: -e[] */
 	OPT_EOF_STRING1 = 1 << OPTBIT_EOF_STRING1, /* SUS: -E */
-	OPT_INTERACTIVE = USE_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
-	OPT_TERMINATE   = USE_FEATURE_XARGS_SUPPORT_TERMOPT(     (1 << OPTBIT_TERMINATE  )) + 0,
-	OPT_ZEROTERM    = USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1 << OPTBIT_ZEROTERM   )) + 0,
+	OPT_INTERACTIVE = IF_FEATURE_XARGS_SUPPORT_CONFIRMATION((1 << OPTBIT_INTERACTIVE)) + 0,
+	OPT_TERMINATE   = IF_FEATURE_XARGS_SUPPORT_TERMOPT(     (1 << OPTBIT_TERMINATE  )) + 0,
+	OPT_ZEROTERM    = IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   (1 << OPTBIT_ZEROTERM   )) + 0,
 };
 #define OPTION_STR "+trn:s:e::E:" \
-	USE_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
-	USE_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
-	USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
+	IF_FEATURE_XARGS_SUPPORT_CONFIRMATION("p") \
+	IF_FEATURE_XARGS_SUPPORT_TERMOPT(     "x") \
+	IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(   "0")
 
 int xargs_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 int xargs_main(int argc, char **argv)
@@ -405,7 +405,7 @@
 		eof_str = NULL;
 
 	if (opt & OPT_ZEROTERM)
-		USE_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
+		IF_FEATURE_XARGS_SUPPORT_ZERO_TERM(read_args = process0_stdin);
 
 	argv += optind;
 	argc -= optind;
Index: findutils/grep.c
===================================================================
--- findutils/grep.c	(revision 26172)
+++ findutils/grep.c	(revision 26173)
@@ -25,10 +25,10 @@
 /* options */
 #define OPTSTR_GREP \
 	"lnqvscFiHhe:f:Lorm:" \
-	USE_FEATURE_GREP_CONTEXT("A:B:C:") \
-	USE_FEATURE_GREP_EGREP_ALIAS("E") \
-	USE_DESKTOP("w") \
-	USE_EXTRA_COMPAT("z") \
+	IF_FEATURE_GREP_CONTEXT("A:B:C:") \
+	IF_FEATURE_GREP_EGREP_ALIAS("E") \
+	IF_DESKTOP("w") \
+	IF_EXTRA_COMPAT("z") \
 	"aI"
 
 /* ignored: -a "assume all files to be text" */
@@ -51,12 +51,12 @@
 	OPTBIT_o, /* show only matching parts of lines */
 	OPTBIT_r, /* recurse dirs */
 	OPTBIT_m, /* -m MAX_MATCHES */
-	USE_FEATURE_GREP_CONTEXT(    OPTBIT_A ,) /* -A NUM: after-match context */
-	USE_FEATURE_GREP_CONTEXT(    OPTBIT_B ,) /* -B NUM: before-match context */
-	USE_FEATURE_GREP_CONTEXT(    OPTBIT_C ,) /* -C NUM: -A and -B combined */
-	USE_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
-	USE_DESKTOP(                 OPTBIT_w ,) /* whole word match */
-	USE_EXTRA_COMPAT(            OPTBIT_z ,) /* input is NUL terminated */
+	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 */
+	IF_FEATURE_GREP_EGREP_ALIAS(OPTBIT_E ,) /* extended regexp */
+	IF_DESKTOP(                 OPTBIT_w ,) /* whole word match */
+	IF_EXTRA_COMPAT(            OPTBIT_z ,) /* input is NUL terminated */
 	OPT_l = 1 << OPTBIT_l,
 	OPT_n = 1 << OPTBIT_n,
 	OPT_q = 1 << OPTBIT_q,
@@ -73,12 +73,12 @@
 	OPT_o = 1 << OPTBIT_o,
 	OPT_r = 1 << OPTBIT_r,
 	OPT_m = 1 << OPTBIT_m,
-	OPT_A = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_A)) + 0,
-	OPT_B = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_B)) + 0,
-	OPT_C = USE_FEATURE_GREP_CONTEXT(    (1 << OPTBIT_C)) + 0,
-	OPT_E = USE_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
-	OPT_w = USE_DESKTOP(                 (1 << OPTBIT_w)) + 0,
-	OPT_z = USE_EXTRA_COMPAT(            (1 << OPTBIT_z)) + 0,
+	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,
+	OPT_E = IF_FEATURE_GREP_EGREP_ALIAS((1 << OPTBIT_E)) + 0,
+	OPT_w = IF_DESKTOP(                 (1 << OPTBIT_w)) + 0,
+	OPT_z = IF_EXTRA_COMPAT(            (1 << OPTBIT_z)) + 0,
 };
 
 #define PRINT_FILES_WITH_MATCHES    (option_mask32 & OPT_l)
@@ -105,7 +105,7 @@
 	int lines_before;
 	int lines_after;
 	char **before_buf;
-	USE_EXTRA_COMPAT(size_t *before_buf_size;)
+	IF_EXTRA_COMPAT(size_t *before_buf_size;)
 	int last_line_printed;
 #endif
 	/* globals used internally */
@@ -400,7 +400,7 @@
 				/* Add the line to the circular 'before' buffer */
 				free(before_buf[curpos]);
 				before_buf[curpos] = line;
-				USE_EXTRA_COMPAT(before_buf_size[curpos] = line_len;)
+				IF_EXTRA_COMPAT(before_buf_size[curpos] = line_len;)
 				curpos = (curpos + 1) % lines_before;
 				/* avoid free(line) - we took the line */
 				line = NULL;
@@ -544,7 +544,7 @@
 		lines_after = 0;
 	} else if (lines_before > 0) {
 		before_buf = xzalloc(lines_before * sizeof(before_buf[0]));
-		USE_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));)
+		IF_EXTRA_COMPAT(before_buf_size = xzalloc(lines_before * sizeof(before_buf_size[0]));)
 	}
 #else
 	/* with auto sanity checks */
Index: mailutils/popmaildir.c
===================================================================
--- mailutils/popmaildir.c	(revision 26172)
+++ mailutils/popmaildir.c	(revision 26173)
@@ -73,9 +73,9 @@
 	// parse options
 	opt_complementary = "-1:dd:t+:R+:L+:H+";
 	opts = getopt32(argv,
-		"bdmVcasTkt:" "R:Z:L:H:" USE_FEATURE_POPMAILDIR_DELIVERY("M:F:"),
+		"bdmVcasTkt:" "R:Z:L:H:" IF_FEATURE_POPMAILDIR_DELIVERY("M:F:"),
 		&timeout, NULL, NULL, NULL, &opt_nlines
-		USE_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same
+		IF_FEATURE_POPMAILDIR_DELIVERY(, &delivery, &delivery) // we treat -M and -F the same
 	);
 	//argc -= optind;
 	argv += optind;
Index: mailutils/mime.c
===================================================================
--- mailutils/mime.c	(revision 26172)
+++ mailutils/mime.c	(revision 26173)
@@ -341,11 +341,11 @@
 
 	// parse options
 	// N.B. only -x and -X are supported so far
-	opt_complementary = "x--X:X--x" USE_FEATURE_REFORMIME_COMPAT(":m::");
+	opt_complementary = "x--X:X--x" IF_FEATURE_REFORMIME_COMPAT(":m::");
 	opts = getopt32(argv,
-		"x:X" USE_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"),
+		"x:X" IF_FEATURE_REFORMIME_COMPAT("deis:r:c:m:h:o:O:"),
 		&opt_prefix
-		USE_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL)
+		IF_FEATURE_REFORMIME_COMPAT(, NULL, NULL, &G.opt_charset, NULL, NULL, NULL, NULL)
 	);
 	//argc -= optind;
 	argv += optind;
Index: procps/pidof.c
===================================================================
--- procps/pidof.c	(revision 26172)
+++ procps/pidof.c	(revision 26173)
@@ -10,10 +10,10 @@
 #include "libbb.h"
 
 enum {
-	USE_FEATURE_PIDOF_SINGLE(OPTBIT_SINGLE,)
-	USE_FEATURE_PIDOF_OMIT(  OPTBIT_OMIT  ,)
-	OPT_SINGLE = USE_FEATURE_PIDOF_SINGLE((1< 0) {
 			// if the insert is before "dot" then we need to update
Index: editors/cmp.c
===================================================================
--- editors/cmp.c	(revision 26172)
+++ editors/cmp.c	(revision 26173)
@@ -37,7 +37,7 @@
 {
 	FILE *fp1, *fp2, *outfile = stdout;
 	const char *filename1, *filename2 = "-";
-	USE_DESKTOP(off_t skip1 = 0, skip2 = 0;)
+	IF_DESKTOP(off_t skip1 = 0, skip2 = 0;)
 	off_t char_pos = 0;
 	int line_pos = 1; /* Hopefully won't overflow... */
 	const char *fmt;
@@ -48,8 +48,8 @@
 	xfunc_error_retval = 2;	/* 1 is returned if files are different. */
 
 	opt_complementary = "-1"
-			USE_DESKTOP(":?4")
-			SKIP_DESKTOP(":?2")
+			IF_DESKTOP(":?4")
+			IF_NOT_DESKTOP(":?2")
 			":l--s:s--l";
 	opt = getopt32(argv, opt_chars);
 	argv += optind;
Index: editors/diff.c
===================================================================
--- editors/diff.c	(revision 26172)
+++ editors/diff.c	(revision 26173)
@@ -103,8 +103,8 @@
 	smallint exit_status;
 	int opt_U_context;
 	size_t max_context;     /* size of context_vec_start */
-	USE_FEATURE_DIFF_DIR(int dl_count;)
-	USE_FEATURE_DIFF_DIR(char **dl;)
+	IF_FEATURE_DIFF_DIR(int dl_count;)
+	IF_FEATURE_DIFF_DIR(char **dl;)
 	char *opt_S_start;
 	const char *label1;
 	const char *label2;
Index: util-linux/fdisk.c
===================================================================
--- util-linux/fdisk.c	(revision 26172)
+++ util-linux/fdisk.c	(revision 26173)
@@ -17,7 +17,7 @@
 /* Looks like someone forgot to add this to config system */
 #ifndef ENABLE_FEATURE_FDISK_BLKSIZE
 # define ENABLE_FEATURE_FDISK_BLKSIZE 0
-# define USE_FEATURE_FDISK_BLKSIZE(a)
+# define IF_FEATURE_FDISK_BLKSIZE(a)
 #endif
 
 #define DEFAULT_SECTOR_SIZE      512
@@ -1302,7 +1302,7 @@
 // or get_boot() [table is bad] -> create_sunlabel() -> get_boot(CREATE_EMPTY_SUN).
 // (just factor out re-init of ptes[0,1,2,3] in a separate fn instead?)
 // So skip opening device _again_...
-	if (what == CREATE_EMPTY_DOS  USE_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
+	if (what == CREATE_EMPTY_DOS  IF_FEATURE_SUN_LABEL(|| what == CREATE_EMPTY_SUN))
 		goto created_table;
 
 	fd = open(disk_device, (option_mask32 & OPT_l) ? O_RDONLY : O_RDWR);
@@ -1372,7 +1372,7 @@
 				  "partition table, nor Sun, SGI or OSF "
 				  "disklabel\n");
 #ifdef __sparc__
-			USE_FEATURE_SUN_LABEL(create_sunlabel();)
+			IF_FEATURE_SUN_LABEL(create_sunlabel();)
 #else
 			create_doslabel();
 #endif
@@ -1385,7 +1385,7 @@
 #endif /* FEATURE_FDISK_WRITABLE */
 
 
-	USE_FEATURE_FDISK_WRITABLE(warn_cylinders();)
+	IF_FEATURE_FDISK_WRITABLE(warn_cylinders();)
 	warn_geometry();
 
 	for (i = 0; i < 4; i++) {
@@ -1406,7 +1406,7 @@
 				pe->sectorbuffer[510],
 				pe->sectorbuffer[511],
 				i + 1);
-			USE_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
+			IF_FEATURE_FDISK_WRITABLE(pe->changed = 1;)
 		}
 	}
 
@@ -2797,7 +2797,7 @@
 	close_dev_fd(); /* needed: fd 3 must not stay closed */
 
 	opt_complementary = "b+:C+:H+:S+"; /* numeric params */
-	opt = getopt32(argv, "b:C:H:lS:u" USE_FEATURE_FDISK_BLKSIZE("s"),
+	opt = getopt32(argv, "b:C:H:lS:u" IF_FEATURE_FDISK_BLKSIZE("s"),
 				§or_size, &user_cylinders, &user_heads, &user_sectors);
 	argc -= optind;
 	argv += optind;
Index: util-linux/hexdump.c
===================================================================
--- util-linux/hexdump.c	(revision 26172)
+++ util-linux/hexdump.c	(revision 26173)
@@ -41,7 +41,7 @@
 
 static const char add_first[] ALIGN1 = "\"%07.7_Ax\n\"";
 
-static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" USE_FEATURE_HEXDUMP_REVERSE("R");
+static const char hexdump_opts[] ALIGN1 = "bcdoxCe:f:n:s:v" IF_FEATURE_HEXDUMP_REVERSE("R");
 
 static const struct suffix_mult suffixes[] = {
 	{ "b", 512 },
Index: util-linux/acpid.c
===================================================================
--- util-linux/acpid.c	(revision 26172)
+++ util-linux/acpid.c	(revision 26173)
@@ -61,9 +61,9 @@
 	const char *opt_logfile = "/var/log/acpid.log";
 
 	getopt32(argv, "c:e:l:d"
-		USE_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
+		IF_FEATURE_ACPID_COMPAT("g:m:s:S:v"),
 		&opt_conf, &opt_input, &opt_logfile
-		USE_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
+		IF_FEATURE_ACPID_COMPAT(, NULL, NULL, NULL, NULL, NULL)
 	);
 
 	// daemonize unless -d given
Index: util-linux/mount.c
===================================================================
--- util-linux/mount.c	(revision 26172)
+++ util-linux/mount.c	(revision 26173)
@@ -105,22 +105,22 @@
 static const int32_t mount_options[] = {
 	// MS_FLAGS set a bit.  ~MS_FLAGS disable that bit.  0 flags are NOPs.
 
-	USE_FEATURE_MOUNT_LOOP(
+	IF_FEATURE_MOUNT_LOOP(
 		/* "loop" */ 0,
 	)
 
-	USE_FEATURE_MOUNT_FSTAB(
+	IF_FEATURE_MOUNT_FSTAB(
 		/* "defaults" */ 0,
 		/* "quiet" 0 - do not filter out, vfat wants to see it */
 		/* "noauto" */ MOUNT_NOAUTO,
 		/* "sw"     */ MOUNT_SWAP,
 		/* "swap"   */ MOUNT_SWAP,
-		USE_DESKTOP(/* "user"  */ MOUNT_USERS,)
-		USE_DESKTOP(/* "users" */ MOUNT_USERS,)
+		IF_DESKTOP(/* "user"  */ MOUNT_USERS,)
+		IF_DESKTOP(/* "users" */ MOUNT_USERS,)
 		/* "_netdev" */ 0,
 	)
 
-	USE_FEATURE_MOUNT_FLAGS(
+	IF_FEATURE_MOUNT_FLAGS(
 		// vfs flags
 		/* "nosuid"      */ MS_NOSUID,
 		/* "suid"        */ ~MS_NOSUID,
@@ -161,20 +161,20 @@
 };
 
 static const char mount_option_str[] =
-	USE_FEATURE_MOUNT_LOOP(
+	IF_FEATURE_MOUNT_LOOP(
 		"loop\0"
 	)
-	USE_FEATURE_MOUNT_FSTAB(
+	IF_FEATURE_MOUNT_FSTAB(
 		"defaults\0"
 		// "quiet\0" - do not filter out, vfat wants to see it
 		"noauto\0"
 		"sw\0"
 		"swap\0"
-		USE_DESKTOP("user\0")
-		USE_DESKTOP("users\0")
+		IF_DESKTOP("user\0")
+		IF_DESKTOP("users\0")
 		"_netdev\0"
 	)
-	USE_FEATURE_MOUNT_FLAGS(
+	IF_FEATURE_MOUNT_FLAGS(
 		// vfs flags
 		"nosuid\0"
 		"suid\0"
@@ -1781,9 +1781,9 @@
 	int i, j, rc = 0;
 	unsigned opt;
 	struct mntent mtpair[2], *mtcur = mtpair;
-	SKIP_DESKTOP(const int nonroot = 0;)
+	IF_NOT_DESKTOP(const int nonroot = 0;)
 
-	USE_DESKTOP(int nonroot = ) sanitize_env_if_suid();
+	IF_DESKTOP(int nonroot = ) sanitize_env_if_suid();
 
 	// Parse long options, like --bind and --move.  Note that -o option
 	// and --option are synonymous.  Yes, this means --remount,rw works.
@@ -1797,9 +1797,9 @@
 
 	// Parse remaining options
 	// Max 2 params; -o is a list, -v is a counter
-	opt_complementary = "?2o::" USE_FEATURE_MOUNT_VERBOSE("vv");
+	opt_complementary = "?2o::" IF_FEATURE_MOUNT_VERBOSE("vv");
 	opt = getopt32(argv, OPTION_STR, &lst_o, &fstype, &O_optmatch
-			USE_FEATURE_MOUNT_VERBOSE(, &verbose));
+			IF_FEATURE_MOUNT_VERBOSE(, &verbose));
 	while (lst_o) append_mount_options(&cmdopts, llist_pop(&lst_o)); // -o
 	if (opt & OPT_r) append_mount_options(&cmdopts, "ro"); // -r
 	if (opt & OPT_w) append_mount_options(&cmdopts, "rw"); // -w
Index: util-linux/fsck_minix.c
===================================================================
--- util-linux/fsck_minix.c	(revision 26172)
+++ util-linux/fsck_minix.c	(revision 26173)
@@ -151,7 +151,7 @@
 	char superblock_buffer[BLOCK_SIZE];
 	char add_zone_ind_blk[BLOCK_SIZE];
 	char add_zone_dind_blk[BLOCK_SIZE];
-	USE_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];)
+	IF_FEATURE_MINIX2(char add_zone_tind_blk[BLOCK_SIZE];)
 	char check_file_blk[BLOCK_SIZE];
 
 	/* File-name data */

 ------------------------------------------------------------------------
r26172 | vda | 2009-04-20 19:52:21 -0500 (Mon, 20 Apr 2009) | 8 lines
Changed paths:
   M /trunk/busybox/archival/libunarchive/data_extract_all.c
   M /trunk/busybox/archival/tar.c
   M /trunk/busybox/include/unarchive.h

tar: support for tar --numeric-owner. By Natanael Copa.

function                                             old     new   delta
tar_longopts                                         221     237     +16
data_extract_all                                     692     705     +13
tar_main                                             690     702     +12


 ------------------------------------------------------------------------

Index: archival/tar.c
===================================================================
--- archival/tar.c	(revision 26171)
+++ archival/tar.c	(revision 26172)
@@ -738,6 +738,7 @@
 	USE_FEATURE_SEAMLESS_Z(   OPTBIT_COMPRESS    ,)
 	OPTBIT_NOPRESERVE_OWN,
 	OPTBIT_NOPRESERVE_PERM,
+	OPTBIT_NUMERIC_OWNER,
 	OPT_TEST         = 1 << 0, // t
 	OPT_EXTRACT      = 1 << 1, // x
 	OPT_BASEDIR      = 1 << 2, // C
@@ -756,6 +757,7 @@
 	OPT_COMPRESS     = USE_FEATURE_SEAMLESS_Z(   (1 << OPTBIT_COMPRESS    )) + 0, // Z
 	OPT_NOPRESERVE_OWN  = 1 << OPTBIT_NOPRESERVE_OWN , // no-same-owner
 	OPT_NOPRESERVE_PERM = 1 << OPTBIT_NOPRESERVE_PERM, // no-same-permissions
+	OPT_NUMERIC_OWNER = 1 << OPTBIT_NUMERIC_OWNER,
 };
 #if ENABLE_FEATURE_TAR_LONG_OPTIONS
 static const char tar_longopts[] ALIGN1 =
@@ -787,6 +789,7 @@
 # if ENABLE_FEATURE_SEAMLESS_Z
 	"compress\0"            No_argument       "Z"
 # endif
+	"numeric-owner\0"       No_argument       "\xfc"
 	"no-same-owner\0"       No_argument       "\xfd"
 	"no-same-permissions\0" No_argument       "\xfe"
 	/* --exclude takes next bit position in option mask, */
@@ -873,6 +876,9 @@
 	if (opt & OPT_NOPRESERVE_PERM)
 		tar_handle->ah_flags |= ARCHIVE_NOPRESERVE_PERM;
 
+	if (opt & OPT_NUMERIC_OWNER)
+		tar_handle->ah_flags |= ARCHIVE_NUMERIC_OWNER;
+
 	if (opt & OPT_GZIP)
 		get_header_ptr = get_header_tar_gz;
 
Index: archival/libunarchive/data_extract_all.c
===================================================================
--- archival/libunarchive/data_extract_all.c	(revision 26171)
+++ archival/libunarchive/data_extract_all.c	(revision 26172)
@@ -114,22 +114,24 @@
 	}
 
 	if (!(archive_handle->ah_flags & ARCHIVE_NOPRESERVE_OWN)) {
-#if ENABLE_FEATURE_TAR_UNAME_GNAME
-		uid_t uid = file_header->uid;
-		gid_t gid = file_header->gid;
+		if (ENABLE_FEATURE_TAR_UNAME_GNAME
+		 && !(archive_handle->ah_flags & ARCHIVE_NUMERIC_OWNER)
+		) {
+			uid_t uid = file_header->uid;
+			gid_t gid = file_header->gid;
 
-		if (file_header->uname) {
-			struct passwd *pwd = getpwnam(file_header->uname);
-			if (pwd) uid = pwd->pw_uid;
+			if (file_header->uname) {
+				struct passwd *pwd = getpwnam(file_header->uname);
+				if (pwd) uid = pwd->pw_uid;
+			}
+			if (file_header->gname) {
+				struct group *grp = getgrnam(file_header->gname);
+				if (grp) gid = grp->gr_gid;
+			}
+			lchown(file_header->name, uid, gid);
+		} else {
+			lchown(file_header->name, file_header->uid, file_header->gid);
 		}
-		if (file_header->gname) {
-			struct group *grp = getgrnam(file_header->gname);
-			if (grp) gid = grp->gr_gid;
-		}
-		lchown(file_header->name, uid, gid);
-#else
-		lchown(file_header->name, file_header->uid, file_header->gid);
-#endif
 	}
 	if ((file_header->mode & S_IFMT) != S_IFLNK) {
 		/* uclibc has no lchmod, glibc is even stranger -
Index: include/unarchive.h
===================================================================
--- include/unarchive.h	(revision 26171)
+++ include/unarchive.h	(revision 26172)
@@ -11,6 +11,7 @@
 #define ARCHIVE_EXTRACT_NEWER           16
 #define ARCHIVE_NOPRESERVE_OWN          32
 #define ARCHIVE_NOPRESERVE_PERM         64
+#define ARCHIVE_NUMERIC_OWNER           128
 
 typedef struct file_header_t {
 	char *name;

 ------------------------------------------------------------------------
r26171 | vda | 2009-04-20 19:41:57 -0500 (Mon, 20 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/networking/udhcp/leases.c

udhcpc: fix truncation of last char in client hostnames


 ------------------------------------------------------------------------

Index: networking/udhcp/leases.c
===================================================================
--- networking/udhcp/leases.c	(revision 26170)
+++ networking/udhcp/leases.c	(revision 26171)
@@ -63,7 +63,8 @@
 	if (oldest) {
 		oldest->hostname[0] = '\0';
 		if (hostname) {
-        		hostname_length = hostname[-1]; /* look at option size byte */
+			/* option size byte, + 1 for NUL */
+        		hostname_length = hostname[-1] + 1;
 			if (hostname_length > sizeof(oldest->hostname))
 				hostname_length = sizeof(oldest->hostname);
             		hostname = (uint8_t*) safe_strncpy((char*)oldest->hostname, (char*)hostname, hostname_length);

 ------------------------------------------------------------------------
r26170 | vda | 2009-04-20 19:29:17 -0500 (Mon, 20 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/switch_root.c

switch_root: print errno on failure


 ------------------------------------------------------------------------

Index: util-linux/switch_root.c
===================================================================
--- util-linux/switch_root.c	(revision 26169)
+++ util-linux/switch_root.c	(revision 26170)
@@ -97,7 +97,7 @@
 	// Overmount / with newdir and chroot into it.  The chdir is needed to
 	// recalculate "." and ".." links.
 	if (mount(".", "/", NULL, MS_MOVE, NULL))
-		bb_error_msg_and_die("error moving root");
+		bb_perror_msg_and_die("error moving root");
 	xchroot(".");
 	xchdir("/");
 

 ------------------------------------------------------------------------
r26169 | vda | 2009-04-20 19:17:00 -0500 (Mon, 20 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/examples/udhcp/simple.script

tweak example udhcp script


 ------------------------------------------------------------------------

Index: examples/udhcp/simple.script
===================================================================
--- examples/udhcp/simple.script	(revision 26168)
+++ examples/udhcp/simple.script	(revision 26169)
@@ -1,10 +1,10 @@
 #!/bin/sh
-
 # udhcpc script edited by Tim Riker 
 
-[ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
+RESOLV_CONF="/etc/resolv.conf"
 
-RESOLV_CONF="/etc/resolv.conf"
+[ -n "$1" ] || echo "Error: should be called from udhcpc" && exit 1
+
 NETMASK=""
 [ -n "$subnet" ] && NETMASK="netmask $subnet"
 BROADCAST="broadcast +"
@@ -35,10 +35,10 @@
 
 		echo "Recreating $RESOLV_CONF"
 		echo -n > $RESOLV_CONF-$$
-		[ -n "$domain" ] && echo search $domain >> $RESOLV_CONF-$$
+		[ -n "$domain" ] && echo "search $domain" >> $RESOLV_CONF-$$
 		for i in $dns ; do
 			echo " Adding DNS server $i"
-			echo nameserver $i >> $RESOLV_CONF-$$
+			echo "nameserver $i" >> $RESOLV_CONF-$$
 		done
 		mv $RESOLV_CONF-$$ $RESOLV_CONF
 		;;

 ------------------------------------------------------------------------
r26167 | vda | 2009-04-20 17:04:21 -0500 (Mon, 20 Apr 2009) | 8 lines
Changed paths:
   M /trunk/busybox/shell/Config.in
   M /trunk/busybox/shell/hush.c
   A /trunk/busybox/shell/hush_test/hush-misc/export-n.right
   A /trunk/busybox/shell/hush_test/hush-misc/export-n.tests

hush: export -n support

function                                             old     new   delta
builtin_export                                       206     256     +50
set_local_var                                        248     265     +17
expand_variables                                    2204    2203      -1


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26166)
+++ shell/hush.c	(revision 26167)
@@ -1253,10 +1253,10 @@
 /* str holds "NAME=VAL" and is expected to be malloced.
  * We take ownership of it.
  * flg_export:
- *  0: do not export
- *  1: export
- * -1: if NAME is set, leave export status alone
- *     if NAME is not set, do not export
+ *  0: do not change export flag
+ *     (if creating new variable, flag will be 0)
+ *  1: set export flag and putenv the variable
+ * -1: clear export flag and unsetenv the variable
  * flg_read_only is set only when we handle -R var=val
  */
 #if BB_MMU
@@ -1297,6 +1297,7 @@
 			free(str);
 			return -1;
 		}
+//TODO: optimize out redundant unsetenv/putenv's?
 		debug_printf_env("%s: unsetenv '%s'\n", __func__, str);
 		unsetenv(str); /* just in case */
 		*value = '=';
@@ -1331,8 +1332,13 @@
 	if (flg_export == 1)
 		cur->flg_export = 1;
 	if (cur->flg_export) {
-		debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
-		return putenv(cur->varstr);
+		if (flg_export == -1) {
+			cur->flg_export = 0;
+			/* unsetenv was already done */
+		} else {
+			debug_printf_env("%s: putenv '%s'\n", __func__, cur->varstr);
+			return putenv(cur->varstr);
+		}
 	}
 	return 0;
 }
@@ -2214,7 +2220,7 @@
 								val = NULL;
 							} else {
 								char *new_var = xasprintf("%s=%s", var, val);
-								set_local_var(new_var, -1, 0);
+								set_local_var(new_var, 0, 0);
 							}
 						}
 					}
@@ -6400,7 +6406,9 @@
 
 static int builtin_export(char **argv)
 {
-	if (*++argv == NULL) {
+	unsigned opt_unexport;
+
+	if (argv[1] == NULL) {
 		char **e = environ;
 		if (e) {
 			while (*e) {
@@ -6426,15 +6434,33 @@
 		return EXIT_SUCCESS;
 	}
 
+#if ENABLE_HUSH_EXPORT_N
+	opt_unexport = getopt32(argv, "+n"); /* "+": stop at 1st non-option */
+	argv += optind;
+#else
+	opt_unexport = 0;
+	argv++;
+#endif
+
 	do {
 		char *name = *argv;
 
-		/* So far we do not check that name is valid */
+		/* So far we do not check that name is valid (TODO?) */
+
 		if (strchr(name, '=') == NULL) {
-			/* Exporting a name without a =VALUE */
 			struct variable *var;
 
 			var = get_local_var(name);
+			if (opt_unexport) {
+				/* export -n NAME (without =VALUE) */
+				if (var) {
+					var->flg_export = 0;
+					debug_printf_env("%s: unsetenv '%s'\n", __func__, name);
+					unsetenv(name);
+				} /* else: export -n NOT_EXISTING_VAR: no-op */
+				continue;
+			}
+			/* export NAME (without =VALUE) */
 			if (var) {
 				var->flg_export = 1;
 				debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
@@ -6448,10 +6474,13 @@
 			 * We just set it to "" and export. */
 			name = xasprintf("%s=", name);
 		} else {
-			/* Exporting VAR=VALUE */
+			/* (Un)exporting NAME=VALUE */
 			name = xstrdup(name);
 		}
-		set_local_var(name, 1, 0);
+		set_local_var(name,
+			/*export:*/ (opt_unexport ? -1 : 1),
+			/*readonly:*/ 0
+		);
 	} while (*++argv);
 
 	return EXIT_SUCCESS;
Index: shell/hush_test/hush-misc/export-n.right
===================================================================
--- shell/hush_test/hush-misc/export-n.right	(revision 0)
+++ shell/hush_test/hush-misc/export-n.right	(revision 26167)
@@ -0,0 +1,10 @@
+export aaa1="'''"
+export aaa2=''
+export aaa3="'''"'abc'
+export aaa8='8'
+aaa9=9
+aaa10=10
+Nothing:
+Nothing:
+Nothing:
+Done
Index: shell/hush_test/hush-misc/export-n.tests
===================================================================
--- shell/hush_test/hush-misc/export-n.tests	(revision 0)
+++ shell/hush_test/hush-misc/export-n.tests	(revision 26167)
@@ -0,0 +1,37 @@
+export aaa1="'''"
+export aaa2=""
+export aaa3="'''abc"
+export | grep aaa.=
+
+export -n aaa1
+unset aaa2; export -n aaa2="ghi"
+export -n aaa3="klm"
+export | grep aaa.=
+
+export aaa4=4 aaa5=5
+export -n aaa4=4n
+export -n aaa5
+export | grep aaa.=
+
+export aaa5=5 aaa6=6 aaa7=7 aaa8=8
+export -n aaa5 aaa6=6n aaa7
+export | grep aaa.=
+
+aaa9=9
+export -n aaa9
+set | grep ^aaa9=
+
+export aaa10=10
+export -n aaa10
+set | grep ^aaa10=
+
+
+export EXPORTED=qwe
+export -nnnnnn nnnnnn; echo "Nothing:"; env | grep nnnnnn
+
+export -n EXPORTED=123; echo "Nothing:"; env | grep ^EXPORTED
+
+export EXPORTED=qwe
+export -n EXPORTED; EXPORTED=123; echo "Nothing:"; env | grep ^EXPORTED
+
+echo Done

Property changes on: shell/hush_test/hush-misc/export-n.tests
___________________________________________________________________
Name: svn:executable
   + *

Index: shell/Config.in
===================================================================
--- shell/Config.in	(revision 26166)
+++ shell/Config.in	(revision 26167)
@@ -232,6 +232,13 @@
 	help
 	  Enable support for shell functions in hush. +800 bytes.
 
+config HUSH_EXPORT_N
+	bool "Support export '-n' option"
+	default n
+	depends on HUSH
+	help
+	  Enable support for export '-n' option in hush. It is a bash extension.
+
 config LASH
 	bool "lash (deprecated: aliased to hush)"
 	default n

 ------------------------------------------------------------------------
r26166 | vda | 2009-04-20 05:52:31 -0500 (Mon, 20 Apr 2009) | 3 lines
Changed paths:
   A /trunk/busybox/shell/hush_test/hush-bugs/env_and_func.right
   A /trunk/busybox/shell/hush_test/hush-bugs/env_and_func.tests
   A /trunk/busybox/shell/hush_test/hush-misc/func_args1.right
   A /trunk/busybox/shell/hush_test/hush-misc/func_args1.tests

hush: add two testcases


 ------------------------------------------------------------------------

Index: shell/hush_test/hush-misc/func_args1.right
===================================================================
--- shell/hush_test/hush-misc/func_args1.right	(revision 0)
+++ shell/hush_test/hush-misc/func_args1.right	(revision 26166)
@@ -0,0 +1,5 @@
+params: a b c
+'f 1 2 3' called
+params: a b c
+'f 1 2 3' called
+params: a b c
Index: shell/hush_test/hush-misc/func_args1.tests
===================================================================
--- shell/hush_test/hush-misc/func_args1.tests	(revision 0)
+++ shell/hush_test/hush-misc/func_args1.tests	(revision 26166)
@@ -0,0 +1,10 @@
+# UNFIXED BUG
+
+f() { echo "'f $1 $2 $3' called"; }
+
+set -- a b c
+echo "params: $1 $2 $3"
+f 1 2 3
+echo "params: $1 $2 $3"
+true | f 1 2 3
+echo "params: $1 $2 $3"

Property changes on: shell/hush_test/hush-misc/func_args1.tests
___________________________________________________________________
Name: svn:executable
   + *

Index: shell/hush_test/hush-bugs/env_and_func.right
===================================================================
--- shell/hush_test/hush-bugs/env_and_func.right	(revision 0)
+++ shell/hush_test/hush-bugs/env_and_func.right	(revision 26166)
@@ -0,0 +1,2 @@
+var=val
+var=old
Index: shell/hush_test/hush-bugs/env_and_func.tests
===================================================================
--- shell/hush_test/hush-bugs/env_and_func.tests	(revision 0)
+++ shell/hush_test/hush-bugs/env_and_func.tests	(revision 26166)
@@ -0,0 +1,6 @@
+# UNFIXED BUG
+
+var=old
+f() { echo "var=$var"; }
+var=val f
+echo "var=$var"

Property changes on: shell/hush_test/hush-bugs/env_and_func.tests
___________________________________________________________________
Name: svn:executable
   + *


 ------------------------------------------------------------------------
r26165 | vda | 2009-04-20 04:26:17 -0500 (Mon, 20 Apr 2009) | 7 lines
Changed paths:
   M /trunk/busybox/miscutils/watchdog.c

watchdog: enable it before setting timeout

function                                             old     new   delta
watchdog_main                                        239     259     +20
static.enable                                          -       4      +4


 ------------------------------------------------------------------------

Index: miscutils/watchdog.c
===================================================================
--- miscutils/watchdog.c	(revision 26164)
+++ miscutils/watchdog.c	(revision 26165)
@@ -59,13 +59,20 @@
 	/* WDIOC_SETTIMEOUT takes seconds, not milliseconds */
 	htimer_duration = htimer_duration / 1000;
 #ifndef WDIOC_SETTIMEOUT
-#error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet
+# error WDIOC_SETTIMEOUT is not defined, cannot compile watchdog applet
 #else
+# if defined WDIOC_SETOPTIONS && defined WDIOS_ENABLECARD
+	{
+		static const int enable = WDIOS_ENABLECARD;
+		ioctl_or_warn(3, WDIOC_SETOPTIONS, (void*) &enable);
+	}
+# endif
 	ioctl_or_warn(3, WDIOC_SETTIMEOUT, &htimer_duration);
 #endif
+
 #if 0
 	ioctl_or_warn(3, WDIOC_GETTIMEOUT, &htimer_duration);
-	printf("watchdog: SW timer is %dms, HW timer is %dms\n",
+	printf("watchdog: SW timer is %dms, HW timer is %ds\n",
 		stimer_duration, htimer_duration * 1000);
 #endif
 

 ------------------------------------------------------------------------
r26164 | vda | 2009-04-19 19:34:01 -0500 (Sun, 19 Apr 2009) | 6 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   A /trunk/busybox/shell/hush_test/hush-misc/redir5.right
   A /trunk/busybox/shell/hush_test/hush-misc/redir5.tests

hush: fix stdin of backgrounded pipe 

function                                             old     new   delta
run_list                                            2450    2502     +52


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26163)
+++ shell/hush.c	(revision 26164)
@@ -3369,7 +3369,6 @@
 	static const char *const null_ptr = NULL;
 	int i;
 	int nextin;
-	int pipefds[2];		/* pipefds[0] is for reading */
 	struct command *command;
 	char **argv_expanded;
 	char **argv;
@@ -3552,6 +3551,7 @@
 	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;
@@ -3568,10 +3568,10 @@
 		}
 
 		/* pipes are inserted between pairs of commands */
-		pipefds[0] = 0;
-		pipefds[1] = 1;
+		pipefds.rd = 0;
+		pipefds.wr = 1;
 		if ((i + 1) < pi->num_cmds)
-			xpipe(pipefds);
+			xpiped_pair(pipefds);
 
 		command->pid = BB_MMU ? fork() : vfork();
 		if (!command->pid) { /* child */
@@ -3592,10 +3592,18 @@
 				}
 			}
 #endif
-			xmove_fd(nextin, 0);
-			xmove_fd(pipefds[1], 1); /* write end */
-			if (pipefds[0] > 1)
-				close(pipefds[0]); /* read end */
+			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);
+			} else {
+				xmove_fd(nextin, 0);
+			}
+			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))
@@ -3640,9 +3648,9 @@
 		if (i)
 			close(nextin);
 		if ((i + 1) < pi->num_cmds)
-			close(pipefds[1]); /* write end */
+			close(pipefds.wr);
 		/* Pass read (output) pipe end to next iteration */
-		nextin = pipefds[0];
+		nextin = pipefds.rd;
 	}
 
 	if (!pi->alive_cmds) {
Index: shell/hush_test/hush-misc/redir5.tests
===================================================================
--- shell/hush_test/hush-misc/redir5.tests	(revision 0)
+++ shell/hush_test/hush-misc/redir5.tests	(revision 26164)
@@ -0,0 +1,13 @@
+echo "Backgrounded pipes shall have their stdin redirected to /dev/null"
+
+# 1. bash does not redirect stdin to /dev/null if it is interactive.
+# hush does it always (this is allowed by standards).
+
+# 2. Failure will result in this script hanging
+
+cat & wait; echo Zero:$?
+
+# This does not work for bash! bash bug?
+cat | cat & wait; echo Zero:$?
+
+echo Done

Property changes on: shell/hush_test/hush-misc/redir5.tests
___________________________________________________________________
Name: svn:executable
   + *

Index: shell/hush_test/hush-misc/redir5.right
===================================================================
--- shell/hush_test/hush-misc/redir5.right	(revision 0)
+++ shell/hush_test/hush-misc/redir5.right	(revision 26164)
@@ -0,0 +1,4 @@
+Backgrounded pipes shall have their stdin redirected to /dev/null
+Zero:0
+Zero:0
+Done

 ------------------------------------------------------------------------
r26163 | vda | 2009-04-19 18:38:08 -0500 (Sun, 19 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/mdev.c

mdev: enlarge inline documentation


 ------------------------------------------------------------------------

Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26162)
+++ util-linux/mdev.c	(revision 26163)
@@ -15,6 +15,8 @@
  * contains "4:0\n". Directory name is taken as device name, path component
  * directly after /sys/class/ as subsystem. In this example, "tty0" and "tty".
  * Then mdev creates the /dev/device_name node.
+ * If /sys/class/.../dev file does not exist, mdev still may act
+ * on this device: see "@|$|*command args..." parameter in config file.
  *
  * mdev w/o parameters is called as hotplug helper. It takes device
  * and subsystem names from $DEVPATH and $SUBSYSTEM, extracts
@@ -29,20 +31,34 @@
  *
  * [-][subsystem/]device  user:grp  mode  [>|=path] [@|$|*command args...]
  * [-]@maj,min[-min2]     user:grp  mode  [>|=path] [@|$|*command args...]
+ * [-]$envvar=val         user:grp  mode  [>|=path] [@|$|*command args...]
  *
- * The device name or "subsystem/device" combo is matched against 1st field
- * (which is a regex), or maj,min is matched against 1st field.
- *
  * Leading minus in 1st field means "don't stop on this line", otherwise
  * search is stopped after the matching line is encountered.
  *
- * When line matches, the device node is created, chmod'ed and chown'ed.
- * Then it moved to path, and if >path, a symlink to moved node is created
+ * The device name or "subsystem/device" combo is matched against 1st field
+ * (which is a regex), or maj,min is matched against 1st field,
+ * or specified environment variable (as regex) is matched against 1st field.
+ *
+ * $envvar=val format is useful for loading modules for hot-plugged devices
+ * which do not have driver loaded yet. In this case /sys/class/.../dev
+ * does not exist, but $MODALIAS is set to needed module's name
+ * (actually, an alias to it) by kernel. This rule instructs mdev
+ * to load the module and exit:
+ *    $MODALIAS=.* 0:0 660 @modprobe "$MODALIAS"
+ * The kernel will generate another hotplug event when /sys/class/.../dev
+ * file appears.
+ *
+ * When line matches, the device node is created, chmod'ed and chown'ed,
+ * moved to path, and if >path, a symlink to moved node is created,
+ * all this if /sys/class/.../dev exists.
  *    Examples:
  *    =loop/      - moves to /dev/loop
  *    >disk/sda%1 - moves to /dev/disk/sdaN, makes /dev/sdaN a symlink
- * Then "command args" is executed (via sh -c 'command args').
+ *
+ * Then "command args..." is executed (via sh -c 'command args...').
  * @:execute on creation, $:on deletion, *:on both.
+ * This happens regardless of /sys/class/.../dev existence.
  */
 
 struct globals {

 ------------------------------------------------------------------------
r26162 | vda | 2009-04-19 18:07:51 -0500 (Sun, 19 Apr 2009) | 9 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/shell/hush_leaktool.sh
   M /trunk/busybox/shell/hush_test/hush-trap/catch.right
   M /trunk/busybox/shell/hush_test/hush-z_slow/leak_all1.tests

hush: fix "export not_yet_defined_var", fix parsing of "cmd | }"
 corner case; improve hush_leaktool.sh;
 fix some false positives in testsuite

function                                             old     new   delta
builtin_export                                       191     206     +15
parse_stream                                        2196    2200      +4


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26161)
+++ shell/hush.c	(revision 26162)
@@ -4459,10 +4459,6 @@
 			}
 		}
 		command->argv = add_string_to_strings(command->argv, xstrdup(word->data));
-//SEGV, but good idea.
-//		command->argv = add_string_to_strings(command->argv, word->data);
-//		word->data = NULL;
-//		word->length = 0;
 		debug_print_strings("word appended to argv", command->argv);
 	}
 
@@ -5481,14 +5477,16 @@
 		 * } is an ordinary char in this case, even inside { cmd; }
 		 * Pathological example: { ""}; } should exec "}" cmd
 		 */
-		if (ch == '}'
-		 && !(IS_NULL_PIPE(ctx.pipe)
-		     && IS_NULL_CMD(ctx.command)
-		     && dest.length == 0
-		     && !dest.o_quoted
-		    )
-		) {
-			goto ordinary_char;
+		if (ch == '}') {
+			if (!IS_NULL_CMD(ctx.command) /* cmd } */
+			 || dest.length != 0 /* word} */
+			 || dest.o_quoted    /* ""} */
+			) {
+				goto ordinary_char;
+			}
+			if (!IS_NULL_PIPE(ctx.pipe)) /* cmd | } */
+				goto skip_end_trigger;
+			/* else: } does terminate a group */
 		}
 
 		if (end_trigger && end_trigger == ch
@@ -5531,6 +5529,7 @@
 				return ctx.list_head;
 			}
 		}
+ skip_end_trigger:
 		if (is_ifs)
 			continue;
 
@@ -6420,12 +6419,11 @@
 	}
 
 	do {
-		const char *value;
 		char *name = *argv;
 
-		value = strchr(name, '=');
-		if (!value) {
-			/* They are exporting something without a =VALUE */
+		/* So far we do not check that name is valid */
+		if (strchr(name, '=') == NULL) {
+			/* Exporting a name without a =VALUE */
 			struct variable *var;
 
 			var = get_local_var(name);
@@ -6433,12 +6431,19 @@
 				var->flg_export = 1;
 				debug_printf_env("%s: putenv '%s'\n", __func__, var->varstr);
 				putenv(var->varstr);
+				continue;
 			}
-			/* bash does not return an error when trying to export
-			 * an undefined variable.  Do likewise. */
-			continue;
+			/* Exporting non-existing variable.
+			 * bash does not put it in environment,
+			 * but remembers that it is exported,
+			 * and does put it in env when it is set later.
+			 * We just set it to "" and export. */
+			name = xasprintf("%s=", name);
+		} else {
+			/* Exporting VAR=VALUE */
+			name = xstrdup(name);
 		}
-		set_local_var(xstrdup(name), 1, 0);
+		set_local_var(name, 1, 0);
 	} while (*++argv);
 
 	return EXIT_SUCCESS;
Index: shell/hush_test/hush-z_slow/leak_all1.tests
===================================================================
--- shell/hush_test/hush-z_slow/leak_all1.tests	(revision 26161)
+++ shell/hush_test/hush-z_slow/leak_all1.tests	(revision 26162)
@@ -67,6 +67,7 @@
     f >/dev/null
     : $((i++))
 done
+unset -f f
 
 memleak
 
@@ -133,6 +134,7 @@
     f >/dev/null
     : $((i++))
 done
+unset -f f
 
 
 memleak
Index: shell/hush_test/hush-trap/catch.right
===================================================================
--- shell/hush_test/hush-trap/catch.right	(revision 26161)
+++ shell/hush_test/hush-trap/catch.right	(revision 26162)
@@ -2,3 +2,4 @@
 caught
 sending USR2
 sending USR2
+USR2
Index: shell/hush_leaktool.sh
===================================================================
--- shell/hush_leaktool.sh	(revision 26161)
+++ shell/hush_leaktool.sh	(revision 26162)
@@ -6,8 +6,20 @@
 freelist=`grep 'free 0x' "$output" | cut -d' ' -f2 | sort | uniq | xargs`
 
 grep -v free "$output" >"$output.leaked"
+
+i=8
+list=
 for freed in $freelist; do
-    echo Dropping $freed
-    grep -v $freed <"$output.leaked" >"$output.temp"
+    list="$list -e $freed"
+    test $((--i)) != 0 && continue
+    echo Dropping $list
+    grep -F -v $list <"$output.leaked" >"$output.temp"
     mv "$output.temp" "$output.leaked"
+    i=8
+    list=
 done
+if test "$list"; then
+    echo Dropping $list
+    grep -F -v $list <"$output.leaked" >"$output.temp"
+    mv "$output.temp" "$output.leaked"
+fi

 ------------------------------------------------------------------------
r26161 | vda | 2009-04-19 16:37:07 -0500 (Sun, 19 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/testsuite/mdev.tests
   M /trunk/busybox/util-linux/mdev.c

mdev: support $ENVVAR=regex


 ------------------------------------------------------------------------

Index: testsuite/mdev.tests
===================================================================
--- testsuite/mdev.tests	(revision 26160)
+++ testsuite/mdev.tests	(revision 26161)
@@ -61,6 +61,19 @@
 
 # continuing to use directory structure from prev test
 rm -rf mdev.testdir/dev/*
+echo "\$MODALIAS=qw  1:1 666" >mdev.testdir/etc/mdev.conf
+echo "\$MODALIAS=qw. 2:2 444" >>mdev.testdir/etc/mdev.conf
+echo "\$MODALIAS=qw. 3:3 400" >>mdev.testdir/etc/mdev.conf
+testing "mdev \$ENVVAR=regex match" \
+	"env - PATH=$PATH ACTION=add DEVPATH=/block/sda MODALIAS=qwe chroot mdev.testdir /mdev 2>&1;
+	ls -ln mdev.testdir/dev | $FILTER_LS" \
+"\
+br--r--r-- 1 2 2 8,0 sda
+" \
+	"" ""
+
+# continuing to use directory structure from prev test
+rm -rf mdev.testdir/dev/*
 echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf
 testing "mdev move/symlink rule '>bar/baz'" \
 	"env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26160)
+++ util-linux/mdev.c	(revision 26161)
@@ -89,15 +89,11 @@
 /* NB: "mdev -s" may call us many times, do not leak memory/fds! */
 static void make_device(char *path, int delete)
 {
-	const char *device_name;
+	char *device_name;
 	int major, minor, type, len;
 	int mode;
-	char *dev_maj_min = path + strlen(path);
 	parser_t *parser;
 
-	/* Force the configuration file settings exactly. */
-	umask(0);
-
 	/* Try to read major/minor string.  Note that the kernel puts \n after
 	 * the data, so we don't need to worry about null terminating the string
 	 * because sscanf() will stop at the first nondigit, which \n is.
@@ -105,21 +101,23 @@
 	 */
 	major = -1;
 	if (!delete) {
+		char *dev_maj_min = path + strlen(path);
+
 		strcpy(dev_maj_min, "/dev");
 		len = open_read_close(path, dev_maj_min + 1, 64);
-		*dev_maj_min++ = '\0';
+		*dev_maj_min = '\0';
 		if (len < 1) {
 			if (!ENABLE_FEATURE_MDEV_EXEC)
 				return;
-			/* no "dev" file, so just try to run script */
-			*dev_maj_min = '\0';
-		} else if (sscanf(dev_maj_min, "%u:%u", &major, &minor) != 2) {
+			/* no "dev" file, but we can still run scripts
+			 * based on device name */
+		} else if (sscanf(++dev_maj_min, "%u:%u", &major, &minor) != 2) {
 			major = -1;
 		}
 	}
 
 	/* Determine device name, type, major and minor */
-	device_name = bb_basename(path);
+	device_name = (char*) bb_basename(path);
 	/* http://kernel.org/doc/pending/hotplug.txt says that only
 	 * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
 	 * But since 2.6.25 block devices are also in /sys/class/block,
@@ -139,9 +137,7 @@
 		parser = config_open2("/etc/mdev.conf", fopen_for_read);
 
 	do {
-		regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
 		int keep_matching;
-		char *val, *name;
 		struct bb_uidgid_t ugid;
 		char *tokens[4];
 		char *command = NULL;
@@ -156,19 +152,22 @@
 		if (ENABLE_FEATURE_MDEV_CONF
 		 && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)
 		) {
+			char *val;
+			char *str_to_match;
+			regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
+
 			val = tokens[0];
 			keep_matching = ('-' == val[0]);
 			val += keep_matching; /* swallow leading dash */
 
 			/* Match against either "subsystem/device_name"
 			 * or "device_name" alone */
-			name = strchr(val, '/') ? path : (char *) device_name;
+			str_to_match = strchr(val, '/') ? path : device_name;
 
 			/* Fields: regex uid:gid mode [alias] [cmd] */
 
-			/* 1st field: @... */
 			if (val[0] == '@') {
-				/* @major,minor[-last] */
+				/* @major,minor[-minor2] */
 				/* (useful when name is ambiguous:
 				 * "/sys/class/usb/lp0" and
 				 * "/sys/class/printer/lp0") */
@@ -182,15 +181,29 @@
 				) {
 					continue; /* this line doesn't match */
 				}
-			} else { /* ... or regex to match device name */
+				goto line_matches;
+			}
+			if (val[0] == '$') {
+				/* regex to match an environment variable */
+				char *eq = strchr(++val, '=');
+				if (!eq)
+					continue;
+				*eq = '\0';
+				str_to_match = getenv(val);
+				if (!str_to_match)
+					continue;
+				str_to_match -= strlen(val) + 1;
+				*eq = '=';
+			}
+			/* else: regex to match [subsystem/]device_name */
+
+			{
 				regex_t match;
 				int result;
 
-				/* Is this it? */
 				xregcomp(&match, val, REG_EXTENDED);
-				result = regexec(&match, name, ARRAY_SIZE(off), off, 0);
+				result = regexec(&match, str_to_match, ARRAY_SIZE(off), off, 0);
 				regfree(&match);
-
 				//bb_error_msg("matches:");
 				//for (int i = 0; i < ARRAY_SIZE(off); i++) {
 				//	if (off[i].rm_so < 0) continue;
@@ -199,18 +212,18 @@
 				//		device_name + off[i].rm_so);
 				//}
 
-				/* If not this device, skip rest of line */
+				/* If no match, skip rest of line */
 				/* (regexec returns whole pattern as "range" 0) */
 				if (result || off[0].rm_so
-				 || ((int)off[0].rm_eo != (int)strlen(name))
+				 || ((int)off[0].rm_eo != (int)strlen(str_to_match))
 				) {
 					continue; /* this line doesn't match */
 				}
 			}
+ line_matches:
+			/* This line matches. Stop parsing after parsing
+			 * the rest the line unless keep_matching == 1 */
 
-			/* This line matches: stop parsing the file after parsing
-			 * the rest of fields unless keep_matching == 1 */
-
 			/* 2nd field: uid:gid - device ownership */
 			parse_chown_usergroup_or_die(&ugid, tokens[1]);
 
@@ -243,7 +256,7 @@
 							if (*s++ == '%')
 								n++;
 
-						p = alias = xzalloc(strlen(a) + n * strlen(name));
+						p = alias = xzalloc(strlen(a) + n * strlen(str_to_match));
 						s = a + 1;
 						while (*s) {
 							*p = *s;
@@ -251,7 +264,7 @@
 								i = (s[1] - '0');
 								if (i <= 9 && off[i].rm_so >= 0) {
 									n = off[i].rm_eo - off[i].rm_so;
-									strncpy(p, name + off[i].rm_so, n);
+									strncpy(p, str_to_match + off[i].rm_so, n);
 									p += n - 1;
 									s++;
 								}
@@ -447,9 +460,11 @@
 
 	/* We can be called as hotplug helper */
 	/* Kernel cannot provide suitable stdio fds for us, do it ourself */
-
 	bb_sanitize_stdio();
 
+	/* Force the configuration file settings exactly */
+	umask(0);
+
 	xchdir("/dev");
 
 	if (argv[1] && strcmp(argv[1], "-s") == 0) {

 ------------------------------------------------------------------------
r26160 | vda | 2009-04-19 09:12:50 -0500 (Sun, 19 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/applets/Kbuild

another stab at fixing out-of-tree build


 ------------------------------------------------------------------------

Index: applets/Kbuild
===================================================================
--- applets/Kbuild	(revision 26159)
+++ applets/Kbuild	(revision 26160)
@@ -16,7 +16,7 @@
 
 # This trick decreases amount of rebuilds
 # if tree is merely renamed/copied
-ifeq ($(src),$(obj))
+ifeq ($(srctree),$(objtree))
 srctree_slash =
 else
 srctree_slash = $(srctree)/

 ------------------------------------------------------------------------
r26159 | vda | 2009-04-19 09:03:11 -0500 (Sun, 19 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

same as previous, but -100 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26158)
+++ shell/hush.c	(revision 26159)
@@ -5476,22 +5476,24 @@
 				 * will still trigger for us */
 			}
 		}
+
+		/* "cmd}" or "cmd }..." without semicolon or &:
+		 * } is an ordinary char in this case, even inside { cmd; }
+		 * Pathological example: { ""}; } should exec "}" cmd
+		 */
+		if (ch == '}'
+		 && !(IS_NULL_PIPE(ctx.pipe)
+		     && IS_NULL_CMD(ctx.command)
+		     && dest.length == 0
+		     && !dest.o_quoted
+		    )
+		) {
+			goto ordinary_char;
+		}
+
 		if (end_trigger && end_trigger == ch
 		 && (heredoc_cnt == 0 || end_trigger != ';')
 		) {
-			/* "{ cmd}" or "{ cmd }..." without semicolon or &:
-			 * } is an ordinary char in this case.
-			 * Pathological example: { ""}; } should exec "}" cmd
-			 */
-			if (ch == '}'
-			 && !(IS_NULL_PIPE(ctx.pipe)
-			     && IS_NULL_CMD(ctx.command)
-			     && dest.length == 0
-			     && !dest.o_quoted
-			    )
-			) {
-				goto ordinary_char;
-			}
 			if (heredoc_cnt) {
 				/* This is technically valid:
 				 * { cat <
 ------------------------------------------------------------------------
r26158 | vda | 2009-04-19 08:57:51 -0500 (Sun, 19 Apr 2009) | 7 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   M /trunk/busybox/shell/hush_test/hush-misc/export.right
   A /trunk/busybox/shell/hush_test/hush-parsing/group1.right
   A /trunk/busybox/shell/hush_test/hush-parsing/group1.tests
   M /trunk/busybox/shell/hush_test/hush-vars/var_posix1.right
   M /trunk/busybox/shell/hush_test/hush-vars/var_posix1.tests

hush: fix handling of } which is not a closing one in { cmd; }

function                                             old     new   delta
parse_stream                                        2176    2302    +126
builtin_unset                                        381     387      +6


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26157)
+++ shell/hush.c	(revision 26158)
@@ -1822,7 +1822,7 @@
 		goto literal;
 	}
 	if (gr != 0) { /* GLOB_ABORTED ? */
-//TODO: testcase for bad glob pattern behavior
+		/* TODO: testcase for bad glob pattern behavior */
 		bb_error_msg("glob(3) error %d on '%s'", gr, pattern);
 	}
 	if (globdata.gl_pathv && globdata.gl_pathv[0]) {
@@ -2339,7 +2339,8 @@
 			if (HUSH_DEBUG)
 				if (list[n-1] + strlen(list[n-1]) + 1 != list[n])
 					bb_error_msg_and_die("BUG in varexp3");
-			list[n][-1] = ' '; /* TODO: or to G.ifs[0]? */
+			/* bash uses ' ' regardless of $IFS contents */
+			list[n][-1] = ' ';
 			n++;
 		}
 	}
@@ -5128,14 +5129,16 @@
 		while (1) {
 			ch = i_getch(input);
 			nommu_addchr(as_string, ch);
-			if (ch == '}')
+			if (ch == '}') {
 				break;
+			}
 
 			if (first_char) {
-				if (ch == '#')
+				if (ch == '#') {
 					/* ${#var}: length of var contents */
 					goto char_ok;
-				else if (isdigit(ch)) {
+				}
+				if (isdigit(ch)) {
 					all_digits = true;
 					goto char_ok;
 				}
@@ -5186,7 +5189,7 @@
 			o_addchr(dest, ch | quote_mask);
 			quote_mask = 0;
 			first_char = false;
-		}
+		} /* while (1) */
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 		break;
 	}
@@ -5432,6 +5435,7 @@
 				, ch);
 
 		if (!is_special && !is_ifs) { /* ordinary char */
+ ordinary_char:
 			o_addQchr(&dest, ch);
 			if ((dest.o_assignment == MAYBE_ASSIGNMENT
 			    || dest.o_assignment == WORD_IS_KEYWORD)
@@ -5475,6 +5479,19 @@
 		if (end_trigger && end_trigger == ch
 		 && (heredoc_cnt == 0 || end_trigger != ';')
 		) {
+			/* "{ cmd}" or "{ cmd }..." without semicolon or &:
+			 * } is an ordinary char in this case.
+			 * Pathological example: { ""}; } should exec "}" cmd
+			 */
+			if (ch == '}'
+			 && !(IS_NULL_PIPE(ctx.pipe)
+			     && IS_NULL_CMD(ctx.command)
+			     && dest.length == 0
+			     && !dest.o_quoted
+			    )
+			) {
+				goto ordinary_char;
+			}
 			if (heredoc_cnt) {
 				/* This is technically valid:
 				 * { cat <
 ------------------------------------------------------------------------
r26157 | vda | 2009-04-19 07:15:51 -0500 (Sun, 19 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/applets/Kbuild

hopefully fix out-of-tree build broken by 26139


 ------------------------------------------------------------------------

Index: applets/Kbuild
===================================================================
--- applets/Kbuild	(revision 26156)
+++ applets/Kbuild	(revision 26157)
@@ -13,21 +13,27 @@
 always:= $(hostprogs-y)
 
 # Generated files need additional love
-# NB: __srctree is either empty or "srctree/"
-# using it instead of srctree decreases amount of rebuilds
+
+# This trick decreases amount of rebuilds
 # if tree is merely renamed/copied
+ifeq ($(src),$(obj))
+srctree_slash =
+else
+srctree_slash = $(srctree)/
+endif
 
-HOSTCFLAGS_usage.o = -I$(__srctree)include
 
+HOSTCFLAGS_usage.o = -I$(srctree_slash)include
+
 applets/applets.o: include/usage_compressed.h include/applet_tables.h
 
-applets/usage:         .config $(__srctree)applets/usage_compressed
+applets/usage:         .config $(srctree_slash)applets/usage_compressed
 applets/applet_tables: .config
 
 quiet_cmd_gen_usage_compressed = GEN     include/usage_compressed.h
-      cmd_gen_usage_compressed = $(__srctree)applets/usage_compressed include/usage_compressed.h applets
+      cmd_gen_usage_compressed = $(srctree_slash)applets/usage_compressed include/usage_compressed.h applets
 
-include/usage_compressed.h: applets/usage $(__srctree)applets/usage_compressed
+include/usage_compressed.h: applets/usage $(srctree_slash)applets/usage_compressed
 	$(call cmd,gen_usage_compressed)
 
 quiet_cmd_gen_applet_tables = GEN     include/applet_tables.h

 ------------------------------------------------------------------------
r26156 | vda | 2009-04-18 20:27:20 -0500 (Sat, 18 Apr 2009) | 4 lines
Changed paths:
   M /trunk/busybox/coreutils/stty.c
   M /trunk/busybox/editors/awk.c
   M /trunk/busybox/libbb/parse_config.c
   M /trunk/busybox/networking/libiproute/ll_map.c
   M /trunk/busybox/networking/libiproute/ll_map.h
   M /trunk/busybox/selinux/setfiles.c
   M /trunk/busybox/util-linux/mdev.c

mdev: Rob's #if forest removal
*: remove superfluous conts in "f(type *const param)"


 ------------------------------------------------------------------------

Index: networking/libiproute/ll_map.c
===================================================================
--- networking/libiproute/ll_map.c	(revision 26155)
+++ networking/libiproute/ll_map.c	(revision 26156)
@@ -133,7 +133,7 @@
 	return 0;
 }
 
-int xll_name_to_index(const char *const name)
+int xll_name_to_index(const char *name)
 {
 	int ret = 0;
 	int sock_fd;
Index: networking/libiproute/ll_map.h
===================================================================
--- networking/libiproute/ll_map.h	(revision 26155)
+++ networking/libiproute/ll_map.h	(revision 26156)
@@ -6,7 +6,7 @@
 
 int ll_remember_index(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg);
 int ll_init_map(struct rtnl_handle *rth);
-int xll_name_to_index(const char *const name);
+int xll_name_to_index(const char *name);
 const char *ll_index_to_name(int idx);
 const char *ll_idx_n2a(int idx, char *buf);
 /* int ll_index_to_type(int idx); */
Index: coreutils/stty.c
===================================================================
--- coreutils/stty.c	(revision 26155)
+++ coreutils/stty.c	(revision 26156)
@@ -677,8 +677,8 @@
 	return NULL;
 }
 
-static void set_speed_or_die(enum speed_setting type, const char *const arg,
-					struct termios * const mode)
+static void set_speed_or_die(enum speed_setting type, const char *arg,
+					struct termios *mode)
 {
 	speed_t baud;
 
@@ -801,7 +801,7 @@
 	param_ospeed  = 8 | 0x80,
 };
 
-static int find_param(const char *const name)
+static int find_param(const char *name)
 {
 	static const char params[] ALIGN1 =
 		"line\0"    /* 1 */
Index: libbb/parse_config.c
===================================================================
--- libbb/parse_config.c	(revision 26155)
+++ libbb/parse_config.c	(revision 26156)
@@ -79,7 +79,7 @@
 	return config_open2(filename, fopen_or_warn_stdin);
 }
 
-static void config_free_data(parser_t *const parser)
+static void config_free_data(parser_t *parser)
 {
 	free(parser->line);
 	parser->line = NULL;
Index: selinux/setfiles.c
===================================================================
--- selinux/setfiles.c	(revision 26155)
+++ selinux/setfiles.c	(revision 26156)
@@ -112,7 +112,7 @@
 	}
 }
 
-static void add_exclude(const char *const directory)
+static void add_exclude(const char *directory)
 {
 	struct stat sb;
 	size_t len;
Index: editors/awk.c
===================================================================
--- editors/awk.c	(revision 26155)
+++ editors/awk.c	(revision 26156)
@@ -521,8 +521,8 @@
 	memset(vp, 0, sizeof(*vp));
 }
 
-static void syntax_error(const char *const message) NORETURN;
-static void syntax_error(const char *const message)
+static void syntax_error(const char *message) NORETURN;
+static void syntax_error(const char *message)
 {
 	bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
 }
Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26155)
+++ util-linux/mdev.c	(revision 26156)
@@ -52,7 +52,7 @@
 #define G (*(struct globals*)&bb_common_bufsiz1)
 #define root_major (G.root_major)
 #define root_minor (G.root_minor)
-#define subsystem (G.subsystem)
+#define subsystem  (G.subsystem )
 
 /* Prevent infinite loops in /sys symlinks */
 #define MAX_SYSFS_DEPTH 3
@@ -60,9 +60,9 @@
 /* We use additional 64+ bytes in make_device() */
 #define SCRATCH_SIZE 80
 
-#if ENABLE_FEATURE_MDEV_RENAME
 /* Builds an alias path.
  * This function potentionally reallocates the alias parameter.
+ * Only used for ENABLE_FEATURE_MDEV_RENAME
  */
 static char *build_alias(char *alias, const char *device_name)
 {
@@ -84,19 +84,16 @@
 
 	return alias;
 }
-#endif
 
 /* mknod in /dev based on a path like "/sys/block/hda/hda1" */
 /* NB: "mdev -s" may call us many times, do not leak memory/fds! */
 static void make_device(char *path, int delete)
 {
-#if ENABLE_FEATURE_MDEV_CONF
-	parser_t *parser;
-#endif
 	const char *device_name;
 	int major, minor, type, len;
 	int mode;
 	char *dev_maj_min = path + strlen(path);
+	parser_t *parser;
 
 	/* Force the configuration file settings exactly. */
 	umask(0);
@@ -137,170 +134,153 @@
 	else
 		path += sizeof("/sys/class/") - 1;
 
-#if !ENABLE_FEATURE_MDEV_CONF
-	mode = 0660;
-#else
 	/* If we have config file, look up user settings */
-	parser = config_open2("/etc/mdev.conf", fopen_for_read);
-	while (1) {
+	if (ENABLE_FEATURE_MDEV_CONF)
+		parser = config_open2("/etc/mdev.conf", fopen_for_read);
+
+	do {
 		regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
 		int keep_matching;
 		char *val, *name;
 		struct bb_uidgid_t ugid;
 		char *tokens[4];
-# if ENABLE_FEATURE_MDEV_EXEC
 		char *command = NULL;
-# endif
-# if ENABLE_FEATURE_MDEV_RENAME
 		char *alias = NULL;
 		char aliaslink = aliaslink; /* for compiler */
-# endif
+
 		/* Defaults in case we won't match any line */
 		ugid.uid = ugid.gid = 0;
 		keep_matching = 0;
 		mode = 0660;
 
-		if (!config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) {
-			/* End of file, create dev node with default params */
-			goto line_matches;
-		}
+		if (ENABLE_FEATURE_MDEV_CONF
+		 && config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)
+		) {
+			val = tokens[0];
+			keep_matching = ('-' == val[0]);
+			val += keep_matching; /* swallow leading dash */
 
-		val = tokens[0];
-		keep_matching = ('-' == val[0]);
-		val += keep_matching; /* swallow leading dash */
+			/* Match against either "subsystem/device_name"
+			 * or "device_name" alone */
+			name = strchr(val, '/') ? path : (char *) device_name;
 
-		/* Match against either "subsystem/device_name"
-		 * or "device_name" alone */
-		name = strchr(val, '/') ? path : (char *) device_name;
+			/* Fields: regex uid:gid mode [alias] [cmd] */
 
-		/* Fields: regex uid:gid mode [alias] [cmd] */
+			/* 1st field: @... */
+			if (val[0] == '@') {
+				/* @major,minor[-last] */
+				/* (useful when name is ambiguous:
+				 * "/sys/class/usb/lp0" and
+				 * "/sys/class/printer/lp0") */
+				int cmaj, cmin0, cmin1, sc;
+				if (major < 0)
+					continue; /* no dev, no match */
+				sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1);
+				if (sc < 1 || major != cmaj
+				 || (sc == 2 && minor != cmin0)
+				 || (sc == 3 && (minor < cmin0 || minor > cmin1))
+				) {
+					continue; /* this line doesn't match */
+				}
+			} else { /* ... or regex to match device name */
+				regex_t match;
+				int result;
 
-		/* 1st field: @... */
-		if (val[0] == '@') {
-			/* @major,minor[-last] */
-			/* (useful when name is ambiguous:
-			 * "/sys/class/usb/lp0" and
-			 * "/sys/class/printer/lp0") */
-			int cmaj, cmin0, cmin1, sc;
-			if (major < 0)
-				continue; /* no dev, no match */
-			sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1);
-			if (sc < 1 || major != cmaj
-			 || (sc == 2 && minor != cmin0)
-			 || (sc == 3 && (minor < cmin0 || minor > cmin1))
-			) {
-				continue; /* this line doesn't match */
-			}
-		} else { /* ... or regex to match device name */
-			regex_t match;
-			int result;
+				/* Is this it? */
+				xregcomp(&match, val, REG_EXTENDED);
+				result = regexec(&match, name, ARRAY_SIZE(off), off, 0);
+				regfree(&match);
 
-			/* Is this it? */
-			xregcomp(&match, val, REG_EXTENDED);
-			result = regexec(&match, name, ARRAY_SIZE(off), off, 0);
-			regfree(&match);
+				//bb_error_msg("matches:");
+				//for (int i = 0; i < ARRAY_SIZE(off); i++) {
+				//	if (off[i].rm_so < 0) continue;
+				//	bb_error_msg("match %d: '%.*s'\n", i,
+				//		(int)(off[i].rm_eo - off[i].rm_so),
+				//		device_name + off[i].rm_so);
+				//}
 
-			//bb_error_msg("matches:");
-			//for (int i = 0; i < ARRAY_SIZE(off); i++) {
-			//	if (off[i].rm_so < 0) continue;
-			//	bb_error_msg("match %d: '%.*s'\n", i,
-			//		(int)(off[i].rm_eo - off[i].rm_so),
-			//		device_name + off[i].rm_so);
-			//}
-
-			/* If not this device, skip rest of line */
-			/* (regexec returns whole pattern as "range" 0) */
-			if (result || off[0].rm_so
-			 || ((int)off[0].rm_eo != (int)strlen(name))
-			) {
-				continue; /* this line doesn't match */
+				/* If not this device, skip rest of line */
+				/* (regexec returns whole pattern as "range" 0) */
+				if (result || off[0].rm_so
+				 || ((int)off[0].rm_eo != (int)strlen(name))
+				) {
+					continue; /* this line doesn't match */
+				}
 			}
-		}
 
-		/* This line matches: stop parsing the file after parsing
-		 * the rest of fields unless keep_matching == 1 */
+			/* This line matches: stop parsing the file after parsing
+			 * the rest of fields unless keep_matching == 1 */
 
-		/* 2nd field: uid:gid - device ownership */
-		parse_chown_usergroup_or_die(&ugid, tokens[1]);
+			/* 2nd field: uid:gid - device ownership */
+			parse_chown_usergroup_or_die(&ugid, tokens[1]);
 
-		/* 3rd field: mode - device permissions */
-		mode = strtoul(tokens[2], NULL, 8);
+			/* 3rd field: mode - device permissions */
+			mode = strtoul(tokens[2], NULL, 8);
 
-		val = tokens[3];
-		/* 4th field (opt): >|=alias */
-# if ENABLE_FEATURE_MDEV_RENAME
-		if (!val)
-			goto line_matches;
-		aliaslink = val[0];
-		if (aliaslink == '>' || aliaslink == '=') {
-			char *a, *s, *st;
-#  if ENABLE_FEATURE_MDEV_RENAME_REGEXP
-			char *p;
-			unsigned i, n;
-#  endif
-			a = val;
-			s = strchrnul(val, ' ');
-			st = strchrnul(val, '\t');
-			if (st < s)
-				s = st;
-			val = (s[0] && s[1]) ? s+1 : NULL;
-			s[0] = '\0';
+			val = tokens[3];
+			/* 4th field (opt): >|=alias */
 
-#  if ENABLE_FEATURE_MDEV_RENAME_REGEXP
-			/* substitute %1..9 with off[1..9], if any */
-			n = 0;
-			s = a;
-			while (*s)
-				if (*s++ == '%')
-					n++;
+			if (ENABLE_FEATURE_MDEV_RENAME && val) {
+				aliaslink = val[0];
+				if (aliaslink == '>' || aliaslink == '=') {
+					char *a, *s, *st;
+					char *p;
+					unsigned i, n;
 
-			p = alias = xzalloc(strlen(a) + n * strlen(name));
-			s = a + 1;
-			while (*s) {
-				*p = *s;
-				if ('%' == *s) {
-					i = (s[1] - '0');
-					if (i <= 9 && off[i].rm_so >= 0) {
-						n = off[i].rm_eo - off[i].rm_so;
-						strncpy(p, name + off[i].rm_so, n);
-						p += n - 1;
-						s++;
+					a = val;
+					s = strchrnul(val, ' ');
+					st = strchrnul(val, '\t');
+					if (st < s)
+						s = st;
+					val = (s[0] && s[1]) ? s+1 : NULL;
+					s[0] = '\0';
+
+					if (ENABLE_FEATURE_MDEV_RENAME_REGEXP) {
+						/* substitute %1..9 with off[1..9], if any */
+						n = 0;
+						s = a;
+						while (*s)
+							if (*s++ == '%')
+								n++;
+
+						p = alias = xzalloc(strlen(a) + n * strlen(name));
+						s = a + 1;
+						while (*s) {
+							*p = *s;
+							if ('%' == *s) {
+								i = (s[1] - '0');
+								if (i <= 9 && off[i].rm_so >= 0) {
+									n = off[i].rm_eo - off[i].rm_so;
+									strncpy(p, name + off[i].rm_so, n);
+									p += n - 1;
+									s++;
+								}
+							}
+							p++;
+							s++;
+						}
+					} else {
+						alias = xstrdup(a + 1);
 					}
 				}
-				p++;
-				s++;
 			}
-#  else
-			alias = xstrdup(a + 1);
-#  endif
-		}
-# endif /* ENABLE_FEATURE_MDEV_RENAME */
 
-# if ENABLE_FEATURE_MDEV_EXEC
-		/* The rest (opt): @|$|*command */
-		if (!val)
-			goto line_matches;
-		{
-			const char *s = "@$*";
-			const char *s2 = strchr(s, val[0]);
+			if (ENABLE_FEATURE_MDEV_EXEC && val) {
+				const char *s = "$@*";
+				const char *s2 = strchr(s, val[0]);
 
-			if (!s2)
-				bb_error_msg_and_die("bad line %u", parser->lineno);
+				if (!s2)
+					bb_error_msg_and_die("bad line %u", parser->lineno);
 
-			/* Correlate the position in the "@$*" with the delete
-			 * step so that we get the proper behavior:
-			 * @cmd: run on create
-			 * $cmd: run on delete
-			 * *cmd: run on both
-			 */
-			if ((s2 - s + 1) /*1/2/3*/ & /*1/2*/ (1 + delete)) {
-				command = xstrdup(val + 1);
+				/* Are we running this command now?
+				 * Run $cmd on delete, @cmd on create, *cmd on both
+				 */
+				if (s2-s != delete)
+					command = xstrdup(val + 1);
 			}
 		}
-# endif
+
 		/* End of field parsing */
- line_matches:
-#endif /* ENABLE_FEATURE_MDEV_CONF */
 
 		/* "Execute" the line we found */
 
@@ -311,11 +291,11 @@
 				bb_perror_msg_and_die("mknod %s", device_name);
 			if (major == root_major && minor == root_minor)
 				symlink(device_name, "root");
-#if ENABLE_FEATURE_MDEV_CONF
-			chmod(device_name, mode);
-			chown(device_name, ugid.uid, ugid.gid);
-# if ENABLE_FEATURE_MDEV_RENAME
-			if (alias) {
+			if (ENABLE_FEATURE_MDEV_CONF) {
+				chmod(device_name, mode);
+				chown(device_name, ugid.uid, ugid.gid);
+			}
+			if (ENABLE_FEATURE_MDEV_RENAME && alias) {
 				alias = build_alias(alias, device_name);
 				/* move the device, and optionally
 				 * make a symlink to moved device node */
@@ -323,11 +303,9 @@
 					symlink(alias, device_name);
 				free(alias);
 			}
-# endif
-#endif
 		}
-#if ENABLE_FEATURE_MDEV_EXEC
-		if (command) {
+
+		if (ENABLE_FEATURE_MDEV_EXEC && command) {
 			/* setenv will leak memory, use putenv/unsetenv/free */
 			char *s = xasprintf("%s=%s", "MDEV", device_name);
 			char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem);
@@ -341,29 +319,29 @@
 			free(s);
 			free(command);
 		}
-#endif
+
 		if (delete) {
 			unlink(device_name);
 			/* At creation time, device might have been moved
 			 * and a symlink might have been created. Undo that. */
-#if ENABLE_FEATURE_MDEV_RENAME
-			if (alias) {
+
+			if (ENABLE_FEATURE_MDEV_RENAME && alias) {
 				alias = build_alias(alias, device_name);
 				unlink(alias);
 				free(alias);
 			}
-#endif
 		}
 
-#if ENABLE_FEATURE_MDEV_CONF
 		/* We found matching line.
 		 * Stop unless it was prefixed with '-' */
-		if (!keep_matching)
+		if (ENABLE_FEATURE_MDEV_CONF && !keep_matching)
 			break;
-	} /* end of "while line is read from /etc/mdev.conf" */
 
-	config_close(parser);
-#endif /* ENABLE_FEATURE_MDEV_CONF */
+	/* end of "while line is read from /etc/mdev.conf" */
+	} while (ENABLE_FEATURE_MDEV_CONF);
+
+	if (ENABLE_FEATURE_MDEV_CONF)
+		config_close(parser);
 }
 
 /* File callback for /sys/ traversal */
@@ -415,7 +393,7 @@
  * - userspace writes "0" (worked) or "-1" (failed) to /sys/$DEVPATH/loading
  * - kernel loads firmware into device
  */
-static void load_firmware(const char *const firmware, const char *const sysfs_path)
+static void load_firmware(const char *firmware, const char *sysfs_path)
 {
 	int cnt;
 	int firmware_fd, loading_fd, data_fd;
@@ -469,18 +447,8 @@
 
 	/* We can be called as hotplug helper */
 	/* Kernel cannot provide suitable stdio fds for us, do it ourself */
-#if 1
+
 	bb_sanitize_stdio();
-#else
-	/* Debug code */
-	/* Replace LOGFILE by other file or device name if you need */
-#define LOGFILE "/dev/console"
-	/* Just making sure fd 0 is not closed,
-	 * we don't really intend to read from it */
-	xmove_fd(xopen("/", O_RDONLY), STDIN_FILENO);
-	xmove_fd(xopen(LOGFILE, O_WRONLY|O_APPEND), STDOUT_FILENO);
-	xmove_fd(xopen(LOGFILE, O_WRONLY|O_APPEND), STDERR_FILENO);
-#endif
 
 	xchdir("/dev");
 

 ------------------------------------------------------------------------
r26152 | vapier | 2009-04-18 16:04:25 -0500 (Sat, 18 Apr 2009) | 1 line
Changed paths:
   M /trunk/busybox/shell/hush.c

fix build errors when function support is turned off
 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26151)
+++ shell/hush.c	(revision 26152)
@@ -2901,13 +2901,17 @@
 static int run_function(const struct function *funcp, char **argv)
 {
 	int rc;
+	save_arg_t sv;
+#if ENABLE_HUSH_FUNCTIONS
 	smallint sv_flg;
-	save_arg_t sv;
+#endif
 
 	save_and_replace_G_args(&sv, argv);
+#if ENABLE_HUSH_FUNCTIONS
 	/* "we are in function, ok to use return" */
 	sv_flg = G.flag_return_in_progress;
 	G.flag_return_in_progress = -1;
+#endif
 
 	/* On MMU, funcp->body is always non-NULL */
 #if !BB_MMU
@@ -2921,7 +2925,9 @@
 		rc = run_list(funcp->body);
 	}
 
+#if ENABLE_HUSH_FUNCTIONS
 	G.flag_return_in_progress = sv_flg;
+#endif
 	restore_G_args(&sv, argv);
 
 	return rc;
@@ -6775,8 +6781,10 @@
 static int builtin_source(char **argv)
 {
 	FILE *input;
+	save_arg_t sv;
+#if ENABLE_HUSH_FUNCTIONS
 	smallint sv_flg;
-	save_arg_t sv;
+#endif
 
 	if (*++argv == NULL)
 		return EXIT_FAILURE;
@@ -6789,16 +6797,20 @@
 	}
 	close_on_exec_on(fileno(input));
 
+#if ENABLE_HUSH_FUNCTIONS
 	sv_flg = G.flag_return_in_progress;
 	/* "we are inside sourced file, ok to use return" */
 	G.flag_return_in_progress = -1;
+#endif
 	save_and_replace_G_args(&sv, argv);
 
 	parse_and_run_file(input);
 	fclose(input);
 
 	restore_G_args(&sv, argv);
+#if ENABLE_HUSH_FUNCTIONS
 	G.flag_return_in_progress = sv_flg;
+#endif
 
 	return G.last_exitcode;
 }

 ------------------------------------------------------------------------
r26149 | vda | 2009-04-18 08:05:10 -0500 (Sat, 18 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: fix thinko in error msg


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26148)
+++ shell/hush.c	(revision 26149)
@@ -6430,7 +6430,6 @@
 
 static int builtin_trap(char **argv)
 {
-	int i;
 	int sig;
 	char *new_cmd;
 
@@ -6439,6 +6438,7 @@
 
 	argv++;
 	if (!*argv) {
+		int i;
 		/* No args: print all trapped */
 		for (i = 0; i < NSIG; ++i) {
 			if (G.traps[i]) {
@@ -6452,7 +6452,6 @@
 	}
 
 	new_cmd = NULL;
-	i = 0;
 	/* If first arg is a number: reset all specified signals */
 	sig = bb_strtou(*argv, NULL, 10);
 	if (errno == 0) {
@@ -6464,7 +6463,7 @@
 			if (sig < 0 || sig >= NSIG) {
 				ret = EXIT_FAILURE;
 				/* Mimic bash message exactly */
-				bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
+				bb_perror_msg("trap: %s: invalid signal specification", argv[-1]);
 				continue;
 			}
 
@@ -6488,8 +6487,8 @@
 					continue;
 				sigdelset(&G.blocked_set, sig);
 			}
-			sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
 		}
+		sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
 		return ret;
 	}
 

 ------------------------------------------------------------------------
r26148 | vda | 2009-04-18 07:58:19 -0500 (Sat, 18 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: fix "trap -- handler SIGs..."; escape handlers in "trap" output


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26147)
+++ shell/hush.c	(revision 26148)
@@ -3246,14 +3246,16 @@
 					fg_pipe->alive_cmds--;
 					if (i == fg_pipe->num_cmds - 1) {
 						/* last process gives overall exitstatus */
+						/* Note: is WIFSIGNALED, WEXITSTATUS = sig + 128 */
 						rcode = WEXITSTATUS(status);
 						IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
 						/* bash prints killing signal's name for *last*
 						 * process in pipe (prints just newline for SIGINT).
-						 * we just print newline for any sig:
+						 * Mimic this. Example: "sleep 5" + ^\
 						 */
 						if (WIFSIGNALED(status)) {
-							bb_putchar('\n');
+							int sig = WTERMSIG(status);
+							printf("%s\n", sig == SIGINT ? "" : get_signame(sig));
 						}
 					}
 				} else {
@@ -3489,6 +3491,7 @@
 					debug_printf_exec(": builtin '%s' '%s'...\n",
 						x->cmd, argv_expanded[1]);
 					rcode = x->function(argv_expanded) & 0xff;
+					fflush(NULL);
 				}
 #if ENABLE_HUSH_FUNCTIONS
 				else {
@@ -6251,81 +6254,6 @@
 /*
  * Built-ins
  */
-static int builtin_trap(char **argv)
-{
-	int i;
-	int sig;
-	char *new_cmd;
-
-	if (!G.traps)
-		G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
-
-	argv++;
-	if (!*argv) {
-		/* No args: print all trapped. This isn't 100% correct as we
-		 * should be escaping the cmd so that it can be pasted back in
-		 */
-		for (i = 0; i < NSIG; ++i)
-			if (G.traps[i])
-				printf("trap -- '%s' %s\n", G.traps[i], get_signame(i));
-		return EXIT_SUCCESS;
-	}
-
-	new_cmd = NULL;
-	i = 0;
-	/* If first arg is decimal: reset all specified signals */
-	sig = bb_strtou(*argv, NULL, 10);
-	if (errno == 0) {
-		int ret;
- set_all:
-		ret = EXIT_SUCCESS;
-		while (*argv) {
-			sig = get_signum(*argv++);
-			if (sig < 0 || sig >= NSIG) {
-				ret = EXIT_FAILURE;
-				/* Mimic bash message exactly */
-				bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
-				continue;
-			}
-
-			free(G.traps[sig]);
-			G.traps[sig] = xstrdup(new_cmd);
-
-			debug_printf("trap: setting SIG%s (%i) to '%s'",
-				get_signame(sig), sig, G.traps[sig]);
-
-			/* There is no signal for 0 (EXIT) */
-			if (sig == 0)
-				continue;
-
-			if (new_cmd) {
-				sigaddset(&G.blocked_set, sig);
-			} else {
-				/* There was a trap handler, we are removing it
-				 * (if sig has non-DFL handling,
-				 * we don't need to do anything) */
-				if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
-					continue;
-				sigdelset(&G.blocked_set, sig);
-			}
-			sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
-		}
-		return ret;
-	}
-
-	/* First arg is "-": reset all specified to default */
-	/* First arg is "": ignore all specified */
-	/* Everything else: execute first arg upon signal */
-	if (!argv[1]) {
-		bb_error_msg("trap: invalid arguments");
-		return EXIT_FAILURE;
-	}
-	if (NOT_LONE_DASH(*argv))
-		new_cmd = *argv;
-	argv++;
-	goto set_all;
-}
-
 static int builtin_true(char **argv UNUSED_PARAM)
 {
 	return 0;
@@ -6427,6 +6355,26 @@
 	hush_exit(xatoi(*argv) & 0xff);
 }
 
+static void print_escaped(const char *s)
+{
+	do {
+		if (*s != '\'') {
+			const char *p;
+
+			p = strchrnul(s, '\'');
+			/* print 'xxxx', possibly just '' */
+			printf("'%.*s'", (int)(p - s), s);
+			if (*p == '\0')
+				break;
+			s = p;
+		}
+		/* s points to '; print "'''...'''" */
+		putchar('"');
+		do putchar('\''); while (*++s == '\'');
+		putchar('"');
+	} while (*s);
+}
+
 static int builtin_export(char **argv)
 {
 	if (*++argv == NULL) {
@@ -6446,25 +6394,11 @@
 					continue;
 				/* export var= */
 				printf("export %.*s", (int)(p - s) + 1, s);
-				s = p + 1;
-				while (*s) {
-					if (*s != '\'') {
-						p = strchrnul(s, '\'');
-						/* print 'xxxx' */
-						printf("'%.*s'", (int)(p - s), s);
-						if (*p == '\0')
-							break;
-						s = p;
-					}
-					/* s points to '; print ''...'''" */
-					putchar('"');
-					do putchar('\''); while (*++s == '\'');
-					putchar('"');
-				}
+				print_escaped(p + 1);
 				putchar('\n');
 #endif
 			}
-			fflush(stdout);
+			/*fflush(stdout); - done after each builtin anyway */
 		}
 		return EXIT_SUCCESS;
 	}
@@ -6494,6 +6428,96 @@
 	return EXIT_SUCCESS;
 }
 
+static int builtin_trap(char **argv)
+{
+	int i;
+	int sig;
+	char *new_cmd;
+
+	if (!G.traps)
+		G.traps = xzalloc(sizeof(G.traps[0]) * NSIG);
+
+	argv++;
+	if (!*argv) {
+		/* No args: print all trapped */
+		for (i = 0; i < NSIG; ++i) {
+			if (G.traps[i]) {
+				printf("trap -- ");
+				print_escaped(G.traps[i]);
+				printf(" %s\n", get_signame(i));
+			}
+		}
+		/*fflush(stdout); - done after each builtin anyway */
+		return EXIT_SUCCESS;
+	}
+
+	new_cmd = NULL;
+	i = 0;
+	/* If first arg is a number: reset all specified signals */
+	sig = bb_strtou(*argv, NULL, 10);
+	if (errno == 0) {
+		int ret;
+ process_sig_list:
+		ret = EXIT_SUCCESS;
+		while (*argv) {
+			sig = get_signum(*argv++);
+			if (sig < 0 || sig >= NSIG) {
+				ret = EXIT_FAILURE;
+				/* Mimic bash message exactly */
+				bb_perror_msg("trap: %s: invalid signal specification", argv[i]);
+				continue;
+			}
+
+			free(G.traps[sig]);
+			G.traps[sig] = xstrdup(new_cmd);
+
+			debug_printf("trap: setting SIG%s (%i) to '%s'",
+				get_signame(sig), sig, G.traps[sig]);
+
+			/* There is no signal for 0 (EXIT) */
+			if (sig == 0)
+				continue;
+
+			if (new_cmd) {
+				sigaddset(&G.blocked_set, sig);
+			} else {
+				/* There was a trap handler, we are removing it
+				 * (if sig has non-DFL handling,
+				 * we don't need to do anything) */
+				if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
+					continue;
+				sigdelset(&G.blocked_set, sig);
+			}
+			sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
+		}
+		return ret;
+	}
+
+	if (!argv[1]) { /* no second arg */
+		bb_error_msg("trap: invalid arguments");
+		return EXIT_FAILURE;
+	}
+
+	/* First arg is "-": reset all specified to default */
+	/* First arg is "--": skip it, the rest is "handler SIGs..." */
+	/* Everything else: set arg as signal handler
+	 * (includes "" case, which ignores signal) */
+	if (argv[0][0] == '-') {
+		if (argv[0][1] == '\0') { /* "-" */
+			/* new_cmd remains NULL: "reset these sigs" */
+			goto reset_traps;
+		}
+		if (argv[0][1] == '-' && argv[0][2] == '\0') { /* "--" */
+			argv++;
+		}
+		/* else: "-something", no special meaning */
+	}
+	new_cmd = *argv;
+ reset_traps:
+	argv++;
+	goto process_sig_list;
+}
+
 #if ENABLE_HUSH_JOB
 /* built-in 'fg' and 'bg' handler */
 static int builtin_fg_bg(char **argv)

 ------------------------------------------------------------------------
r26147 | vda | 2009-04-18 06:35:16 -0500 (Sat, 18 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/acpid.c

acpid: prevent creation of zombies


 ------------------------------------------------------------------------

Index: util-linux/acpid.c
===================================================================
--- util-linux/acpid.c	(revision 26146)
+++ util-linux/acpid.c	(revision 26147)
@@ -78,8 +78,8 @@
 	// goto configuration directory
 	xchdir(opt_conf);
 
-//	// setup signals
-//	bb_signals(BB_FATAL_SIGS, record_signo);
+	// prevent zombies
+	signal(SIGCHLD, SIG_IGN);
 
 	// no explicit evdev files given? -> use proc event interface
 	if (!*argv) {

 ------------------------------------------------------------------------
r26146 | vda | 2009-04-18 06:25:18 -0500 (Sat, 18 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: fix thinko in unset_func


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26145)
+++ shell/hush.c	(revision 26146)
@@ -2863,6 +2863,7 @@
 			free(funcp);
 			break;
 		}
+		funcpp = &funcp->next;
 	}
 }
 

 ------------------------------------------------------------------------
r26145 | vda | 2009-04-18 06:23:38 -0500 (Sat, 18 Apr 2009) | 9 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: implement unset -f; beautify the handling of signal-killed pipe
 four TODOs are gone

function                                             old     new   delta
builtin_unset                                        271     364     +93
checkjobs                                            394     428     +34
builtin_exit                                          49      47      -2


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26144)
+++ shell/hush.c	(revision 26145)
@@ -1185,7 +1185,6 @@
 //			G.count_SIGCHLD++;
 //			break;
 		case SIGINT:
-//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C)
 			/* Builtin was ^C'ed, make it look prettier: */
 			bb_putchar('\n');
 			G.flag_SIGINT = 1;
@@ -2842,6 +2841,31 @@
 	return funcp;
 }
 
+static void unset_func(const char *name)
+{
+	struct function *funcp;
+	struct function **funcpp = &G.top_func;
+
+	while ((funcp = *funcpp) != NULL) {
+		if (strcmp(funcp->name, name) == 0) {
+			*funcpp = funcp->next;
+			/* funcp is unlinked now, deleting it */
+			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
+			}
+			free(funcp);
+			break;
+		}
+	}
+}
+
 #if BB_MMU
 #define exec_function(nommu_save, funcp, argv) \
 	exec_function(funcp, argv)
@@ -3223,6 +3247,13 @@
 						/* last process gives overall exitstatus */
 						rcode = WEXITSTATUS(status);
 						IF_HAS_KEYWORDS(if (fg_pipe->pi_inverted) rcode = !rcode;)
+						/* bash prints killing signal's name for *last*
+						 * process in pipe (prints just newline for SIGINT).
+						 * we just print newline for any sig:
+						 */
+						if (WIFSIGNALED(status)) {
+							bb_putchar('\n');
+						}
 					}
 				} else {
 					fg_pipe->cmds[i].is_stopped = 1;
@@ -6372,12 +6403,20 @@
 static int builtin_exit(char **argv)
 {
 	debug_printf_exec("%s()\n", __func__);
-// TODO: bash does it ONLY on top-level sh exit (+interacive only?)
-	//puts("exit"); /* bash does it */
-// TODO: warn if we have background jobs: "There are stopped jobs"
-// On second consecutive 'exit', exit anyway.
-// perhaps use G.exiting = -1 as indicator "last cmd was exit"
 
+	/* interactive bash:
+	 * # trap "echo EEE" EXIT
+	 * # exit
+	 * exit
+	 * There are stopped jobs.
+	 * (if there are _stopped_ jobs, running ones don't count)
+	 * # exit
+	 * exit
+	 # EEE (then bash exits)
+	 *
+	 * we can use G.exiting = -1 as indicator "last cmd was exit"
+	 */
+
 	/* note: EXIT trap is run by hush_exit */
 	if (*++argv == NULL)
 		hush_exit(G.last_exitcode);
@@ -6776,28 +6815,34 @@
 {
 	int ret;
 	char var;
+	char *arg;
 
 	if (!*++argv)
 		return EXIT_SUCCESS;
 
-	var = 'v';
-	if (argv[0][0] == '-') {
-		switch (argv[0][1]) {
-		case 'v':
-		case 'f':
-			var = argv[0][1];
-			break;
-		default:
-			bb_error_msg("unset: %s: invalid option", *argv);
-			return EXIT_FAILURE;
+	var = 0;
+	while ((arg = *argv) != NULL && arg[0] == '-') {
+		while (*++arg) {
+			switch (*arg) {
+			case 'v':
+			case 'f':
+				if (var == 0 || var == *arg) {
+					var = *arg;
+					break;
+				}
+				/* else: unset -vf, which is illegal.
+				 * fall through */
+			default:
+				bb_error_msg("unset: %s: invalid option", *argv);
+				return EXIT_FAILURE;
+			}
 		}
-//TODO: disallow "unset -vf ..." too
 		argv++;
 	}
 
 	ret = EXIT_SUCCESS;
 	while (*argv) {
-		if (var == 'v') {
+		if (var != 'f') {
 			if (unset_local_var(*argv)) {
 				/* unset  doesn't fail.
 				 * Error is when one tries to unset RO var.
@@ -6805,11 +6850,11 @@
 				ret = EXIT_FAILURE;
 			}
 		}
-//#if ENABLE_HUSH_FUNCTIONS
-//		else {
-//			unset_local_func(*argv);
-//		}
-//#endif
+#if ENABLE_HUSH_FUNCTIONS
+		else {
+			unset_func(*argv);
+		}
+#endif
 		argv++;
 	}
 	return ret;

 ------------------------------------------------------------------------
r26144 | vda | 2009-04-17 21:06:54 -0500 (Fri, 17 Apr 2009) | 6 lines
Changed paths:
   M /trunk/busybox/shell/ash.c
   M /trunk/busybox/shell/hush.c

hush: deal with umask TODO (symbolic modes)

function                                             old     new   delta
builtin_umask                                         79     125     +46


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26143)
+++ shell/hush.c	(revision 26144)
@@ -6742,24 +6742,33 @@
 
 static int builtin_umask(char **argv)
 {
-	mode_t new_umask;
-	const char *arg = argv[1];
-	if (arg) {
-//TODO: umask may take chmod-like symbolic masks
-		new_umask = bb_strtou(arg, NULL, 8);
-		if (errno) {
-			//Message? bash examples:
-			//bash: umask: 'q': invalid symbolic mode operator
-			//bash: umask: 999: octal number out of range
-			return EXIT_FAILURE;
+	int rc;
+	mode_t mask;
+
+	mask = umask(0);
+	if (argv[1]) {
+		mode_t old_mask = mask;
+
+		mask ^= 0777;
+		rc = bb_parse_mode(argv[1], &mask);
+		mask ^= 0777;
+		if (rc == 0) {
+			mask = old_mask;
+			/* bash messages:
+			 * bash: umask: 'q': invalid symbolic mode operator
+			 * bash: umask: 999: octal number out of range
+			 */
+			bb_error_msg("%s: '%s' invalid mode", argv[0], argv[1]);
 		}
 	} else {
-		new_umask = umask(0);
-		printf("%.3o\n", (unsigned) new_umask);
-		/* fall through and restore new_umask which we set to 0 */
+		rc = 1;
+		/* Mimic bash */
+		printf("%04o\n", (unsigned) mask);
+		/* fall through and restore mask which we set to 0 */
 	}
-	umask(new_umask);
-	return EXIT_SUCCESS;
+	umask(mask);
+
+	return !rc; /* rc != 0 - success */
 }
 
 /* http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#unset */
Index: shell/ash.c
===================================================================
--- shell/ash.c	(revision 26143)
+++ shell/ash.c	(revision 26144)
@@ -12646,6 +12646,8 @@
 		S_IROTH, S_IWOTH, S_IXOTH
 	};
 
+	/* TODO: use bb_parse_mode() instead */
+
 	char *ap;
 	mode_t mask;
 	int i;
@@ -12712,7 +12714,6 @@
  *
  * Public domain.
  */
-
 struct limits {
 	uint8_t cmd;          /* RLIMIT_xxx fit into it */
 	uint8_t factor_shift; /* shift by to get rlim_{cur,max} values */

 ------------------------------------------------------------------------
r26143 | vda | 2009-04-17 20:23:21 -0500 (Fri, 17 Apr 2009) | 8 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: implement proper SIGHUP handling

function                                             old     new   delta
check_and_run_traps                                  164     229     +65
insert_bg_job                                        376     366     -10
hush_main                                            937     927     -10


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26142)
+++ shell/hush.c	(revision 26143)
@@ -52,11 +52,10 @@
  *      grep for "TODO" and fix (some of them are easy)
  *      change { and } from special chars to reserved words
  *      $var refs in function do not pick up values set by "var=val func"
- *      builtins: return, ulimit
+ *      builtins: ulimit
  *      follow IFS rules more precisely, including update semantics
  *      figure out what to do with backslash-newline
  *      continuation lines, both explicit and implicit - done?
- *      SIGHUP handling
  *      separate job control from interactiveness
  *      (testcase: booting with init=/bin/hush does not show prompt (2009-04))
  *
@@ -1070,8 +1069,9 @@
  * "trap 'cmd' SIGxxx":
  *    set bit in blocked_set (even if 'cmd' is '')
  * after [v]fork, if we plan to be a shell:
- *    nothing for {} child shell (say, "true | { true; true; } | true")
- *    unset all traps if () shell.
+ *    unblock signals with special interactive handling
+ *    (child shell is not interactive),
+ *    unset all traps (note: regardless of child shell's type - {}, (), etc)
  * after [v]fork, if we plan to exec:
  *    POSIX says pending signal mask is cleared in child - no need to clear it.
  *    Restore blocked signal set to one inherited by shell just prior to exec.
@@ -1084,9 +1084,9 @@
 	SPECIAL_INTERACTIVE_SIGS = 0
 #if ENABLE_HUSH_JOB
 		| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
+		| (1 << SIGHUP)
 #endif
 		| (1 << SIGTERM)
-//TODO		| (1 << SIGHUP)
 		| (1 << SIGINT)
 };
 
@@ -1095,53 +1095,6 @@
 //	G.count_SIGCHLD++;
 //}
 
-static int check_and_run_traps(int sig)
-{
-	static const struct timespec zero_timespec = { 0, 0 };
-	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)
-			break;
- jump_in:
-		last_sig = 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 };
-				save_rcode = G.last_exitcode;
-				builtin_eval(argv);
-				free(argv[1]);
-				G.last_exitcode = save_rcode;
-			} /* else: "" trap, ignoring signal */
-			continue;
-		}
-		/* not a trap: special action */
-		switch (sig) {
-//		case SIGCHLD:
-//			G.count_SIGCHLD++;
-//			break;
-		case SIGINT:
-//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C)
-			/* Builtin was ^C'ed, make it look prettier: */
-			bb_putchar('\n');
-			G.flag_SIGINT = 1;
-			break;
-//TODO
-//		case SIGHUP: ...
-//			break;
-		default: /* ignored: */
-			/* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
-			break;
-		}
-	}
-	return last_sig;
-}
-
 #if ENABLE_HUSH_JOB
 
 /* After [v]fork, in child: do not restore tty pgrp on xfunc death */
@@ -1151,7 +1104,7 @@
 
 /* Restores tty foreground process group, and exits.
  * May be called as signal handler for fatal signal
- * (will faithfully resend signal to itself, producing correct exit state)
+ * (will resend signal to itself, producing correct exit state)
  * or called directly with -EXITCODE.
  * We also call it if xfunc is exiting. */
 static void sigexit(int sig) NORETURN;
@@ -1201,7 +1154,66 @@
 #endif
 }
 
+static int check_and_run_traps(int sig)
+{
+	static const struct timespec zero_timespec = { 0, 0 };
+	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)
+			break;
+ jump_in:
+		last_sig = 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 };
+				save_rcode = G.last_exitcode;
+				builtin_eval(argv);
+				free(argv[1]);
+				G.last_exitcode = save_rcode;
+			} /* else: "" trap, ignoring signal */
+			continue;
+		}
+		/* not a trap: special action */
+		switch (sig) {
+//		case SIGCHLD:
+//			G.count_SIGCHLD++;
+//			break;
+		case SIGINT:
+//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C)
+			/* Builtin was ^C'ed, make it look prettier: */
+			bb_putchar('\n');
+			G.flag_SIGINT = 1;
+			break;
+#if ENABLE_HUSH_JOB
+		case SIGHUP: {
+			struct pipe *job;
+			/* bash is observed to signal whole process groups,
+			 * not individual processes */
+			for (job = G.job_list; job; job = job->next) {
+				if (job->pgrp <= 0)
+					continue;
+				debug_printf_exec("HUPing pgrp %d\n", job->pgrp);
+				if (kill(- job->pgrp, SIGHUP) == 0)
+					kill(- job->pgrp, SIGCONT);
+			}
+			sigexit(SIGHUP);
+		}
+#endif
+		default: /* ignored: */
+			/* SIGTERM, SIGQUIT, SIGTTIN, SIGTTOU, SIGTSTP */
+			break;
+		}
+	}
+	return last_sig;
+}
+
+
 static const char *set_cwd(void)
 {
 	/* xrealloc_getcwd_or_warn(arg) calls free(arg),
@@ -2061,7 +2073,9 @@
 		case '`': /* `cmd */
 			*p = '\0';
 			arg++;
-//TODO: can we just stuff it into "output" directly?
+			/* 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);
 			process_command_subs(&subst_result, arg);
 			debug_printf_subst("SUBST RES '%s'\n", subst_result.data);
@@ -2777,7 +2791,8 @@
 		}
 		funcp = funcp->next;
 	}
-	debug_printf_exec("found function '%s'\n", name);
+	if (funcp)
+		debug_printf_exec("found function '%s'\n", name);
 	return funcp;
 }
 
@@ -2819,7 +2834,7 @@
 		}
 		goto skip;
 	}
-	debug_printf_exec("remembering new function '%s'\n", command->argv[0]);
+	debug_printf_exec("remembering new function '%s'\n", name);
 	funcp = *funcpp = xzalloc(sizeof(*funcp));
 	/*funcp->next = NULL;*/
  skip:
@@ -3059,8 +3074,11 @@
 	}
 
 	len = 0;
-	do len += strlen(*argv) + 1; while (*++argv);
-	pi->cmdtext = p = xmalloc(len);
+	do {
+		len += strlen(*argv) + 1;
+	} while (*++argv);
+	p = xmalloc(len);
+	pi->cmdtext = p;// = xmalloc(len);
 	argv = pi->cmds[0].argv;
 	do {
 		len = strlen(*argv);
@@ -3074,44 +3092,36 @@
 
 static void insert_bg_job(struct pipe *pi)
 {
-	struct pipe *thejob;
+	struct pipe *job, **jobp;
 	int i;
 
 	/* Linear search for the ID of the job to use */
 	pi->jobid = 1;
-	for (thejob = G.job_list; thejob; thejob = thejob->next)
-		if (thejob->jobid >= pi->jobid)
-			pi->jobid = thejob->jobid + 1;
+	for (job = G.job_list; job; job = job->next)
+		if (job->jobid >= pi->jobid)
+			pi->jobid = job->jobid + 1;
 
-	/* Add thejob to the list of running jobs */
-	if (!G.job_list) {
-		thejob = G.job_list = xmalloc(sizeof(*thejob));
-	} else {
-		for (thejob = G.job_list; thejob->next; thejob = thejob->next)
-			continue;
-		thejob->next = xmalloc(sizeof(*thejob));
-		thejob = thejob->next;
-	}
+	/* Add job to the list of running jobs */
+	jobp = &G.job_list;
+	while ((job = *jobp) != NULL)
+		jobp = &job->next;
+	job = *jobp = xmalloc(sizeof(*job));
 
-	/* Physically copy the struct job */
-	memcpy(thejob, pi, sizeof(struct pipe));
-	thejob->cmds = xzalloc(sizeof(pi->cmds[0]) * pi->num_cmds);
-	/* We cannot copy entire pi->cmds[] vector! Double free()s will happen */
+	*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++) {
-// TODO: do we really need to have so many fields which are just dead weight
-// at execution stage?
-		thejob->cmds[i].pid = pi->cmds[i].pid;
+		job->cmds[i].pid = pi->cmds[i].pid;
 		/* all other fields are not used and stay zero */
 	}
-	thejob->next = NULL;
-	thejob->cmdtext = xstrdup(get_cmdtext(pi));
+	job->cmdtext = xstrdup(get_cmdtext(pi));
 
-	/* We don't wait for background thejobs to return -- append it
-	   to the list of backgrounded thejobs and leave it alone */
 	if (G_interactive_fd)
-		printf("[%d] %d %s\n", thejob->jobid, thejob->cmds[0].pid, thejob->cmdtext);
-	G.last_bg_pid = thejob->cmds[0].pid;
-	G.last_jobid = thejob->jobid;
+		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;
 }
 
 static void remove_bg_job(struct pipe *pi)
@@ -3306,7 +3316,7 @@
  * 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.
+ * with run_list. If it isn't one of these, we fork and exec cmd.
  *
  * Cases when we must fork:
  * non-single:   cmd | cmd
@@ -3942,7 +3952,11 @@
 				check_and_run_traps(0);
 #if ENABLE_HUSH_JOB
 				if (G.run_list_level == 1)
+{
+debug_printf_exec("insert_bg_job1\n");
 					insert_bg_job(pi);
+debug_printf_exec("insert_bg_job2\n");
+}
 #endif
 				G.last_exitcode = rcode = EXIT_SUCCESS;
 				debug_printf_exec(": cmd&: exitcode EXIT_SUCCESS\n");
@@ -5853,11 +5867,10 @@
 	/* bash 3.2 seems to handle these just like 'fatal' ones */
 	maybe_set_to_sigexit(SIGPIPE);
 	maybe_set_to_sigexit(SIGALRM);
-//TODO: disable and move down when proper SIGHUP handling is added
-	maybe_set_to_sigexit(SIGHUP );
-	/* if we are interactive, [SIGHUP,] SIGTERM and SIGINT are masked.
+	/* if we are interactive, SIGHUP, SIGTERM and SIGINT are masked.
 	 * if we aren't interactive... but in this case
 	 * we never want to restore pgrp on exit, and this fn is not called */
+	/*maybe_set_to_sigexit(SIGHUP );*/
 	/*maybe_set_to_sigexit(SIGTERM);*/
 	/*maybe_set_to_sigexit(SIGINT );*/
 }
@@ -6350,7 +6363,7 @@
 #if !BB_MMU
 		nommu_save_t dummy;
 #endif
-// TODO: if exec fails, bash does NOT exit! We do...
+		/* TODO: if exec fails, bash does NOT exit! We do... */
 		pseudo_exec_argv(&dummy, argv, 0, NULL);
 		/* never returns */
 	}
@@ -6472,8 +6485,8 @@
 	bb_error_msg("%s: %d: no such job", argv[0], jobnum);
 	return EXIT_FAILURE;
  found:
-	// TODO: bash prints a string representation
-	// of job being foregrounded (like "sleep 1 | cat")
+	/* TODO: bash prints a string representation
+	 * of job being foregrounded (like "sleep 1 | cat") */
 	if (argv[0][0] == 'f') {
 		/* Put the job into the foreground.  */
 		tcsetpgrp(G_interactive_fd, pi->pgrp);
@@ -6705,7 +6718,7 @@
 	if (*++argv == NULL)
 		return EXIT_FAILURE;
 
-	/* TODO: search through $PATH is missing */
+// TODO: search through $PATH is missing
 	input = fopen_or_warn(*argv, "r");
 	if (!input) {
 		/* bb_perror_msg("%s", *argv); - done by fopen_or_warn */

 ------------------------------------------------------------------------
r26142 | vda | 2009-04-17 18:53:15 -0500 (Fri, 17 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

builtin_return's parameter is not unused


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26141)
+++ shell/hush.c	(revision 26142)
@@ -6904,7 +6904,7 @@
 #endif
 
 #if ENABLE_HUSH_FUNCTIONS
-static int builtin_return(char **argv UNUSED_PARAM)
+static int builtin_return(char **argv)
 {
 	int rc;
 

 ------------------------------------------------------------------------
r26141 | vda | 2009-04-17 18:44:18 -0500 (Fri, 17 Apr 2009) | 4 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   A /trunk/busybox/shell/hush_test/hush-misc/func3.right
   A /trunk/busybox/shell/hush_test/hush-misc/func3.tests

hush: return builtin by Bayram Kurumahmut (kbayram AT ubicom.com)
 ~+200 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26140)
+++ shell/hush.c	(revision 26141)
@@ -444,6 +444,13 @@
 #if ENABLE_HUSH_LOOPS
 	smallint flag_break_continue;
 #endif
+#if ENABLE_HUSH_FUNCTIONS
+	/* 0: outside of a function (or sourced file)
+	 * -1: inside of a function, ok to use return builtin
+	 * 1: return is invoked, skip all till end of func.
+	 */
+	smallint flag_return_in_progress;
+#endif
 	smallint fake_mode;
 	smallint exiting; /* used to prevent EXIT trap recursion */
 	/* These four support $?, $#, and $1 */
@@ -522,6 +529,9 @@
 static int builtin_break(char **argv);
 static int builtin_continue(char **argv);
 #endif
+#if ENABLE_HUSH_FUNCTIONS
+static int builtin_return(char **argv);
+#endif
 
 /* Table of built-in functions.  They can be forked or not, depending on
  * context: within pipes, they fork.  As simple commands, they do not.
@@ -575,7 +585,9 @@
 #endif
 	BLTIN("pwd"     , builtin_pwd     , "Print current directory"),
 	BLTIN("read"    , builtin_read    , "Input environment variable"),
-//	BLTIN("return"  , builtin_return  , "Return from a function"),
+#if ENABLE_HUSH_FUNCTIONS
+	BLTIN("return"  , builtin_return  , "Return from a function"),
+#endif
 	BLTIN("set"     , builtin_set     , "Set/unset shell local variables"),
 	BLTIN("shift"   , builtin_shift   , "Shift positional parameters"),
 	BLTIN("test"    , builtin_test    , "Test condition"),
@@ -2849,9 +2861,14 @@
 static int run_function(const struct function *funcp, char **argv)
 {
 	int rc;
+	smallint sv_flg;
 	save_arg_t sv;
 
 	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;
+
 	/* On MMU, funcp->body is always non-NULL */
 #if !BB_MMU
 	if (!funcp->body) {
@@ -2863,6 +2880,8 @@
 	{
 		rc = run_list(funcp->body);
 	}
+
+	G.flag_return_in_progress = sv_flg;
 	restore_G_args(&sv, argv);
 
 	return rc;
@@ -3886,7 +3905,8 @@
 #endif
 			rcode = r = run_pipe(pi); /* NB: rcode is a smallint */
 			if (r != -1) {
-				/* We only ran a builtin: rcode is already known
+				/* 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);
@@ -3910,6 +3930,10 @@
 					continue;
 				}
 #endif
+#if ENABLE_HUSH_FUNCTIONS
+				if (G.flag_return_in_progress == 1)
+					goto check_jobs_and_break;
+#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:
@@ -6675,6 +6699,7 @@
 static int builtin_source(char **argv)
 {
 	FILE *input;
+	smallint sv_flg;
 	save_arg_t sv;
 
 	if (*++argv == NULL)
@@ -6688,12 +6713,17 @@
 	}
 	close_on_exec_on(fileno(input));
 
-	/* Now run the file */
+	sv_flg = G.flag_return_in_progress;
+	/* "we are inside sourced file, ok to use return" */
+	G.flag_return_in_progress = -1;
 	save_and_replace_G_args(&sv, argv);
+
 	parse_and_run_file(input);
-	restore_G_args(&sv, argv);
 	fclose(input);
 
+	restore_G_args(&sv, argv);
+	G.flag_return_in_progress = sv_flg;
+
 	return G.last_exitcode;
 }
 
@@ -6833,25 +6863,36 @@
 	return ret;
 }
 
+#if ENABLE_HUSH_LOOPS || ENABLE_HUSH_FUNCTIONS
+static unsigned parse_numeric_argv1(char **argv, unsigned def, unsigned def_min)
+{
+	if (argv[1]) {
+		def = bb_strtou(argv[1], NULL, 10);
+		if (errno || def < def_min || argv[2]) {
+			bb_error_msg("%s: bad arguments", argv[0]);
+			def = UINT_MAX;
+		}
+	}
+	return def;
+}
+#endif
+
 #if ENABLE_HUSH_LOOPS
 static int builtin_break(char **argv)
 {
+	unsigned depth;
 	if (G.depth_of_loop == 0) {
 		bb_error_msg("%s: only meaningful in a loop", argv[0]);
 		return EXIT_SUCCESS; /* bash compat */
 	}
 	G.flag_break_continue++; /* BC_BREAK = 1 */
-	G.depth_break_continue = 1;
-	if (argv[1]) {
-		G.depth_break_continue = bb_strtou(argv[1], NULL, 10);
-		if (errno || !G.depth_break_continue || argv[2]) {
-			bb_error_msg("%s: bad arguments", argv[0]);
-			G.flag_break_continue = BC_BREAK;
-			G.depth_break_continue = UINT_MAX;
-		}
-	}
-	if (G.depth_of_loop < G.depth_break_continue)
+
+	G.depth_break_continue = depth = parse_numeric_argv1(argv, 1, 1);
+	if (depth == UINT_MAX)
+		G.flag_break_continue = BC_BREAK;
+	if (G.depth_of_loop < depth)
 		G.depth_break_continue = G.depth_of_loop;
+
 	return EXIT_SUCCESS;
 }
 
@@ -6861,3 +6902,27 @@
 	return builtin_break(argv);
 }
 #endif
+
+#if ENABLE_HUSH_FUNCTIONS
+static int builtin_return(char **argv UNUSED_PARAM)
+{
+	int rc;
+
+	if (G.flag_return_in_progress != -1) {
+		bb_error_msg("%s: not in a function or sourced script", argv[0]);
+		return EXIT_FAILURE; /* bash compat */
+	}
+
+	G.flag_return_in_progress = 1;
+
+	/* bash:
+	 * out of range: wraps around at 256, does not error out
+	 * non-numeric param:
+	 * f() { false; return qwe; }; f; echo $?
+	 * bash: return: qwe: numeric argument required  <== we do this
+	 * 255  <== we also do this
+	 */
+	rc = parse_numeric_argv1(argv, G.last_exitcode, 0);
+	return rc;
+}
+#endif
Index: shell/hush_test/hush-misc/func3.right
===================================================================
--- shell/hush_test/hush-misc/func3.right	(revision 0)
+++ shell/hush_test/hush-misc/func3.right	(revision 26141)
@@ -0,0 +1,4 @@
+One:1
+Zero:0
+One:1
+Five:5
Index: shell/hush_test/hush-misc/func3.tests
===================================================================
--- shell/hush_test/hush-misc/func3.tests	(revision 0)
+++ shell/hush_test/hush-misc/func3.tests	(revision 26141)
@@ -0,0 +1,8 @@
+f() { false; return; echo BAD; };
+{ f; echo One:$?; }; echo Zero:$?
+
+f() { false; return; };
+f; echo One:$?
+
+f() { return 5; };
+f; echo Five:$?

Property changes on: shell/hush_test/hush-misc/func3.tests
___________________________________________________________________
Name: svn:executable
   + *


 ------------------------------------------------------------------------
r26140 | vda | 2009-04-17 17:20:44 -0500 (Fri, 17 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/include/platform.h

fix move_to_unaligned32


 ------------------------------------------------------------------------

Index: include/platform.h
===================================================================
--- include/platform.h	(revision 26139)
+++ include/platform.h	(revision 26140)
@@ -173,7 +173,10 @@
 /* performs reasonably well (gcc usually inlines memcpy here) */
 #define move_from_unaligned16(v, u16p) (memcpy(&(v), (u16p), 2))
 #define move_from_unaligned32(v, u32p) (memcpy(&(v), (u32p), 4))
-#define move_to_unaligned32(u32p, v)   (memcpy((u32p), &(v), 4))
+#define move_to_unaligned32(u32p, v) do { \
+	uint32_t __t = (v); \
+	memcpy((u32p), &__t, 4); \
+} while (0)
 #endif
 
 /* ---- Networking ------------------------------------------ */

 ------------------------------------------------------------------------
r26139 | vda | 2009-04-17 16:56:02 -0500 (Fri, 17 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/applets/Kbuild

build system: remove some unnecessary rebuilds


 ------------------------------------------------------------------------

Index: applets/Kbuild
===================================================================
--- applets/Kbuild	(revision 26138)
+++ applets/Kbuild	(revision 26139)
@@ -13,18 +13,21 @@
 always:= $(hostprogs-y)
 
 # Generated files need additional love
+# NB: __srctree is either empty or "srctree/"
+# using it instead of srctree decreases amount of rebuilds
+# if tree is merely renamed/copied
 
-HOSTCFLAGS_usage.o = -I$(srctree)/include
+HOSTCFLAGS_usage.o = -I$(__srctree)include
 
 applets/applets.o: include/usage_compressed.h include/applet_tables.h
 
-applets/usage:         .config $(srctree)/applets/usage_compressed
+applets/usage:         .config $(__srctree)applets/usage_compressed
 applets/applet_tables: .config
 
 quiet_cmd_gen_usage_compressed = GEN     include/usage_compressed.h
-      cmd_gen_usage_compressed = $(srctree)/applets/usage_compressed include/usage_compressed.h applets
+      cmd_gen_usage_compressed = $(__srctree)applets/usage_compressed include/usage_compressed.h applets
 
-include/usage_compressed.h: applets/usage $(srctree)/applets/usage_compressed
+include/usage_compressed.h: applets/usage $(__srctree)applets/usage_compressed
 	$(call cmd,gen_usage_compressed)
 
 quiet_cmd_gen_applet_tables = GEN     include/applet_tables.h

 ------------------------------------------------------------------------
r26138 | vda | 2009-04-17 13:54:50 -0500 (Fri, 17 Apr 2009) | 11 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: set $n properly for "source" builtin

function                                             old     new   delta
restore_G_args                                         -      78     +78
save_and_replace_G_args                                -      64     +64
builtin_source                                        72     107     +35
run_list                                            2549    2367    -182
 ------------------------------------------------------------------------------

(add/remove: 2/0 grow/shrink: 1/1 up/down: 177/-182)           Total: -5 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26137)
+++ shell/hush.c	(revision 26138)
@@ -939,6 +939,52 @@
 }
 
 
+/* Helpers for setting new $n and restoring them back
+ */
+typedef struct save_arg_t {
+	char *sv_argv0;
+	char **sv_g_argv;
+	int sv_g_argc;
+	smallint sv_g_malloced;
+} save_arg_t;
+
+static void save_and_replace_G_args(save_arg_t *sv, char **argv)
+{
+	int n;
+
+	sv->sv_argv0 = argv[0];
+	sv->sv_g_argv = G.global_argv;
+	sv->sv_g_argc = G.global_argc;
+	sv->sv_g_malloced = G.global_args_malloced;
+
+	argv[0] = G.global_argv[0]; /* retain $0 */
+	G.global_argv = argv;
+	G.global_args_malloced = 0;
+
+	n = 1;
+	while (*++argv)
+		n++;
+	G.global_argc = n;
+}
+
+static void restore_G_args(save_arg_t *sv, char **argv)
+{
+	char **pp;
+
+	if (G.global_args_malloced) {
+		/* someone ran "set -- arg1 arg2 ...", undo */
+		pp = G.global_argv;
+		while (*++pp) /* note: does not free $0 */
+			free(*pp);
+		free(G.global_argv);
+	}
+	argv[0] = sv->sv_argv0;
+	G.global_argv = sv->sv_g_argv;
+	G.global_argc = sv->sv_g_argc;
+	G.global_args_malloced = sv->sv_g_malloced;
+}
+
+
 /* Basic theory of signal handling in shell
  * ========================================
  * This does not describe what hush does, rather, it is current understanding
@@ -2802,54 +2848,24 @@
 
 static int run_function(const struct function *funcp, char **argv)
 {
-	int n;
-	char **pp;
-	char *sv_argv0;
-	smallint sv_g_malloced;
-	int sv_g_argc;
-	char **sv_g_argv;
+	int rc;
+	save_arg_t sv;
 
-	sv_argv0 = argv[0];
-	sv_g_malloced = G.global_args_malloced;
-	sv_g_argc = G.global_argc;
-	sv_g_argv = G.global_argv;
-
-	pp = argv;
-	n = 1;
-	while (*++pp)
-		n++;
-
-	argv[0] = G.global_argv[0]; /* retain $0 */
-	G.global_args_malloced = 0;
-	G.global_argc = n;
-	G.global_argv = argv;
-
+	save_and_replace_G_args(&sv, argv);
 	/* 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);
-		n = G.last_exitcode;
+		rc = G.last_exitcode;
 	} else
 #endif
 	{
-		n = run_list(funcp->body);
+		rc = run_list(funcp->body);
 	}
+	restore_G_args(&sv, argv);
 
-	if (G.global_args_malloced) {
-		/* function ran "set -- arg1 arg2 ..." */
-		pp = G.global_argv;
-		while (*++pp)
-			free(*pp);
-		free(G.global_argv);
-	}
-
-	argv[0] = sv_argv0;
-	G.global_args_malloced = sv_g_malloced;
-	G.global_argc = sv_g_argc;
-	G.global_argv = sv_g_argv;
-
-	return n;
+	return rc;
 }
 #endif
 
@@ -6659,6 +6675,7 @@
 static int builtin_source(char **argv)
 {
 	FILE *input;
+	save_arg_t sv;
 
 	if (*++argv == NULL)
 		return EXIT_FAILURE;
@@ -6672,11 +6689,11 @@
 	close_on_exec_on(fileno(input));
 
 	/* Now run the file */
-	/* TODO: argv and argc are broken; need to save old G.global_argv
-	 * (pointer only is OK!) on this stack frame,
-	 * set G.global_argv=argv+1, recurse, and restore. */
+	save_and_replace_G_args(&sv, argv);
 	parse_and_run_file(input);
+	restore_G_args(&sv, argv);
 	fclose(input);
+
 	return G.last_exitcode;
 }
 

 ------------------------------------------------------------------------
r26135 | vda | 2009-04-17 09:35:43 -0500 (Fri, 17 Apr 2009) | 6 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: fix non-interactive response to pipe being stopped.

function                                             old     new   delta
checkjobs                                            380     394     +14


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26134)
+++ shell/hush.c	(revision 26135)
@@ -2863,7 +2863,7 @@
 
 /* Called after [v]fork() in run_pipe, or from builtin_exec.
  * Never returns.
- * XXX no exit() here.  If you don't exec, use _exit instead.
+ * 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,
@@ -3136,12 +3136,8 @@
  * [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]
  */
-
-//FIXME: non-interactive bash does not continue even if all processes in fg pipe
-//are stopped. Testcase: "cat | cat" in a script (not on command line)
-// + killall -STOP cat
-
  wait_more:
 	while (1) {
 		int i;
@@ -3175,7 +3171,6 @@
 				debug_printf_jobs("check pid %d\n", fg_pipe->cmds[i].pid);
 				if (fg_pipe->cmds[i].pid != childpid)
 					continue;
-				/* printf("process %d exit %d\n", i, WEXITSTATUS(status)); */
 				if (dead) {
 					fg_pipe->cmds[i].pid = 0;
 					fg_pipe->alive_cmds--;
@@ -3191,12 +3186,17 @@
 				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/stopped */
+					/* 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);
+						if (fg_pipe->alive_cmds)
+							insert_bg_job(fg_pipe);
 #endif
-					return rcode;
+						return rcode;
+					}
 				}
 				/* There are still running processes in the fg pipe */
 				goto wait_more; /* do waitpid again */
@@ -3400,10 +3400,10 @@
 					goto clean_up_and_ret1;
 				}
 			}
-			/* XXX setup_redirects acts on file descriptors, not FILEs.
+			/* setup_redirects acts on file descriptors, not FILEs.
 			 * This is perfect for work that comes after exec().
 			 * Is it really safe for inline use?  Experimentally,
-			 * things seem to work with glibc. */
+			 * things seem to work. */
 			rcode = setup_redirects(command, squirrel);
 			if (rcode == 0) {
 				new_env = expand_assignments(argv, command->assignment_cnt);
@@ -5026,7 +5026,7 @@
 		o_addchr(dest, SPECIAL_VAR_SYMBOL);
 		ch = i_getch(input);
 		nommu_addchr(as_string, ch);
-		/* XXX maybe someone will try to escape the '}' */
+		/* TODO: maybe someone will try to escape the '}' */
 		expansion = 0;
 		first_char = true;
 		all_digits = false;
@@ -5992,7 +5992,7 @@
 	/* If we are login shell... */
 	if (argv[0] && argv[0][0] == '-') {
 		FILE *input;
-		/* XXX what should argv be while sourcing /etc/profile? */
+		/* TODO: what should argv be while sourcing /etc/profile? */
 		debug_printf("sourcing /etc/profile\n");
 		input = fopen_for_read("/etc/profile");
 		if (input != NULL) {
@@ -6310,7 +6310,7 @@
 #if !BB_MMU
 		nommu_save_t dummy;
 #endif
-// FIXME: if exec fails, bash does NOT exit! We do...
+// TODO: if exec fails, bash does NOT exit! We do...
 		pseudo_exec_argv(&dummy, argv, 0, NULL);
 		/* never returns */
 	}
@@ -6663,7 +6663,7 @@
 	if (*++argv == NULL)
 		return EXIT_FAILURE;
 
-	/* XXX search through $PATH is missing */
+	/* TODO: search through $PATH is missing */
 	input = fopen_or_warn(*argv, "r");
 	if (!input) {
 		/* bb_perror_msg("%s", *argv); - done by fopen_or_warn */
@@ -6672,8 +6672,7 @@
 	close_on_exec_on(fileno(input));
 
 	/* Now run the file */
-//TODO:
-	/* XXX argv and argc are broken; need to save old G.global_argv
+	/* TODO: argv and argc are broken; need to save old G.global_argv
 	 * (pointer only is OK!) on this stack frame,
 	 * set G.global_argv=argv+1, recurse, and restore. */
 	parse_and_run_file(input);

 ------------------------------------------------------------------------
r26132 | vda | 2009-04-17 08:52:51 -0500 (Fri, 17 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: unblock TERM, INT, HUP in child shells too.


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26131)
+++ shell/hush.c	(revision 26132)
@@ -1022,6 +1022,15 @@
  * are to count SIGCHLDs [disabled - bug somewhere, + bloat]
  * and to restore tty pgrp on signal-induced exit.
  */
+enum {
+	SPECIAL_INTERACTIVE_SIGS = 0
+#if ENABLE_HUSH_JOB
+		| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
+#endif
+		| (1 << SIGTERM)
+//TODO		| (1 << SIGHUP)
+		| (1 << SIGINT)
+};
 
 //static void SIGCHLD_handler(int sig UNUSED_PARAM)
 //{
@@ -1059,6 +1068,8 @@
 //			G.count_SIGCHLD++;
 //			break;
 		case SIGINT:
+//TODO: add putchar('\n') also when we detect that child was killed (sleep 5 + ^C)
+			/* Builtin was ^C'ed, make it look prettier: */
 			bb_putchar('\n');
 			G.flag_SIGINT = 1;
 			break;
@@ -2284,37 +2295,46 @@
 
 static void reset_traps_to_defaults(void)
 {
-	enum {
-		JOBSIGS = (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
-	};
-	unsigned sig;
-
-	if (!G.traps && !(G.non_DFL_mask & JOBSIGS))
-		return;
-
-	/* This function is always called in a child shell.
+	/* This function is always called in a child shell
+	 * after fork (not vfork, NOMMU doesn't use this function).
 	 * 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.
 	 */
-	G.non_DFL_mask &= ~JOBSIGS;
-	sigdelset(&G.blocked_set, SIGTTIN);
-	sigdelset(&G.blocked_set, SIGTTOU);
-	sigdelset(&G.blocked_set, SIGTSTP);
+	unsigned sig;
+	unsigned mask;
 
-	if (G.traps) for (sig = 0; sig < NSIG; sig++) {
-		if (!G.traps[sig]) {
+	if (!G.traps && !(G.non_DFL_mask & SPECIAL_INTERACTIVE_SIGS))
+		return;
+
+	/* Stupid. It can be done with *single* &= op, but we can't use
+	 * the fact that G.blocked_set is implemented as a bitmask... */
+	mask = (SPECIAL_INTERACTIVE_SIGS >> 1);
+	sig = 1;
+	while (1) {
+		if (mask & 1)
+			sigdelset(&G.blocked_set, sig);
+		mask >>= 1;
+		if (!mask)
+			break;
+		sig++;
+	}
+
+	G.non_DFL_mask &= ~SPECIAL_INTERACTIVE_SIGS;
+	mask = G.non_DFL_mask;
+	if (G.traps) for (sig = 0; sig < NSIG; sig++, mask >>= 1) {
+		if (!G.traps[sig])
 			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 are removing it
-		 * (if sig has non-DFL handling,
-		 * we don't need to do anything) */
-		if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
+		/* There was a trap handler, we are removing it.
+		 * But if sig still has non-DFL handling,
+		 * we should not unblock it. */
+		if (mask & 1)
 			continue;
 		sigdelset(&G.blocked_set, sig);
 	}
@@ -5740,17 +5760,8 @@
 	unsigned mask;
 
 	mask = (1 << SIGQUIT);
-	if (G_interactive_fd) {
-		mask = 0
-			| (1 << SIGQUIT)
-			| (1 << SIGTERM)
-//TODO			| (1 << SIGHUP)
-#if ENABLE_HUSH_JOB
-			| (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
-#endif
-			| (1 << SIGINT)
-		;
-	}
+	if (G_interactive_fd)
+		mask = (1 << SIGQUIT) | SPECIAL_INTERACTIVE_SIGS;
 	G.non_DFL_mask = mask;
 
 	if (!second_time)

 ------------------------------------------------------------------------
r26131 | vda | 2009-04-17 06:55:42 -0500 (Fri, 17 Apr 2009) | 10 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: disallow "{echo hi; }" (require whitespace)
 and "{ echo hi }" (require semicolon or &)

function                                             old     new   delta
parse_stream                                        2098    2176     +78
done_command                                          98      84     -14
 ------------------------------------------------------------------------------

(add/remove: 0/0 grow/shrink: 1/1 up/down: 78/-14)             Total: 64 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26130)
+++ shell/hush.c	(revision 26131)
@@ -319,7 +319,11 @@
  */
 	struct redir_struct *redirects; /* I/O redirections */
 };
+/* Is there anything in this command at all? */
+#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 */
@@ -341,6 +345,9 @@
 	PIPE_OR  = 3,
 	PIPE_BG  = 4,
 } pipe_style;
+/* Is there anything in this pipe at all? */
+#define IS_NULL_PIPE(pi) \
+	((pi)->num_cmds == 0 IF_HAS_KEYWORDS( && (pi)->res_word == RES_NONE))
 
 /* This holds pointers to the various results of parsing */
 struct parse_context {
@@ -3971,8 +3978,10 @@
 	return pi;
 }
 
-/* Command (member of a pipe) is complete. The only possible error here
- * is out of memory, in which case xmalloc exits. */
+/* 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)
 {
 	/* The command is really already in the pipe structure, so
@@ -3981,13 +3990,9 @@
 	struct command *command = ctx->command;
 
 	if (command) {
-		if (command->group == NULL
-		 && command->argv == NULL
-		 && command->redirects == NULL
-		) {
+		if (IS_NULL_CMD(command)) {
 			debug_printf_parse("done_command: skipping null cmd, num_cmds=%d\n", pi->num_cmds);
-			memset(command, 0, sizeof(*command)); /* paranoia */
-			return pi->num_cmds;
+			goto clear_and_ret;
 		}
 		pi->num_cmds++;
 		debug_printf_parse("done_command: ++num_cmds=%d\n", pi->num_cmds);
@@ -3999,12 +4004,9 @@
 	/* 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));
-	command = &pi->cmds[pi->num_cmds];
+	ctx->command = command = &pi->cmds[pi->num_cmds];
+ clear_and_ret:
 	memset(command, 0, sizeof(*command));
-
-	ctx->command = command;
-	/* but ctx->pipe and ctx->list_head remain unchanged */
-
 	return pi->num_cmds; /* used only for 0/nonzero check */
 }
 
@@ -4024,9 +4026,7 @@
 
 	/* 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.
-	 * RES_NONE case is for "for a in; do ..." (empty IN set)
-	 * and other cases to work. */
+	 * IOW: it is safe to do it unconditionally. */
 	if (not_null
 #if ENABLE_HUSH_IF
 	 || ctx->ctx_res_w == RES_FI
@@ -4048,7 +4048,7 @@
 		ctx->pipe->next = new_p;
 		ctx->pipe = new_p;
 		/* RES_THEN, RES_DO etc are "sticky" -
-		 * they remain set for commands inside if/while.
+		 * 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):
@@ -4304,7 +4304,7 @@
 		 && ctx->ctx_res_w != RES_IN
 # endif
 		) {
-			debug_printf_parse(": checking '%s' for reserved-ness\n", word->data);
+			debug_printf_parse("checking '%s' for reserved-ness\n", word->data);
 			if (reserved_word(word, ctx)) {
 				o_reset_to_empty_unquoted(word);
 				debug_printf_parse("done_word return %d\n",
@@ -4775,6 +4775,14 @@
 	if (ch == '(') {
 		endch = ')';
 		command->grp_type = GRP_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;
+		}
+		nommu_addchr(&ctx->as_string, ch);
 	}
 
 	{
@@ -5352,13 +5360,11 @@
 		if (end_trigger && end_trigger == ch
 		 && (heredoc_cnt == 0 || end_trigger != ';')
 		) {
-//TODO: disallow "{ cmd }" without semicolon
 			if (heredoc_cnt) {
 				/* This is technically valid:
 				 * { cat <
 ------------------------------------------------------------------------
r26127 | vda | 2009-04-16 19:01:04 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/mdev.c

mdev: add large comment, fix a buglet with subsystem and /sys/block


 ------------------------------------------------------------------------

Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26126)
+++ util-linux/mdev.c	(revision 26127)
@@ -10,6 +10,41 @@
 #include "libbb.h"
 #include "xregex.h"
 
+/* "mdev -s" scans /sys/class/xxx, looking for directories which have dev
+ * file (it is of the form "M:m\n"). Example: /sys/class/tty/tty0/dev
+ * contains "4:0\n". Directory name is taken as device name, path component
+ * directly after /sys/class/ as subsystem. In this example, "tty0" and "tty".
+ * Then mdev creates the /dev/device_name node.
+ *
+ * mdev w/o parameters is called as hotplug helper. It takes device
+ * and subsystem names from $DEVPATH and $SUBSYSTEM, extracts
+ * maj,min from "/sys/$DEVPATH/dev" and also examines
+ * $ACTION ("add"/"delete") and $FIRMWARE.
+ *
+ * If action is "add", mdev creates /dev/device_name similarly to mdev -s.
+ * (todo: explain "delete" and $FIRMWARE)
+ *
+ * If /etc/mdev.conf exists, it may modify /dev/device_name's properties.
+ * /etc/mdev.conf file format:
+ *
+ * [-][subsystem/]device  user:grp  mode  [>|=path] [@|$|*command args...]
+ * [-]@maj,min[-min2]     user:grp  mode  [>|=path] [@|$|*command args...]
+ *
+ * The device name or "subsystem/device" combo is matched against 1st field
+ * (which is a regex), or maj,min is matched against 1st field.
+ *
+ * Leading minus in 1st field means "don't stop on this line", otherwise
+ * search is stopped after the matching line is encountered.
+ *
+ * When line matches, the device node is created, chmod'ed and chown'ed.
+ * Then it moved to path, and if >path, a symlink to moved node is created
+ *    Examples:
+ *    =loop/      - moves to /dev/loop
+ *    >disk/sda%1 - moves to /dev/disk/sdaN, makes /dev/sdaN a symlink
+ * Then "command args" is executed (via sh -c 'command args').
+ * @:execute on creation, $:on deletion, *:on both.
+ */
+
 struct globals {
 	int root_major, root_minor;
 	char *subsystem;
@@ -96,8 +131,11 @@
 	if (strstr(path, "/block/"))
 		type = S_IFBLK;
 
-	/* Make path point to subsystem/device_name */
-	path += sizeof("/sys/class/") - 1;
+	/* Make path point to "subsystem/device_name" */
+	if (path[5] == 'b') /* legacy /sys/block? */
+		path += sizeof("/sys/") - 1;
+	else
+		path += sizeof("/sys/class/") - 1;
 
 #if !ENABLE_FEATURE_MDEV_CONF
 	mode = 0660;
@@ -131,8 +169,8 @@
 		keep_matching = ('-' == val[0]);
 		val += keep_matching; /* swallow leading dash */
 
-		/* Match against either subsystem/device_name
-		 * or device_name alone */
+		/* Match against either "subsystem/device_name"
+		 * or "device_name" alone */
 		name = strchr(val, '/') ? path : (char *) device_name;
 
 		/* Fields: regex uid:gid mode [alias] [cmd] */

 ------------------------------------------------------------------------
r26126 | vda | 2009-04-16 18:05:59 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/scripts/defconfig

disable FLASH_ERASEALL in defconfig


 ------------------------------------------------------------------------

Index: scripts/defconfig
===================================================================
--- scripts/defconfig	(revision 26125)
+++ scripts/defconfig	(revision 26126)
@@ -579,7 +579,7 @@
 CONFIG_EJECT=y
 CONFIG_FEATURE_EJECT_SCSI=y
 CONFIG_FBSPLASH=y
-CONFIG_FLASH_ERASEALL=y
+# CONFIG_FLASH_ERASEALL is not set
 CONFIG_IONICE=y
 # CONFIG_INOTIFYD is not set
 CONFIG_LAST=y

 ------------------------------------------------------------------------
r26125 | vda | 2009-04-16 17:42:01 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/testsuite/mdev.tests
   M /trunk/busybox/util-linux/mdev.c

mdev: set mode, needed when device node already exists.


 ------------------------------------------------------------------------

Index: testsuite/mdev.tests
===================================================================
--- testsuite/mdev.tests	(revision 26124)
+++ testsuite/mdev.tests	(revision 26125)
@@ -49,6 +49,18 @@
 
 # continuing to use directory structure from prev test
 rm -rf mdev.testdir/dev/*
+echo "-.* 1:1 666" >mdev.testdir/etc/mdev.conf
+echo "sda 2:2 444" >>mdev.testdir/etc/mdev.conf
+testing "mdev does not stop on dash-rule" \
+	"env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
+	ls -ln mdev.testdir/dev | $FILTER_LS" \
+"\
+br--r--r-- 1 2 2 8,0 sda
+" \
+	"" ""
+
+# continuing to use directory structure from prev test
+rm -rf mdev.testdir/dev/*
 echo "sda 0:0 444 >disk/scsiA" >mdev.testdir/etc/mdev.conf
 testing "mdev move/symlink rule '>bar/baz'" \
 	"env - PATH=$PATH ACTION=add DEVPATH=/block/sda chroot mdev.testdir /mdev 2>&1;
Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26124)
+++ util-linux/mdev.c	(revision 26125)
@@ -274,6 +274,7 @@
 			if (major == root_major && minor == root_minor)
 				symlink(device_name, "root");
 #if ENABLE_FEATURE_MDEV_CONF
+			chmod(device_name, mode);
 			chown(device_name, ugid.uid, ugid.gid);
 # if ENABLE_FEATURE_MDEV_RENAME
 			if (alias) {

 ------------------------------------------------------------------------
r26124 | vda | 2009-04-16 16:42:12 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/util-linux/mdev.c

mdev: change subsystem syntax from /subsystem to subsystem/devname


 ------------------------------------------------------------------------

Index: util-linux/mdev.c
===================================================================
--- util-linux/mdev.c	(revision 26123)
+++ util-linux/mdev.c	(revision 26124)
@@ -90,21 +90,24 @@
 	device_name = bb_basename(path);
 	/* http://kernel.org/doc/pending/hotplug.txt says that only
 	 * "/sys/block/..." is for block devices. "/sys/bus" etc is not.
-	 * But since 2.6.25 block devices are also in /sys/class/block.
-	 * We use strstr("/block/") to forestall future surprises. */
+	 * But since 2.6.25 block devices are also in /sys/class/block,
+	 * we use strstr("/block/") to forestall future surprises. */
 	type = S_IFCHR;
 	if (strstr(path, "/block/"))
 		type = S_IFBLK;
 
+	/* Make path point to subsystem/device_name */
+	path += sizeof("/sys/class/") - 1;
+
 #if !ENABLE_FEATURE_MDEV_CONF
 	mode = 0660;
 #else
 	/* If we have config file, look up user settings */
 	parser = config_open2("/etc/mdev.conf", fopen_for_read);
 	while (1) {
-		regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP];
+		regmatch_t off[1 + 9 * ENABLE_FEATURE_MDEV_RENAME_REGEXP];
 		int keep_matching;
-		char *val;
+		char *val, *name;
 		struct bb_uidgid_t ugid;
 		char *tokens[4];
 # if ENABLE_FEATURE_MDEV_EXEC
@@ -128,6 +131,10 @@
 		keep_matching = ('-' == val[0]);
 		val += keep_matching; /* swallow leading dash */
 
+		/* Match against either subsystem/device_name
+		 * or device_name alone */
+		name = strchr(val, '/') ? path : (char *) device_name;
+
 		/* Fields: regex uid:gid mode [alias] [cmd] */
 
 		/* 1st field: @... */
@@ -149,15 +156,10 @@
 		} else { /* ... or regex to match device name */
 			regex_t match;
 			int result;
-			const char *dev_name_or_subsystem = device_name;
-			if ('/' == val[0] && subsystem) {
-				dev_name_or_subsystem = subsystem;
-				val++;
-			}
 
 			/* Is this it? */
 			xregcomp(&match, val, REG_EXTENDED);
-			result = regexec(&match, dev_name_or_subsystem, ARRAY_SIZE(off), off, 0);
+			result = regexec(&match, name, ARRAY_SIZE(off), off, 0);
 			regfree(&match);
 
 			//bb_error_msg("matches:");
@@ -171,7 +173,7 @@
 			/* If not this device, skip rest of line */
 			/* (regexec returns whole pattern as "range" 0) */
 			if (result || off[0].rm_so
-			 || ((int)off[0].rm_eo != (int)strlen(dev_name_or_subsystem))
+			 || ((int)off[0].rm_eo != (int)strlen(name))
 			) {
 				continue; /* this line doesn't match */
 			}
@@ -214,7 +216,7 @@
 				if (*s++ == '%')
 					n++;
 
-			p = alias = xzalloc(strlen(a) + n * strlen(device_name));
+			p = alias = xzalloc(strlen(a) + n * strlen(name));
 			s = a + 1;
 			while (*s) {
 				*p = *s;
@@ -222,7 +224,7 @@
 					i = (s[1] - '0');
 					if (i <= 9 && off[i].rm_so >= 0) {
 						n = off[i].rm_eo - off[i].rm_so;
-						strncpy(p, device_name + off[i].rm_so, n);
+						strncpy(p, name + off[i].rm_so, n);
 						p += n - 1;
 						s++;
 					}

 ------------------------------------------------------------------------
r26123 | vda | 2009-04-16 15:04:09 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/examples/udhcp/simple.script

update example udhcpc script


 ------------------------------------------------------------------------

Index: examples/udhcp/simple.script
===================================================================
--- examples/udhcp/simple.script	(revision 26122)
+++ examples/udhcp/simple.script	(revision 26123)
@@ -5,35 +5,42 @@
 [ -z "$1" ] && echo "Error: should be called from udhcpc" && exit 1
 
 RESOLV_CONF="/etc/resolv.conf"
+NETMASK=""
+[ -n "$subnet" ] && NETMASK="netmask $subnet"
+BROADCAST="broadcast +"
 [ -n "$broadcast" ] && BROADCAST="broadcast $broadcast"
-[ -n "$subnet" ] && NETMASK="netmask $subnet"
 
 case "$1" in
 	deconfig)
-		/sbin/ifconfig $interface 0.0.0.0
+		echo "Setting IP address 0.0.0.0 on $interface"
+		ifconfig $interface 0.0.0.0
 		;;
 
 	renew|bound)
-		/sbin/ifconfig $interface $ip $BROADCAST $NETMASK
+		echo "Setting IP address $ip on $interface"
+		ifconfig $interface $ip $NETMASK $BROADCAST
 
 		if [ -n "$router" ] ; then
-			echo "deleting routers"
+			echo "Deleting routers"
 			while route del default gw 0.0.0.0 dev $interface ; do
 				:
 			done
 
 			metric=0
 			for i in $router ; do
+				echo "Adding router $i"
 				route add default gw $i dev $interface metric $((metric++))
 			done
 		fi
 
-		echo -n > $RESOLV_CONF
-		[ -n "$domain" ] && echo search $domain >> $RESOLV_CONF
+		echo "Recreating $RESOLV_CONF"
+		echo -n > $RESOLV_CONF-$$
+		[ -n "$domain" ] && echo search $domain >> $RESOLV_CONF-$$
 		for i in $dns ; do
-			echo adding dns $i
-			echo nameserver $i >> $RESOLV_CONF
+			echo " Adding DNS server $i"
+			echo nameserver $i >> $RESOLV_CONF-$$
 		done
+		mv $RESOLV_CONF-$$ $RESOLV_CONF
 		;;
 esac
 

 ------------------------------------------------------------------------
r26122 | vda | 2009-04-16 07:00:15 -0500 (Thu, 16 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: add a TODO


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26121)
+++ shell/hush.c	(revision 26122)
@@ -51,6 +51,7 @@
  * TODOs:
  *      grep for "TODO" and fix (some of them are easy)
  *      change { and } from special chars to reserved words
+ *      $var refs in function do not pick up values set by "var=val func"
  *      builtins: return, ulimit
  *      follow IFS rules more precisely, including update semantics
  *      figure out what to do with backslash-newline

 ------------------------------------------------------------------------
r26121 | vda | 2009-04-16 05:59:40 -0500 (Thu, 16 Apr 2009) | 7 lines
Changed paths:
   M /trunk/busybox/shell/hush.c
   A /trunk/busybox/shell/hush_test/hush-parsing/groups_and_keywords1.right
   A /trunk/busybox/shell/hush_test/hush-parsing/groups_and_keywords1.tests
   M /trunk/busybox/shell/hush_test/hush-vars/param_glob.tests

hush: fix "if { echo foo; } then { echo bar; } fi" parsing

function                                             old     new   delta
done_word                                            728     793     +65
parse_stream                                        2084    2098     +14


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26120)
+++ shell/hush.c	(revision 26121)
@@ -4154,6 +4154,8 @@
 	}
 	return NULL;
 }
+/* Return 0: not a keyword, 1: keyword
+ */
 static int reserved_word(o_string *word, struct parse_context *ctx)
 {
 #if ENABLE_HUSH_CASE
@@ -4163,6 +4165,8 @@
 #endif
 	const struct reserved_combo *r;
 
+	if (word->o_quoted)
+		return 0;
 	r = match_reserved_word(word);
 	if (!r)
 		return 0;
@@ -4177,13 +4181,14 @@
 	if (r->flag == 0) { /* '!' */
 		if (ctx->ctx_inverted) { /* bash doesn't accept '! ! true' */
 			syntax_error("! ! command");
-			IF_HAS_KEYWORDS(ctx->ctx_res_w = RES_SNTX;)
+			ctx->ctx_res_w = RES_SNTX;
 		}
 		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 */
@@ -4193,11 +4198,21 @@
 		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);
 	}
+
 	ctx->ctx_res_w = r->res;
 	ctx->old_flag = r->flag;
+	word->o_assignment = r->assignment_flag;
+
 	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;
@@ -4213,7 +4228,6 @@
 		*ctx = *old;   /* physical copy */
 		free(old);
 	}
-	word->o_assignment = r->assignment_flag;
 	return 1;
 }
 #endif
@@ -4273,19 +4287,6 @@
 			word->o_assignment = MAYBE_ASSIGNMENT;
 		}
 
-		if (command->group) {
-			/* "{ echo foo; } echo bar" - bad */
-			/* NB: bash allows e.g.:
-			 * if true; then { echo foo; } fi
-			 * while if false; then false; fi do break; done
-			 * and disallows:
-			 * while if false; then false; fi; do; break; done
-			 * TODO? */
-			syntax_error_at(word->data);
-			debug_printf_parse("done_word return 1: syntax error, "
-					"groups and arglists don't mix\n");
-			return 1;
-		}
 #if HAS_KEYWORDS
 # if ENABLE_HUSH_CASE
 		if (ctx->ctx_dsemicolon
@@ -4311,6 +4312,13 @@
 			}
 		}
 #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 (word->o_quoted /* word had "xx" or 'xx' at least as part of it. */
 		 /* optimization: and if it's ("" or '') or ($v... or `cmd`...): */
 		 && (word->data[0] == '\0' || word->data[0] == SPECIAL_VAR_SYMBOL)
@@ -4720,7 +4728,8 @@
 #if ENABLE_HUSH_FUNCTIONS
 	if (ch == '(' && !dest->o_quoted) {
 		if (dest->length)
-			done_word(dest, ctx);
+			if (done_word(dest, ctx))
+				return 1;
 		if (!command->argv)
 			goto skip; /* (... */
 		if (command->argv[1]) { /* word word ... (... */
@@ -4778,10 +4787,10 @@
 #endif
 		/* empty ()/{} or parse error? */
 		if (!pipe_list || pipe_list == ERR_PTR) {
+			/* parse_stream already emitted error msg */
 #if !BB_MMU
 			free(as_string);
 #endif
-			syntax_error(NULL);
 			debug_printf_parse("parse_group return 1: "
 				"parse_stream returned %p\n", pipe_list);
 			return 1;
Index: shell/hush_test/hush-vars/param_glob.tests
===================================================================
--- shell/hush_test/hush-vars/param_glob.tests	(revision 26120)
+++ shell/hush_test/hush-vars/param_glob.tests	(revision 26121)
@@ -1,5 +1,5 @@
 if test $# = 0; then
-    #BUG in builtin_exec! will glob param!
+    # UNFIXED BUG in builtin_exec! will glob param!
     #exec "$THIS_SH" "$0" 'param_glob.t*'
     "$THIS_SH" "$0" 'param_glob.t*'
     exit
Index: shell/hush_test/hush-parsing/groups_and_keywords1.right
===================================================================
--- shell/hush_test/hush-parsing/groups_and_keywords1.right	(revision 0)
+++ shell/hush_test/hush-parsing/groups_and_keywords1.right	(revision 26121)
@@ -0,0 +1,11 @@
+Semicolons after } can be omitted 1:
+foo
+bar
+Semicolons after } can be omitted 2:
+foo
+bar
+Semicolons after fi can be omitted:
+foo
+bar
+baz
+Done:0
Index: shell/hush_test/hush-parsing/groups_and_keywords1.tests
===================================================================
--- shell/hush_test/hush-parsing/groups_and_keywords1.tests	(revision 0)
+++ shell/hush_test/hush-parsing/groups_and_keywords1.tests	(revision 26121)
@@ -0,0 +1,10 @@
+echo "Semicolons after } can be omitted 1:"
+if { echo foo; } then { echo bar; } fi
+
+echo "Semicolons after } can be omitted 2:"
+while { echo foo; } do { echo bar; break; } done
+
+echo "Semicolons after fi can be omitted:"
+while if echo foo; then echo bar; fi do echo baz; break; done
+
+echo Done:$?

Property changes on: shell/hush_test/hush-parsing/groups_and_keywords1.tests
___________________________________________________________________
Name: svn:executable
   + *


 ------------------------------------------------------------------------
r26120 | vda | 2009-04-15 18:29:44 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: stop ignoring ^Z in child shells


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26119)
+++ shell/hush.c	(revision 26120)
@@ -2276,15 +2276,28 @@
 
 static void reset_traps_to_defaults(void)
 {
+	enum {
+		JOBSIGS = (1 << SIGTTIN) | (1 << SIGTTOU) | (1 << SIGTSTP)
+	};
 	unsigned sig;
-	int dirty;
 
-	if (!G.traps)
+	if (!G.traps && !(G.non_DFL_mask & JOBSIGS))
 		return;
-	dirty = 0;
-	for (sig = 0; sig < NSIG; sig++) {
-		if (!G.traps[sig])
+
+	/* This function is always called in a child shell.
+	 * Child shells are not interactive.
+	 * SIGTTIN/SIGTTOU/SIGTSTP should not have special handling.
+	 * Testcase: (while :; do :; done) + ^Z should background.
+	 */
+	G.non_DFL_mask &= ~JOBSIGS;
+	sigdelset(&G.blocked_set, SIGTTIN);
+	sigdelset(&G.blocked_set, SIGTTOU);
+	sigdelset(&G.blocked_set, SIGTSTP);
+
+	if (G.traps) for (sig = 0; sig < NSIG; sig++) {
+		if (!G.traps[sig]) {
 			continue;
+		}
 		free(G.traps[sig]);
 		G.traps[sig] = NULL;
 		/* There is no signal for 0 (EXIT) */
@@ -2296,10 +2309,8 @@
 		if (sig < 32 && (G.non_DFL_mask & (1 << sig)))
 			continue;
 		sigdelset(&G.blocked_set, sig);
-		dirty = 1;
 	}
-	if (dirty)
-		sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
+	sigprocmask(SIG_SETMASK, &G.blocked_set, NULL);
 }
 
 #else /* !BB_MMU */

 ------------------------------------------------------------------------
r26119 | vda | 2009-04-15 18:29:00 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: remove old disabled ^Z handling


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26118)
+++ shell/hush.c	(revision 26119)
@@ -56,7 +56,6 @@
  *      figure out what to do with backslash-newline
  *      continuation lines, both explicit and implicit - done?
  *      SIGHUP handling
- *      ^Z handling (and explain it in comments for mere humans)
  *      separate job control from interactiveness
  *      (testcase: booting with init=/bin/hush does not show prompt (2009-04))
  *
@@ -432,7 +431,6 @@
 	int last_jobid;
 	struct pipe *job_list;
 	struct pipe *toplevel_list;
-////	smallint ctrl_z_flag;
 #endif
 	smallint flag_SIGINT;
 #if ENABLE_HUSH_LOOPS
@@ -474,12 +472,6 @@
 	int debug_indent;
 #endif
 	char user_input_buf[ENABLE_FEATURE_EDITING ? BUFSIZ : 2];
-#if ENABLE_FEATURE_SH_STANDALONE
-	struct nofork_save_area nofork_save;
-#endif
-#if ENABLE_HUSH_JOB
-	sigjmp_buf toplevel_jb;
-#endif
 };
 #define G (*ptr_to_globals)
 /* Not #defining name to G.name - this quickly gets unwieldy
@@ -977,13 +969,14 @@
  * SIGHUP (interactive):
  *    send SIGCONT to stopped jobs, send SIGHUP to all jobs and exit
  * SIGTTIN, SIGTTOU, SIGTSTP (if job control is on): ignore
- *    (note that ^Z is handled not by trapping SIGTSTP, but by seeing
- *    that all pipe members are stopped) (right?)
+ *    Note that ^Z is handled not by trapping SIGTSTP, but by seeing
+ *    that all pipe members are stopped. Try this in bash:
+ *    while :; do :; done - ^Z does not background it
+ *    (while :; do :; done) - ^Z backgrounds it
  * SIGINT (interactive): wait for last pipe, ignore the rest
  *    of the command line, show prompt. NB: ^C does not send SIGINT
  *    to interactive shell while shell is waiting for a pipe,
  *    since shell is bg'ed (is not in foreground process group).
- *    (check/expand this)
  *    Example 1: this waits 5 sec, but does not execute ls:
  *    "echo $$; sleep 5; ls -l" + "kill -INT "
  *    Example 2: this does not wait and does not execute ls:
@@ -3411,12 +3404,11 @@
 		if (i >= 0 && APPLET_IS_NOFORK(i)) {
 			rcode = setup_redirects(command, squirrel);
 			if (rcode == 0) {
-				save_nofork_data(&G.nofork_save);
 				new_env = expand_assignments(argv, command->assignment_cnt);
 				old_env = putenv_all_and_save_old(new_env);
 				debug_printf_exec(": run_nofork_applet '%s' '%s'...\n",
 					argv_expanded[0], argv_expanded[1]);
-				rcode = run_nofork_applet_prime(&G.nofork_save, i, argv_expanded);
+				rcode = run_nofork_applet(i, argv_expanded);
 			}
 			goto clean_up_and_ret;
 		}
@@ -3643,7 +3635,7 @@
 	smallint last_rword; /* ditto */
 #endif
 
-	debug_printf_exec("run_list start lvl %d\n", G.run_list_level + 1);
+	debug_printf_exec("run_list start lvl %d\n", G.run_list_level);
 	debug_enter();
 
 #if ENABLE_HUSH_LOOPS
@@ -3677,51 +3669,9 @@
 	 * in order to return, no direct "return" statements please.
 	 * This helps to ensure that no memory is leaked. */
 
-////TODO: ctrl-Z handling needs re-thinking and re-testing
-
 #if ENABLE_HUSH_JOB
-	/* Example of nested list: "while true; do { sleep 1 | exit 2; } done".
-	 * We are saving state before entering outermost list ("while...done")
-	 * so that ctrl-Z will correctly background _entire_ outermost list,
-	 * not just a part of it (like "sleep 1 | exit 2") */
-	if (++G.run_list_level == 1 && G_interactive_fd) {
-		if (sigsetjmp(G.toplevel_jb, 1)) {
-			/* ctrl-Z forked and we are parent; or ctrl-C.
-			 * Sighandler has longjmped us here */
-			signal(SIGINT, SIG_IGN);
-			signal(SIGTSTP, SIG_IGN);
-			/* Restore level (we can be coming from deep inside
-			 * nested levels) */
-			G.run_list_level = 1;
-#if ENABLE_FEATURE_SH_STANDALONE
-			if (G.nofork_save.saved) { /* if save area is valid */
-				debug_printf_jobs("exiting nofork early\n");
-				restore_nofork_data(&G.nofork_save);
-			}
+	G.run_list_level++;
 #endif
-////			if (G.ctrl_z_flag) {
-////				/* ctrl-Z has forked and stored pid of the child in pi->pid.
-////				 * Remember this child as background job */
-////				insert_bg_job(pi);
-////			} else {
-				/* ctrl-C. We just stop doing whatever we were doing */
-				bb_putchar('\n');
-////			}
-			USE_HUSH_LOOPS(loop_top = NULL;)
-			USE_HUSH_LOOPS(G.depth_of_loop = 0;)
-			rcode = 0;
-			goto ret;
-		}
-////		/* ctrl-Z handler will store pid etc in pi */
-////		G.toplevel_list = pi;
-////		G.ctrl_z_flag = 0;
-#if ENABLE_FEATURE_SH_STANDALONE
-		G.nofork_save.saved = 0; /* in case we will run a nofork later */
-#endif
-////		signal_SA_RESTART_empty_mask(SIGTSTP, handler_ctrl_z);
-////		signal(SIGINT, handler_ctrl_c);
-	}
-#endif /* JOB */
 
 #if HAS_KEYWORDS
 	rword = RES_NONE;
@@ -3967,18 +3917,7 @@
 	} /* for (pi) */
 
 #if ENABLE_HUSH_JOB
-////	if (G.ctrl_z_flag) {
-////		/* ctrl-Z forked somewhere in the past, we are the child,
-////		 * and now we completed running the list. Exit. */
-//////TODO: _exit?
-////		exit(rcode);
-////	}
- ret:
 	G.run_list_level--;
-////	if (!G.run_list_level && G_interactive_fd) {
-////		signal(SIGTSTP, SIG_IGN);
-////		signal(SIGINT, SIG_IGN);
-////	}
 #endif
 #if ENABLE_HUSH_LOOPS
 	if (loop_top)

 ------------------------------------------------------------------------
r26118 | vda | 2009-04-15 16:58:14 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: fix heredoc_huge.tests broken in last commits


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26117)
+++ shell/hush.c	(revision 26118)
@@ -2461,11 +2461,15 @@
 	 * 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 = vfork();
 	if (pid < 0)
 		bb_perror_msg_and_die("vfork");
 	if (pid == 0) {
 		/* child */
+		disable_restore_tty_pgrp_on_exit();
 		pid = BB_MMU ? fork() : vfork();
 		if (pid < 0)
 			bb_perror_msg_and_die(BB_MMU ? "fork" : "vfork");
@@ -2478,7 +2482,6 @@
 		_exit(0);
 #else
 		/* Delegate blocking writes to another process */
-		disable_restore_tty_pgrp_on_exit();
 		xmove_fd(pair.wr, STDOUT_FILENO);
 		re_execute_shell(&to_free, heredoc, NULL, NULL);
 #endif

 ------------------------------------------------------------------------
r26117 | vda | 2009-04-15 16:49:48 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: remove TODO comment itself :)


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26116)
+++ shell/hush.c	(revision 26117)
@@ -147,8 +147,7 @@
 static const char hush_version_str[] ALIGN1 = "HUSH_VERSION="BB_VER;
 
 /* This supports saving pointers malloced in vfork child,
- * to be freed in the parent. One pointer is saved in
- * G.argv_from_re_execing global var instead. TODO: unify.
+ * to be freed in the parent.
  */
 #if !BB_MMU
 typedef struct nommu_save_t {

 ------------------------------------------------------------------------
r26116 | vda | 2009-04-15 16:48:23 -0500 (Wed, 15 Apr 2009) | 13 lines
Changed paths:
   M /trunk/busybox/shell/hush.c

hush: deal with a TODO: move argv_from_re_execing out of globals

function                                             old     new   delta
generate_stream_from_string                          156     165      +9
setup_heredoc                                        312     320      +8
re_execute_shell                                     387     391      +4
pseudo_exec_argv                                     129     133      +4
run_pipe                                            1790    1783      -7
clean_up_after_re_execute                             30       -     -30
 ------------------------------------------------------------------------------

(add/remove: 0/1 grow/shrink: 4/1 up/down: 25/-37)            Total: -12 bytes


 ------------------------------------------------------------------------

Index: shell/hush.c
===================================================================
--- shell/hush.c	(revision 26115)
+++ shell/hush.c	(revision 26116)
@@ -155,6 +155,7 @@
 	char **new_env;
 	char **old_env;
 	char **argv;
+	char **argv_from_re_execing;
 } nommu_save_t;
 #endif
 
@@ -449,7 +450,6 @@
 	char **global_argv;
 #if !BB_MMU
 	char *argv0_for_re_execing;
-	char **argv_from_re_execing;
 #endif
 #if ENABLE_HUSH_LOOPS
 	unsigned depth_break_continue;
@@ -2280,10 +2280,8 @@
 
 #if BB_MMU
 /* never called */
-void re_execute_shell(const char *s, char *argv0, char **argv);
+void re_execute_shell(char ***to_free, const char *s, char *argv0, char **argv);
 
-#define clean_up_after_re_execute() ((void)0)
-
 static void reset_traps_to_defaults(void)
 {
 	unsigned sig;
@@ -2314,8 +2312,8 @@
 
 #else /* !BB_MMU */
 
-static void re_execute_shell(const char *s, char *g_argv0, char **g_argv) NORETURN;
-static void re_execute_shell(const char *s, char *g_argv0, char **g_argv)
+static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv) NORETURN;
+static void re_execute_shell(char ***to_free, const char *s, char *g_argv0, char **g_argv)
 {
 	char param_buf[sizeof("-$%x:%x:%x:%x") + sizeof(unsigned) * 4];
 	char *heredoc_argv[4];
@@ -2357,7 +2355,7 @@
 	pp = g_argv;
 	while (*pp++)
 		cnt++;
-	G.argv_from_re_execing = argv = pp = xzalloc(sizeof(argv[0]) * 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) {
@@ -2415,16 +2413,6 @@
 	xfunc_error_retval = 127;
 	bb_error_msg_and_die("can't re-execute the shell");
 }
-
-static void clean_up_after_re_execute(void)
-{
-	char **pp = G.argv_from_re_execing;
-	if (pp) {
-		/* Must match re_execute_shell's allocations (if any) */
-		free(pp);
-		G.argv_from_re_execing = NULL;
-	}
-}
 #endif  /* !BB_MMU */
 
 
@@ -2436,6 +2424,9 @@
 	/* the _body_ of heredoc (misleading field name) */
 	const char *heredoc = redir->rd_filename;
 	char *expanded;
+#if !BB_MMU
+	char **to_free;
+#endif
 
 	expanded = NULL;
 	if (!(redir->rd_dup & HEREDOC_QUOTED)) {
@@ -2490,12 +2481,14 @@
 		/* Delegate blocking writes to another process */
 		disable_restore_tty_pgrp_on_exit();
 		xmove_fd(pair.wr, STDOUT_FILENO);
-		re_execute_shell(heredoc, NULL, NULL);
+		re_execute_shell(&to_free, heredoc, NULL, NULL);
 #endif
 	}
 	/* parent */
 	enable_restore_tty_pgrp_on_exit();
-	clean_up_after_re_execute();
+#if !BB_MMU
+	free(to_free);
+#endif
 	close(pair.wr);
 	free(expanded);
 	wait(NULL); /* wait till child has died */
@@ -2742,8 +2735,16 @@
 	return funcp;
 }
 
-static void exec_function(const struct function *funcp, char **argv) NORETURN;
-static void exec_function(const struct function *funcp, char **argv)
+#if BB_MMU
+#define exec_function(nommu_save, funcp, argv) \
+	exec_function(funcp, argv)
+#endif
+static void exec_function(nommu_save_t *nommu_save,
+		const struct function *funcp,
+		char **argv) NORETURN;
+static void exec_function(nommu_save_t *nommu_save,
+		const struct function *funcp,
+		char **argv)
 {
 # if BB_MMU
 	int n = 1;
@@ -2758,7 +2759,10 @@
 	fflush(NULL);
 	_exit(n);
 # else
-	re_execute_shell(funcp->body_as_string, G.global_argv[0], argv + 1);
+	re_execute_shell(&nommu_save->argv_from_re_execing,
+			funcp->body_as_string,
+			G.global_argv[0],
+			argv + 1);
 # endif
 }
 
@@ -2889,7 +2893,7 @@
 	{
 		const struct function *funcp = find_function(argv[0]);
 		if (funcp) {
-			exec_function(funcp, argv);
+			exec_function(nommu_save, funcp, argv);
 		}
 	}
 #endif
@@ -2955,7 +2959,8 @@
 		 * since this process is about to exit */
 		_exit(rcode);
 #else
-		re_execute_shell(command->group_as_string,
+		re_execute_shell(&nommu_save->argv_from_re_execing,
+				command->group_as_string,
 				G.global_argv[0],
 				G.global_argv + 1);
 #endif
@@ -3432,6 +3437,7 @@
 		nommu_save.new_env = NULL;
 		nommu_save.old_env = NULL;
 		nommu_save.argv = NULL;
+		nommu_save.argv_from_re_execing = NULL;
 #endif
 		command = &(pi->cmds[i]);
 		if (command->argv) {
@@ -3489,8 +3495,8 @@
 		enable_restore_tty_pgrp_on_exit();
 #if !BB_MMU
 		/* Clean up after vforked child */
-		clean_up_after_re_execute();
 		free(nommu_save.argv);
+		free(nommu_save.argv_from_re_execing);
 		free_strings_and_unsetenv(nommu_save.new_env, 1);
 		putenv_all(nommu_save.old_env);
 		/* Free the pointers, but the strings themselves
@@ -4657,6 +4663,9 @@
 {
 	FILE *pf;
 	int pid, channel[2];
+#if !BB_MMU
+	char **to_free;
+#endif
 
 	xpipe(channel);
 	pid = BB_MMU ? fork() : vfork();
@@ -4688,7 +4697,8 @@
 	 * huge=`cat BIG` # was blocking here forever
 	 * echo OK
 	 */
-		re_execute_shell(s,
+		re_execute_shell(&to_free,
+				s,
 				G.global_argv[0],
 				G.global_argv + 1);
 #endif
@@ -4696,7 +4706,9 @@
 
 	/* parent */
 	enable_restore_tty_pgrp_on_exit();
-	clean_up_after_re_execute();
+#if !BB_MMU
+	free(to_free);
+#endif
 	close(channel[1]);
 	pf = fdopen(channel[0], "r");
 	return pf;

 ------------------------------------------------------------------------
r26109 | vda | 2009-04-15 08:04:52 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/Makefile

Start 1.15.x development


 ------------------------------------------------------------------------

Index: Makefile
===================================================================
--- Makefile	(revision 26108)
+++ Makefile	(revision 26109)
@@ -1,7 +1,7 @@
 VERSION = 1
-PATCHLEVEL = 14
+PATCHLEVEL = 15
 SUBLEVEL = 0
-EXTRAVERSION =
+EXTRAVERSION = .svn
 NAME = Unnamed
 
 # *DOCUMENTATION*

 ------------------------------------------------------------------------
r26106 | vda | 2009-04-15 06:55:27 -0500 (Wed, 15 Apr 2009) | 3 lines
Changed paths:
   M /trunk/busybox/docs/busybox.net/news.html

website: another tweak


 ------------------------------------------------------------------------

Index: docs/busybox.net/news.html
===================================================================
--- docs/busybox.net/news.html	(revision 26105)
+++ docs/busybox.net/news.html	(revision 26106)
@@ -82,7 +82,7 @@
 	
  • brctl: fix compilation on 2.4.x kernels
  • chat: treat timeout more correctly
  • chat: recognize RECORD directive
  • -
  • cksum, printenv: report errors via exitcode
  • +
  • cksum, head, printenv: report errors via exitcode
  • cpio: add -p, -0 and -L options
  • crond, crontab: make cron directory location configurable
  • crond: correct more of logfile to 0666 (as usual, umask allows user to remove unwanted bits)
  • @@ -90,14 +90,12 @@
  • dc: fix the "base 2" patch omission of base not being set
  • depmod: accept and ignore -r. Linux kernel build needs this
  • depmod: fix -b option. By timo.teras AT iki.fi
  • -
  • udhcpd, dumpleases: write and use 64-bit current time in lease file. Without it, determination of remaining lease time is unreliable
  • -
  • udhcpd: remember hostnames of clients
  • -
  • dumpleases: fix -a option
  • -
  • dumpleases: show hostnames
  • udhcpc: fix a problem where we don't open listening socket fast enough
  • udhcpc: stop filtering environment passed to the script
  • -
  • udhcpd: add code which rejects lease files with suspicious or old timestamp
  • -
  • udhcpd: disable opton to have absolute lease times in lease file (that does not work with dumpleases)
  • +
  • udhcpd: disable option to have absolute lease times in lease file (that does not work with dumpleases)
  • +
  • udhcpd: write 64-bit current time in lease file. Without it, determination of remaining lease time is unreliable
  • +
  • udhcpd: remember hostnames of clients
  • +
  • dumpleases: fix -a option, use recorded current time in lease file, show hostnames
  • dnsd: fix a number of bugs. Ideas by Ming-Ching Tiew (mctiew AT yahoo.com)
  • dpkg: better and shorter code to compare versions. Taken from "official" dpkg by Eugene T. Bordenkircher (eugebo AT gmail.com)
  • du: fix "du /dir /dir" case
  • @@ -108,7 +106,6 @@
  • getty: make speed 0 mean "don't change speed", stop using non-portable way of setting speeds
  • grep: support -z
  • gzip: fix gzip -dc bug caused by using stale getopt state
  • -
  • head: report file open errors with exitcode 1 (was happily returning 0)
  • httpd: set $HOST to Host: header value. By Tobias Poschwatta (tp AT fonz.de)
  • ifupdown: allow options to udhcpc to be configurable from .config
  • init: do not eat last char in messages; do not print duplicate "init:" prefix to syslog
  • ------------------------------------------------------------------------ r26105 | vda | 2009-04-15 06:51:18 -0500 (Wed, 15 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/docs/busybox.net/news.html website: yet another small tweak ------------------------------------------------------------------------ Index: docs/busybox.net/news.html =================================================================== --- docs/busybox.net/news.html (revision 26104) +++ docs/busybox.net/news.html (revision 26105) @@ -68,14 +68,13 @@
  • util-linux/volumeid: abort early on read failures. Should help with probing missing fdd's
  • util-linux/volumeid: fix bug 249 "findfs finds the wrong partition"
  • adduser: allow adding to group 0; don't _create_ /etc/shadow, only append data if it exists
  • -
  • ash: fix mishandled ^C
  • +
  • ash: fix mishandled ^C and SIGINT (several cases)
  • ash: fix "ash -c 'exec 1>&0'" complaining that fd 0 is busy
  • ash: fix $IFS handling in read. Closes bug 235
  • -
  • ash: fix a case where we close wrong descriptor
  • +
  • ash: fix a case where we were closing wrong descriptor
  • ash: fix bad interaction between ash -c '....&' and bash compat
  • ash: fix miscalculation of memory needed for eval tree. Found by Timo Teras (timo.teras AT iki.fi)
  • ash: make dot command search current directory first, as bash does
  • -
  • ash: make evaltree save/restore int suppression depth. Hopefully this fixes bug 189
  • ash: printf builtin with no arguments should not exit
  • awk: fix long field separators case. By Ian Wienand (ianw AT vmware.com)
  • awk: in BEGIN section $0 should be "", not "0"
  • ------------------------------------------------------------------------ r26104 | vda | 2009-04-15 06:48:25 -0500 (Wed, 15 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/docs/busybox.net/news.html website: another tiny tweak ------------------------------------------------------------------------ Index: docs/busybox.net/news.html =================================================================== --- docs/busybox.net/news.html (revision 26103) +++ docs/busybox.net/news.html (revision 26104) @@ -106,7 +106,7 @@
  • expand, unexpand: fix incorrect expansion in some cases
  • expr: a bit more robust handling of regexps with groups. Closes bug 87
  • find: support --mindepth
  • -
  • getty: fix handling of speed 0; stop using non-portable way of setting speeds
  • +
  • getty: make speed 0 mean "don't change speed", stop using non-portable way of setting speeds
  • grep: support -z
  • gzip: fix gzip -dc bug caused by using stale getopt state
  • head: report file open errors with exitcode 1 (was happily returning 0)
  • ------------------------------------------------------------------------ r26103 | vda | 2009-04-15 06:11:19 -0500 (Wed, 15 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/docs/busybox.net/news.html website: textual fixes in 1.14.0 announcement text ------------------------------------------------------------------------ Index: docs/busybox.net/news.html =================================================================== --- docs/busybox.net/news.html (revision 26102) +++ docs/busybox.net/news.html (revision 26103) @@ -44,10 +44,10 @@

    New applets:

    • flash_eraseall: by Sebastian Andrzej Siewior (bigeasy AT linutronix.de)
    • -
    • acpid,mkdosfs (aka mkfs.vfat),tunctl: by Vladimir
    • -
    • ftpd: by Adam Tkac
    • +
    • acpid, mkdosfs, tunctl: by Vladimir
    • +
    • ftpd: by Adam Tkac (vonsch AT gmail.com)
    • timeout: by Roberto Foglietta
    • -
    • ionice: adapted from Linux kernel' example by Walter Harms
    • +
    • ionice: adapted from Linux kernel example by Walter Harms
    • mkpasswd: synonym to cryptpw. mkpasswd is in Debian, OTOH cryptpw was added to busybox earlier. Trying to make both camps happy by making those two applets just aliases. They are command-line compatible
    @@ -55,16 +55,18 @@

    lash and msh are deprecated, please migrate to hush. -

    hush had many, many fixes and features added: here documents, arithmetic evaluation, function support, and all this works on NOMMU too, safely: 100kb-sized `command` and heredocs. Here document support, arithmetic evaluation, improved ${var} ops, other fixes are by Mike Frysinger (vapier AT gentoo.org). +

    hush had many, many fixes and features added: here documents, arithmetic evaluation, function support, and all this works on NOMMU too, safely, including 100kb-sized `command` and here documents. Here document support, arithmetic evaluation, improved ${var} operations, other fixes are by Mike Frysinger (vapier AT gentoo.org).

    Other changes:

    • libbb: unify concurrent-safe update of /etc/{passwd,group,[g]shadow}. By Tito (farmatito AT tiscali.it)
    • -
    • libbb/sha1/256/512: major code shrink
    • +
    • libbb/sha{1,256,512}: major code shrink
    • libbb/lineedit: make history saving/loading concurrent-safe
    • libbb: shrink linked list ops. By xmaks AT email.cz
    • -
    • libbb: str2sockaddr shuld accept [IPv6] addr without port - wget 'ftp://[::1]/file' needs that to work
    • +
    • libbb: str2sockaddr should accept [IPv6] addr without port - wget 'ftp://[::1]/file' needs that to work
    • libbb: make bb_info_msg do atomic, unbuffered writes
    • +
    • util-linux/volumeid: abort early on read failures. Should help with probing missing fdd's
    • +
    • util-linux/volumeid: fix bug 249 "findfs finds the wrong partition"
    • adduser: allow adding to group 0; don't _create_ /etc/shadow, only append data if it exists
    • ash: fix mishandled ^C
    • ash: fix "ash -c 'exec 1>&0'" complaining that fd 0 is busy
    • @@ -72,7 +74,6 @@
    • ash: fix a case where we close wrong descriptor
    • ash: fix bad interaction between ash -c '....&' and bash compat
    • ash: fix miscalculation of memory needed for eval tree. Found by Timo Teras (timo.teras AT iki.fi)
    • -
    • ash: in dotrap(), do not clear gotsig[] for SIGINT if there is no handler for it, otherwise raise interrupt gets confused later
    • ash: make dot command search current directory first, as bash does
    • ash: make evaltree save/restore int suppression depth. Hopefully this fixes bug 189
    • ash: printf builtin with no arguments should not exit
    • @@ -84,16 +85,16 @@
    • chat: recognize RECORD directive
    • cksum, printenv: report errors via exitcode
    • cpio: add -p, -0 and -L options
    • -
    • crond,crontab: make cron directory location configurable
    • +
    • crond, crontab: make cron directory location configurable
    • crond: correct more of logfile to 0666 (as usual, umask allows user to remove unwanted bits)
    • crond: put tasks in separate process groups
    • dc: fix the "base 2" patch omission of base not being set
    • depmod: accept and ignore -r. Linux kernel build needs this
    • depmod: fix -b option. By timo.teras AT iki.fi
    • -
    • udhcpd,dumpleases: write and use 64-bit current time in lease file. without it, determination of remaining lease time is unreliable
    • -
    • udhcpd: remember and record hostnames
    • -
    • dhcprelay: fix usage text. Simplify and make code more readable
    • -
    • dumpleases: fix -a option; show hostnames
    • +
    • udhcpd, dumpleases: write and use 64-bit current time in lease file. Without it, determination of remaining lease time is unreliable
    • +
    • udhcpd: remember hostnames of clients
    • +
    • dumpleases: fix -a option
    • +
    • dumpleases: show hostnames
    • udhcpc: fix a problem where we don't open listening socket fast enough
    • udhcpc: stop filtering environment passed to the script
    • udhcpd: add code which rejects lease files with suspicious or old timestamp
    • @@ -102,7 +103,7 @@
    • dpkg: better and shorter code to compare versions. Taken from "official" dpkg by Eugene T. Bordenkircher (eugebo AT gmail.com)
    • du: fix "du /dir /dir" case
    • env: support -uVAR=VAL
    • -
    • expand: fix incorrect expansion exactly on tab boundary; shrink the code
    • +
    • expand, unexpand: fix incorrect expansion in some cases
    • expr: a bit more robust handling of regexps with groups. Closes bug 87
    • find: support --mindepth
    • getty: fix handling of speed 0; stop using non-portable way of setting speeds
    • @@ -119,7 +120,6 @@
    • init: test for vt terminal with VT_OPENQRY, assume that anything else is TERM=vt102, not TERM=linux. Closes bug 195
    • inotifyd: add x, o, and u events
    • inotifyd: fix buffer overflow and "unreaped zombies" problem
    • -
    • inotifyd: exit if x event happened for all files
    • inotifyd: conserve resourses by closing unused inotify descriptors
    • insmod/modprobe: do not pass NULL to kernel as module parameter
    • ip: in "ip rule add from all table 1", "all" is taken as 0.0.0.0/32, whereas "any" and "default" would be 0.0.0.0/0. They must be all 0.0.0.0/0. Closes bug 57
    • @@ -134,14 +134,11 @@
    • mdev: ignore events with "$SUBSYSTEM" == "firmware" && "$ACTION" == "remove"
    • mdev: provide $SUBSYSTEM. By Vladimir
    • modprobe/insmod for 2.4: support compressed modules. By Guenter (lists AT gknw.net)
    • -
    • modprobe: emit "can't open 'modules.dep': (errno)" instead of "module not found"
    • modprobe: rework/speedup by Timo Teras (timo.teras AT iki.fi)
    • modutils-24: fix bad interaction of xzalloc with xrealloc_vector
    • -
    • mount: support "-O option"
    • -
    • mount: stop trying to mount swap partitions
    • -
    • mount: fix CIFS support
    • +
    • mount: support "-O option", stop trying to mount swap partitions, fix CIFS support
    • mountpoint: add -n option. By Vladimir
    • -
    • nslookup: allow usage of IPv6 addresses or hostnames for DNS server name; allow for port specification. Tested to work: "nslookup google.com [::1]:5353". glibc + IPv6 address of DNS server still does not work
    • +
    • nslookup: allow usage of IPv6 addresses or hostnames for DNS server name; allow for port specification. Tested to work on uclibc svn: "nslookup google.com [::1]:5353". glibc + IPv6 address of DNS server still does not work
    • popmaildir: fix several grave bugs with using memory past end of malloc block
    • printf: fix 1.12.0 breakage (from %*d fix), it was misinterpreting "*"
    • printf: make integer format strings print long long-sized values
    • @@ -154,7 +151,7 @@
    • sysctl: fix another corner case with "dots and slashes"
    • sysctl: fix broken -p [file]. Closes bug 231
    • sysctl: support recursing if name is a directory: "sysctl net.ipv4.conf". Patch by xmaks AT email.cz
    • -
    • syslogd: comment out file locking; make signal handling syncronous
    • +
    • syslogd: make signal handling syncronous
    • syslogd: create logfile with 0666 (affected by umask as usual), not 0600
    • tail: fix tail +N syntax not working. Closes bug 221
    • tar: do not change new tarfile's mode, GNU tar doesn't do it
    • @@ -164,21 +161,15 @@
    • tftp: when we infer local name from remote (-r [/]path/path/file), strip path. This mimics wget and is generally more intuitive
    • timeout: fix parsing of -t NUM on MMU
    • top: make it work again on 2.4 kernels. Closes bug 125
    • -
    • tr: fix overflow in expand and complement, fix stop after [:class:]
    • -
    • tr: support -C as synonym to -c
    • -
    • tr: support [:xdigit:], fix handling of ranges and [x]'s
    • +
    • tr: fix overflow in expand and complement, fix stop after [:class:], fix handling of ranges and [x]'s
    • +
    • tr: support -C as synonym to -c, support [:xdigit:]
    • traceroute: rewrite. Do not emit raw IP packets, instead send UDP or ICMP packets and rely on the kernel to form IP headers, select source IP and interface
    • -
    • uname: add support for -i and -o, fix printing of unknown -p value with -a option
    • -
    • uname: support long options
    • -
    • unexpand: fix incorrect expansion
    • +
    • uname: add support for -i and -o, fix printing of unknown -p value with -a option, support long options
    • unzip: fix thinko with le/be conv and size. Closes bug 129
    • vi: fix several instances of major goof: when text grows, text[] might get reallocated! We were keeping around pointers to old place
    • vi: speedup and code shrink. By Walter Harms
    • -
    • volume_id: abort early on read failures. Should help with probing missing fdd's
    • -
    • volumeid: fix bug 249 "findfs finds the wrong partition"
    • wget: --post-data support. By Harald Kuthe (harald-tuxbox AT arcor.de)
    • -
    • wget: fix --header handling
    • -
    • wget: more robust EINTR detection
    • +
    • wget: fix --header handling, more robust EINTR detection

    ------------------------------------------------------------------------ r26101 | vda | 2009-04-14 21:13:14 -0500 (Tue, 14 Apr 2009) | 4 lines Changed paths: M /trunk/busybox/Makefile M /trunk/busybox/docs/busybox.net/news.html M /trunk/busybox/libbb/Kbuild M /trunk/busybox/scripts/defconfig website: announce 1.14.0 and 1.13.4 Makefile: bump version to 1.14.0 ------------------------------------------------------------------------ Index: scripts/defconfig =================================================================== --- scripts/defconfig (revision 26100) +++ scripts/defconfig (revision 26101) @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit -# Busybox version: 1.14.0.svn -# Mon Apr 13 16:22:36 2009 +# Busybox version: 1.14.0 +# Wed Apr 15 04:12:17 2009 # CONFIG_HAVE_DOT_CONFIG=y Index: docs/busybox.net/news.html =================================================================== --- docs/busybox.net/news.html (revision 26100) +++ docs/busybox.net/news.html (revision 26101) @@ -22,6 +22,166 @@

    +
  • 15 April 2009 -- BusyBox 1.14.0 (unstable), BusyBox 1.13.4 (stable) +

    BusyBox 1.14.0. + (svn, + patches, + how to add a patch)

    +

    BusyBox 1.13.4. + (svn, + patches, + how to add a patch)

    + +

    Sizes of busybox-1.13.4 and busybox-1.14.0 (with equivalent config, static uclibc build):

    +   text    data     bss     dec     hex filename
    + 785501     483    7036  793020   c19bc busybox.1.13.4/busybox
    + 788380     467    6960  795807   c249f busybox.1.14.0/busybox
    +  15361       0       0   15361    3c01 busybox.1.13.4/shell/hush.o
    +  20724       0       0   20724    50f4 busybox.1.14.0/shell/hush.o
    +
    +

    Most of growth is in hush. The rest shrank a bit. + +

    New applets: +

      +
    • flash_eraseall: by Sebastian Andrzej Siewior (bigeasy AT linutronix.de)
    • +
    • acpid,mkdosfs (aka mkfs.vfat),tunctl: by Vladimir
    • +
    • ftpd: by Adam Tkac
    • +
    • timeout: by Roberto Foglietta
    • +
    • ionice: adapted from Linux kernel' example by Walter Harms
    • +
    • mkpasswd: synonym to cryptpw. mkpasswd is in Debian, OTOH cryptpw was added to busybox earlier. Trying to make both camps happy by making those two applets just aliases. They are command-line compatible
    • +
    + +

    Changes since previous release: + +

    lash and msh are deprecated, please migrate to hush. + +

    hush had many, many fixes and features added: here documents, arithmetic evaluation, function support, and all this works on NOMMU too, safely: 100kb-sized `command` and heredocs. Here document support, arithmetic evaluation, improved ${var} ops, other fixes are by Mike Frysinger (vapier AT gentoo.org). + +

    Other changes: +

      +
    • libbb: unify concurrent-safe update of /etc/{passwd,group,[g]shadow}. By Tito (farmatito AT tiscali.it)
    • +
    • libbb/sha1/256/512: major code shrink
    • +
    • libbb/lineedit: make history saving/loading concurrent-safe
    • +
    • libbb: shrink linked list ops. By xmaks AT email.cz
    • +
    • libbb: str2sockaddr shuld accept [IPv6] addr without port - wget 'ftp://[::1]/file' needs that to work
    • +
    • libbb: make bb_info_msg do atomic, unbuffered writes
    • +
    • adduser: allow adding to group 0; don't _create_ /etc/shadow, only append data if it exists
    • +
    • ash: fix mishandled ^C
    • +
    • ash: fix "ash -c 'exec 1>&0'" complaining that fd 0 is busy
    • +
    • ash: fix $IFS handling in read. Closes bug 235
    • +
    • ash: fix a case where we close wrong descriptor
    • +
    • ash: fix bad interaction between ash -c '....&' and bash compat
    • +
    • ash: fix miscalculation of memory needed for eval tree. Found by Timo Teras (timo.teras AT iki.fi)
    • +
    • ash: in dotrap(), do not clear gotsig[] for SIGINT if there is no handler for it, otherwise raise interrupt gets confused later
    • +
    • ash: make dot command search current directory first, as bash does
    • +
    • ash: make evaltree save/restore int suppression depth. Hopefully this fixes bug 189
    • +
    • ash: printf builtin with no arguments should not exit
    • +
    • awk: fix long field separators case. By Ian Wienand (ianw AT vmware.com)
    • +
    • awk: in BEGIN section $0 should be "", not "0"
    • +
    • awk: make "struct global" hack more robust wrt alignment. Closes bug 131
    • +
    • brctl: fix compilation on 2.4.x kernels
    • +
    • chat: treat timeout more correctly
    • +
    • chat: recognize RECORD directive
    • +
    • cksum, printenv: report errors via exitcode
    • +
    • cpio: add -p, -0 and -L options
    • +
    • crond,crontab: make cron directory location configurable
    • +
    • crond: correct more of logfile to 0666 (as usual, umask allows user to remove unwanted bits)
    • +
    • crond: put tasks in separate process groups
    • +
    • dc: fix the "base 2" patch omission of base not being set
    • +
    • depmod: accept and ignore -r. Linux kernel build needs this
    • +
    • depmod: fix -b option. By timo.teras AT iki.fi
    • +
    • udhcpd,dumpleases: write and use 64-bit current time in lease file. without it, determination of remaining lease time is unreliable
    • +
    • udhcpd: remember and record hostnames
    • +
    • dhcprelay: fix usage text. Simplify and make code more readable
    • +
    • dumpleases: fix -a option; show hostnames
    • +
    • udhcpc: fix a problem where we don't open listening socket fast enough
    • +
    • udhcpc: stop filtering environment passed to the script
    • +
    • udhcpd: add code which rejects lease files with suspicious or old timestamp
    • +
    • udhcpd: disable opton to have absolute lease times in lease file (that does not work with dumpleases)
    • +
    • dnsd: fix a number of bugs. Ideas by Ming-Ching Tiew (mctiew AT yahoo.com)
    • +
    • dpkg: better and shorter code to compare versions. Taken from "official" dpkg by Eugene T. Bordenkircher (eugebo AT gmail.com)
    • +
    • du: fix "du /dir /dir" case
    • +
    • env: support -uVAR=VAL
    • +
    • expand: fix incorrect expansion exactly on tab boundary; shrink the code
    • +
    • expr: a bit more robust handling of regexps with groups. Closes bug 87
    • +
    • find: support --mindepth
    • +
    • getty: fix handling of speed 0; stop using non-portable way of setting speeds
    • +
    • grep: support -z
    • +
    • gzip: fix gzip -dc bug caused by using stale getopt state
    • +
    • head: report file open errors with exitcode 1 (was happily returning 0)
    • +
    • httpd: set $HOST to Host: header value. By Tobias Poschwatta (tp AT fonz.de)
    • +
    • ifupdown: allow options to udhcpc to be configurable from .config
    • +
    • init: do not eat last char in messages; do not print duplicate "init:" prefix to syslog
    • +
    • init: fix a bug where on reload order of entries might be wrong
    • +
    • init: major improvement in documentation and signal handling. Lots of nasty, but hard to trip, races are fixed
    • +
    • init: reinstate proper handling of !ENABLE_FEATURE_USE_INITTAB
    • +
    • init: remove wait loop on restart, it may be dangerous
    • +
    • init: test for vt terminal with VT_OPENQRY, assume that anything else is TERM=vt102, not TERM=linux. Closes bug 195
    • +
    • inotifyd: add x, o, and u events
    • +
    • inotifyd: fix buffer overflow and "unreaped zombies" problem
    • +
    • inotifyd: exit if x event happened for all files
    • +
    • inotifyd: conserve resourses by closing unused inotify descriptors
    • +
    • insmod/modprobe: do not pass NULL to kernel as module parameter
    • +
    • ip: in "ip rule add from all table 1", "all" is taken as 0.0.0.0/32, whereas "any" and "default" would be 0.0.0.0/0. They must be all 0.0.0.0/0. Closes bug 57
    • +
    • iproute: fix ipXXX utilities trying to parse their applet name as their 1st parameter
    • +
    • klogctl: fix a problem where we don't terminate read data with '\0' and then misinterpret it
    • +
    • ls: do not follow links with -s. Closes bug 33
    • +
    • ls: implement -Q and -g (-g was accepted but ignored)
    • +
    • ls: make readlink error to not disrupt output (try ls -l /proc/self/fd)
    • +
    • man: better check for duplicated MANPATH
    • +
    • mdev: add support for - ("dont stop here") char
    • +
    • mdev: if /sys/class/block exists, don't scan /sys/block
    • +
    • mdev: ignore events with "$SUBSYSTEM" == "firmware" && "$ACTION" == "remove"
    • +
    • mdev: provide $SUBSYSTEM. By Vladimir
    • +
    • modprobe/insmod for 2.4: support compressed modules. By Guenter (lists AT gknw.net)
    • +
    • modprobe: emit "can't open 'modules.dep': (errno)" instead of "module not found"
    • +
    • modprobe: rework/speedup by Timo Teras (timo.teras AT iki.fi)
    • +
    • modutils-24: fix bad interaction of xzalloc with xrealloc_vector
    • +
    • mount: support "-O option"
    • +
    • mount: stop trying to mount swap partitions
    • +
    • mount: fix CIFS support
    • +
    • mountpoint: add -n option. By Vladimir
    • +
    • nslookup: allow usage of IPv6 addresses or hostnames for DNS server name; allow for port specification. Tested to work: "nslookup google.com [::1]:5353". glibc + IPv6 address of DNS server still does not work
    • +
    • popmaildir: fix several grave bugs with using memory past end of malloc block
    • +
    • printf: fix 1.12.0 breakage (from %*d fix), it was misinterpreting "*"
    • +
    • printf: make integer format strings print long long-sized values
    • +
    • rmmod: fix bug 263 "modutils/rmmod can't remove modules with dash in name on 2.4 kernels"
    • +
    • sendmail: document and fix usage of fd #4, fix check for helper failure
    • +
    • sendmail: update by Vladimir
    • +
    • seq: add -w support. By Natanael Copa
    • +
    • seq: add support for "-s separator"
    • +
    • stat: make stat -f show filesystem "ID:" as coreutils does
    • +
    • sysctl: fix another corner case with "dots and slashes"
    • +
    • sysctl: fix broken -p [file]. Closes bug 231
    • +
    • sysctl: support recursing if name is a directory: "sysctl net.ipv4.conf". Patch by xmaks AT email.cz
    • +
    • syslogd: comment out file locking; make signal handling syncronous
    • +
    • syslogd: create logfile with 0666 (affected by umask as usual), not 0600
    • +
    • tail: fix tail +N syntax not working. Closes bug 221
    • +
    • tar: do not change new tarfile's mode, GNU tar doesn't do it
    • +
    • tar: support GNU tar's "base256" encoding
    • +
    • telnetd: correctly output 0xff char
    • +
    • telnetd: do not advertise TELNET_LFLOW, we do not support it properly
    • +
    • tftp: when we infer local name from remote (-r [/]path/path/file), strip path. This mimics wget and is generally more intuitive
    • +
    • timeout: fix parsing of -t NUM on MMU
    • +
    • top: make it work again on 2.4 kernels. Closes bug 125
    • +
    • tr: fix overflow in expand and complement, fix stop after [:class:]
    • +
    • tr: support -C as synonym to -c
    • +
    • tr: support [:xdigit:], fix handling of ranges and [x]'s
    • +
    • traceroute: rewrite. Do not emit raw IP packets, instead send UDP or ICMP packets and rely on the kernel to form IP headers, select source IP and interface
    • +
    • uname: add support for -i and -o, fix printing of unknown -p value with -a option
    • +
    • uname: support long options
    • +
    • unexpand: fix incorrect expansion
    • +
    • unzip: fix thinko with le/be conv and size. Closes bug 129
    • +
    • vi: fix several instances of major goof: when text grows, text[] might get reallocated! We were keeping around pointers to old place
    • +
    • vi: speedup and code shrink. By Walter Harms
    • +
    • volume_id: abort early on read failures. Should help with probing missing fdd's
    • +
    • volumeid: fix bug 249 "findfs finds the wrong partition"
    • +
    • wget: --post-data support. By Harald Kuthe (harald-tuxbox AT arcor.de)
    • +
    • wget: fix --header handling
    • +
    • wget: more robust EINTR detection
    • +
    +

    +
  • 8 March 2009 -- BusyBox 1.13.3 (stable)

    BusyBox 1.13.3. (svn, Index: libbb/Kbuild =================================================================== --- libbb/Kbuild (revision 26100) +++ libbb/Kbuild (revision 26101) @@ -122,6 +122,7 @@ lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o lib-$(CONFIG_ADDGROUP) += update_passwd.o 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_CHPASSWD) += pw_encrypt.o update_passwd.o Index: Makefile =================================================================== --- Makefile (revision 26100) +++ Makefile (revision 26101) @@ -1,7 +1,7 @@ VERSION = 1 PATCHLEVEL = 14 SUBLEVEL = 0 -EXTRAVERSION = .svn +EXTRAVERSION = NAME = Unnamed # *DOCUMENTATION* ------------------------------------------------------------------------ r26099 | vda | 2009-04-14 16:23:33 -0500 (Tue, 14 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/util-linux/mdev.c mdev: safer handling of $SUBSYSTEM in mdev -s ------------------------------------------------------------------------ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26098) +++ util-linux/mdev.c (revision 26099) @@ -1,6 +1,5 @@ /* vi: set sw=4 ts=4: */ /* - * * mdev - Mini udev for busybox * * Copyright 2005 Rob Landley @@ -8,7 +7,6 @@ * * Licensed under GPL version 2, see file LICENSE in this tarball for details. */ - #include "libbb.h" #include "xregex.h" @@ -353,11 +351,13 @@ void *userData UNUSED_PARAM, int depth) { - /* Extract device subsystem -- the name of the directory under /sys/class/ */ + /* Extract device subsystem -- the name of the directory + * under /sys/class/ */ if (1 == depth) { + free(subsystem); subsystem = strrchr(fileName, '/'); if (subsystem) - subsystem++; + subsystem = xstrdup(subsystem + 1); } return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); @@ -397,17 +397,17 @@ goto out; loading: - /* tell kernel we're loading by `echo 1 > /sys/$DEVPATH/loading` */ + /* tell kernel we're loading by "echo 1 > /sys/$DEVPATH/loading" */ if (full_write(loading_fd, "1", 1) != 1) goto out; - /* load firmware by `cat /lib/firmware/$FIRMWARE > /sys/$DEVPATH/data */ + /* load firmware into /sys/$DEVPATH/data */ data_fd = open("data", O_WRONLY); if (data_fd == -1) goto out; cnt = bb_copyfd_eof(firmware_fd, data_fd); - /* tell kernel result by `echo [0|-1] > /sys/$DEVPATH/loading` */ + /* tell kernel result by "echo [0|-1] > /sys/$DEVPATH/loading" */ if (cnt > 0) full_write(loading_fd, "0", 1); else ------------------------------------------------------------------------ r26097 | vda | 2009-04-14 04:58:11 -0500 (Tue, 14 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/loginutils/adduser.c pointless whitespace/comment fixes, no code changes ------------------------------------------------------------------------ Index: loginutils/adduser.c =================================================================== --- loginutils/adduser.c (revision 26096) +++ loginutils/adduser.c (revision 26097) @@ -127,8 +127,8 @@ free(p); #if ENABLE_FEATURE_SHADOWPASSWDS - p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL) / 86400)); /* sp->sp_lstchg */ - /* Ignore errors: if file is missing we suppose admin doesn't want it */ + p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL) / 86400)); /* sp->sp_lstchg */ + /* ignore errors: if file is missing we suppose admin doesn't want it */ update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL); if (ENABLE_FEATURE_CLEAN_UP) free(p); @@ -140,7 +140,7 @@ if (!usegroup) addgroup_wrapper(&pw); - /* Clear the umask for this process so it doesn't + /* clear the umask for this process so it doesn't * screw up the permissions on the mkdir and chown. */ umask(0); if (!(option_mask32 & OPT_DONT_MAKE_HOME)) { ------------------------------------------------------------------------ r26096 | vda | 2009-04-14 03:06:59 -0500 (Tue, 14 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/libbb/update_passwd.c M /trunk/busybox/shell/hush.c M /trunk/busybox/util-linux/mdev.c randomconfig fixes ------------------------------------------------------------------------ Index: shell/hush.c =================================================================== --- shell/hush.c (revision 26095) +++ shell/hush.c (revision 26096) @@ -4069,11 +4069,15 @@ * RES_NONE case is for "for a in; do ..." (empty IN set) * and other cases to work. */ if (not_null -#if HAS_KEYWORDS +#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 ) { Index: libbb/update_passwd.c =================================================================== --- libbb/update_passwd.c (revision 26095) +++ libbb/update_passwd.c (revision 26096) @@ -224,8 +224,10 @@ } if (changed_lines == 0) { - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && member) +#if ENABLE_FEATURE_DEL_USER_FROM_GROUP + if (member) bb_error_msg("can't find %s in %s", member, filename); +#endif if ((ENABLE_ADDUSER || ENABLE_ADDGROUP) && applet_name[0] == 'a' && !member ) { Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26095) +++ util-linux/mdev.c (revision 26096) @@ -98,10 +98,11 @@ if (strstr(path, "/block/")) type = S_IFBLK; -#if ENABLE_FEATURE_MDEV_CONF +#if !ENABLE_FEATURE_MDEV_CONF + mode = 0660; +#else + /* If we have config file, look up user settings */ parser = config_open2("/etc/mdev.conf", fopen_for_read); - - /* If we have config file, look up user settings */ while (1) { regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP]; int keep_matching; ------------------------------------------------------------------------ r26093 | vda | 2009-04-13 20:31:41 -0500 (Mon, 13 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/docs/busybox.net/products.html website: update ActionTec URL to http://opensource.actiontec.com/ ------------------------------------------------------------------------ Index: docs/busybox.net/products.html =================================================================== --- docs/busybox.net/products.html (revision 26092) +++ docs/busybox.net/products.html (revision 26093) @@ -146,7 +146,7 @@ with source here

  • ActionTec GT701-WG Wireless Gateway/DSL Modem - with source here + with source here
  • S.M.A.R.T. Linux
  • DLink - Model GSL-G604T, DSL-300T, and possibly other models with source here, ------------------------------------------------------------------------ r26092 | vda | 2009-04-13 19:59:37 -0500 (Mon, 13 Apr 2009) | 6 lines Changed paths: M /trunk/busybox/docs/busybox.net/subversion.html website: fix obsolete "svn co svn://busybox.net/branches/busybox_1_12_stable" example ------------------------------------------------------------------------ Index: docs/busybox.net/subversion.html =================================================================== --- docs/busybox.net/subversion.html (revision 26091) +++ docs/busybox.net/subversion.html (revision 26092) @@ -18,9 +18,9 @@ svn co svn://busybox.net/trunk/busybox
  • -The current stable branch can be obtained with +The stable branches can be obtained with

    -svn co svn://busybox.net/branches/busybox_1_12_stable
    +svn co svn://busybox.net/branches/busybox_1_NN_stable
     

    ------------------------------------------------------------------------ r26091 | vda | 2009-04-13 19:51:05 -0500 (Mon, 13 Apr 2009) | 22 lines Changed paths: M /trunk/busybox/include/libbb.h M /trunk/busybox/libbb/Kbuild M /trunk/busybox/libbb/update_passwd.c M /trunk/busybox/loginutils/addgroup.c M /trunk/busybox/loginutils/adduser.c M /trunk/busybox/loginutils/chpasswd.c M /trunk/busybox/loginutils/deluser.c M /trunk/busybox/loginutils/passwd.c *: unify concurrent-safe update of /etc/{passwd,group,[g]shadow} by Tito (farmatito AT tiscali.it) function old new delta update_passwd 743 1171 +428 bb_perror_nomsg - 9 +9 find_main 436 444 +8 passwd_main 1023 1027 +4 nameval 202 206 +4 chpasswd_main 315 319 +4 bb__parsespent 119 117 -2 adduser_main 654 650 -4 addgroup_main 345 341 -4 sv_main 1228 1222 -6 deluser_main 173 160 -13 bb_internal_putpwent 69 - -69 add_user_to_group 231 - -231 del_line_matching 460 31 -429 ------------------------------------------------------------------------------ (add/remove: 1/2 grow/shrink: 5/6 up/down: 457/-758) Total: -301 bytes ------------------------------------------------------------------------ Index: libbb/update_passwd.c =================================================================== --- libbb/update_passwd.c (revision 26090) +++ libbb/update_passwd.c (revision 26091) @@ -8,9 +8,11 @@ * * Moved from loginutils/passwd.c by Alexander Shishkin * + * 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. */ - #include "libbb.h" #if ENABLE_SELINUX @@ -35,12 +37,44 @@ freecon(context); } #else -#define check_selinux_update_passwd(username) ((void)0) +# define check_selinux_update_passwd(username) ((void)0) #endif -int FAST_FUNC update_passwd(const char *filename, const char *username, - const char *new_pw) +/* + 1) add a user: update_passwd(FILE, USER, REMAINING_PWLINE, NULL) + only if CONFIG_ADDUSER=y and applet_name[0] == 'a' like in adduser + + 2) add a group: update_passwd(FILE, GROUP, REMAINING_GRLINE, NULL) + only if CONFIG_ADDGROUP=y and applet_name[0] == 'a' like in addgroup + + 3) add a user to a group: update_passwd(FILE, GROUP, NULL, MEMBER) + only if CONFIG_FEATURE_ADDUSER_TO_GROUP=y, applet_name[0] == 'a' + like in addgroup and member != NULL + + 4) delete a user: update_passwd(FILE, USER, NULL, NULL) + + 5) delete a group: update_passwd(FILE, GROUP, NULL, NULL) + + 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) + 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 + + This function does not validate the arguments fed to it + so the calling program should take care of that. + + Returns number of lines changed, or -1 on error. +*/ +int FAST_FUNC update_passwd(const char *filename, + const char *name, + const char *new_passwd, + const char *member) { +#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) +#define member NULL +#endif struct stat sb; struct flock lock; FILE *old_fp; @@ -51,22 +85,25 @@ int old_fd; int new_fd; int i; - int cnt = 0; + int changed_lines; int ret = -1; /* failure */ filename = xmalloc_follow_symlinks(filename); if (filename == NULL) - return -1; + return ret; - check_selinux_update_passwd(username); + check_selinux_update_passwd(name); /* New passwd file, "/etc/passwd+" for now */ fnamesfx = xasprintf("%s+", filename); sfx_char = &fnamesfx[strlen(fnamesfx)-1]; - username = xasprintf("%s:", username); - user_len = strlen(username); + name = xasprintf("%s:", name); + user_len = strlen(name); - old_fp = fopen(filename, "r+"); + if (strstr(filename, "shadow")) + old_fp = fopen(filename, "r+"); + else + old_fp = fopen_or_warn(filename, "r+"); if (!old_fp) goto free_mem; old_fd = fileno(old_fp); @@ -82,7 +119,7 @@ if (errno != EEXIST) break; usleep(100000); /* 0.1 sec */ } while (--i); - bb_perror_msg("cannot create '%s'", fnamesfx); + bb_perror_msg("can't create '%s'", fnamesfx); goto close_old_fp; created: @@ -90,8 +127,10 @@ fchmod(new_fd, sb.st_mode & 0777); /* ignore errors */ fchown(new_fd, sb.st_uid, sb.st_gid); } + errno = 0; new_fp = fdopen(new_fd, "w"); if (!new_fp) { + bb_perror_nomsg(); close(new_fd); goto unlink_new; } @@ -102,7 +141,8 @@ i = (unlink(fnamesfx) && errno != ENOENT); /* Create backup as a hardlink to current */ if (i || link(filename, fnamesfx)) - bb_perror_msg("warning: cannot create backup copy '%s'", fnamesfx); + bb_perror_msg("warning: can't create backup copy '%s'", + fnamesfx); *sfx_char = '+'; /* Lock the password file before updating */ @@ -111,38 +151,107 @@ lock.l_start = 0; lock.l_len = 0; if (fcntl(old_fd, F_SETLK, &lock) < 0) - bb_perror_msg("warning: cannot lock '%s'", filename); + bb_perror_msg("warning: can't lock '%s'", filename); lock.l_type = F_UNLCK; /* Read current password file, write updated /etc/passwd+ */ + changed_lines = 0; while (1) { - char *line = xmalloc_fgets(old_fp); - if (!line) break; /* EOF/error */ - if (strncmp(username, line, user_len) == 0) { - /* we have a match with "username:"... */ - const char *cp = line + user_len; - /* now cp -> old passwd, skip it: */ - cp = strchrnul(cp, ':'); - /* now cp -> ':' after old passwd or -> "" */ - fprintf(new_fp, "%s%s%s", username, new_pw, cp); - cnt++; + char *cp, *line; + + line = xmalloc_fgetline(old_fp); + if (!line) /* EOF/error */ + break; + if (strncmp(name, line, user_len) != 0) { + fprintf(new_fp, "%s\n", line); + goto next; + } + + /* We have a match with "name:"... */ + cp = line + user_len; /* move past name: */ + +#if ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP + if (member) { + /* It's actually /etc/group+, not /etc/passwd+ */ + if (ENABLE_FEATURE_ADDUSER_TO_GROUP + && applet_name[0] == 'a' + ) { + /* Add user to group */ + fprintf(new_fp, "%s%s%s\n", line, + last_char_is(line, ':') ? "" : ",", + member); + changed_lines++; + } else if (ENABLE_FEATURE_DEL_USER_FROM_GROUP + /* && applet_name[0] == 'd' */ + ) { + /* Delete user from group */ + char *tmp; + const char *fmt = "%s"; + + /* find the start of the member list: last ':' */ + cp = strrchr(line, ':'); + /* cut it */ + *cp++ = '\0'; + /* write the cut line name:passwd:gid: + * or name:!:: */ + fprintf(new_fp, "%s:", line); + /* parse the tokens of the member list */ + tmp = cp; + while ((cp = strsep(&tmp, ",")) != NULL) { + if (strcmp(member, cp) != 0) { + fprintf(new_fp, fmt, cp); + fmt = ",%s"; + } else { + /* found member, skip it */ + changed_lines++; + } + } + fprintf(new_fp, "\n"); + } } else - fputs(line, new_fp); +#endif + if ((ENABLE_PASSWD && applet_name[0] == 'p') + || (ENABLE_CHPASSWD && applet_name[0] == 'c') + ) { + /* Change passwd */ + cp = strchrnul(cp, ':'); /* move past old passwd */ + /* name: + new_passwd + :rest of line */ + fprintf(new_fp, "%s%s%s\n", name, new_passwd, cp); + changed_lines++; + } /* else delete user or group: skip the line */ + next: free(line); } + + if (changed_lines == 0) { + if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && member) + bb_error_msg("can't find %s in %s", member, filename); + if ((ENABLE_ADDUSER || ENABLE_ADDGROUP) + && applet_name[0] == 'a' && !member + ) { + /* add user or group */ + fprintf(new_fp, "%s%s\n", name, new_passwd); + changed_lines++; + } + } + fcntl(old_fd, F_SETLK, &lock); /* We do want all of them to execute, thus | instead of || */ + errno = 0; if ((ferror(old_fp) | fflush(new_fp) | fsync(new_fd) | fclose(new_fp)) || rename(fnamesfx, filename) ) { /* At least one of those failed */ + bb_perror_nomsg(); goto unlink_new; } - ret = cnt; /* whee, success! */ + /* Success: ret >= 0 */ + ret = changed_lines; unlink_new: - if (ret < 0) unlink(fnamesfx); + if (ret < 0) + unlink(fnamesfx); close_old_fp: fclose(old_fp); @@ -150,6 +259,6 @@ free_mem: free(fnamesfx); free((char *)filename); - free((char *)username); + free((char *)name); return ret; } Index: libbb/Kbuild =================================================================== --- libbb/Kbuild (revision 26090) +++ libbb/Kbuild (revision 26091) @@ -120,6 +120,9 @@ lib-$(CONFIG_FEATURE_MOUNT_LOOP) += loop.o lib-$(CONFIG_LOSETUP) += loop.o lib-$(CONFIG_FEATURE_MTAB_SUPPORT) += mtab.o +lib-$(CONFIG_ADDGROUP) += update_passwd.o +lib-$(CONFIG_ADDUSER) += update_passwd.o +lib-$(CONFIG_DELUSER) += update_passwd.o lib-$(CONFIG_PASSWD) += pw_encrypt.o update_passwd.o lib-$(CONFIG_CHPASSWD) += pw_encrypt.o update_passwd.o lib-$(CONFIG_CRYPTPW) += pw_encrypt.o Index: include/libbb.h =================================================================== --- include/libbb.h (revision 26090) +++ include/libbb.h (revision 26091) @@ -1142,9 +1142,16 @@ * (otherwise we risk having same salt generated) */ extern int crypt_make_salt(char *p, int cnt, int rnd) FAST_FUNC; + /* Returns number of lines changed, or -1 on error */ -extern int update_passwd(const char *filename, const char *username, - const char *new_pw) FAST_FUNC; +#if !(ENABLE_FEATURE_ADDUSER_TO_GROUP || ENABLE_FEATURE_DEL_USER_FROM_GROUP) +#define update_passwd(filename, username, data, member) \ + update_passwd(filename, username, data) +#endif +extern int update_passwd(const char *filename, + const char *username, + const char *data, + const char *member) FAST_FUNC; int index_in_str_array(const char *const string_array[], const char *key) FAST_FUNC; int index_in_strings(const char *strings, const char *key) FAST_FUNC; Index: loginutils/passwd.c =================================================================== --- loginutils/passwd.c (revision 26090) +++ loginutils/passwd.c (revision 26091) @@ -2,7 +2,6 @@ /* * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #include @@ -181,12 +180,12 @@ #if ENABLE_FEATURE_SHADOWPASSWDS filename = bb_path_shadow_file; - rc = update_passwd(bb_path_shadow_file, name, newp); + rc = update_passwd(bb_path_shadow_file, name, newp, NULL); if (rc == 0) /* no lines updated, no errors detected */ #endif { filename = bb_path_passwd_file; - rc = update_passwd(bb_path_passwd_file, name, newp); + rc = update_passwd(bb_path_passwd_file, name, newp, NULL); } /* LOGMODE_BOTH */ if (rc < 0) Index: loginutils/deluser.c =================================================================== --- loginutils/deluser.c (revision 26090) +++ loginutils/deluser.c (revision 26091) @@ -9,117 +9,48 @@ * Licensed under GPL version 2, see file LICENSE in this tarball for details. * */ - #include "libbb.h" -/* Status */ -#define STATUS_OK 0 -#define NAME_NOT_FOUND 1 -#define MEMBER_NOT_FOUND 2 - -static void del_line_matching(char **args, - const char *filename, - FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) +static int del_line_matching(char **args, const char *filename) { - FILE *passwd; - smallint error = NAME_NOT_FOUND; - char *name = (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) ? args[2] : args[1]; - char *line, *del; - char *new = xzalloc(1); - - passwd = fopen_func(filename, "r"); - if (passwd) { - while ((line = xmalloc_fgets(passwd))) { - int len = strlen(name); - - if (strncmp(line, name, len) == 0 - && line[len] == ':' - ) { - error = STATUS_OK; - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP) { - struct group *gr; - char *p; - if (args[2] - /* There were two args on commandline */ - && (gr = getgrnam(name)) - /* The group was not deleted in the meanwhile */ - && (p = strrchr(line, ':')) - /* We can find a pointer to the last ':' */ - ) { - error = MEMBER_NOT_FOUND; - /* Move past ':' (worst case to '\0') and cut the line */ - p[1] = '\0'; - /* Reuse p */ - for (p = xzalloc(1); *gr->gr_mem != NULL; gr->gr_mem++) { - /* Add all the other group members */ - if (strcmp(args[1], *gr->gr_mem) != 0) { - del = p; - p = xasprintf("%s%s%s", p, p[0] ? "," : "", *gr->gr_mem); - free(del); - } else - error = STATUS_OK; - } - /* Recompose the line */ - line = xasprintf("%s%s\n", line, p); - if (ENABLE_FEATURE_CLEAN_UP) free(p); - } else - goto skip; - } - } - del = new; - new = xasprintf("%s%s", new, line); - free(del); - skip: - free(line); - } - - if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); - - if (error) { - if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && error == MEMBER_NOT_FOUND) { - /* Set the correct values for error message */ - filename = name; - name = args[1]; - } - bb_error_msg("can't find %s in %s", name, filename); - } else { - passwd = fopen_func(filename, "w"); - if (passwd) { - fputs(new, passwd); - if (ENABLE_FEATURE_CLEAN_UP) fclose(passwd); - } - } + if (ENABLE_FEATURE_DEL_USER_FROM_GROUP && args[2]) { + return update_passwd(filename, args[2], NULL, args[1]); } - free(new); + return update_passwd(filename, args[1], NULL, NULL); } 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)) + if (argc != 2 + && (!ENABLE_FEATURE_DEL_USER_FROM_GROUP + || (applet_name[3] != 'g' || argc != 3)) ) { - if (geteuid()) - bb_error_msg_and_die(bb_msg_perm_denied_are_you_root); + bb_show_usage(); + } - if ((ENABLE_FEATURE_DEL_USER_FROM_GROUP && argc != 3) - || ENABLE_DELUSER - || (ENABLE_DELGROUP && ENABLE_DESKTOP) + if (geteuid()) + 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 (ENABLE_DELUSER - && (!ENABLE_DELGROUP || applet_name[3] == 'u') - ) { - del_line_matching(argv, bb_path_passwd_file, xfopen); - if (ENABLE_FEATURE_SHADOWPASSWDS) - del_line_matching(argv, bb_path_shadow_file, fopen_or_warn); - } else if (ENABLE_DESKTOP && ENABLE_DELGROUP && getpwnam(argv[1])) - bb_error_msg_and_die("can't remove primary group of user %s", argv[1]); - } - del_line_matching(argv, bb_path_group_file, xfopen); - if (ENABLE_FEATURE_SHADOWPASSWDS) - del_line_matching(argv, bb_path_gshadow_file, fopen_or_warn); - return EXIT_SUCCESS; - } else - bb_show_usage(); + if (del_line_matching(argv, bb_path_passwd_file) < 0) + return EXIT_FAILURE; + if (ENABLE_FEATURE_SHADOWPASSWDS) { + del_line_matching(argv, bb_path_shadow_file); + } + } 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); + } + return EXIT_SUCCESS; } Index: loginutils/addgroup.c =================================================================== --- loginutils/addgroup.c (revision 26090) +++ loginutils/addgroup.c (revision 26091) @@ -9,7 +9,6 @@ * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. * */ - #include "libbb.h" static void xgroup_study(struct group *g) @@ -45,8 +44,8 @@ /* append a new user to the passwd file */ static void new_group(char *group, gid_t gid) { - FILE *file; struct group gr; + char *p; /* make sure gid and group haven't already been allocated */ gr.gr_gid = gid; @@ -54,67 +53,17 @@ xgroup_study(&gr); /* add entry to group */ - file = xfopen(bb_path_group_file, "a"); - /* group:passwd:gid:userlist */ - fprintf(file, "%s:x:%u:\n", group, (unsigned)gr.gr_gid); + p = xasprintf("x:%u:", gr.gr_gid); + if (update_passwd(bb_path_group_file, group, p, NULL) < 0) + exit(EXIT_FAILURE); if (ENABLE_FEATURE_CLEAN_UP) - fclose(file); + free(p); #if ENABLE_FEATURE_SHADOWPASSWDS - file = fopen_or_warn(bb_path_gshadow_file, "a"); - if (file) { - fprintf(file, "%s:!::\n", group); - if (ENABLE_FEATURE_CLEAN_UP) - fclose(file); - } + /* Ignore errors: if file is missing we suppose admin doesn't want it */ + update_passwd(bb_path_gshadow_file, group, "!::", NULL); #endif } -#if ENABLE_FEATURE_ADDUSER_TO_GROUP -static void add_user_to_group(char **args, - const char *path, - FILE* FAST_FUNC (*fopen_func)(const char *fileName, const char *mode)) -{ - char *line; - int len = strlen(args[1]); - llist_t *plist = NULL; - FILE *group_file; - - group_file = fopen_func(path, "r"); - - if (!group_file) return; - - while ((line = xmalloc_fgetline(group_file)) != NULL) { - /* Find the group */ - if (!strncmp(line, args[1], len) - && line[len] == ':' - ) { - /* Add the new user */ - line = xasprintf("%s%s%s", line, - last_char_is(line, ':') ? "" : ",", - args[0]); - } - llist_add_to_end(&plist, line); - } - - if (ENABLE_FEATURE_CLEAN_UP) { - fclose(group_file); - group_file = fopen_func(path, "w"); - while ((line = llist_pop(&plist))) { - if (group_file) - fprintf(group_file, "%s\n", line); - free(line); - } - if (group_file) - fclose(group_file); - } else { - group_file = fopen_func(path, "w"); - if (group_file) - while ((line = llist_pop(&plist))) - fprintf(group_file, "%s\n", line); - } -} -#endif - /* * addgroup will take a login_name as its first parameter. * @@ -166,10 +115,12 @@ return EXIT_SUCCESS; } } - add_user_to_group(argv, bb_path_group_file, xfopen); -#if ENABLE_FEATURE_SHADOWPASSWDS - add_user_to_group(argv, bb_path_gshadow_file, fopen_or_warn); -#endif + if (update_passwd(bb_path_group_file, argv[1], NULL, argv[0]) < 0) { + return EXIT_FAILURE; + } +# if ENABLE_FEATURE_SHADOWPASSWDS + update_passwd(bb_path_gshadow_file, argv[1], NULL, argv[0]); +# endif } else #endif /* ENABLE_FEATURE_ADDUSER_TO_GROUP */ { Index: loginutils/adduser.c =================================================================== --- loginutils/adduser.c (revision 26090) +++ loginutils/adduser.c (revision 26091) @@ -7,14 +7,12 @@ * * Licensed under the GPL v2 or later, see the file LICENSE in this tarball. */ - #include "libbb.h" #define OPT_DONT_SET_PASS (1 << 4) #define OPT_SYSTEM_ACCOUNT (1 << 5) #define OPT_DONT_MAKE_HOME (1 << 6) - /* remix */ /* recoded such that the uid may be passed in *p */ static void passwd_study(struct passwd *p) @@ -88,10 +86,7 @@ { struct passwd pw; const char *usegroup = NULL; - FILE *file; -#if ENABLE_FEATURE_SHADOWPASSWDS - int fd; -#endif + char *p; #if ENABLE_FEATURE_ADDUSER_LONG_OPTIONS applet_long_options = adduser_longopts; @@ -124,32 +119,19 @@ /* make sure everything is kosher and setup uid && maybe gid */ passwd_study(&pw); - /* add to passwd */ - file = xfopen(bb_path_passwd_file, "a"); - //fseek(file, 0, SEEK_END); /* paranoia, "a" should ensure that anyway */ - if (putpwent(&pw, file) != 0) { - bb_perror_nomsg_and_die(); + p = xasprintf("x:%u:%u:%s:%s:%s", pw.pw_uid, pw.pw_gid, pw.pw_gecos, pw.pw_dir, pw.pw_shell); + if (update_passwd(bb_path_passwd_file, pw.pw_name, p, NULL) < 0) { + return EXIT_FAILURE; } - /* do fclose even if !ENABLE_FEATURE_CLEAN_UP. - * We will exec passwd, files must be flushed & closed before that! */ - fclose(file); + if (ENABLE_FEATURE_CLEAN_UP) + free(p); #if ENABLE_FEATURE_SHADOWPASSWDS - /* add to shadow if necessary */ - /* fopen(..., "a"); would create shadow file, which is wrong. - * If shadow file doesn't exist, admin probably does not want it */ - fd = open_or_warn(bb_path_shadow_file, O_WRONLY | O_APPEND); - if (fd >= 0) { - char *s = xasprintf("%s:!:%u:0:99999:7:::\n", - pw.pw_name, /* username */ - (unsigned)(time(NULL) / 86400) /* sp->sp_lstchg */ - /*0,*/ /* sp->sp_min */ - /*99999,*/ /* sp->sp_max */ - /*7*/ /* sp->sp_warn */ - ); - xwrite_str(fd, s); - close(fd); - } + p = xasprintf("!:%u:0:99999:7:::", (unsigned)(time(NULL) / 86400)); /* sp->sp_lstchg */ + /* Ignore errors: if file is missing we suppose admin doesn't want it */ + update_passwd(bb_path_shadow_file, pw.pw_name, p, NULL); + if (ENABLE_FEATURE_CLEAN_UP) + free(p); #endif /* add to group */ Index: loginutils/chpasswd.c =================================================================== --- loginutils/chpasswd.c (revision 26090) +++ loginutils/chpasswd.c (revision 26091) @@ -5,7 +5,6 @@ * Written for SLIND (from passwd.c) by Alexander Shishkin * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "libbb.h" #if ENABLE_GETOPT_LONG @@ -53,10 +52,10 @@ /* 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); + rc = update_passwd(bb_path_shadow_file, name, pass, NULL); if (rc == 0) /* no lines updated, no errors detected */ #endif - rc = update_passwd(bb_path_passwd_file, name, pass); + rc = update_passwd(bb_path_passwd_file, name, pass, NULL); /* LOGMODE_BOTH logs to syslog also */ logmode = LOGMODE_BOTH; if (rc < 0) ------------------------------------------------------------------------ r26090 | vda | 2009-04-13 18:18:52 -0500 (Mon, 13 Apr 2009) | 9 lines Changed paths: M /trunk/busybox/include/usage.h M /trunk/busybox/util-linux/mdev.c mdev: add support for - "dont stop here" char function old new delta make_device 1340 1362 +22 packed_usage 26291 26299 +8 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 2/0 up/down: 30/0) Total: 30 bytes ------------------------------------------------------------------------ Index: include/usage.h =================================================================== --- include/usage.h (revision 26089) +++ include/usage.h (revision 26090) @@ -2560,7 +2560,7 @@ " echo /bin/mdev >/proc/sys/kernel/hotplug\n" \ USE_FEATURE_MDEV_CONF( \ "It uses /etc/mdev.conf with lines\n" \ - "DEVNAME UID:GID PERM" \ + "[-]DEVNAME UID:GID PERM" \ USE_FEATURE_MDEV_RENAME(" [>|=PATH]") \ USE_FEATURE_MDEV_EXEC(" [@|$|*COMMAND]") \ ) \ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26089) +++ util-linux/mdev.c (revision 26090) @@ -57,21 +57,12 @@ /* NB: "mdev -s" may call us many times, do not leak memory/fds! */ static void make_device(char *path, int delete) { - const char *device_name; - int major, minor, type, len; - int mode = 0660; #if ENABLE_FEATURE_MDEV_CONF - struct bb_uidgid_t ugid = { 0, 0 }; parser_t *parser; - char *tokens[5]; -# if ENABLE_FEATURE_MDEV_EXEC - char *command = NULL; -# endif -# if ENABLE_FEATURE_MDEV_RENAME - char *alias = NULL; - char aliaslink = aliaslink; /* for compiler */ -# endif #endif + const char *device_name; + int major, minor, type, len; + int mode; char *dev_maj_min = path + strlen(path); /* Force the configuration file settings exactly. */ @@ -111,14 +102,37 @@ parser = config_open2("/etc/mdev.conf", fopen_for_read); /* If we have config file, look up user settings */ - while (config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) { + while (1) { regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP]; - char *val = tokens[0]; + int keep_matching; + char *val; + struct bb_uidgid_t ugid; + char *tokens[4]; +# if ENABLE_FEATURE_MDEV_EXEC + char *command = NULL; +# endif +# if ENABLE_FEATURE_MDEV_RENAME + char *alias = NULL; + char aliaslink = aliaslink; /* for compiler */ +# endif + /* Defaults in case we won't match any line */ + ugid.uid = ugid.gid = 0; + keep_matching = 0; + mode = 0660; + if (!config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) { + /* End of file, create dev node with default params */ + goto line_matches; + } + + val = tokens[0]; + keep_matching = ('-' == val[0]); + val += keep_matching; /* swallow leading dash */ + /* Fields: regex uid:gid mode [alias] [cmd] */ /* 1st field: @... */ - if (tokens[0][0] == '@') { + if (val[0] == '@') { /* @major,minor[-last] */ /* (useful when name is ambiguous: * "/sys/class/usb/lp0" and @@ -126,12 +140,12 @@ int cmaj, cmin0, cmin1, sc; if (major < 0) continue; /* no dev, no match */ - sc = sscanf(tokens[0], "@%u,%u-%u", &cmaj, &cmin0, &cmin1); + sc = sscanf(val, "@%u,%u-%u", &cmaj, &cmin0, &cmin1); if (sc < 1 || major != cmaj || (sc == 2 && minor != cmin0) || (sc == 3 && (minor < cmin0 || minor > cmin1)) ) { - continue; /* no match */ + continue; /* this line doesn't match */ } } else { /* ... or regex to match device name */ regex_t match; @@ -160,12 +174,12 @@ if (result || off[0].rm_so || ((int)off[0].rm_eo != (int)strlen(dev_name_or_subsystem)) ) { - continue; + continue; /* this line doesn't match */ } } - /* This line matches: stop parsing the file - * after parsing the rest of fields */ + /* This line matches: stop parsing the file after parsing + * the rest of fields unless keep_matching == 1 */ /* 2nd field: uid:gid - device ownership */ parse_chown_usergroup_or_die(&ugid, tokens[1]); @@ -174,24 +188,25 @@ mode = strtoul(tokens[2], NULL, 8); val = tokens[3]; - /* 4th field (opt): >alias */ + /* 4th field (opt): >|=alias */ # if ENABLE_FEATURE_MDEV_RENAME if (!val) - break; - aliaslink = *val; + goto line_matches; + aliaslink = val[0]; if (aliaslink == '>' || aliaslink == '=') { - char *s, *st; + char *a, *s, *st; # if ENABLE_FEATURE_MDEV_RENAME_REGEXP char *p; unsigned i, n; # endif - char *a = val; + a = val; s = strchrnul(val, ' '); st = strchrnul(val, '\t'); if (st < s) s = st; val = (s[0] && s[1]) ? s+1 : NULL; s[0] = '\0'; + # if ENABLE_FEATURE_MDEV_RENAME_REGEXP /* substitute %1..9 with off[1..9], if any */ n = 0; @@ -223,12 +238,12 @@ # endif /* ENABLE_FEATURE_MDEV_RENAME */ # if ENABLE_FEATURE_MDEV_EXEC - /* The rest (opt): command to run */ + /* The rest (opt): @|$|*command */ if (!val) - break; + goto line_matches; { const char *s = "@$*"; - const char *s2 = strchr(s, *val); + const char *s2 = strchr(s, val[0]); if (!s2) bb_error_msg_and_die("bad line %u", parser->lineno); @@ -244,71 +259,71 @@ } } # endif - /* end of field parsing */ - break; /* we found matching line, stop */ - } /* end of "while line is read from /etc/mdev.conf" */ - - config_close(parser); + /* End of field parsing */ + line_matches: #endif /* ENABLE_FEATURE_MDEV_CONF */ - if (!delete && major >= 0) { + /* "Execute" the line we found */ - if (ENABLE_FEATURE_MDEV_RENAME) - unlink(device_name); - - if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) - bb_perror_msg_and_die("mknod %s", device_name); - - if (major == root_major && minor == root_minor) - symlink(device_name, "root"); - + if (!delete && major >= 0) { + if (ENABLE_FEATURE_MDEV_RENAME) + unlink(device_name); + if (mknod(device_name, mode | type, makedev(major, minor)) && errno != EEXIST) + bb_perror_msg_and_die("mknod %s", device_name); + if (major == root_major && minor == root_minor) + symlink(device_name, "root"); #if ENABLE_FEATURE_MDEV_CONF - chown(device_name, ugid.uid, ugid.gid); - + chown(device_name, ugid.uid, ugid.gid); # if ENABLE_FEATURE_MDEV_RENAME - if (alias) { - alias = build_alias(alias, device_name); - - /* move the device, and optionally - * make a symlink to moved device node */ - if (rename(device_name, alias) == 0 && aliaslink == '>') - symlink(alias, device_name); - - free(alias); - } + if (alias) { + alias = build_alias(alias, device_name); + /* move the device, and optionally + * make a symlink to moved device node */ + if (rename(device_name, alias) == 0 && aliaslink == '>') + symlink(alias, device_name); + free(alias); + } # endif #endif - } - + } #if ENABLE_FEATURE_MDEV_EXEC - if (command) { - /* setenv will leak memory, use putenv/unsetenv/free */ - char *s = xasprintf("%s=%s", "MDEV", device_name); - char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem); - putenv(s); - putenv(s1); - if (system(command) == -1) - bb_perror_msg_and_die("can't run '%s'", command); - unsetenv("SUBSYSTEM"); - free(s1); - unsetenv("MDEV"); - free(s); - free(command); - } + if (command) { + /* setenv will leak memory, use putenv/unsetenv/free */ + char *s = xasprintf("%s=%s", "MDEV", device_name); + char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem); + putenv(s); + putenv(s1); + if (system(command) == -1) + bb_perror_msg_and_die("can't run '%s'", command); + unsetenv("SUBSYSTEM"); + free(s1); + unsetenv("MDEV"); + free(s); + free(command); + } #endif - - if (delete) { - unlink(device_name); - /* At creation time, device might have been moved - * and a symlink might have been created. Undo that. */ + if (delete) { + unlink(device_name); + /* At creation time, device might have been moved + * and a symlink might have been created. Undo that. */ #if ENABLE_FEATURE_MDEV_RENAME - if (alias) { - alias = build_alias(alias, device_name); - unlink(alias); - free(alias); + if (alias) { + alias = build_alias(alias, device_name); + unlink(alias); + free(alias); + } +#endif } -#endif - } + +#if ENABLE_FEATURE_MDEV_CONF + /* We found matching line. + * Stop unless it was prefixed with '-' */ + if (!keep_matching) + break; + } /* end of "while line is read from /etc/mdev.conf" */ + + config_close(parser); +#endif /* ENABLE_FEATURE_MDEV_CONF */ } /* File callback for /sys/ traversal */ ------------------------------------------------------------------------ r26089 | vda | 2009-04-13 17:23:02 -0500 (Mon, 13 Apr 2009) | 10 lines Changed paths: M /trunk/busybox/util-linux/mdev.c mdev: provide $SUBSYSTEM (by Vladimir) function old new delta make_device 1265 1340 +75 dirAction 14 60 +46 mdev_main 676 695 +19 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 3/0 up/down: 140/0) Total: 140 bytes ------------------------------------------------------------------------ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26088) +++ util-linux/mdev.c (revision 26089) @@ -14,10 +14,12 @@ struct globals { int root_major, root_minor; + char *subsystem; }; #define G (*(struct globals*)&bb_common_bufsiz1) #define root_major (G.root_major) #define root_minor (G.root_minor) +#define subsystem (G.subsystem) /* Prevent infinite loops in /sys symlinks */ #define MAX_SYSFS_DEPTH 3 @@ -111,7 +113,7 @@ /* If we have config file, look up user settings */ while (config_read(parser, tokens, 4, 3, "# \t", PARSE_NORMAL)) { regmatch_t off[1 + 9*ENABLE_FEATURE_MDEV_RENAME_REGEXP]; - char *val; + char *val = tokens[0]; /* Fields: regex uid:gid mode [alias] [cmd] */ @@ -134,10 +136,15 @@ } else { /* ... or regex to match device name */ regex_t match; int result; + const char *dev_name_or_subsystem = device_name; + if ('/' == val[0] && subsystem) { + dev_name_or_subsystem = subsystem; + val++; + } /* Is this it? */ - xregcomp(&match, tokens[0], REG_EXTENDED); - result = regexec(&match, device_name, ARRAY_SIZE(off), off, 0); + xregcomp(&match, val, REG_EXTENDED); + result = regexec(&match, dev_name_or_subsystem, ARRAY_SIZE(off), off, 0); regfree(&match); //bb_error_msg("matches:"); @@ -151,7 +158,7 @@ /* If not this device, skip rest of line */ /* (regexec returns whole pattern as "range" 0) */ if (result || off[0].rm_so - || ((int)off[0].rm_eo != (int)strlen(device_name)) + || ((int)off[0].rm_eo != (int)strlen(dev_name_or_subsystem)) ) { continue; } @@ -276,10 +283,14 @@ #if ENABLE_FEATURE_MDEV_EXEC if (command) { /* setenv will leak memory, use putenv/unsetenv/free */ - char *s = xasprintf("MDEV=%s", device_name); + char *s = xasprintf("%s=%s", "MDEV", device_name); + char *s1 = xasprintf("%s=%s", "SUBSYSTEM", subsystem); putenv(s); + putenv(s1); if (system(command) == -1) bb_perror_msg_and_die("can't run '%s'", command); + unsetenv("SUBSYSTEM"); + free(s1); unsetenv("MDEV"); free(s); free(command); @@ -326,6 +337,13 @@ void *userData UNUSED_PARAM, int depth) { + /* Extract device subsystem -- the name of the directory under /sys/class/ */ + if (1 == depth) { + subsystem = strrchr(fileName, '/'); + if (subsystem) + subsystem++; + } + return (depth >= MAX_SYSFS_DEPTH ? SKIP : TRUE); } @@ -445,13 +463,14 @@ char *env_path; /* Hotplug: - * env ACTION=... DEVPATH=... [SEQNUM=...] mdev + * env ACTION=... DEVPATH=... SUBSYSTEM=... [SEQNUM=...] mdev * ACTION can be "add" or "remove" * DEVPATH is like "/block/sda" or "/class/input/mice" */ action = getenv("ACTION"); env_path = getenv("DEVPATH"); - if (!action || !env_path) + subsystem = getenv("SUBSYSTEM"); + if (!action || !env_path /*|| !subsystem*/) bb_show_usage(); fw = getenv("FIRMWARE"); ------------------------------------------------------------------------ r26088 | vda | 2009-04-13 15:52:00 -0500 (Mon, 13 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/include/libbb.h M /trunk/busybox/libbb/llist.c M /trunk/busybox/modutils/modutils.c M /trunk/busybox/modutils/modutils.h M /trunk/busybox/networking/ifupdown.c M /trunk/busybox/procps/pidof.c move llist_find_str from modutils to libbb ------------------------------------------------------------------------ Index: networking/ifupdown.c =================================================================== --- networking/ifupdown.c (revision 26087) +++ networking/ifupdown.c (revision 26088) @@ -692,20 +692,6 @@ return NULL; } -static const llist_t *find_list_string(const llist_t *list, const char *string) -{ - if (string == NULL) - return NULL; - - while (list) { - if (strcmp(list->data, string) == 0) { - return list; - } - list = list->link; - } - return NULL; -} - static struct interfaces_file_t *read_interfaces(const char *filename) { /* Let's try to be compatible. @@ -836,7 +822,7 @@ while ((first_word = next_word(&rest_of_line)) != NULL) { /* Check the interface isnt already listed */ - if (find_list_string(defn->autointerfaces, first_word)) { + if (llist_find_str(defn->autointerfaces, first_word)) { bb_perror_msg_and_die("interface declared auto twice \"%s\"", buf); } Index: modutils/modutils.c =================================================================== --- modutils/modutils.c (revision 26087) +++ modutils/modutils.c (revision 26088) @@ -16,19 +16,6 @@ # define delete_module(mod, flags) syscall(__NR_delete_module, mod, flags) #endif -/* - a libbb candidate from ice age! -*/ -llist_t FAST_FUNC *llist_find(llist_t *first, const char *str) -{ - while (first != NULL) { - if (strcmp(first->data, str) == 0) - return first; - first = first->link; - } - return NULL; -} - void FAST_FUNC replace(char *s, char what, char with) { while (*s) { Index: modutils/modutils.h =================================================================== --- modutils/modutils.h (revision 26087) +++ modutils/modutils.h (revision 26088) @@ -18,7 +18,6 @@ #define MODULE_NAME_LEN 256 const char *moderror(int err) FAST_FUNC; -llist_t *llist_find(llist_t *first, const char *str) FAST_FUNC; 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; Index: libbb/llist.c =================================================================== --- libbb/llist.c (revision 26087) +++ libbb/llist.c (revision 26088) @@ -86,3 +86,13 @@ } return rev; } + +llist_t* FAST_FUNC llist_find_str(llist_t *list, const char *str) +{ + while (list) { + if (strcmp(list->data, str) == 0) + break; + list = list->link; + } + return list; +} Index: include/libbb.h =================================================================== --- include/libbb.h (revision 26087) +++ include/libbb.h (revision 26088) @@ -859,6 +859,7 @@ void llist_unlink(llist_t **head, llist_t *elm) FAST_FUNC; void llist_free(llist_t *elm, void (*freeit)(void *data)) FAST_FUNC; llist_t *llist_rev(llist_t *list) FAST_FUNC; +llist_t *llist_find_str(llist_t *first, const char *str) FAST_FUNC; /* BTW, surprisingly, changing API to * llist_t *llist_add_to(llist_t *old_head, void *data) * etc does not result in smaller code... */ Index: procps/pidof.c =================================================================== --- procps/pidof.c (revision 26087) +++ procps/pidof.c (revision 26088) @@ -35,12 +35,12 @@ /* fill omit list. */ { llist_t *omits_p = omits; - while (omits_p) { + while (1) { + omits_p = llist_find_str(omits_p, "%PPID"); + if (!omits_p) + break; /* are we asked to exclude the parent's process ID? */ - if (strcmp(omits_p->data, "%PPID") == 0) { - omits_p->data = utoa((unsigned)getppid()); - } - omits_p = omits_p->link; + omits_p->data = utoa((unsigned)getppid()); } } #endif ------------------------------------------------------------------------ r26087 | vda | 2009-04-13 15:32:31 -0500 (Mon, 13 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/modutils/modutils.c modutils: remove redundant sanitization ------------------------------------------------------------------------ Index: modutils/modutils.c =================================================================== --- modutils/modutils.c (revision 26086) +++ modutils/modutils.c (revision 26087) @@ -5,7 +5,6 @@ * * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. */ - #include "modutils.h" #ifdef __UCLIBC__ @@ -111,9 +110,9 @@ int FAST_FUNC bb_init_module(const char *filename, const char *options) { - size_t len = MAXINT(ssize_t); + size_t len; char *image; - int rc = ENOENT; + int rc; if (!options) options = ""; @@ -124,10 +123,12 @@ #endif /* Use the 2.6 way */ + len = INT_MAX - 4095; + rc = ENOENT; image = xmalloc_open_zipped_read_close(filename, &len); if (image) { rc = 0; - if (init_module(image, len, options ? options : "") != 0) + if (init_module(image, len, options) != 0) rc = errno; free(image); } ------------------------------------------------------------------------ r26085 | vda | 2009-04-13 09:23:12 -0500 (Mon, 13 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/scripts/defconfig M /trunk/busybox/shell/Config.in M /trunk/busybox/shell/hush.c hush: make function support configurable ------------------------------------------------------------------------ Index: scripts/defconfig =================================================================== --- scripts/defconfig (revision 26084) +++ scripts/defconfig (revision 26085) @@ -1,10 +1,8 @@ -# defconfig is allyesconfig minus any features that are -# specialized (debugging etc) or make applet behavior change -# significantly from "standard" version of utilities. -# Applets which are severely incompatible with "standard" utilities -# or are not maintained /tested for some time, appear to be buggy -# and carry serious potential of breakage if used, may also be excluded - +# +# Automatically generated make config: don't edit +# Busybox version: 1.14.0.svn +# Mon Apr 13 16:22:36 2009 +# CONFIG_HAVE_DOT_CONFIG=y # @@ -49,6 +47,7 @@ # CONFIG_FEATURE_SHARED_BUSYBOX is not set CONFIG_LFS=y CONFIG_CROSS_COMPILER_PREFIX="" +CONFIG_EXTRA_CFLAGS="" # # Debugging Options @@ -210,6 +209,8 @@ 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 @@ -389,6 +390,7 @@ 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_ADDUSER_TO_GROUP=y CONFIG_DELGROUP=y @@ -425,8 +427,6 @@ # # Linux Module Utilities # -CONFIG_DEFAULT_MODULES_DIR="/lib/modules" -CONFIG_DEFAULT_DEPMOD_FILE="modules.dep" CONFIG_MODPROBE_SMALL=y CONFIG_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE=y CONFIG_FEATURE_MODPROBE_SMALL_CHECK_ALREADY_LOADED=y @@ -450,10 +450,14 @@ # 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_ACPID=y +CONFIG_FEATURE_ACPID_COMPAT=y CONFIG_BLKID=y CONFIG_DMESG=y CONFIG_FEATURE_DMESG_PRETTY=y @@ -479,6 +483,7 @@ # Minix filesystem support # CONFIG_FEATURE_MINIX2=y +CONFIG_MKFS_VFAT=y CONFIG_GETOPT=y CONFIG_HEXDUMP=y CONFIG_FEATURE_HEXDUMP_REVERSE=y @@ -561,6 +566,7 @@ 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 @@ -573,6 +579,8 @@ CONFIG_EJECT=y CONFIG_FEATURE_EJECT_SCSI=y CONFIG_FBSPLASH=y +CONFIG_FLASH_ERASEALL=y +CONFIG_IONICE=y # CONFIG_INOTIFYD is not set CONFIG_LAST=y # CONFIG_FEATURE_LAST_SMALL is not set @@ -581,11 +589,11 @@ CONFIG_FEATURE_LESS_MAXLINES=9999999 CONFIG_FEATURE_LESS_BRACKETS=y CONFIG_FEATURE_LESS_FLAGS=y -CONFIG_FEATURE_LESS_DASHCMD=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_FEATURE_LESS_WINCH=y CONFIG_HDPARM=y CONFIG_FEATURE_HDPARM_GET_IDENTITY=y CONFIG_FEATURE_HDPARM_HDIO_SCAN_HWIF=y @@ -609,6 +617,7 @@ # CONFIG_TASKSET is not set # CONFIG_FEATURE_TASKSET_FANCY is not set CONFIG_TIME=y +CONFIG_TIMEOUT=y CONFIG_TTYSIZE=y CONFIG_WATCHDOG=y @@ -626,6 +635,8 @@ CONFIG_DNSD=y CONFIG_ETHER_WAKE=y CONFIG_FAKEIDENTD=y +CONFIG_FTPD=y +CONFIG_FEATURE_FTP_WRITE=y CONFIG_FTPGET=y CONFIG_FTPPUT=y CONFIG_FEATURE_FTPGETPUT_LONG_OPTIONS=y @@ -723,6 +734,7 @@ CONFIG_FEATURE_UDHCP_RFC3397=y CONFIG_UDHCPC_DEFAULT_SCRIPT="/usr/share/udhcpc/default.script" CONFIG_UDHCPC_SLACK_FOR_BUGGY_SERVERS=80 +CONFIG_IFUPDOWN_UDHCPC_CMD_OPTIONS="-R -n" CONFIG_VCONFIG=y CONFIG_WGET=y CONFIG_FEATURE_WGET_STATUSBAR=y @@ -730,6 +742,8 @@ CONFIG_FEATURE_WGET_LONG_OPTIONS=y CONFIG_ZCIP=y CONFIG_TCPSVD=y +CONFIG_TUNCTL=y +CONFIG_FEATURE_TUNCTL_UG=y CONFIG_UDPSVD=y # @@ -749,8 +763,6 @@ CONFIG_REFORMIME=y CONFIG_FEATURE_REFORMIME_COMPAT=y CONFIG_SENDMAIL=y -CONFIG_FEATURE_SENDMAIL_MAILX=y -CONFIG_FEATURE_SENDMAIL_MAILXX=y # # Process Utilities @@ -768,7 +780,7 @@ CONFIG_PKILL=y CONFIG_PS=y CONFIG_FEATURE_PS_WIDE=y -CONFIG_FEATURE_PS_TIME=y +# CONFIG_FEATURE_PS_TIME is not set # CONFIG_FEATURE_PS_UNUSUAL_SYSTEMS is not set CONFIG_RENICE=y CONFIG_BB_SYSCTL=y @@ -829,8 +841,6 @@ CONFIG_ASH_READ_NCHARS=y CONFIG_ASH_READ_TIMEOUT=y CONFIG_ASH_ALIAS=y -CONFIG_ASH_MATH_SUPPORT=y -CONFIG_ASH_MATH_SUPPORT_64=y CONFIG_ASH_GETOPTS=y CONFIG_ASH_BUILTIN_ECHO=y CONFIG_ASH_BUILTIN_PRINTF=y @@ -848,12 +858,15 @@ CONFIG_HUSH_IF=y CONFIG_HUSH_LOOPS=y CONFIG_HUSH_CASE=y +CONFIG_HUSH_FUNCTIONS=y # CONFIG_LASH is not set CONFIG_MSH=y # # Bourne Shell Options # +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 Index: shell/hush.c =================================================================== --- shell/hush.c (revision 26084) +++ shell/hush.c (revision 26085) @@ -83,8 +83,6 @@ * Keeping 1 for now even in released versions. */ #define HUSH_DEBUG 1 -/* In progress... */ -#define ENABLE_HUSH_FUNCTIONS 1 #if BUILD_AS_NOMMU Index: shell/Config.in =================================================================== --- shell/Config.in (revision 26084) +++ shell/Config.in (revision 26085) @@ -159,16 +159,15 @@ bool "hush" default n help - hush is a very small shell (just 18k) and it has fairly complete - Bourne shell grammar. It even handles all the normal flow control - options such as if/then/elif/else/fi, for/in/do/done, while loops, - case/esac. + 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, functions, here documents ( << - word ), aliases, brace expansion, tilde expansion, - &> and >& redirection of stdout+stderr, etc. + It does not handle select, aliases, brace expansion, + tilde expansion, &>file and >&file redirection of stdout+stderr. config HUSH_HELP bool "help builtin" @@ -226,6 +225,13 @@ help Enable case ... esac statement in hush. +400 bytes. +config HUSH_FUNCTIONS + bool "Support funcname() { commands; } syntax" + default n + depends on HUSH + help + Enable support for shell functions in hush. +800 bytes. + config LASH bool "lash (deprecated: aliased to hush)" default n @@ -237,16 +243,17 @@ bool "msh (deprecated: please use hush)" default n help - 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. - 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. + + comment "Bourne Shell Options" depends on MSH || LASH || HUSH || ASH ------------------------------------------------------------------------ r26084 | vda | 2009-04-13 08:59:26 -0500 (Mon, 13 Apr 2009) | 3 lines Changed paths: M /trunk/busybox/util-linux/mdev.c mdev: fix a bug where \t is not treated as delimiter after [>|=PATH] ------------------------------------------------------------------------ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26083) +++ util-linux/mdev.c (revision 26084) @@ -173,13 +173,16 @@ break; aliaslink = *val; if (aliaslink == '>' || aliaslink == '=') { - char *s; + char *s, *st; # if ENABLE_FEATURE_MDEV_RENAME_REGEXP char *p; unsigned i, n; # endif char *a = val; s = strchrnul(val, ' '); + st = strchrnul(val, '\t'); + if (st < s) + s = st; val = (s[0] && s[1]) ? s+1 : NULL; s[0] = '\0'; # if ENABLE_FEATURE_MDEV_RENAME_REGEXP ------------------------------------------------------------------------ r26083 | vda | 2009-04-13 08:33:02 -0500 (Mon, 13 Apr 2009) | 6 lines Changed paths: M /trunk/busybox/include/usage.h M /trunk/busybox/util-linux/mdev.c mdev: make usage text more useful function old new delta packed_usage 26235 26291 +56 ------------------------------------------------------------------------ Index: include/usage.h =================================================================== --- include/usage.h (revision 26082) +++ include/usage.h (revision 26083) @@ -2556,8 +2556,14 @@ #define mdev_full_usage "\n\n" \ " -s Scan /sys and populate /dev during system boot\n" \ "\n" \ - "Called with no options (via hotplug) it uses environment variables\n" \ - "to determine which device to add/remove." + "It can be run by kernel as a hotplug helper. To activate it:\n" \ + " echo /bin/mdev >/proc/sys/kernel/hotplug\n" \ + USE_FEATURE_MDEV_CONF( \ + "It uses /etc/mdev.conf with lines\n" \ + "DEVNAME UID:GID PERM" \ + USE_FEATURE_MDEV_RENAME(" [>|=PATH]") \ + USE_FEATURE_MDEV_EXEC(" [@|$|*COMMAND]") \ + ) \ #define mdev_notes_usage "" \ USE_FEATURE_MDEV_CONFIG( \ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26082) +++ util-linux/mdev.c (revision 26083) @@ -62,13 +62,13 @@ struct bb_uidgid_t ugid = { 0, 0 }; parser_t *parser; char *tokens[5]; -#endif -#if ENABLE_FEATURE_MDEV_EXEC +# if ENABLE_FEATURE_MDEV_EXEC char *command = NULL; -#endif -#if ENABLE_FEATURE_MDEV_RENAME +# endif +# if ENABLE_FEATURE_MDEV_RENAME char *alias = NULL; char aliaslink = aliaslink; /* for compiler */ +# endif #endif char *dev_maj_min = path + strlen(path); @@ -168,21 +168,21 @@ val = tokens[3]; /* 4th field (opt): >alias */ -#if ENABLE_FEATURE_MDEV_RENAME +# if ENABLE_FEATURE_MDEV_RENAME if (!val) break; aliaslink = *val; if (aliaslink == '>' || aliaslink == '=') { char *s; -#if ENABLE_FEATURE_MDEV_RENAME_REGEXP +# if ENABLE_FEATURE_MDEV_RENAME_REGEXP char *p; unsigned i, n; -#endif +# endif char *a = val; s = strchrnul(val, ' '); val = (s[0] && s[1]) ? s+1 : NULL; s[0] = '\0'; -#if ENABLE_FEATURE_MDEV_RENAME_REGEXP +# if ENABLE_FEATURE_MDEV_RENAME_REGEXP /* substitute %1..9 with off[1..9], if any */ n = 0; s = a; @@ -206,13 +206,13 @@ p++; s++; } -#else +# else alias = xstrdup(a + 1); -#endif +# endif } -#endif /* ENABLE_FEATURE_MDEV_RENAME */ +# endif /* ENABLE_FEATURE_MDEV_RENAME */ -#if ENABLE_FEATURE_MDEV_EXEC +# if ENABLE_FEATURE_MDEV_EXEC /* The rest (opt): command to run */ if (!val) break; @@ -233,7 +233,7 @@ command = xstrdup(val + 1); } } -#endif +# endif /* end of field parsing */ break; /* we found matching line, stop */ } /* end of "while line is read from /etc/mdev.conf" */ @@ -255,7 +255,7 @@ #if ENABLE_FEATURE_MDEV_CONF chown(device_name, ugid.uid, ugid.gid); -#if ENABLE_FEATURE_MDEV_RENAME +# if ENABLE_FEATURE_MDEV_RENAME if (alias) { alias = build_alias(alias, device_name); @@ -266,8 +266,8 @@ free(alias); } +# endif #endif -#endif } #if ENABLE_FEATURE_MDEV_EXEC @@ -406,7 +406,7 @@ xchdir("/dev"); - if (argv[1] && !strcmp(argv[1], "-s")) { + if (argv[1] && strcmp(argv[1], "-s") == 0) { /* Scan: * mdev -s */ @@ -501,5 +501,5 @@ if (ENABLE_FEATURE_CLEAN_UP) RELEASE_CONFIG_BUFFER(temp); - return 0; + return EXIT_SUCCESS; } ------------------------------------------------------------------------ r26082 | vda | 2009-04-12 22:33:46 -0500 (Sun, 12 Apr 2009) | 4 lines Changed paths: M /trunk/busybox/include/usage.h M /trunk/busybox/networking/udhcp/dhcprelay.c dhcprelay: fix usage text. Simplify and make code more readable. Add TODOs. ------------------------------------------------------------------------ Index: networking/udhcp/dhcprelay.c =================================================================== --- networking/udhcp/dhcprelay.c (revision 26081) +++ networking/udhcp/dhcprelay.c (revision 26082) @@ -13,7 +13,6 @@ #include "common.h" #include "options.h" -/* constants */ #define SERVER_PORT 67 #define SELECT_TIMEOUT 5 /* select timeout in sec. */ #define MAX_LIFETIME 2*60 /* lifetime of an xid entry in sec. */ @@ -149,19 +148,21 @@ } -/* Creates listen sockets (in fds) and returns numerically max fd. */ -static int init_sockets(char **client, int num_clients, - char *server, int *fds) +/* 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) { int i, n; /* talk to real server on bootps */ - fds[0] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, server); + 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[i-1]); + fds[i] = udhcp_listen_socket(/*INADDR_ANY,*/ SERVER_PORT, client_ifaces[i-1]); if (fds[i] > n) n = fds[i]; } @@ -170,11 +171,11 @@ /** - * pass_on() - forwards dhcp packets from client to server + * pass_to_server() - forwards dhcp packets from client to server * p - packet to send * client - number of the client */ -static void pass_on(struct dhcpMessage *p, int packet_len, int client, int *fds, +static void pass_to_server(struct dhcpMessage *p, int packet_len, int client, int *fds, struct sockaddr_in *client_addr, struct sockaddr_in *server_addr) { int res, type; @@ -193,19 +194,19 @@ item = 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("pass_on"); - return; + bb_perror_msg("sendto"); } } /** - * pass_back() - forwards dhcp packets from server to client + * pass_to_client() - forwards dhcp packets from server to client * p - packet to send */ -static void pass_back(struct dhcpMessage *p, int packet_len, int *fds) +static void pass_to_client(struct dhcpMessage *p, int packet_len, int *fds) { int res, type; struct xid_item *item; @@ -224,10 +225,11 @@ if (item->ip.sin_addr.s_addr == htonl(INADDR_ANY)) item->ip.sin_addr.s_addr = htonl(INADDR_BROADCAST); - res = sendto(fds[item->client], p, packet_len, 0, (struct sockaddr*)(&item->ip), - sizeof(item->ip)); + 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("pass_back"); + bb_perror_msg("sendto"); return; } @@ -235,20 +237,53 @@ xid_del(p->xid); } -static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients, - struct sockaddr_in *server_addr, uint32_t gw_ip) NORETURN; -static void dhcprelay_loop(int *fds, int num_sockets, int max_socket, char **clients, - struct sockaddr_in *server_addr, uint32_t gw_ip) +int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int dhcprelay_main(int argc, char **argv) { struct dhcpMessage dhcp_msg; + struct sockaddr_in server_addr; + struct sockaddr_in client_addr; fd_set rfds; - size_t packlen; - socklen_t addr_size; - struct sockaddr_in client_addr; - struct timeval tv; - int i; + char **client_ifaces; + int *fds; + int num_sockets, max_socket; + uint32_t our_ip; + server_addr.sin_family = AF_INET; + server_addr.sin_port = htons(SERVER_PORT); + + /* 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 { + bb_show_usage(); + } + + /* Produce list of client ifaces */ + client_ifaces = get_client_devices(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); + + /* Get our IP on server_iface */ + if (udhcp_read_interface(argv[2], NULL, &our_ip, NULL)) + return 1; + + /* Main loop */ while (1) { +//reinit stuff from time to time? go back to get_client_devices +//every N minutes? + struct timeval tv; + size_t packlen; + socklen_t addr_size; + int i; + FD_ZERO(&rfds); for (i = 0; i < num_sockets; i++) FD_SET(fds[i], &rfds); @@ -259,56 +294,32 @@ if (FD_ISSET(fds[0], &rfds)) { packlen = udhcp_recv_kernel_packet(&dhcp_msg, fds[0]); if (packlen > 0) { - pass_back(&dhcp_msg, packlen, fds); + pass_to_client(&dhcp_msg, packlen, fds); } } + /* clients */ for (i = 1; i < num_sockets; i++) { - /* clients */ if (!FD_ISSET(fds[i], &rfds)) continue; addr_size = sizeof(struct sockaddr_in); packlen = recvfrom(fds[i], &dhcp_msg, sizeof(dhcp_msg), 0, - (struct sockaddr *)(&client_addr), &addr_size); + (struct sockaddr *)(&client_addr), &addr_size); if (packlen <= 0) continue; - if (udhcp_read_interface(clients[i-1], NULL, &dhcp_msg.giaddr, NULL)) - dhcp_msg.giaddr = gw_ip; - pass_on(&dhcp_msg, packlen, i, fds, &client_addr, server_addr); + + /* 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.giaddr, NULL)) { + /* Fall back to our server_iface's IP */ +//this makes more sense! + dhcp_msg.giaddr = our_ip; + } +//maybe set dhcp_msg.flags |= BROADCAST_FLAG too? + pass_to_server(&dhcp_msg, packlen, i, fds, &client_addr, &server_addr); } } xid_expire(); - } -} + } /* while (1) */ -int dhcprelay_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int dhcprelay_main(int argc, char **argv) -{ - int num_sockets, max_socket; - int *fds; - uint32_t gw_ip; - char **clients; - struct sockaddr_in server_addr; - - server_addr.sin_family = AF_INET; - server_addr.sin_port = htons(SERVER_PORT); - if (argc == 4) { - if (!inet_aton(argv[3], &server_addr.sin_addr)) - bb_perror_msg_and_die("didn't grok server"); - } else if (argc == 3) { - server_addr.sin_addr.s_addr = htonl(INADDR_BROADCAST); - } else { - bb_show_usage(); - } - - clients = get_client_devices(argv[1], &num_sockets); - num_sockets++; /* for server socket at fds[0] */ - fds = xmalloc(num_sockets * sizeof(fds[0])); - max_socket = init_sockets(clients, num_sockets, argv[2], fds); - - if (udhcp_read_interface(argv[2], NULL, &gw_ip, NULL)) - return 1; - - /* doesn't return */ - dhcprelay_loop(fds, num_sockets, max_socket, clients, &server_addr, gw_ip); /* return 0; - not reached */ } Index: include/usage.h =================================================================== --- include/usage.h (revision 26081) +++ include/usage.h (revision 26082) @@ -802,10 +802,9 @@ "/dev/sda3 17381728 17107080 274648 98% /\n" #define dhcprelay_trivial_usage \ - "[client1,client2,...] [server_device]" + "CLIENT_IFACE[,CLIENT_IFACE2...] SERVER_IFACE [SERVER_IP]" #define dhcprelay_full_usage "\n\n" \ - "Relay dhcp requests from client devices to server device.\n" \ - "Pass clients as CSV" + "Relay DHCP requests between clients and server" \ #define diff_trivial_usage \ "[-abdiNqrTstw] [-L LABEL] [-S FILE] [-U LINES] FILE1 FILE2" ------------------------------------------------------------------------ r26081 | vda | 2009-04-12 21:25:40 -0500 (Sun, 12 Apr 2009) | 7 lines Changed paths: M /trunk/busybox/modutils/insmod.c M /trunk/busybox/modutils/modprobe-small.c M /trunk/busybox/modutils/modutils-24.c M /trunk/busybox/modutils/rmmod.c rmmod: fix bug 263 "modutils/rmmod can't remove modules with dash in name on 2.4 kernels" function old new delta rmmod_main 187 220 +33 ------------------------------------------------------------------------ Index: modutils/rmmod.c =================================================================== --- modutils/rmmod.c (revision 26080) +++ modutils/rmmod.c (revision 26081) @@ -15,12 +15,11 @@ int rmmod_main(int argc UNUSED_PARAM, char **argv) { int n; - unsigned int flags = O_NONBLOCK|O_EXCL; + unsigned flags = O_NONBLOCK | O_EXCL; /* Parse command line. */ n = getopt32(argv, "wfas"); // -s ignored argv += optind; - if (n & 1) // --wait flags &= ~O_NONBLOCK; if (n & 2) // --force @@ -35,11 +34,18 @@ if (!*argv) bb_show_usage(); + n = ENABLE_FEATURE_2_4_MODULES && get_linux_version_code() < KERNEL_VERSION(2,6,0); while (*argv) { char modname[MODULE_NAME_LEN]; - filename2modname(bb_basename(*argv++), modname); + const char *bname; + + bname = bb_basename(*argv++); + if (n) + safe_strncpy(modname, bname, MODULE_NAME_LEN); + else + filename2modname(bname, modname); if (bb_delete_module(modname, flags)) - bb_error_msg_and_die("cannot unload '%s': %s", + bb_error_msg_and_die("can't unload '%s': %s", modname, moderror(errno)); } Index: modutils/modutils-24.c =================================================================== --- modutils/modutils-24.c (revision 26080) +++ modutils/modutils-24.c (revision 26081) @@ -3803,7 +3803,7 @@ if (m_has_modinfo) { int m_version = new_get_module_version(f, m_strversion); if (m_version == -1) { - bb_error_msg_and_die("cannot find the kernel version " + bb_error_msg_and_die("can't find the kernel version " "the module was compiled for"); } } Index: modutils/insmod.c =================================================================== --- modutils/insmod.c (revision 26080) +++ modutils/insmod.c (revision 26081) @@ -35,7 +35,7 @@ rc = bb_init_module(filename, parse_cmdline_module_options(argv)); if (rc) - bb_error_msg("cannot insert '%s': %s", filename, moderror(rc)); + bb_error_msg("can't insert '%s': %s", filename, moderror(rc)); return rc; } Index: modutils/modprobe-small.c =================================================================== --- modutils/modprobe-small.c (revision 26080) +++ modutils/modprobe-small.c (revision 26081) @@ -776,7 +776,7 @@ USE_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE(options ? options : "") SKIP_FEATURE_MODPROBE_SMALL_OPTIONS_ON_CMDLINE("") ) != 0) - bb_error_msg_and_die("cannot insert '%s': %s", + bb_error_msg_and_die("can't insert '%s': %s", *argv, moderror(errno)); return 0; } ------------------------------------------------------------------------ r26080 | vda | 2009-04-12 21:15:57 -0500 (Sun, 12 Apr 2009) | 6 lines Changed paths: M /trunk/busybox/util-linux/mdev.c mdev: ignore events with "$SUBSYSTEM" == "firmware" && "$ACTION" == "remove" function old new delta mdev_main 665 676 +11 ------------------------------------------------------------------------ Index: util-linux/mdev.c =================================================================== --- util-linux/mdev.c (revision 26079) +++ util-linux/mdev.c (revision 26080) @@ -436,11 +436,10 @@ ACTION_RECURSE | ACTION_FOLLOWLINKS, fileAction, dirAction, temp, 0); } else { + char *fw; char *seq; char *action; char *env_path; - char seqbuf[sizeof(int)*3 + 2]; - int seqlen = seqlen; /* for compiler */ /* Hotplug: * env ACTION=... DEVPATH=... [SEQNUM=...] mdev @@ -451,14 +450,23 @@ env_path = getenv("DEVPATH"); if (!action || !env_path) bb_show_usage(); + fw = getenv("FIRMWARE"); + /* If it exists, does /dev/mdev.seq match $SEQNUM? + * If it does not match, earlier mdev is running + * in parallel, and we need to wait */ seq = getenv("SEQNUM"); if (seq) { - int timeout = 2000 / 32; + int timeout = 2000 / 32; /* 2000 msec */ do { + int seqlen; + char seqbuf[sizeof(int)*3 + 2]; + seqlen = open_read_close("mdev.seq", seqbuf, sizeof(seqbuf-1)); - if (seqlen < 0) + if (seqlen < 0) { + seq = NULL; break; + } seqbuf[seqlen] = '\0'; if (seqbuf[0] == '\n' /* seed file? */ || strcmp(seq, seqbuf) == 0 /* correct idx? */ @@ -470,19 +478,22 @@ } snprintf(temp, PATH_MAX, "/sys%s", env_path); - if (!strcmp(action, "remove")) - make_device(temp, 1); - else if (!strcmp(action, "add")) { + if (strcmp(action, "remove") == 0) { + /* Ignoring "remove firmware". It was reported + * to happen and to cause erroneous deletion + * of device nodes. */ + if (!fw) + make_device(temp, 1); + } + else if (strcmp(action, "add") == 0) { make_device(temp, 0); - if (ENABLE_FEATURE_MDEV_LOAD_FIRMWARE) { - char *fw = getenv("FIRMWARE"); if (fw) load_firmware(fw, temp); } } - if (seq && seqlen >= 0) { + if (seq) { xopen_xwrite_close("mdev.seq", utoa(xatou(seq) + 1)); } } ------------------------------------------------------------------------ r26079 | vda | 2009-04-12 19:55:42 -0500 (Sun, 12 Apr 2009) | 4 lines Changed paths: M /trunk/busybox/docs/busybox.net/products.html website: add http://www.dream-multimedia-tv.de/ to list of products using bbox ------------------------------------------------------------------------ Index: docs/busybox.net/products.html =================================================================== --- docs/busybox.net/products.html (revision 26078) +++ docs/busybox.net/products.html (revision 26079) @@ -114,6 +114,7 @@