svn commit: trunk/busybox: applets archival archival/libunarchive c etc...

vda at busybox.net vda at busybox.net
Tue Apr 10 21:40:20 UTC 2007


Author: vda
Date: 2007-04-10 14:40:19 -0700 (Tue, 10 Apr 2007)
New Revision: 18392

Log:
make compressed help code NOMMU- and NOFORK-friendly -
no forking anymore, bunzip2 unpack routine now does all it in memory.


Modified:
   trunk/busybox/applets/applets.c
   trunk/busybox/archival/gzip.c
   trunk/busybox/archival/libunarchive/decompress_bunzip2.c
   trunk/busybox/archival/libunarchive/decompress_unzip.c
   trunk/busybox/archival/libunarchive/get_header_tar_gz.c
   trunk/busybox/coreutils/cksum.c
   trunk/busybox/include/libbb.h
   trunk/busybox/include/unarchive.h
   trunk/busybox/libbb/crc32.c
   trunk/busybox/libbb/vfork_daemon_rexec.c
   trunk/busybox/libbb/xfuncs.c


Changeset:
Modified: trunk/busybox/applets/applets.c
===================================================================
--- trunk/busybox/applets/applets.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/applets/applets.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -403,44 +403,32 @@
 
 static const char *unpack_usage_messages(void)
 {
-	int input[2], output[2], pid;
-	char *buf;
+	char *outbuf = NULL;
+	bunzip_data *bd;
+	int i;
 
-	if (pipe(input) < 0 || pipe(output) < 0)
-		exit(1);
-
-//TODO: not NOMMU friendly!
-	pid = fork();
-	switch (pid) {
-	case -1: /* error */
-		exit(1);
-	case 0: /* child */
-		close(input[1]);
-		close(output[0]);
-		uncompressStream(input[0], output[1]);
-		exit(0);
+	i = start_bunzip(&bd,
+			/* src_fd: */ -1,
+			/* inbuf:  */ packed_usage,
+			/* len:    */ sizeof(packed_usage));
+	/* read_bunzip can longjmp to start_bunzip, and ultimately
+	 * end up here with i != 0 on read data errors! Not trivial */
+	if (!i) {
+		/* Cannot use xmalloc: will leak bd in NOFORK case! */
+		outbuf = malloc_or_warn(SIZEOF_usage_messages);
+		if (outbuf)
+			read_bunzip(bd, outbuf, SIZEOF_usage_messages);
 	}
-	/* parent */
-
-	close(input[0]);
-	close(output[1]);
-	pid = fork();
-	switch (pid) {
-	case -1: /* error */
-		exit(1);
-	case 0: /* child */
-		full_write(input[1], packed_usage, sizeof(packed_usage));
-		exit(0);
-	}
-	/* parent */
-	close(input[1]);
-
-	buf = xmalloc(SIZEOF_usage_messages);
-	full_read(output[0], buf, SIZEOF_usage_messages);
-	return buf;
+	dealloc_bunzip(bd);
+	return outbuf;
 }
+#define dealloc_usage_messages(s) free(s)
+
 #else
+
 #define unpack_usage_messages() usage_messages
+#define dealloc_usage_messages(s) ((void)(s))
+
 #endif /* FEATURE_COMPRESS_USAGE */
 
 
@@ -448,22 +436,23 @@
 {
 	if (ENABLE_SHOW_USAGE) {
 		const char *format_string;
-		const char *usage_string = unpack_usage_messages();
+		const char *p;
+		const char *usage_string = p = unpack_usage_messages();
 		int i;
 
 		i = current_applet - applets;
 		while (i) {
-			while (*usage_string++) continue;
+			while (*p++) continue;
 			i--;
 		}
 
 		format_string = "%s\n\nUsage: %s %s\n\n";
-		if (*usage_string == '\b')
+		if (*p == '\b')
 			format_string = "%s\n\nNo help available.\n\n";
 		fprintf(stderr, format_string, bb_msg_full_version,
-					applet_name, usage_string);
+					applet_name, p);
+		dealloc_usage_messages((char*)usage_string);
 	}
-
 	xfunc_die();
 }
 

Modified: trunk/busybox/archival/gzip.c
===================================================================
--- trunk/busybox/archival/gzip.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/archival/gzip.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -2079,7 +2079,7 @@
 	ALLOC(ush, G1.prev, 1L << BITS);
 
 	/* Initialise the CRC32 table */
-	G1.crc_32_tab = crc32_filltable(0);
+	G1.crc_32_tab = crc32_filltable(NULL, 0);
 
 	return bbunpack(argv, make_new_name_gzip, pack_gzip);
 }

Modified: trunk/busybox/archival/libunarchive/decompress_bunzip2.c
===================================================================
--- trunk/busybox/archival/libunarchive/decompress_bunzip2.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/archival/libunarchive/decompress_bunzip2.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -62,35 +62,32 @@
 /* Structure holding all the housekeeping data, including IO buffers and
    memory that persists between calls to bunzip */
 
-typedef struct {
+struct bunzip_data {
 	/* State for interrupting output loop */
-
 	int writeCopies, writePos, writeRunCountdown, writeCount, writeCurrent;
 
 	/* I/O tracking data (file handles, buffers, positions, etc.) */
-
 	int in_fd, out_fd, inbufCount, inbufPos /*, outbufPos*/;
 	unsigned char *inbuf /*,*outbuf*/;
 	unsigned inbufBitCount, inbufBits;
 
 	/* The CRC values stored in the block header and calculated from the data */
+	uint32_t headerCRC, totalCRC, writeCRC;
 
-	uint32_t headerCRC, totalCRC, writeCRC;
-	uint32_t *crc32Table;
 	/* Intermediate buffer and its size (in bytes) */
-
 	unsigned *dbuf, dbufSize;
 
-	/* These things are a bit too big to go on the stack */
+	/* For I/O error handling */
+	jmp_buf jmpbuf;
 
+	/* Big things go last (register-relative addressing can be larger for big offsets */
+	uint32_t crc32Table[256];
 	unsigned char selectors[32768];			/* nSelectors=15 bits */
 	struct group_data groups[MAX_GROUPS];	/* Huffman coding tables */
+};
+/* typedef struct bunzip_data bunzip_data; -- done in .h file */
 
-	/* For I/O error handling */
 
-	jmp_buf jmpbuf;
-} bunzip_data;
-
 /* Return the next nnn bits of input.  All reads from the compressed input
    are done through this function.  All reads are big endian */
 
@@ -106,6 +103,7 @@
 		/* If we need to read more data from file into byte buffer, do so */
 
 		if (bd->inbufPos == bd->inbufCount) {
+			/* if "no input fd" case: in_fd == -1, read fails, we jump */
 			bd->inbufCount = read(bd->in_fd, bd->inbuf, IOBUF_SIZE);
 			if (bd->inbufCount <= 0)
 				longjmp(bd->jmpbuf, RETVAL_UNEXPECTED_INPUT_EOF);
@@ -519,7 +517,7 @@
    are ignored, data is written to out_fd and return is RETVAL_OK or error.
 */
 
-static int read_bunzip(bunzip_data *bd, char *outbuf, int len)
+int read_bunzip(bunzip_data *bd, char *outbuf, int len)
 {
 	const unsigned *dbuf;
 	int pos, current, previous, gotcount;
@@ -627,11 +625,16 @@
 	goto decode_next_byte;
 }
 
+
 /* Allocate the structure, read file header.  If in_fd==-1, inbuf must contain
    a complete bunzip file (len bytes long).  If in_fd!=-1, inbuf and len are
    ignored, and data is read from file handle into temporary buffer. */
 
-static int start_bunzip(bunzip_data **bdp, int in_fd, unsigned char *inbuf,
+/* Because bunzip2 is used for help text unpacking, and because bb_show_usage()
+   should work for NOFORK applets too, we must be extremely careful to not leak
+   any allocations! */
+
+int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf,
 						int len)
 {
 	bunzip_data *bd;
@@ -653,14 +656,15 @@
 
 	bd->in_fd = in_fd;
 	if (-1 == in_fd) {
-		bd->inbuf = inbuf;
+		/* in this case, bd->inbuf is read-only */
+		bd->inbuf = (void*)inbuf; /* cast away const-ness */
 		bd->inbufCount = len;
 	} else
 		bd->inbuf = (unsigned char *)(bd + 1);
 
 	/* Init the CRC32 table (big endian) */
 
-	bd->crc32Table = crc32_filltable(1);
+	crc32_filltable(bd->crc32Table, 1);
 
 	/* Setup for I/O error handling via longjmp */
 
@@ -670,20 +674,31 @@
 	/* Ensure that file starts with "BZh['1'-'9']." */
 
 	i = get_bits(bd, 32);
-	if (((unsigned)(i - BZh0 - 1)) >= 9) return RETVAL_NOT_BZIP_DATA;
+	if ((unsigned)(i - BZh0 - 1) >= 9) return RETVAL_NOT_BZIP_DATA;
 
 	/* Fourth byte (ascii '1'-'9'), indicates block size in units of 100k of
 	   uncompressed data.  Allocate intermediate buffer for block. */
 
 	bd->dbufSize = 100000 * (i - BZh0);
 
-	bd->dbuf = xmalloc(bd->dbufSize * sizeof(int));
+	/* Cannot use xmalloc - may leak bd in NOFORK case! */
+	bd->dbuf = malloc_or_warn(bd->dbufSize * sizeof(int));
+	if (!bd->dbuf) {
+		free(bd);
+		xfunc_die();
+	}
 	return RETVAL_OK;
 }
 
-/* Example usage: decompress src_fd to dst_fd.  (Stops at end of bzip data,
-   not end of file.) */
+void dealloc_bunzip(bunzip_data *bd)
+{
+        free(bd->dbuf);
+        free(bd);
+}
 
+
+/* Decompress src_fd to dst_fd.  Stops at end of bzip data, not end of file. */
+
 USE_DESKTOP(long long) int
 uncompressStream(int src_fd, int dst_fd)
 {
@@ -693,7 +708,7 @@
 	int i;
 
 	outbuf = xmalloc(IOBUF_SIZE);
-	i = start_bunzip(&bd, src_fd, 0, 0);
+	i = start_bunzip(&bd, src_fd, NULL, 0);
 	if (!i) {
 		for (;;) {
 			i = read_bunzip(bd, outbuf, IOBUF_SIZE);
@@ -719,8 +734,7 @@
 	} else {
 		bb_error_msg("decompression failed");
 	}
-	free(bd->dbuf);
-	free(bd);
+	dealloc_bunzip(bd);
 	free(outbuf);
 
 	return i ? i : USE_DESKTOP(total_written) + 0;

Modified: trunk/busybox/archival/libunarchive/decompress_unzip.c
===================================================================
--- trunk/busybox/archival/libunarchive/decompress_unzip.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/archival/libunarchive/decompress_unzip.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -1000,7 +1000,7 @@
 	gunzip_bb = 0;
 
 	/* Create the crc table */
-	gunzip_crc_table = crc32_filltable(0);
+	gunzip_crc_table = crc32_filltable(NULL, 0);
 	gunzip_crc = ~0;
 
 	/* Allocate space for buffer */

Modified: trunk/busybox/archival/libunarchive/get_header_tar_gz.c
===================================================================
--- trunk/busybox/archival/libunarchive/get_header_tar_gz.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/archival/libunarchive/get_header_tar_gz.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -3,8 +3,6 @@
  * Licensed under GPLv2 or later, see file LICENSE in this tarball for details.
  */
 
-#include <stdlib.h>
-
 #include "libbb.h"
 #include "unarchive.h"
 

Modified: trunk/busybox/coreutils/cksum.c
===================================================================
--- trunk/busybox/coreutils/cksum.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/coreutils/cksum.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -11,9 +11,8 @@
 int cksum_main(int argc, char **argv);
 int cksum_main(int argc, char **argv)
 {
+	uint32_t *crc32_table = crc32_filltable(NULL, 1);
 
-	uint32_t *crc32_table = crc32_filltable(1);
-
 	FILE *fp;
 	uint32_t crc;
 	long length, filesize;

Modified: trunk/busybox/include/libbb.h
===================================================================
--- trunk/busybox/include/libbb.h	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/include/libbb.h	2007-04-10 21:40:19 UTC (rev 18392)
@@ -403,9 +403,10 @@
 
 /* dmalloc will redefine these to it's own implementation. It is safe
  * to have the prototypes here unconditionally.  */
+extern void *malloc_or_warn(size_t size);
 extern void *xmalloc(size_t size);
+extern void *xzalloc(size_t size);
 extern void *xrealloc(void *old, size_t size);
-extern void *xzalloc(size_t size);
 
 extern ssize_t safe_read(int fd, void *buf, size_t count);
 extern ssize_t full_read(int fd, void *buf, size_t count);
@@ -862,7 +863,7 @@
 void md5_hash(const void *data, size_t length, md5_ctx_t *ctx);
 void *md5_end(void *resbuf, md5_ctx_t *ctx);
 
-uint32_t *crc32_filltable(int endian);
+uint32_t *crc32_filltable(uint32_t *tbl256, int endian);
 
 
 enum {	/* DO NOT CHANGE THESE VALUES!  cp.c, mv.c, install.c depend on them. */

Modified: trunk/busybox/include/unarchive.h
===================================================================
--- trunk/busybox/include/unarchive.h	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/include/unarchive.h	2007-04-10 21:40:19 UTC (rev 18392)
@@ -102,6 +102,11 @@
 extern const llist_t *find_list_entry2(const llist_t *list, const char *filename);
 
 extern USE_DESKTOP(long long) int uncompressStream(int src_fd, int dst_fd);
+/* A bit of bunzip2 internals are exposed for compressed help support: */
+typedef struct bunzip_data bunzip_data;
+int start_bunzip(bunzip_data **bdp, int in_fd, const unsigned char *inbuf, int len);
+int read_bunzip(bunzip_data *bd, char *outbuf, int len);
+void dealloc_bunzip(bunzip_data *bd);
 
 typedef struct inflate_unzip_result {
 	off_t bytes_out;

Modified: trunk/busybox/libbb/crc32.c
===================================================================
--- trunk/busybox/libbb/crc32.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/libbb/crc32.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -16,14 +16,15 @@
 
 #include "libbb.h"
 
-uint32_t *crc32_filltable(int endian)
+uint32_t *crc32_filltable(uint32_t *crc_table, int endian)
 {
-
-	uint32_t *crc_table = xmalloc(256 * sizeof(uint32_t));
 	uint32_t polynomial = endian ? 0x04c11db7 : 0xedb88320;
 	uint32_t c;
 	int i, j;
 
+	if (!crc_table)
+		crc_table = xmalloc(256 * sizeof(uint32_t));
+
 	for (i = 0; i < 256; i++) {
 		c = endian ? (i << 24) : i;
 		for (j = 8; j; j--) {

Modified: trunk/busybox/libbb/vfork_daemon_rexec.c
===================================================================
--- trunk/busybox/libbb/vfork_daemon_rexec.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/libbb/vfork_daemon_rexec.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -102,121 +102,69 @@
 
 int spawn_and_wait(char **argv)
 {
+#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
 	int rc;
+	const struct bb_applet *a = find_applet_by_name(argv[0]);
 
-#if ENABLE_FEATURE_EXEC_PREFER_APPLETS
-	{
-		const struct bb_applet *a = find_applet_by_name(argv[0]);
-		if (a && (a->nofork
+	if (a && (a->nofork
 #ifndef BB_NOMMU
-			 || a->noexec /* NOEXEC cannot be used on NOMMU */
+		 || a->noexec /* NOEXEC cannot be used on NOMMU */
 #endif
-		)) {
-			int argc = 1;
-			char **pp = argv;
-			while (*++pp)
-				argc++;
+	)) {
+		int argc = 1;
+		char **pp = argv;
+		while (*++pp)
+			argc++;
 #ifndef BB_NOMMU
-			if (a->nofork)
+		if (a->nofork)
 #endif
-			{
-				int old_sleep = die_sleep;
-				int old_x = xfunc_error_retval;
-				die_sleep = -1; /* special flag */
-				/* xfunc_die() checks for it */
+		{
+			int old_sleep = die_sleep;
+			int old_x = xfunc_error_retval;
+			die_sleep = -1; /* special flag */
+			/* xfunc_die() checks for it */
 
-				rc = setjmp(die_jmp);
-				if (!rc) {
-					const struct bb_applet *old_a = current_applet;
-					current_applet = a;
-					applet_name = a->name;
+			rc = setjmp(die_jmp);
+			if (!rc) {
+				const struct bb_applet *old_a = current_applet;
+				current_applet = a;
+				applet_name = a->name;
 // what else should we save/restore?
-					rc = a->main(argc, argv);
-					current_applet = old_a;
-					applet_name = old_a->name;					
-				} else {
-					/* xfunc died in NOFORK applet */
-					if (rc == -111)
-						rc = 0;
-				}
-
-				die_sleep = old_sleep;
-				xfunc_error_retval = old_x;
-				return rc;
+// TODO: what if applet will mangle argv vector?
+// xargs needs argv untouched because it frees the vector!
+// shouldn't we pass a copy?
+				rc = a->main(argc, argv);
+				current_applet = old_a;
+				applet_name = old_a->name;					
+			} else {
+				/* xfunc died in NOFORK applet */
+				if (rc == -111)
+					rc = 0;
 			}
+
+			die_sleep = old_sleep;
+			xfunc_error_retval = old_x;
+			return rc;
+		}
 #ifndef BB_NOMMU	/* MMU only */
-			/* a->noexec is true */
-			rc = fork();
-			if (rc)
-				goto w;
-			/* child */
-			current_applet = a;
-			run_current_applet_and_exit(argc, argv);
+		/* a->noexec is true */
+		rc = fork();
+		if (rc)
+			goto w;
+		/* child */
+		current_applet = a;
+		run_current_applet_and_exit(argc, argv);
 #endif
-		}
-
 	}
 	rc = spawn(argv);
  w:
-#else /* !FEATURE_EXEC_PREFER_APPLETS */
-	rc = spawn(argv);
-#endif /* FEATURE_EXEC_PREFER_APPLETS */
 	return wait4pid(rc);
-}
-
-
-#if 0 //ndef BB_NOMMU
-// Die with an error message if we can't daemonize.
-void xdaemon(int nochdir, int noclose)
-{
-	if (daemon(nochdir, noclose))
-		bb_perror_msg_and_die("daemon");
-}
+#else /* !FEATURE_EXEC_PREFER_APPLETS */
+	return wait4pid(spawn(argv));
 #endif
-
-#if 0 // def BB_NOMMU
-void vfork_daemon_rexec(int nochdir, int noclose, char **argv)
-{
-	int fd;
-
-	/* Maybe we are already re-execed and come here again? */
-	if (re_execed)
-		return;
-
-	setsid();
-
-	if (!nochdir)
-		xchdir("/");
-
-	if (!noclose) {
-		/* if "/dev/null" doesn't exist, bail out! */
-		fd = xopen(bb_dev_null, O_RDWR);
-		dup2(fd, STDIN_FILENO);
-		dup2(fd, STDOUT_FILENO);
-		dup2(fd, STDERR_FILENO);
-		while (fd > 2)
-			close(fd--);
-	}
-
-	switch (vfork()) {
-	case 0: /* child */
-		/* Make certain we are not a session leader, or else we
-		 * might reacquire a controlling terminal */
-		if (vfork())
-			_exit(0);
-		/* High-order bit of first char in argv[0] is a hidden
-		 * "we have (alrealy) re-execed, don't do it again" flag */
-		argv[0][0] |= 0x80;
-		execv(CONFIG_BUSYBOX_EXEC_PATH, argv);
-		bb_perror_msg_and_die("exec %s", CONFIG_BUSYBOX_EXEC_PATH);
-	case -1: /* error */
-		bb_perror_msg_and_die("vfork");
-	default: /* parent */
-		exit(0);
-	}
 }
-#endif /* BB_NOMMU */
 
+
 #ifdef BB_NOMMU
 void forkexit_or_rexec(char **argv)
 {

Modified: trunk/busybox/libbb/xfuncs.c
===================================================================
--- trunk/busybox/libbb/xfuncs.c	2007-04-10 21:38:30 UTC (rev 18391)
+++ trunk/busybox/libbb/xfuncs.c	2007-04-10 21:40:19 UTC (rev 18392)
@@ -20,6 +20,15 @@
  * Since dmalloc's prototypes overwrite the impls here as they are
  * included after these prototypes in libbb.h, all is well.
  */
+// Warn if we can't allocate size bytes of memory.
+void *malloc_or_warn(size_t size)
+{
+	void *ptr = malloc(size);
+	if (ptr == NULL && size != 0)
+		bb_error_msg(bb_msg_memory_exhausted);
+	return ptr;
+}
+
 // Die if we can't allocate size bytes of memory.
 void *xmalloc(size_t size)
 {




More information about the busybox-cvs mailing list